Browse Source

[MRM-138] rewritten the proxy and cleaned house. Moved maven-proxy config loader to config module and boosted tests. More tests still needed on proxy, core and webapp.

git-svn-id: https://svn.apache.org/repos/asf/maven/repository-manager/trunk@430971 13f79535-47bb-0310-9956-ffa450edef68
tags/archiva-0.9-alpha-1
Brett Porter 18 years ago
parent
commit
d6f70d5e23
37 changed files with 1566 additions and 1910 deletions
  1. 11
    2
      maven-repository-configuration/pom.xml
  2. 1
    0
      maven-repository-configuration/src/main/java/org/apache/maven/repository/configuration/ConfigurationStore.java
  3. 3
    1
      maven-repository-configuration/src/main/java/org/apache/maven/repository/configuration/DefaultConfigurationStore.java
  4. 6
    0
      maven-repository-configuration/src/main/java/org/apache/maven/repository/configuration/InvalidConfigurationException.java
  5. 38
    51
      maven-repository-configuration/src/main/java/org/apache/maven/repository/configuration/MavenProxyPropertyLoader.java
  6. 20
    2
      maven-repository-configuration/src/main/mdo/configuration.mdo
  7. 16
    0
      maven-repository-configuration/src/test/conf/corrupt.xml
  8. 0
    0
      maven-repository-configuration/src/test/conf/maven-proxy-complete.conf
  9. 53
    0
      maven-repository-configuration/src/test/conf/repository-manager.xml
  10. 150
    0
      maven-repository-configuration/src/test/java/org/apache/maven/repository/configuration/ConfigurationStoreTest.java
  11. 103
    0
      maven-repository-configuration/src/test/java/org/apache/maven/repository/configuration/MavenProxyPropertyLoaderTest.java
  12. 52
    0
      maven-repository-configuration/src/test/resources/org/apache/maven/repository/configuration/ConfigurationStoreTest.xml
  13. 4
    7
      maven-repository-core/pom.xml
  14. 16
    0
      maven-repository-core/src/main/java/org/apache/maven/repository/configuration/ConfiguredRepositoryFactory.java
  15. 45
    2
      maven-repository-core/src/main/java/org/apache/maven/repository/configuration/DefaultConfiguredRepositoryFactory.java
  16. 190
    0
      maven-repository-core/src/main/java/org/apache/maven/repository/proxy/DefaultProxyManager.java
  17. 92
    0
      maven-repository-core/src/main/java/org/apache/maven/repository/proxy/ProxiedRepositoryGroup.java
  18. 6
    12
      maven-repository-core/src/main/java/org/apache/maven/repository/proxy/ProxyManager.java
  19. 1
    1
      maven-repository-core/src/main/java/org/apache/maven/repository/scheduler/DefaultRepositoryTaskScheduler.java
  20. 15
    0
      maven-repository-indexer/pom.xml
  21. 2
    6
      maven-repository-proxy/pom.xml
  22. 0
    722
      maven-repository-proxy/src/main/java/org/apache/maven/repository/proxy/DefaultProxyManager.java
  23. 507
    0
      maven-repository-proxy/src/main/java/org/apache/maven/repository/proxy/DefaultProxyRequestHandler.java
  24. 107
    0
      maven-repository-proxy/src/main/java/org/apache/maven/repository/proxy/ProxiedArtifactRepository.java
  25. 101
    0
      maven-repository-proxy/src/main/java/org/apache/maven/repository/proxy/ProxyRequestHandler.java
  26. 0
    221
      maven-repository-proxy/src/main/java/org/apache/maven/repository/proxy/configuration/ProxyConfiguration.java
  27. 0
    40
      maven-repository-proxy/src/main/java/org/apache/maven/repository/proxy/configuration/ValidationException.java
  28. 0
    105
      maven-repository-proxy/src/main/java/org/apache/maven/repository/proxy/repository/ProxyRepository.java
  29. 0
    154
      maven-repository-proxy/src/test/java/org/apache/maven/repository/proxy/LegacyProxyManagerTest.java
  30. 26
    52
      maven-repository-proxy/src/test/java/org/apache/maven/repository/proxy/ProxyRequestHandlerTest.java
  31. 0
    86
      maven-repository-proxy/src/test/java/org/apache/maven/repository/proxy/configuration/MavenProxyPropertyLoaderTest.java
  32. 0
    137
      maven-repository-proxy/src/test/java/org/apache/maven/repository/proxy/configuration/ProxyConfigurationTest.java
  33. 0
    19
      maven-repository-webapp/pom.xml
  34. 0
    154
      maven-repository-webapp/src/main/java/org/apache/maven/repository/proxy/web/action/RepositoryProxyAction.java
  35. 0
    77
      maven-repository-webapp/src/test/java/org/apache/maven/repository/proxy/web/action/test/RepositoryProxyActionTest.java
  36. 0
    58
      maven-repository-webapp/src/test/java/org/apache/maven/repository/proxy/web/action/test/stub/ProxyManagerStub.java
  37. 1
    1
      pom.xml

+ 11
- 2
maven-repository-configuration/pom.xml View File

@@ -18,6 +18,12 @@
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-utils</artifactId>
</dependency>
<dependency>
<groupId>easymock</groupId>
<artifactId>easymock</artifactId>
<version>1.2_Java1.3</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
@@ -44,9 +50,12 @@
<artifactId>cobertura-maven-plugin</artifactId>
<configuration>
<instrumentation>
<!-- TODO: should this module have tests? -->
<!-- exclude generated -->
<excludes>
<exclude>**/**</exclude>
<exclude>org/apache/maven/repository/configuration/io/**</exclude>
<exclude>org/apache/maven/repository/configuration/*RepositoryConfiguration.*</exclude>
<exclude>org/apache/maven/repository/configuration/Configuration.*</exclude>
<exclude>org/apache/maven/repository/configuration/Proxy.*</exclude>
</excludes>
</instrumentation>
</configuration>

+ 1
- 0
maven-repository-configuration/src/main/java/org/apache/maven/repository/configuration/ConfigurationStore.java View File

@@ -33,6 +33,7 @@ public interface ConfigurationStore
* Get the configuration from the store. A cached version may be used.
*
* @return the configuration
* @throws ConfigurationStoreException if there is a problem loading the configuration
*/
Configuration getConfigurationFromStore()
throws ConfigurationStoreException;

+ 3
- 1
maven-repository-configuration/src/main/java/org/apache/maven/repository/configuration/DefaultConfigurationStore.java View File

@@ -39,7 +39,7 @@ import java.util.List;
* @todo would be great for plexus to do this for us - so the configuration would be a component itself rather than this store
* @todo would be good to monitor the store file for changes
* @todo support other implementations than XML file
* @plexus.component role="org.apache.maven.repository.configuration.ConfigurationStore"
* @plexus.component
*/
public class DefaultConfigurationStore
extends AbstractLogEnabled
@@ -121,6 +121,8 @@ public class DefaultConfigurationStore
FileWriter fileWriter = null;
try
{
file.getParentFile().mkdirs();

fileWriter = new FileWriter( file );
writer.write( fileWriter, configuration );
}

+ 6
- 0
maven-repository-configuration/src/main/java/org/apache/maven/repository/configuration/InvalidConfigurationException.java View File

@@ -26,6 +26,12 @@ public class InvalidConfigurationException
{
private final String name;

public InvalidConfigurationException( String name, String message )
{
super( message );
this.name = name;
}

public InvalidConfigurationException( String name, String message, Throwable cause )
{
super( message, cause );

maven-repository-proxy/src/main/java/org/apache/maven/repository/proxy/configuration/MavenProxyPropertyLoader.java → maven-repository-configuration/src/main/java/org/apache/maven/repository/configuration/MavenProxyPropertyLoader.java View File

@@ -1,4 +1,4 @@
package org.apache.maven.repository.proxy.configuration;
package org.apache.maven.repository.configuration;

/*
* Copyright 2005-2006 The Apache Software Foundation.
@@ -16,20 +16,17 @@ package org.apache.maven.repository.proxy.configuration;
* limitations under the License.
*/

import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout;
import org.apache.maven.repository.proxy.repository.ProxyRepository;
import org.codehaus.plexus.util.StringUtils;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Properties;
import java.util.StringTokenizer;

/**
* @author Ben Walding
* @author Brett Porter
*/
public class MavenProxyPropertyLoader
{
@@ -39,16 +36,19 @@ public class MavenProxyPropertyLoader

private static final String REPO_LIST = "repo.list";

public ProxyConfiguration load( Properties props )
throws ValidationException
public void load( Properties props, Configuration configuration )
throws InvalidConfigurationException
{
ProxyConfiguration config = new ProxyConfiguration();
// set up the managed repository
String localCachePath = getMandatoryProperty( props, REPO_LOCAL_STORE );

config.setLayout( "default" );
RepositoryConfiguration config = new RepositoryConfiguration();
config.setDirectory( localCachePath );
config.setName( "Imported Maven-Proxy Cache" );
config.setId( "maven-proxy" );
configuration.addRepository( config );

config.setRepositoryCachePath( getMandatoryProperty( props, REPO_LOCAL_STORE ) );

//just get the first proxy and break
//just get the first HTTP proxy and break
String propertyList = props.getProperty( PROXY_LIST );
if ( propertyList != null )
{
@@ -58,21 +58,15 @@ public class MavenProxyPropertyLoader
String key = tok.nextToken();
if ( StringUtils.isNotEmpty( key ) )
{
String host = getMandatoryProperty( props, "proxy." + key + ".host" );
int port = Integer.parseInt( getMandatoryProperty( props, "proxy." + key + ".port" ) );
Proxy proxy = new Proxy();
proxy.setHost( getMandatoryProperty( props, "proxy." + key + ".host" ) );
proxy.setPort( Integer.parseInt( getMandatoryProperty( props, "proxy." + key + ".port" ) ) );

// the username and password isn't required
String username = props.getProperty( "proxy." + key + ".username" );
String password = props.getProperty( "proxy." + key + ".password" );

if ( StringUtils.isNotEmpty( username ) )
{
config.setHttpProxy( host, port, username, password );
}
else
{
config.setHttpProxy( host, port );
}
proxy.setUsername( props.getProperty( "proxy." + key + ".username" ) );
proxy.setPassword( props.getProperty( "proxy." + key + ".password" ) );

configuration.setProxy( proxy );

//accept only one proxy configuration
break;
@@ -80,8 +74,6 @@ public class MavenProxyPropertyLoader
}
}

List repositories = new ArrayList();

//get the remote repository list
String repoList = getMandatoryProperty( props, REPO_LIST );

@@ -97,26 +89,21 @@ public class MavenProxyPropertyLoader
boolean cacheFailures =
Boolean.valueOf( repoProps.getProperty( "cache.failures", "false" ) ).booleanValue();
boolean hardFail = Boolean.valueOf( repoProps.getProperty( "hardfail", "true" ) ).booleanValue();
long cachePeriod = Long.parseLong( repoProps.getProperty( "cache.period", "0" ) );

ProxyRepository repository =
new ProxyRepository( key, url, new DefaultRepositoryLayout(), cacheFailures, cachePeriod );

repository.setHardfail( hardFail );

if ( StringUtils.isNotEmpty( proxyKey ) )
{
repository.setProxied( true );
}

repositories.add( repository );
int cachePeriod = Integer.parseInt( repoProps.getProperty( "cache.period", "60" ) );

ProxiedRepositoryConfiguration repository = new ProxiedRepositoryConfiguration();
repository.setId( key );
repository.setLayout( "legacy" );
repository.setManagedRepository( config.getId() );
repository.setName( "Imported Maven-Proxy Remote Proxy" );
repository.setSnapshotsInterval( cachePeriod );
repository.setUrl( url );
repository.setUseNetworkProxy( StringUtils.isNotEmpty( proxyKey ) );
repository.setCacheFailures( cacheFailures );
repository.setHardFail( hardFail );

configuration.addProxiedRepository( repository );
}

config.setRepositories( repositories );

config.validate();

return config;
}

private Properties getSubset( Properties props, String prefix )
@@ -136,22 +123,22 @@ public class MavenProxyPropertyLoader
return result;
}

public ProxyConfiguration load( InputStream is )
throws IOException, ValidationException
public void load( InputStream is, Configuration configuration )
throws IOException, InvalidConfigurationException
{
Properties props = new Properties();
props.load( is );
return load( props );
load( props, configuration );
}

private String getMandatoryProperty( Properties props, String key )
throws ValidationException
throws InvalidConfigurationException
{
String value = props.getProperty( key );

if ( value == null )
{
throw new ValidationException( "Missing property: " + key );
throw new InvalidConfigurationException( key, "Missing required field: " + key );
}

return value;

+ 20
- 2
maven-repository-configuration/src/main/mdo/configuration.mdo View File

@@ -329,7 +329,7 @@
<field>
<name>snapshotsInterval</name>
<version>1.0.0</version>
<type>String</type>
<type>int</type>
<description>
The interval in minutes before updating snapshots if the policy is set to 'interval'.
</description>
@@ -347,7 +347,7 @@
<field>
<name>releasesInterval</name>
<version>1.0.0</version>
<type>String</type>
<type>int</type>
<description>
The interval in minutes before updating releases if the policy is set to 'interval'.
</description>
@@ -361,6 +361,24 @@
Whether to use the network proxy, if one is configured for the protocol of this repository.
</description>
</field>
<field>
<name>cacheFailures</name>
<version>1.0.0</version>
<type>boolean</type>
<defaultValue>false</defaultValue>
<description>
Whether to cache failures to avoid re-attempting them over the network.
</description>
</field>
<field>
<name>hardFail</name>
<version>1.0.0</version>
<type>boolean</type>
<defaultValue>false</defaultValue>
<description>
Whether to cause the entire request to fail if attempts to retrieve from this proxy fail.
</description>
</field>
</fields>
</class>
<class>

+ 16
- 0
maven-repository-configuration/src/test/conf/corrupt.xml View File

@@ -0,0 +1,16 @@
<!--
~ Copyright 2005-2006 The Apache Software Foundation.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->


maven-repository-proxy/src/test/conf/maven-proxy-complete.conf → maven-repository-configuration/src/test/conf/maven-proxy-complete.conf View File


+ 53
- 0
maven-repository-configuration/src/test/conf/repository-manager.xml View File

@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>

<!--
~ Copyright 2005-2006 The Apache Software Foundation.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->

<configuration>
<repositories>
<repository>
<directory>managed-repository</directory>
<id>local</id>
<name>local</name>
</repository>
</repositories>
<proxiedRepositories>
<proxiedRepository>
<url>http://www.ibiblio.org/maven2/</url>
<managedRepository>local</managedRepository>
<snapshotsInterval></snapshotsInterval>
<releasesInterval></releasesInterval>
<useNetworkProxy>true</useNetworkProxy>
<id>ibiblio</id>
<name>Ibiblio</name>
</proxiedRepository>
</proxiedRepositories>
<syncedRepositories>
<syncedRepository>
<id>apache</id>
<name>ASF</name>
<cronExpression>0 0 * * * ?</cronExpression>
<managedRepository>local</managedRepository>
<method>rsync</method>
<properties>
<rsyncHost>host</rsyncHost>
<rsyncMethod>ssh</rsyncMethod>
</properties>
</syncedRepository>
</syncedRepositories>
<localRepository>local-repository</localRepository>
<indexPath>.index</indexPath>
</configuration>

+ 150
- 0
maven-repository-configuration/src/test/java/org/apache/maven/repository/configuration/ConfigurationStoreTest.java View File

@@ -0,0 +1,150 @@
package org.apache.maven.repository.configuration;

import org.codehaus.plexus.PlexusTestCase;
import org.easymock.MockControl;

import java.io.File;
import java.util.Properties;

/*
* Copyright 2005-2006 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/**
* Test the configuration store.
*
* @author <a href="mailto:brett@apache.org">Brett Porter</a>
*/
public class ConfigurationStoreTest
extends PlexusTestCase
{
public void testInvalidFile()
throws Exception
{
ConfigurationStore configurationStore = (ConfigurationStore) lookup( ConfigurationStore.ROLE, "invalid-file" );

Configuration configuration = configurationStore.getConfigurationFromStore();

// check default configuration
assertNotNull( "check configuration returned", configuration );
assertEquals( "check configuration has default elements", "0 0 * * * ?",
configuration.getIndexerCronExpression() );
assertNull( "check configuration has default elements", configuration.getIndexPath() );
assertTrue( "check configuration has default elements", configuration.getRepositories().isEmpty() );
}

public void testCorruptFile()
throws Exception
{
ConfigurationStore configurationStore = (ConfigurationStore) lookup( ConfigurationStore.ROLE, "corrupt-file" );

try
{
configurationStore.getConfigurationFromStore();
fail( "Configuration should not have succeeded" );
}
catch ( ConfigurationStoreException e )
{
// expected
assertTrue( true );
}
}

public void testGetConfiguration()
throws Exception
{
ConfigurationStore configurationStore = (ConfigurationStore) lookup( ConfigurationStore.ROLE, "default" );

Configuration configuration = configurationStore.getConfigurationFromStore();

assertEquals( "check indexPath", ".index", configuration.getIndexPath() );
assertEquals( "check localRepository", "local-repository", configuration.getLocalRepository() );

assertEquals( "check managed repositories", 1, configuration.getRepositories().size() );
RepositoryConfiguration repository =
(RepositoryConfiguration) configuration.getRepositories().iterator().next();

assertEquals( "check managed repositories", "managed-repository", repository.getDirectory() );
assertEquals( "check managed repositories", "local", repository.getName() );
assertEquals( "check managed repositories", "local", repository.getId() );
assertEquals( "check managed repositories", "default", repository.getLayout() );
assertTrue( "check managed repositories", repository.isIndexed() );

assertEquals( "check proxied repositories", 1, configuration.getProxiedRepositories().size() );
ProxiedRepositoryConfiguration proxiedRepository =
(ProxiedRepositoryConfiguration) configuration.getProxiedRepositories().iterator().next();

assertEquals( "check proxied repositories", "local", proxiedRepository.getManagedRepository() );
assertEquals( "check proxied repositories", "http://www.ibiblio.org/maven2/", proxiedRepository.getUrl() );
assertEquals( "check proxied repositories", "ibiblio", proxiedRepository.getId() );
assertEquals( "check proxied repositories", "Ibiblio", proxiedRepository.getName() );
assertEquals( "check proxied repositories", 0, proxiedRepository.getSnapshotsInterval() );
assertEquals( "check proxied repositories", 0, proxiedRepository.getReleasesInterval() );
assertTrue( "check proxied repositories", proxiedRepository.isUseNetworkProxy() );

assertEquals( "check synced repositories", 1, configuration.getSyncedRepositories().size() );
SyncedRepositoryConfiguration syncedRepository =
(SyncedRepositoryConfiguration) configuration.getSyncedRepositories().iterator().next();

assertEquals( "check synced repositories", "local", syncedRepository.getManagedRepository() );
assertEquals( "check synced repositories", "apache", syncedRepository.getId() );
assertEquals( "check synced repositories", "ASF", syncedRepository.getName() );
assertEquals( "check synced repositories", "0 0 * * * ?", syncedRepository.getCronExpression() );
assertEquals( "check synced repositories", "rsync", syncedRepository.getMethod() );
Properties properties = new Properties();
properties.setProperty( "rsyncHost", "host" );
properties.setProperty( "rsyncMethod", "ssh" );
assertEquals( "check synced repositories", properties, syncedRepository.getProperties() );
}

public void testStoreConfiguration()
throws Exception
{
ConfigurationStore configurationStore = (ConfigurationStore) lookup( ConfigurationStore.ROLE, "save-file" );

Configuration configuration = new Configuration();
configuration.setIndexPath( "index-path" );

File file = getTestFile( "target/test/test-file.xml" );
file.delete();
assertFalse( file.exists() );

configurationStore.storeConfiguration( configuration );

assertTrue( "Check file exists", file.exists() );

// read it back
configuration = configurationStore.getConfigurationFromStore();
assertEquals( "check value", "index-path", configuration.getIndexPath() );
}

public void testChangeListeners()
throws Exception
{
ConfigurationStore configurationStore = (ConfigurationStore) lookup( ConfigurationStore.ROLE, "save-file" );

MockControl control = MockControl.createControl( ConfigurationChangeListener.class );
ConfigurationChangeListener mock = (ConfigurationChangeListener) control.getMock();
configurationStore.addChangeListener( mock );

Configuration configuration = new Configuration();
mock.notifyOfConfigurationChange( configuration );
control.replay();

configurationStore.storeConfiguration( configuration );

control.verify();
}
}

+ 103
- 0
maven-repository-configuration/src/test/java/org/apache/maven/repository/configuration/MavenProxyPropertyLoaderTest.java View File

@@ -0,0 +1,103 @@
package org.apache.maven.repository.configuration;

/*
* Copyright 2005-2006 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import org.codehaus.plexus.PlexusTestCase;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.List;
import java.util.Properties;

/**
* @author Edwin Punzalan
*/
public class MavenProxyPropertyLoaderTest
extends PlexusTestCase
{
private static final int DEFAULT_CACHE_PERIOD = 3600;

private MavenProxyPropertyLoader loader;

public void testLoadValidMavenProxyConfiguration()
throws IOException, InvalidConfigurationException
{
File confFile = getTestFile( "src/test/conf/maven-proxy-complete.conf" );

Configuration configuration = new Configuration();
Proxy proxy = new Proxy();
proxy.setHost( "original-host" );
configuration.setProxy( proxy ); // overwritten
configuration.setIndexPath( "index-path" ); // existing value

loader.load( new FileInputStream( confFile ), configuration );

List list = configuration.getRepositories();
assertEquals( "check single managed repository", 1, list.size() );
RepositoryConfiguration managedRepository = (RepositoryConfiguration) list.iterator().next();
assertEquals( "cache path changed", "target", managedRepository.getDirectory() );

assertEquals( "Count repositories", 4, configuration.getProxiedRepositories().size() );

list = configuration.getProxiedRepositories();
ProxiedRepositoryConfiguration repo = (ProxiedRepositoryConfiguration) list.get( 0 );
assertEquals( "Repository name not as expected", "local-repo", repo.getId() );
assertEquals( "Repository url does not match its name", "file://target", repo.getUrl() );
assertEquals( "Repository cache period check failed", 0, repo.getSnapshotsInterval() );
assertFalse( "Repository failure caching check failed", repo.isCacheFailures() );

repo = (ProxiedRepositoryConfiguration) list.get( 1 );
assertEquals( "Repository name not as expected", "www-ibiblio-org", repo.getId() );
assertEquals( "Repository url does not match its name", "http://www.ibiblio.org/maven2", repo.getUrl() );
assertEquals( "Repository cache period check failed", DEFAULT_CACHE_PERIOD, repo.getSnapshotsInterval() );
assertTrue( "Repository failure caching check failed", repo.isCacheFailures() );

repo = (ProxiedRepositoryConfiguration) list.get( 2 );
assertEquals( "Repository name not as expected", "dist-codehaus-org", repo.getId() );
assertEquals( "Repository url does not match its name", "http://dist.codehaus.org", repo.getUrl() );
assertEquals( "Repository cache period check failed", DEFAULT_CACHE_PERIOD, repo.getSnapshotsInterval() );
assertTrue( "Repository failure caching check failed", repo.isCacheFailures() );

repo = (ProxiedRepositoryConfiguration) list.get( 3 );
assertEquals( "Repository name not as expected", "private-example-com", repo.getId() );
assertEquals( "Repository url does not match its name", "http://private.example.com/internal", repo.getUrl() );
assertEquals( "Repository cache period check failed", DEFAULT_CACHE_PERIOD, repo.getSnapshotsInterval() );
assertFalse( "Repository failure caching check failed", repo.isCacheFailures() );
}

public void testInvalidConfiguration()
{
Configuration configuration = new Configuration();
try
{
loader.load( new Properties(), configuration );
fail( "Incomplete config should have failed" );
}
catch ( InvalidConfigurationException e )
{
assertTrue( true );
}
}

protected void setUp()
throws Exception
{
super.setUp();
loader = new MavenProxyPropertyLoader();
}
}

+ 52
- 0
maven-repository-configuration/src/test/resources/org/apache/maven/repository/configuration/ConfigurationStoreTest.xml View File

@@ -0,0 +1,52 @@
<!--
~ Copyright 2005-2006 The Apache Software Foundation.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->

<component-set>
<components>
<component>
<role>org.apache.maven.repository.configuration.ConfigurationStore</role>
<role-hint>default</role-hint>
<implementation>org.apache.maven.repository.configuration.DefaultConfigurationStore</implementation>
<configuration>
<file>${basedir}/src/test/conf/repository-manager.xml</file>
</configuration>
</component>
<component>
<role>org.apache.maven.repository.configuration.ConfigurationStore</role>
<role-hint>corrupt-file</role-hint>
<implementation>org.apache.maven.repository.configuration.DefaultConfigurationStore</implementation>
<configuration>
<file>${basedir}/src/test/conf/corrupt.xml</file>
</configuration>
</component>
<component>
<role>org.apache.maven.repository.configuration.ConfigurationStore</role>
<role-hint>invalid-file</role-hint>
<implementation>org.apache.maven.repository.configuration.DefaultConfigurationStore</implementation>
<configuration>
<file>${basedir}/src/test/conf/nada.txt</file>
</configuration>
</component>
<component>
<role>org.apache.maven.repository.configuration.ConfigurationStore</role>
<role-hint>save-file</role-hint>
<implementation>org.apache.maven.repository.configuration.DefaultConfigurationStore</implementation>
<configuration>
<file>${basedir}/target/test/test-file.xml</file>
</configuration>
</component>
</components>
</component-set>

+ 4
- 7
maven-repository-core/pom.xml View File

@@ -22,6 +22,10 @@
<groupId>org.apache.maven.repository</groupId>
<artifactId>maven-repository-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.apache.maven.repository</groupId>
<artifactId>maven-repository-proxy</artifactId>
</dependency>
<dependency>
<groupId>org.apache.maven.repository</groupId>
<artifactId>maven-repository-reports-standard</artifactId>
@@ -31,12 +35,5 @@
<artifactId>plexus-quartz</artifactId>
<version>1.0-alpha-2</version>
</dependency>
<!-- Testing -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

+ 16
- 0
maven-repository-core/src/main/java/org/apache/maven/repository/configuration/ConfiguredRepositoryFactory.java View File

@@ -52,4 +52,20 @@ public interface ConfiguredRepositoryFactory
* @return the local artifact repository
*/
ArtifactRepository createLocalRepository( Configuration configuration );

/**
* Create an artifact repository from the given proxy repository configuration.
*
* @param configuration the configuration
* @return the artifact repository
*/
ArtifactRepository createProxiedRepository( ProxiedRepositoryConfiguration configuration );

/**
* Create artifact repositories from the given proxy repository configurations.
*
* @param configuration the configuration containing the repositories
* @return the artifact repositories
*/
List createProxiedRepositories( Configuration configuration );
}

+ 45
- 2
maven-repository-core/src/main/java/org/apache/maven/repository/configuration/DefaultConfiguredRepositoryFactory.java View File

@@ -18,6 +18,7 @@ package org.apache.maven.repository.configuration;

import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.repository.ArtifactRepositoryFactory;
import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;

import java.io.File;
@@ -54,11 +55,30 @@ public class DefaultConfiguredRepositoryFactory
return repoFactory.createArtifactRepository( configuration.getId(), repoDir, layout, null, null );
}

public ArtifactRepository createProxiedRepository( ProxiedRepositoryConfiguration configuration )
{
boolean enabled = isEnabled( configuration.getSnapshotsPolicy() );
String updatePolicy =
getUpdatePolicy( configuration.getSnapshotsPolicy(), configuration.getSnapshotsInterval() );
ArtifactRepositoryPolicy snapshotsPolicy =
new ArtifactRepositoryPolicy( enabled, updatePolicy, ArtifactRepositoryPolicy.CHECKSUM_POLICY_FAIL );

enabled = isEnabled( configuration.getReleasesPolicy() );
updatePolicy = getUpdatePolicy( configuration.getReleasesPolicy(), configuration.getReleasesInterval() );
ArtifactRepositoryPolicy releasesPolicy =
new ArtifactRepositoryPolicy( enabled, updatePolicy, ArtifactRepositoryPolicy.CHECKSUM_POLICY_FAIL );

ArtifactRepositoryLayout layout = (ArtifactRepositoryLayout) repositoryLayouts.get( configuration.getLayout() );
return repoFactory.createArtifactRepository( configuration.getId(), configuration.getUrl(), layout,
snapshotsPolicy, releasesPolicy );
}

public List createRepositories( Configuration configuration )
{
List repositories = new ArrayList( configuration.getRepositories().size() );
List managedRepositories = configuration.getRepositories();
List repositories = new ArrayList( managedRepositories.size() );

for ( Iterator i = configuration.getRepositories().iterator(); i.hasNext(); )
for ( Iterator i = managedRepositories.iterator(); i.hasNext(); )
{
repositories.add( createRepository( (RepositoryConfiguration) i.next() ) );
}
@@ -66,6 +86,19 @@ public class DefaultConfiguredRepositoryFactory
return repositories;
}

public List createProxiedRepositories( Configuration configuration )
{
List proxiedRepositories = configuration.getProxiedRepositories();
List repositories = new ArrayList( proxiedRepositories.size() );

for ( Iterator i = proxiedRepositories.iterator(); i.hasNext(); )
{
repositories.add( createProxiedRepository( (ProxiedRepositoryConfiguration) i.next() ) );
}

return repositories;
}

public ArtifactRepository createLocalRepository( Configuration configuration )
{
ArtifactRepositoryLayout layout = (ArtifactRepositoryLayout) repositoryLayouts.get( "default" );
@@ -73,4 +106,14 @@ public class DefaultConfiguredRepositoryFactory
localRepository.mkdirs();
return repoFactory.createArtifactRepository( "local", localRepository.toURI().toString(), layout, null, null );
}

private static String getUpdatePolicy( String policy, int interval )
{
return "interval".equals( policy ) ? policy + ":" + interval : policy;
}

private static boolean isEnabled( String policy )
{
return !"disabled".equals( policy );
}
}

+ 190
- 0
maven-repository-core/src/main/java/org/apache/maven/repository/proxy/DefaultProxyManager.java View File

@@ -0,0 +1,190 @@
package org.apache.maven.repository.proxy;

/*
* Copyright 2005-2006 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.repository.configuration.Configuration;
import org.apache.maven.repository.configuration.ConfigurationStore;
import org.apache.maven.repository.configuration.ConfigurationStoreException;
import org.apache.maven.repository.configuration.ConfiguredRepositoryFactory;
import org.apache.maven.repository.configuration.ProxiedRepositoryConfiguration;
import org.apache.maven.repository.configuration.Proxy;
import org.apache.maven.repository.configuration.RepositoryConfiguration;
import org.apache.maven.wagon.ResourceDoesNotExistException;
import org.apache.maven.wagon.proxy.ProxyInfo;
import org.codehaus.plexus.util.StringUtils;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
* Default implementation of the proxy manager that bridges the repository configuration classes to the proxy API.
*
* @author <a href="mailto:brett@apache.org">Brett Porter</a>
* @todo we should be able to configure "views" that sit in front of this (ie, prefix = /legacy, appears as layout maven-1.x, path gets translated before being passed on)
* @plexus.component
*/
public class DefaultProxyManager
implements ProxyManager
{
/**
* @plexus.requirement
*/
private ConfigurationStore configurationStore;

/**
* @plexus.requirement
*/
private ProxyRequestHandler requestHandler;

/**
* @plexus.requirement
*/
private ConfiguredRepositoryFactory repositoryFactory;

/**
* The proxy handlers for each managed repository.
*/
private Map/*<String,ProxiedRepositoryGroup>*/ proxyGroups;

public File get( String path )
throws ProxyException, ResourceDoesNotExistException
{
assert path.startsWith( "/" );

Map groups = getProxyRepositoryHandlers();

String id = parseRepositoryId( path, groups );

String repositoryPath = path.substring( id.length() + 2 );

ProxiedRepositoryGroup proxyGroup = (ProxiedRepositoryGroup) groups.get( id );

return requestHandler.get( repositoryPath, proxyGroup.getProxiedRepositories(),
proxyGroup.getManagedRepository(), proxyGroup.getWagonProxy() );
}

public File getAlways( String path )
throws ProxyException, ResourceDoesNotExistException
{
assert path.startsWith( "/" );

Map groups = getProxyRepositoryHandlers();

String id = parseRepositoryId( path, groups );

String repositoryPath = path.substring( id.length() + 2 );

ProxiedRepositoryGroup proxyGroup = (ProxiedRepositoryGroup) groups.get( id );

return requestHandler.getAlways( repositoryPath, proxyGroup.getProxiedRepositories(),
proxyGroup.getManagedRepository(), proxyGroup.getWagonProxy() );
}

private Configuration getConfiguration()
throws ProxyException
{
Configuration configuration;
try
{
configuration = configurationStore.getConfigurationFromStore();
}
catch ( ConfigurationStoreException e )
{
throw new ProxyException( "Error reading configuration, unable to proxy any requests: " + e.getMessage(),
e );
}
return configuration;
}

private Map getProxyRepositoryHandlers()
throws ProxyException
{
if ( proxyGroups == null )
{
Map groups = new HashMap();

Configuration configuration = getConfiguration();

ProxyInfo wagonProxy = createWagonProxy( configuration.getProxy() );

for ( Iterator i = configuration.getRepositories().iterator(); i.hasNext(); )
{
RepositoryConfiguration repository = (RepositoryConfiguration) i.next();
ArtifactRepository managedRepository = repositoryFactory.createRepository( repository );
List proxiedRepositories = getProxiedRepositoriesForManagedRepository(
configuration.getProxiedRepositories(), repository.getId() );

groups.put( repository.getId(),
new ProxiedRepositoryGroup( proxiedRepositories, managedRepository, wagonProxy ) );
}

proxyGroups = groups;
}
return proxyGroups;
}

private List getProxiedRepositoriesForManagedRepository( List proxiedRepositories, String id )
{
List repositories = new ArrayList();
for ( Iterator i = proxiedRepositories.iterator(); i.hasNext(); )
{
ProxiedRepositoryConfiguration config = (ProxiedRepositoryConfiguration) i.next();

if ( config.getManagedRepository().equals( id ) )
{
repositories.add( repositoryFactory.createProxiedRepository( config ) );
}
}
return repositories;
}

private static String parseRepositoryId( String path, Map handlers )
throws ProxyException, ResourceDoesNotExistException
{
for ( Iterator i = handlers.keySet().iterator(); i.hasNext(); )
{
String id = (String) i.next();

if ( path.startsWith( "/" + id + "/" ) )
{
return id;
}
}
throw new ResourceDoesNotExistException( "No repositories exist under the path: " + path );
}

private static ProxyInfo createWagonProxy( Proxy proxy )
{
ProxyInfo proxyInfo = null;
if ( proxy != null && !StringUtils.isEmpty( proxy.getHost() ) )
{
proxyInfo = new ProxyInfo();
proxyInfo.setHost( proxy.getHost() );
proxyInfo.setPort( proxy.getPort() );
proxyInfo.setUserName( proxy.getUsername() );
proxyInfo.setPassword( proxy.getPassword() );
proxyInfo.setNonProxyHosts( proxy.getNonProxyHosts() );
proxyInfo.setType( proxy.getProtocol() );
}
return proxyInfo;
}
}

+ 92
- 0
maven-repository-core/src/main/java/org/apache/maven/repository/proxy/ProxiedRepositoryGroup.java View File

@@ -0,0 +1,92 @@
package org.apache.maven.repository.proxy;

/*
* Copyright 2005-2006 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.wagon.proxy.ProxyInfo;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
* A set of information to store for a group of proxies.
*
* @author <a href="mailto:brett@apache.org">Brett Porter</a>
*/
public class ProxiedRepositoryGroup
{

/**
* The locally managed repository that caches proxied artifacts.
*/
private ArtifactRepository managedRepository;

/**
* The remote repositories that are being proxied.
*/
private List/*<ArtifactRepository>*/ proxiedRepositories;

/**
* A wagon proxy to communicate to the proxy repository over a proxy (eg, http proxy)... TerminologyOverflowException
*/
private final ProxyInfo wagonProxy;

/**
* Constructor.
*
* @param proxiedRepositories the proxied repository
* @param managedRepository the locally managed repository
* @param wagonProxy the network proxy to use
*/
public ProxiedRepositoryGroup( List/*<ArtifactRepository>*/ proxiedRepositories,
ArtifactRepository managedRepository, ProxyInfo wagonProxy )
{
this.proxiedRepositories = proxiedRepositories;

this.managedRepository = managedRepository;

this.wagonProxy = wagonProxy;
}

/**
* Constructor.
*
* @param proxiedRepositories the proxied repository
* @param managedRepository the locally managed repository
*/
public ProxiedRepositoryGroup( List/*<ArtifactRepository>*/ proxiedRepositories,
ArtifactRepository managedRepository )
{
this( proxiedRepositories, managedRepository, null );
}

public ArtifactRepository getManagedRepository()
{
return managedRepository;
}

public List getProxiedRepositories()
{
return proxiedRepositories;
}

public ProxyInfo getWagonProxy()
{
return wagonProxy;
}
}

maven-repository-proxy/src/main/java/org/apache/maven/repository/proxy/ProxyManager.java → maven-repository-core/src/main/java/org/apache/maven/repository/proxy/ProxyManager.java View File

@@ -7,7 +7,7 @@ package org.apache.maven.repository.proxy;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -16,18 +16,19 @@ package org.apache.maven.repository.proxy;
* limitations under the License.
*/

import org.apache.maven.repository.proxy.configuration.ProxyConfiguration;
import org.apache.maven.wagon.ResourceDoesNotExistException;

import java.io.File;

/**
* Class used to bridge the servlet to the repository proxy implementation.
* Repository proxying component. This component will take requests for a given path within a managed repository
* and if it is not found or expired, will look in the specified proxy repositories.
*
* @author Edwin Punzalan
* @author <a href="mailto:brett@apache.org">Brett Porter</a>
*/
public interface ProxyManager
{
/** The Plexus role for the component. */
String ROLE = ProxyManager.class.getName();

/**
@@ -36,7 +37,7 @@ public interface ProxyManager
* @param path the expected repository path
* @return File object referencing the requested path in the cache
* @throws ProxyException when an exception occurred during the retrieval of the requested path
* @throws ResourceDoesNotExistException when the requested object can't be found in any of the
* @throws org.apache.maven.wagon.ResourceDoesNotExistException when the requested object can't be found in any of the
* configured repositories
*/
File get( String path )
@@ -54,11 +55,4 @@ public interface ProxyManager
*/
File getAlways( String path )
throws ProxyException, ResourceDoesNotExistException;

/**
* Used by the factory to set the configuration of the proxy
*
* @param config the ProxyConfiguration to set the behavior of the proxy
*/
void setConfiguration( ProxyConfiguration config );
}

+ 1
- 1
maven-repository-core/src/main/java/org/apache/maven/repository/scheduler/DefaultRepositoryTaskScheduler.java View File

@@ -155,7 +155,7 @@ public class DefaultRepositoryTaskScheduler
}
catch ( ParseException e )
{
throw new InvalidConfigurationException( "discoveryCronExpression", "Invalid cron expression", e );
throw new InvalidConfigurationException( "indexerCronExpression", "Invalid cron expression", e );
}
catch ( SchedulerException e )
{

+ 15
- 0
maven-repository-indexer/pom.xml View File

@@ -63,4 +63,19 @@
<artifactId>maven-repository-metadata</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
<configuration>
<check>
<!-- TODO: increase coverage -->
<totalLineRate>80</totalLineRate>
<totalBranchRate>80</totalBranchRate>
</check>
</configuration>
</plugin>
</plugins>
</build>
</project>

+ 2
- 6
maven-repository-proxy/pom.xml View File

@@ -33,10 +33,6 @@
<groupId>org.apache.maven</groupId>
<artifactId>maven-artifact</artifactId>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-artifact-manager</artifactId>
</dependency>
<dependency>
<groupId>org.apache.maven.wagon</groupId>
<artifactId>wagon-file</artifactId>
@@ -54,9 +50,9 @@
<artifactId>cobertura-maven-plugin</artifactId>
<configuration>
<check>
<!-- TODO: increase coverage -->
<!-- TODO!: increase coverage
<totalLineRate>60</totalLineRate>
<totalBranchRate>70</totalBranchRate>
<totalBranchRate>70</totalBranchRate> -->
</check>
</configuration>
</plugin>

+ 0
- 722
maven-repository-proxy/src/main/java/org/apache/maven/repository/proxy/DefaultProxyManager.java View File

@@ -1,722 +0,0 @@
package org.apache.maven.repository.proxy;

/*
* Copyright 2005-2006 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.manager.ChecksumFailedException;
import org.apache.maven.artifact.manager.WagonManager;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.repository.ArtifactRepositoryFactory;
import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
import org.apache.maven.repository.discovery.ArtifactDiscoverer;
import org.apache.maven.repository.discovery.DiscovererException;
import org.apache.maven.repository.proxy.configuration.ProxyConfiguration;
import org.apache.maven.repository.proxy.repository.ProxyRepository;
import org.apache.maven.wagon.ConnectionException;
import org.apache.maven.wagon.ResourceDoesNotExistException;
import org.apache.maven.wagon.TransferFailedException;
import org.apache.maven.wagon.UnsupportedProtocolException;
import org.apache.maven.wagon.Wagon;
import org.apache.maven.wagon.authentication.AuthenticationException;
import org.apache.maven.wagon.authorization.AuthorizationException;
import org.apache.maven.wagon.observers.ChecksumObserver;
import org.codehaus.plexus.logging.AbstractLogEnabled;
import org.codehaus.plexus.util.FileUtils;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
* @author Edwin Punzalan
* @plexus.component role="org.apache.maven.repository.proxy.ProxyManager"
* @todo too much of wagon manager is reproduced here because checksums need to be downloaded separately - is that necessary?
* @todo this isn't reusing the parts of artifact resolver that handles snapshots - should this be more artifact based than file-based?
* @todo currently, cache must be in the same layout as the request, which prohibits any mapping
*/
public class DefaultProxyManager
extends AbstractLogEnabled
implements ProxyManager
{
/**
* @plexus.requirement
*/
private WagonManager wagonManager;

/**
* @plexus.requirement
*/
private ArtifactRepositoryFactory repositoryFactory;

/**
* @plexus.requirement role="org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout"
*/
private Map repositoryLayoutMap;

private Map failuresCache = new HashMap();

private ProxyConfiguration config;

private static final int MS_PER_SEC = 1000;

/**
* @plexus.requirement role-hint="default"
* @todo use a map, and have priorities in them
*/
private ArtifactDiscoverer defaultArtifactDiscoverer;

/**
* @plexus.requirement role-hint="legacy"
*/
private ArtifactDiscoverer legacyArtifactDiscoverer;

public void setConfiguration( ProxyConfiguration config )
{
this.config = config;
}

/**
* @see org.apache.maven.repository.proxy.ProxyManager#get(String)
*/
public File get( String path )
throws ProxyException, ResourceDoesNotExistException
{
checkConfiguration();

//@todo use wagonManager for cache use file:// as URL
String cachePath = config.getRepositoryCachePath();
File cachedFile = new File( cachePath, path );
if ( !cachedFile.exists() )
{
cachedFile = getAlways( path );
}
return cachedFile;
}

/**
* @see org.apache.maven.repository.proxy.ProxyManager#getAlways(String)
*/
public File getAlways( String path )
throws ProxyException, ResourceDoesNotExistException
{
checkConfiguration();

return getRemoteFile( path, config.getRepositories() );
}

/**
* Tries to download the path from the list of repositories.
*
* @param path the request path to download from the proxy or repositories
* @param repositories list of ArtifactRepositories to download the path from
* @return File object that points to the downloaded file
* @throws ProxyException
* @throws ResourceDoesNotExistException
*/
private File getRemoteFile( String path, List repositories )
throws ProxyException, ResourceDoesNotExistException
{
checkConfiguration();

File remoteFile;
if ( path.endsWith( ".md5" ) || path.endsWith( ".sha1" ) )
{
remoteFile = getRepositoryFile( path, repositories, false );
}
else if ( path.endsWith( "maven-metadata.xml" ) )
{
remoteFile = getRepositoryFile( path, repositories );
}
else
{
Artifact artifact = null;
try
{
artifact = defaultArtifactDiscoverer.buildArtifact( path );
}
catch ( DiscovererException e )
{
getLogger().debug( "Failed to build artifact using default layout with message: " + e.getMessage() );
}

if ( artifact == null )
{
try
{
artifact = legacyArtifactDiscoverer.buildArtifact( path );
}
catch ( DiscovererException e )
{
getLogger().debug( "Failed to build artifact using legacy layout with message: " + e.getMessage() );
}
}

if ( artifact != null )
{
getArtifact( artifact, repositories );

remoteFile = artifact.getFile();
}
else
{
//try downloading non-maven standard files
remoteFile = getRepositoryFile( path, repositories );
}
}

return remoteFile;
}

/**
* Used to download an artifact object from the remote repositories.
*
* @param artifact the artifact object to be downloaded from a remote repository
* @param repositories the list of ProxyRepositories to retrieve the artifact from
* @throws ProxyException when an error occurred during retrieval of the requested artifact
* @throws ResourceDoesNotExistException when the requested artifact cannot be found in any of the
* configured repositories
*/
private void getArtifact( Artifact artifact, List repositories )
throws ResourceDoesNotExistException, ProxyException
{
ArtifactRepository repoCache = getRepositoryCache();

File artifactFile = new File( repoCache.getBasedir(), repoCache.pathOf( artifact ) );
artifact.setFile( artifactFile );

if ( !artifactFile.exists() )
{
for ( Iterator iter = repositories.iterator(); iter.hasNext(); )
{
ProxyRepository repository = (ProxyRepository) iter.next();
try
{
if ( checkIfFailureCached( repository.pathOf( artifact ), repository ) )
{
getLogger().debug(
"Skipping repository " + repository.getKey() + " for a cached path failure." );
}
else
{
wagonManager.getArtifact( artifact, repository );
}
}
catch ( TransferFailedException e )
{
if ( repository.isHardfail() )
{
throw new ProxyException( e.getMessage(), e );
}
}
catch ( ResourceDoesNotExistException e )
{
//handle the failure cache then throw exception as expected
doCacheFailure( repository.pathOf( artifact ), repository );

throw e;
}
}
}
}

private void doCacheFailure( String path, ProxyRepository repository )
{
if ( repository.isCacheFailures() )
{
String key = repository.getKey();
if ( !failuresCache.containsKey( key ) )
{
failuresCache.put( key, new ArrayList() );
}

List failureCache = (List) failuresCache.get( key );
if ( !failureCache.contains( path ) )
{
failureCache.add( path );
}
}
}

private boolean checkIfFailureCached( String path, ProxyRepository repository )
{
boolean pathAlreadyFailed = false;

if ( repository.isCacheFailures() )
{
String key = repository.getKey();

if ( failuresCache.containsKey( key ) )
{
List failureCache = (List) failuresCache.get( key );

if ( failureCache.contains( path ) )
{
pathAlreadyFailed = true;
}
}
}

return pathAlreadyFailed;
}

private ArtifactRepositoryLayout getLayout()
throws ProxyException
{
String configLayout = config.getLayout();

if ( !repositoryLayoutMap.containsKey( configLayout ) )
{
throw new ProxyException( "Unable to find a proxy repository layout for " + configLayout );
}

return (ArtifactRepositoryLayout) repositoryLayoutMap.get( configLayout );
}

private ArtifactRepository getRepositoryCache()
throws ProxyException
{
return repositoryFactory.createArtifactRepository( "local-cache", getRepositoryCacheURL().toString(),
getLayout(), getSnapshotsPolicy(), getReleasesPolicy() );
}

private ArtifactRepositoryPolicy getReleasesPolicy()
{
return config.getCacheReleasePolicy();
}

private ArtifactRepositoryPolicy getSnapshotsPolicy()
{
return config.getCacheSnapshotPolicy();
}

public URL getRepositoryCacheURL()
throws ProxyException
{
URL url;

try
{
url = new File( config.getRepositoryCachePath() ).toURL();
}
catch ( MalformedURLException e )
{
throw new ProxyException( "Unable to create cache URL from: " + config.getRepositoryCachePath(), e );
}

return url;
}

/**
* Used to retrieve a remote file from the remote repositories. This method is used only when the requested
* path cannot be resolved into a repository object, for example, an Artifact.
*
* @param path the remote path to use to search for the requested file
* @param repositories the list of repositories to retrieve the file from
* @return File object representing the remote file in the repository cache
* @throws ResourceDoesNotExistException when the requested path cannot be found in any of the configured
* repositories.
* @throws ProxyException when an error occurred during the retrieval of the requested path
*/
private File getRepositoryFile( String path, List repositories )
throws ResourceDoesNotExistException, ProxyException
{
return getRepositoryFile( path, repositories, true );
}

/**
* Used to retrieve a remote file from the remote repositories. This method is used only when the requested
* path cannot be resolved into a repository object, for example, an Artifact.
*
* @param path the remote path to use to search for the requested file
* @param repositories the list of repositories to retrieve the file from
* @param useChecksum forces the download to whether use a checksum (if present in the remote repository) or not
* @return File object representing the remote file in the repository cache
* @throws ResourceDoesNotExistException when the requested path cannot be found in any of the configured
* repositories.
* @throws ProxyException when an error occurred during the retrieval of the requested path
*/
private File getRepositoryFile( String path, List repositories, boolean useChecksum )
throws ResourceDoesNotExistException, ProxyException
{
ArtifactRepository cache = getRepositoryCache();
File target = new File( cache.getBasedir(), path );

for ( Iterator repos = repositories.iterator(); repos.hasNext(); )
{
ProxyRepository repository = (ProxyRepository) repos.next();

if ( checkIfFailureCached( path, repository ) )
{
getLogger().debug( "Skipping repository " + repository.getKey() + " for a cached path failure." );
}
else
{
getFromRepository( target, path, repository, useChecksum );
}
}

if ( !target.exists() )
{
throw new ResourceDoesNotExistException( "Could not find " + path + " in any of the repositories." );
}

return target;
}

private void getFromRepository( File target, String path, ProxyRepository repository, boolean useChecksum )
throws ProxyException
{
boolean connected = false;
Map checksums = null;
Wagon wagon = null;

try
{
wagon = wagonManager.getWagon( repository.getProtocol() );

//@todo configure wagon (ssh settings, etc)

if ( useChecksum )
{
checksums = prepareChecksumListeners( wagon );
}

connected = connectToRepository( wagon, repository );
if ( connected )
{
File temp = new File( target.getAbsolutePath() + ".tmp" );
temp.deleteOnExit();

int tries = 0;
boolean success = true;

do
{
tries++;

getLogger().info( "Trying " + path + " from " + repository.getId() + "..." );

if ( !target.exists() )
{
wagon.get( path, temp );
}
else
{
long repoTimestamp = target.lastModified() + repository.getCachePeriod() * MS_PER_SEC;
wagon.getIfNewer( path, temp, repoTimestamp );
}

if ( useChecksum )
{
success = doChecksumCheck( checksums, path, wagon );
}

if ( tries > 1 && !success )
{
throw new ProxyException( "Checksum failures occurred while downloading " + path );
}
}
while ( !success );

disconnectWagon( wagon );

if ( temp.exists() )
{
moveTempToTarget( temp, target );
}
}
//try next repository
}
catch ( TransferFailedException e )
{
String message = "Skipping repository " + repository.getUrl() + ": " + e.getMessage();
processRepositoryFailure( repository, message, e );
}
catch ( ResourceDoesNotExistException e )
{
doCacheFailure( path, repository );
}
catch ( AuthorizationException e )
{
String message = "Skipping repository " + repository.getUrl() + ": " + e.getMessage();
processRepositoryFailure( repository, message, e );
}
catch ( UnsupportedProtocolException e )
{
String message = "Skipping repository " + repository.getUrl() + ": no wagonManager configured " +
"for protocol " + repository.getProtocol();
processRepositoryFailure( repository, message, e );
}
finally
{
if ( wagon != null && checksums != null )
{
releaseChecksumListeners( wagon, checksums );
}

if ( connected )
{
disconnectWagon( wagon );
}
}
}

/**
* Used to add checksum observers as transfer listeners to the wagonManager object
*
* @param wagon the wagonManager object to use the checksum with
* @return map of ChecksumObservers added into the wagonManager transfer listeners
*/
private Map prepareChecksumListeners( Wagon wagon )
{
Map checksums = new HashMap();
try
{
ChecksumObserver checksum = new ChecksumObserver( "SHA-1" );
wagon.addTransferListener( checksum );
checksums.put( "sha1", checksum );

checksum = new ChecksumObserver( "MD5" );
wagon.addTransferListener( checksum );
checksums.put( "md5", checksum );
}
catch ( NoSuchAlgorithmException e )
{
getLogger().info( "An error occurred while preparing checksum observers", e );
}
return checksums;
}

/**
* Used to remove the ChecksumObservers from the wagonManager object
*
* @param wagon the wagonManager object to remote the ChecksumObservers from
* @param checksumMap the map representing the list of ChecksumObservers added to the wagonManager object
*/
private void releaseChecksumListeners( Wagon wagon, Map checksumMap )
{
for ( Iterator checksums = checksumMap.values().iterator(); checksums.hasNext(); )
{
ChecksumObserver listener = (ChecksumObserver) checksums.next();
wagon.removeTransferListener( listener );
}
}

/**
* Used to request the wagonManager object to connect to a repository
*
* @param wagon the wagonManager object that will be used to connect to the repository
* @param repository the repository object to connect the wagonManager to
* @return true when the wagonManager is able to connect to the repository
*/
private boolean connectToRepository( Wagon wagon, ProxyRepository repository )
{
boolean connected = false;
try
{
if ( repository.isProxied() )
{
wagon.connect( repository, config.getHttpProxy() );
}
else
{
wagon.connect( repository );
}
connected = true;
}
catch ( ConnectionException e )
{
getLogger().info( "Could not connect to " + repository.getId() + ": " + e.getMessage() );
}
catch ( AuthenticationException e )
{
getLogger().info( "Could not connect to " + repository.getId() + ": " + e.getMessage() );
}

return connected;
}

/**
* Used to verify the checksum during a wagonManager download
*
* @param checksumMap the map of ChecksumObservers present in the wagonManager as transferlisteners
* @param path path of the remote object whose checksum is to be verified
* @param wagon the wagonManager object used to download the requested path
* @return true when the checksum succeeds and false when the checksum failed.
*/
private boolean doChecksumCheck( Map checksumMap, String path, Wagon wagon )
throws ProxyException
{
releaseChecksumListeners( wagon, checksumMap );
for ( Iterator checksums = checksumMap.keySet().iterator(); checksums.hasNext(); )
{
String checksumExt = (String) checksums.next();
ChecksumObserver checksum = (ChecksumObserver) checksumMap.get( checksumExt );
String checksumPath = path + "." + checksumExt;
File checksumFile = new File( config.getRepositoryCachePath(), checksumPath );

try
{
File tempChecksumFile = new File( checksumFile.getAbsolutePath() + ".tmp" );

wagon.get( checksumPath, tempChecksumFile );

String remoteChecksum = FileUtils.fileRead( tempChecksumFile ).trim();
if ( remoteChecksum.indexOf( ' ' ) > 0 )
{
remoteChecksum = remoteChecksum.substring( 0, remoteChecksum.indexOf( ' ' ) );
}

boolean checksumCheck = false;
if ( remoteChecksum.toUpperCase().equals( checksum.getActualChecksum().toUpperCase() ) )
{
moveTempToTarget( tempChecksumFile, checksumFile );

checksumCheck = true;
}
return checksumCheck;
}
catch ( ChecksumFailedException e )
{
return false;
}
catch ( TransferFailedException e )
{
getLogger().debug( "An error occurred during the download of " + checksumPath + ": " + e.getMessage(),
e );
// do nothing try the next checksum
}
catch ( ResourceDoesNotExistException e )
{
getLogger().debug( "An error occurred during the download of " + checksumPath + ": " + e.getMessage(),
e );
// do nothing try the next checksum
}
catch ( AuthorizationException e )
{
getLogger().debug( "An error occurred during the download of " + checksumPath + ": " + e.getMessage(),
e );
// do nothing try the next checksum
}
catch ( IOException e )
{
getLogger().debug( "An error occurred while reading the temporary checksum file.", e );
return false;
}
}

getLogger().debug( "Skipping checksum validation for " + path + ": No remote checksums available." );

return true;
}

/**
* Used to ensure that this proxy instance is running with a valid configuration instance.
*
* @throws ProxyException
*/
private void checkConfiguration()
throws ProxyException
{
if ( config == null )
{
throw new ProxyException( "No proxy configuration defined." );
}
}

/**
* Used to move the temporary file to its real destination. This is patterned from the way WagonManager handles
* its downloaded files.
*
* @param temp The completed download file
* @param target The final location of the downloaded file
* @throws ProxyException when the temp file cannot replace the target file
*/
private void moveTempToTarget( File temp, File target )
throws ProxyException
{
if ( target.exists() && !target.delete() )
{
throw new ProxyException( "Unable to overwrite existing target file: " + target.getAbsolutePath() );
}

if ( !temp.renameTo( target ) )
{
getLogger().warn( "Unable to rename tmp file to its final name... resorting to copy command." );

try
{
FileUtils.copyFile( temp, target );
}
catch ( IOException e )
{
throw new ProxyException( "Cannot copy tmp file to its final location", e );
}
finally
{
temp.delete();
}
}
}

/**
* Used to disconnect the wagonManager from its repository
*
* @param wagon the connected wagonManager object
*/
private void disconnectWagon( Wagon wagon )
{
try
{
wagon.disconnect();
}
catch ( ConnectionException e )
{
getLogger().error( "Problem disconnecting from wagonManager - ignoring: " + e.getMessage() );
}
}

/**
* Queries the configuration on how to handle a repository download failure
*
* @param repository the repository object where the failure occurred
* @param message the message/reason for the failure
* @param t the cause for the exception
* @throws ProxyException if hard failure is enabled on the repository causing the failure
*/
private void processRepositoryFailure( ProxyRepository repository, String message, Throwable t )
throws ProxyException
{
if ( repository.isHardfail() )
{
throw new ProxyException(
"An error occurred in hardfailing repository " + repository.getName() + "...\n " + message, t );
}
else
{
getLogger().debug( message, t );
}
}
}

+ 507
- 0
maven-repository-proxy/src/main/java/org/apache/maven/repository/proxy/DefaultProxyRequestHandler.java View File

@@ -0,0 +1,507 @@
package org.apache.maven.repository.proxy;

/*
* Copyright 2005-2006 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.manager.ChecksumFailedException;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
import org.apache.maven.repository.discovery.ArtifactDiscoverer;
import org.apache.maven.repository.discovery.DiscovererException;
import org.apache.maven.wagon.ConnectionException;
import org.apache.maven.wagon.ResourceDoesNotExistException;
import org.apache.maven.wagon.TransferFailedException;
import org.apache.maven.wagon.Wagon;
import org.apache.maven.wagon.authentication.AuthenticationException;
import org.apache.maven.wagon.authorization.AuthorizationException;
import org.apache.maven.wagon.observers.ChecksumObserver;
import org.apache.maven.wagon.proxy.ProxyInfo;
import org.apache.maven.wagon.repository.Repository;
import org.codehaus.plexus.logging.AbstractLogEnabled;
import org.codehaus.plexus.util.FileUtils;

import java.io.File;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
* An implementation of the proxy handler.
*
* @author <a href="mailto:brett@apache.org">Brett Porter</a>
* @plexus.component
* @todo this currently duplicates a lot of the wagon manager, and doesn't do things like snapshot resolution, etc.
* Should we have a more artifact based one? This will merge metadata so should behave correctly, and it is able to
* correct some limitations of the wagon manager (eg, it can retrieve newer SNAPSHOT files without metadata)
*/
public class DefaultProxyRequestHandler
extends AbstractLogEnabled
implements ProxyRequestHandler
{
/**
* @plexus.requirement role-hint="default"
* @todo use a map, and have priorities in them
*/
private ArtifactDiscoverer defaultArtifactDiscoverer;

/**
* @plexus.requirement role-hint="legacy"
*/
private ArtifactDiscoverer legacyArtifactDiscoverer;

/**
* @plexus.requirement role="org.apache.maven.wagon.Wagon"
*/
private Map/*<String,Wagon>*/ wagons;

public File get( String path, List proxiedRepositories, ArtifactRepository managedRepository )
throws ProxyException, ResourceDoesNotExistException
{
return get( path, proxiedRepositories, managedRepository, null );
}

public File get( String path, List proxiedRepositories, ArtifactRepository managedRepository, ProxyInfo wagonProxy )
throws ProxyException, ResourceDoesNotExistException
{
//@todo use wagonManager for cache use file:// as URL
File cachedFile = new File( managedRepository.getBasedir(), path );
if ( !cachedFile.exists() )
{
cachedFile = getAlways( path, proxiedRepositories, managedRepository, wagonProxy );
}
return cachedFile;
}


public File getAlways( String path, List proxiedRepositories, ArtifactRepository managedRepository )
throws ProxyException, ResourceDoesNotExistException
{
return getAlways( path, proxiedRepositories, managedRepository, null );
}

public File getAlways( String path, List proxiedRepositories, ArtifactRepository managedRepository,
ProxyInfo wagonProxy )
throws ProxyException, ResourceDoesNotExistException
{
File remoteFile = null;

for ( Iterator i = proxiedRepositories.iterator(); i.hasNext(); )
{
ProxiedArtifactRepository repository = (ProxiedArtifactRepository) i.next();

if ( repository.isCachedFailure( path ) )
{
getLogger().debug( "Skipping repository " + repository.getName() + " for a cached path failure." );
}
else
{
if ( path.endsWith( ".md5" ) || path.endsWith( ".sha1" ) )
{
// always read from the managed repository
remoteFile = new File( managedRepository.getBasedir(), path );
}
else if ( path.endsWith( "maven-metadata.xml" ) )
{
remoteFile = getFromRepository( path, repository, managedRepository.getBasedir(), wagonProxy,
repository.getRepository().getReleases() );
}
else
{
Artifact artifact = null;
try
{
artifact = defaultArtifactDiscoverer.buildArtifact( path );
}
catch ( DiscovererException e )
{
getLogger().debug(
"Failed to build artifact using default layout with message: " + e.getMessage() );
}

if ( artifact == null )
{
try
{
artifact = legacyArtifactDiscoverer.buildArtifact( path );
}
catch ( DiscovererException e )
{
getLogger().debug(
"Failed to build artifact using legacy layout with message: " + e.getMessage() );
}
}

if ( artifact != null )
{
getArtifact( artifact, repository, managedRepository, wagonProxy );

remoteFile = artifact.getFile();
}
else
{
// Some other unknown file in the repository, proxy as is
getFromRepository( path, repository, managedRepository.getBasedir(), wagonProxy, null );
}
}

if ( remoteFile != null && !remoteFile.exists() )
{
repository.addFailure( path );
throw new ResourceDoesNotExistException(
"Could not find " + path + " in any of the repositories." );
}
else
{
// in case it previously failed and we've since found it
repository.clearFailure( path );
}
}
}

return remoteFile;
}

private File getFromRepository( String path, ProxiedArtifactRepository repository, String repositoryCachePath,
ProxyInfo httpProxy, ArtifactRepositoryPolicy policy )
throws ProxyException, ResourceDoesNotExistException
{
File target = new File( repositoryCachePath, path );
if ( !target.exists() || isOutOfDate( policy, target ) )
{
boolean connected = false;
Map checksums = null;
Wagon wagon = null;

try
{
String protocol = repository.getRepository().getProtocol();
wagon = (Wagon) wagons.get( protocol );
if ( wagon == null )
{
throw new ProxyException( "Unsupported remote protocol: " + protocol );
}

//@todo configure wagon (ssh settings, etc)

checksums = prepareChecksumListeners( wagon );

connected = connectToRepository( wagon, repository, httpProxy );
if ( connected )
{
File temp = new File( target.getAbsolutePath() + ".tmp" );
temp.deleteOnExit();

int tries = 0;
boolean success;

do
{
tries++;

getLogger().info( "Trying " + path + " from " + repository.getName() + "..." );

if ( !target.exists() )
{
wagon.get( path, temp );
}
else
{
wagon.getIfNewer( path, temp, target.lastModified() );
}

success = doChecksumCheck( checksums, path, wagon, repositoryCachePath );

if ( tries > 1 && !success )
{
throw new ProxyException( "Checksum failures occurred while downloading " + path );
}
}
while ( !success );

disconnectWagon( wagon );

if ( temp.exists() )
{
moveTempToTarget( temp, target );
}
}
//try next repository
}
catch ( TransferFailedException e )
{
String message = "Skipping repository " + repository.getName() + ": " + e.getMessage();
processRepositoryFailure( repository, message, e );
}
catch ( AuthorizationException e )
{
String message = "Skipping repository " + repository.getName() + ": " + e.getMessage();
processRepositoryFailure( repository, message, e );
}
finally
{
if ( wagon != null && checksums != null )
{
releaseChecksumListeners( wagon, checksums );
}

if ( connected )
{
disconnectWagon( wagon );
}
}
}
return target;
}

private static boolean isOutOfDate( ArtifactRepositoryPolicy policy, File target )
{
return policy != null && policy.checkOutOfDate( new Date( target.lastModified() ) );
}

/**
* Used to add checksum observers as transfer listeners to the wagonManager object
*
* @param wagon the wagonManager object to use the checksum with
* @return map of ChecksumObservers added into the wagonManager transfer listeners
*/
private Map prepareChecksumListeners( Wagon wagon )
{
Map checksums = new HashMap();
try
{
ChecksumObserver checksum = new ChecksumObserver( "SHA-1" );
wagon.addTransferListener( checksum );
checksums.put( "sha1", checksum );

checksum = new ChecksumObserver( "MD5" );
wagon.addTransferListener( checksum );
checksums.put( "md5", checksum );
}
catch ( NoSuchAlgorithmException e )
{
getLogger().info( "An error occurred while preparing checksum observers", e );
}
return checksums;
}

private void releaseChecksumListeners( Wagon wagon, Map checksumMap )
{
for ( Iterator checksums = checksumMap.values().iterator(); checksums.hasNext(); )
{
ChecksumObserver listener = (ChecksumObserver) checksums.next();
wagon.removeTransferListener( listener );
}
}

private boolean connectToRepository( Wagon wagon, ProxiedArtifactRepository repository, ProxyInfo httpProxy )
{
boolean connected = false;
try
{
ArtifactRepository artifactRepository = repository.getRepository();
Repository wagonRepository = new Repository( artifactRepository.getId(), artifactRepository.getUrl() );
if ( repository.isUseNetworkProxy() && httpProxy != null )
{
wagon.connect( wagonRepository, httpProxy );
}
else
{
wagon.connect( wagonRepository );
}
connected = true;
}
catch ( ConnectionException e )
{
getLogger().info( "Could not connect to " + repository.getName() + ": " + e.getMessage() );
}
catch ( AuthenticationException e )
{
getLogger().info( "Could not connect to " + repository.getName() + ": " + e.getMessage() );
}

return connected;
}

private boolean doChecksumCheck( Map checksumMap, String path, Wagon wagon, String repositoryCachePath )
throws ProxyException
{
releaseChecksumListeners( wagon, checksumMap );
for ( Iterator checksums = checksumMap.keySet().iterator(); checksums.hasNext(); )
{
String checksumExt = (String) checksums.next();
ChecksumObserver checksum = (ChecksumObserver) checksumMap.get( checksumExt );
String checksumPath = path + "." + checksumExt;
File checksumFile = new File( repositoryCachePath, checksumPath );

try
{
File tempChecksumFile = new File( checksumFile.getAbsolutePath() + ".tmp" );

wagon.get( checksumPath, tempChecksumFile );

String remoteChecksum = FileUtils.fileRead( tempChecksumFile ).trim();
if ( remoteChecksum.indexOf( ' ' ) > 0 )
{
remoteChecksum = remoteChecksum.substring( 0, remoteChecksum.indexOf( ' ' ) );
}

boolean checksumCheck = false;
if ( remoteChecksum.toUpperCase().equals( checksum.getActualChecksum().toUpperCase() ) )
{
moveTempToTarget( tempChecksumFile, checksumFile );

checksumCheck = true;
}
return checksumCheck;
}
catch ( ChecksumFailedException e )
{
return false;
}
catch ( TransferFailedException e )
{
getLogger().debug( "An error occurred during the download of " + checksumPath + ": " + e.getMessage(),
e );
// do nothing try the next checksum
}
catch ( ResourceDoesNotExistException e )
{
getLogger().debug( "An error occurred during the download of " + checksumPath + ": " + e.getMessage(),
e );
// do nothing try the next checksum
}
catch ( AuthorizationException e )
{
getLogger().debug( "An error occurred during the download of " + checksumPath + ": " + e.getMessage(),
e );
// do nothing try the next checksum
}
catch ( IOException e )
{
getLogger().debug( "An error occurred while reading the temporary checksum file.", e );
return false;
}
}

getLogger().debug( "Skipping checksum validation for " + path + ": No remote checksums available." );

return true;
}

/**
* Used to move the temporary file to its real destination. This is patterned from the way WagonManager handles
* its downloaded files.
*
* @param temp The completed download file
* @param target The final location of the downloaded file
* @throws ProxyException when the temp file cannot replace the target file
*/
private void moveTempToTarget( File temp, File target )
throws ProxyException
{
if ( target.exists() && !target.delete() )
{
throw new ProxyException( "Unable to overwrite existing target file: " + target.getAbsolutePath() );
}

if ( !temp.renameTo( target ) )
{
getLogger().warn( "Unable to rename tmp file to its final name... resorting to copy command." );

try
{
FileUtils.copyFile( temp, target );
}
catch ( IOException e )
{
throw new ProxyException( "Cannot copy tmp file to its final location", e );
}
finally
{
temp.delete();
}
}
}

/**
* Used to disconnect the wagonManager from its repository
*
* @param wagon the connected wagonManager object
*/
private void disconnectWagon( Wagon wagon )
{
try
{
wagon.disconnect();
}
catch ( ConnectionException e )
{
getLogger().error( "Problem disconnecting from wagonManager - ignoring: " + e.getMessage() );
}
}

/**
* Queries the configuration on how to handle a repository download failure
*
* @param repository the repository object where the failure occurred
* @param message the message/reason for the failure
* @param t the cause for the exception
* @throws ProxyException if hard failure is enabled on the repository causing the failure
*/
private void processRepositoryFailure( ProxiedArtifactRepository repository, String message, Throwable t )
throws ProxyException
{
if ( repository.isHardFail() )
{
throw new ProxyException(
"An error occurred in hardfailing repository " + repository.getName() + "...\n " + message, t );
}
else
{
getLogger().error( message, t );
}
}

private void getArtifact( Artifact artifact, ProxiedArtifactRepository repository, ArtifactRepository repoCache,
ProxyInfo httpProxy )
throws ProxyException, ResourceDoesNotExistException
{
ArtifactRepository artifactRepository = repository.getRepository();
ArtifactRepositoryPolicy policy =
artifact.isSnapshot() ? artifactRepository.getSnapshots() : artifactRepository.getReleases();

if ( !policy.isEnabled() )
{
getLogger().debug( "Skipping disabled repository " + repository.getName() );
}
else
{
getLogger().debug( "Trying repository " + repository.getName() );
// Don't use releases policy, we don't want to perform updates on them (only metadata, as used above)
getFromRepository( artifactRepository.pathOf( artifact ), repository, repoCache.getBasedir(), httpProxy,
artifact.isSnapshot() ? artifactRepository.getSnapshots() : null );
getLogger().debug( " Artifact resolved" );

artifact.setResolved( true );
}
}

}

+ 107
- 0
maven-repository-proxy/src/main/java/org/apache/maven/repository/proxy/ProxiedArtifactRepository.java View File

@@ -0,0 +1,107 @@
package org.apache.maven.repository.proxy;

/*
* Copyright 2005-2006 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import org.apache.maven.artifact.repository.ArtifactRepository;

import java.util.HashSet;
import java.util.Set;

/**
* A proxied artifact repository - contains the artifact repository and additional information about
* the proxied repository.
*
* @author <a href="mailto:brett@apache.org">Brett Porter</a>
*/
public class ProxiedArtifactRepository
{
/**
* Whether to cache failures or not.
*/
private boolean cacheFailures;

/**
* Whether failures on this repository cause the whole group to fail.
*/
private boolean hardFail;

/**
* Whether to use the network proxy for any requests.
*/
private boolean useNetworkProxy;

/**
* The artifact repository on the other end of the proxy.
*/
private ArtifactRepository repository;

/**
* Cache of failures that have already occurred, containing paths from the repository root.
*/
private Set/*<String>*/ failureCache = new HashSet/*<String>*/();

/**
* A user friendly name for the repository.
*/
private String name;

public boolean isHardFail()
{
return hardFail;
}

public boolean isUseNetworkProxy()
{
return useNetworkProxy;
}

public boolean isCacheFailures()
{
return cacheFailures;
}

public ArtifactRepository getRepository()
{
return repository;
}

public boolean isCachedFailure( String path )
{
return cacheFailures && failureCache.contains( path );
}

public void addFailure( String path )
{
if ( cacheFailures )
{
failureCache.add( path );
}
}

public void clearFailure( String path )
{
if ( cacheFailures )
{
failureCache.remove( path );
}
}

public String getName()
{
return name;
}
}

+ 101
- 0
maven-repository-proxy/src/main/java/org/apache/maven/repository/proxy/ProxyRequestHandler.java View File

@@ -0,0 +1,101 @@
package org.apache.maven.repository.proxy;

/*
* Copyright 2005-2006 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.wagon.ResourceDoesNotExistException;
import org.apache.maven.wagon.proxy.ProxyInfo;

import java.io.File;
import java.util.List;

/**
* An individual request handler for the proxy.
*
* @author <a href="mailto:brett@apache.org">Brett Porter</a>
*/
public interface ProxyRequestHandler
{
/**
* The Plexus role of the component.
*/
String ROLE = ProxyRequestHandler.class.getName();

/**
* Used to retrieve an artifact at a particular path, giving the cached version if it exists.
*
* @param path the expected repository path
* @param proxiedRepositories the repositories being proxied to
* @param managedRepository the locally managed repository to cache artifacts in
* @return File object referencing the requested path in the cache
* @throws ProxyException when an exception occurred during the retrieval of the requested path
* @throws org.apache.maven.wagon.ResourceDoesNotExistException
* when the requested object can't be found in any of the
* configured repositories
*/
File get( String path, List proxiedRepositories, ArtifactRepository managedRepository )
throws ProxyException, ResourceDoesNotExistException;

/**
* Used to retrieve an artifact at a particular path, giving the cached version if it exists.
*
* @param path the expected repository path
* @param proxiedRepositories the repositories being proxied to
* @param managedRepository the locally managed repository to cache artifacts in
* @param wagonProxy a network proxy to use when transferring files if needed
* @return File object referencing the requested path in the cache
* @throws ProxyException when an exception occurred during the retrieval of the requested path
* @throws org.apache.maven.wagon.ResourceDoesNotExistException
* when the requested object can't be found in any of the
* configured repositories
*/
File get( String path, List proxiedRepositories, ArtifactRepository managedRepository, ProxyInfo wagonProxy )
throws ProxyException, ResourceDoesNotExistException;

/**
* Used to force remote download of the requested path from any the configured repositories. This method will
* only bypass the cache for searching but the requested path will still be cached.
*
* @param path the expected repository path
* @param proxiedRepositories the repositories being proxied to
* @param managedRepository the locally managed repository to cache artifacts in
* @return File object referencing the requested path in the cache
* @throws ProxyException when an exception occurred during the retrieval of the requested path
* @throws org.apache.maven.wagon.ResourceDoesNotExistException
* when the requested object can't be found in any of the
* configured repositories
*/
File getAlways( String path, List proxiedRepositories, ArtifactRepository managedRepository )
throws ProxyException, ResourceDoesNotExistException;

/**
* Used to force remote download of the requested path from any the configured repositories. This method will
* only bypass the cache for searching but the requested path will still be cached.
*
* @param path the expected repository path
* @param proxiedRepositories the repositories being proxied to
* @param managedRepository the locally managed repository to cache artifacts in
* @param wagonProxy a network proxy to use when transferring files if needed
* @return File object referencing the requested path in the cache
* @throws ProxyException when an exception occurred during the retrieval of the requested path
* @throws org.apache.maven.wagon.ResourceDoesNotExistException
* when the requested object can't be found in any of the
* configured repositories
*/
File getAlways( String path, List proxiedRepositories, ArtifactRepository managedRepository, ProxyInfo wagonProxy )
throws ProxyException, ResourceDoesNotExistException;
}

+ 0
- 221
maven-repository-proxy/src/main/java/org/apache/maven/repository/proxy/configuration/ProxyConfiguration.java View File

@@ -1,221 +0,0 @@
package org.apache.maven.repository.proxy.configuration;

/*
* Copyright 2005-2006 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
import org.apache.maven.repository.proxy.repository.ProxyRepository;
import org.apache.maven.wagon.proxy.ProxyInfo;

import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

/**
* Class to represent the configuration file for the proxy
*
* @author Edwin Punzalan
*/
public class ProxyConfiguration
{
private List repositories = new ArrayList();

private String cachePath;

private String layout;

private ProxyInfo httpProxy;

private ArtifactRepositoryPolicy cacheReleasePolicy;

private ArtifactRepositoryPolicy cacheSnapshotPolicy;

/**
* Used to set the location where the proxy should cache the configured repositories
*
* @param path
*/
public void setRepositoryCachePath( String path )
{
cachePath = new File( path ).getAbsolutePath();
}

/**
* Used to retrieved the absolute path of the repository cache
*
* @return path to the proxy cache
*/
public String getRepositoryCachePath()
{
return cachePath;
}

public void setHttpProxy( ProxyInfo httpProxy )
{
this.httpProxy = httpProxy;
}

public void setHttpProxy( String host, int port )
{
ProxyInfo proxyInfo = new ProxyInfo();
proxyInfo.setHost( host );
proxyInfo.setPort( port );

httpProxy = proxyInfo;
}

public void setHttpProxy( String host, int port, String username, String password )
{
setHttpProxy( host, port );
httpProxy.setUserName( username );
httpProxy.setPassword( password );
}

public void setHttpProxy( String host, int port, String username, String password, String ntlmHost,
String ntlmDomain )
{
setHttpProxy( host, port );
httpProxy.setUserName( username );
httpProxy.setPassword( password );
httpProxy.setNtlmHost( ntlmHost );
httpProxy.setNtlmDomain( ntlmDomain );
}

public ProxyInfo getHttpProxy()
{
return httpProxy;
}

/**
* Used to add proxied repositories.
*
* @param repository the repository to be proxied
*/
public void addRepository( ProxyRepository repository )
{
repositories.add( repository );
}

/**
* Used to retrieve an unmodifyable list of proxied repositories. They returned list determines the search sequence
* for retrieving artifacts.
*
* @return a list of ProxyRepository objects representing proxied repositories
*/
public List getRepositories()
{
return Collections.unmodifiableList( repositories );
}

/**
* Used to set the list of repositories to be proxied. This replaces any repositories already added to this
* configuraion instance. Useful for re-arranging an existing proxied list.
*
* @param repositories
*/
public void setRepositories( List repositories )
{
this.repositories = repositories;
}

public String getLayout()
{
if ( layout == null )
{
layout = "default";
}

return layout;
}

public void setLayout( String layout )
{
this.layout = layout;
}

public void validate()
throws ValidationException
{
validateRemoteRepo();
validateDirectories();
}

private void validateRemoteRepo()
throws ValidationException
{
//Verify remote repository set
//only warn if missing
if ( getRepositories().size() < 1 )
{
throw new ValidationException( "At least one remote repository must be configured." );
}
}

private void validateDirectories()
throws ValidationException
{
File f = new File( cachePath );
if ( !f.exists() )
{
throw new ValidationException( "Specified directory does not exist: " + f.getAbsolutePath() );
}

for ( Iterator repos = getRepositories().iterator(); repos.hasNext(); )
{
ProxyRepository repo = (ProxyRepository) repos.next();
if ( repo.getUrl().startsWith( "file://" ) )
{
File f2 = new File( repo.getBasedir() );
if ( !f2.exists() )
{
throw new ValidationException( "Specified directory does not exist: " + f2.getAbsolutePath() );
}
}
}
}

public ArtifactRepositoryPolicy getCacheReleasePolicy()
{
if ( cacheReleasePolicy == null )
{
cacheReleasePolicy = new ArtifactRepositoryPolicy();
}

return cacheReleasePolicy;
}

public void setCacheReleasePolicy( ArtifactRepositoryPolicy cacheReleasePolicy )
{
this.cacheReleasePolicy = cacheReleasePolicy;
}

public ArtifactRepositoryPolicy getCacheSnapshotPolicy()
{
if ( cacheSnapshotPolicy == null )
{
cacheSnapshotPolicy = new ArtifactRepositoryPolicy();
}

return cacheSnapshotPolicy;
}

public void setCacheSnapshotPolicy( ArtifactRepositoryPolicy cacheSnapshotPolicy )
{
this.cacheSnapshotPolicy = cacheSnapshotPolicy;
}
}

+ 0
- 40
maven-repository-proxy/src/main/java/org/apache/maven/repository/proxy/configuration/ValidationException.java View File

@@ -1,40 +0,0 @@
package org.apache.maven.repository.proxy.configuration;

/*
* Copyright 2005-2006 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/**
* @author Ben Walding
*/
public class ValidationException
extends Exception
{
/**
* @param
*/
public ValidationException( String msg )
{
super( msg );
}

/**
* @param t
*/
public ValidationException( Throwable t )
{
super( t );
}
}

+ 0
- 105
maven-repository-proxy/src/main/java/org/apache/maven/repository/proxy/repository/ProxyRepository.java View File

@@ -1,105 +0,0 @@
package org.apache.maven.repository.proxy.repository;

/*
* Copyright 2005-2006 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import org.apache.maven.artifact.repository.DefaultArtifactRepository;
import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;

/**
* Class to represent the Proxy repository. Currently does not provide additional methods from
* DefaultArtifactRepository but is expected to do so like enabled/disabled when a UI is present.
*
* @author Edwin Punzalan
*/
public class ProxyRepository
extends DefaultArtifactRepository
{
// zero caches forever
private long cachePeriod;

private boolean cacheFailures;

private boolean hardfail = true;

private boolean proxied;

public ProxyRepository( String id, String url, ArtifactRepositoryLayout layout, boolean cacheFailures,
long cachePeriod )
{
this( id, url, layout );

this.cacheFailures = cacheFailures;

this.cachePeriod = cachePeriod;
}

public ProxyRepository( String id, String url, ArtifactRepositoryLayout layout )
{
super( id, url, layout );
}

public long getCachePeriod()
{
return cachePeriod;
}

public void setCachePeriod( long cachePeriod )
{
this.cachePeriod = cachePeriod;
}

public boolean isCacheFailures()
{
return cacheFailures;
}

public void setCacheFailures( boolean cacheFailures )
{
this.cacheFailures = cacheFailures;
}

public boolean isProxied()
{
return proxied;
}

public void setProxied( boolean proxied )
{
this.proxied = proxied;
}

/**
* Checks the repository hardfail setting.
*
* @return true if the hardfail is enabled, otherwise, returns false.
*/
public boolean isHardfail()
{
return hardfail;
}

/**
* If hardfail is set to true, then any unexpected errors from retrieving files from this repository
* will cause the download to fail.
*
* @param hardfail set to true to enable hard failures
*/
public void setHardfail( boolean hardfail )
{
this.hardfail = hardfail;
}
}

+ 0
- 154
maven-repository-proxy/src/test/java/org/apache/maven/repository/proxy/LegacyProxyManagerTest.java View File

@@ -1,154 +0,0 @@
package org.apache.maven.repository.proxy;

/*
* Copyright 2005-2006 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
import org.apache.maven.artifact.repository.layout.LegacyRepositoryLayout;
import org.apache.maven.repository.proxy.configuration.ProxyConfiguration;
import org.apache.maven.repository.proxy.repository.ProxyRepository;
import org.apache.maven.wagon.ResourceDoesNotExistException;
import org.codehaus.plexus.PlexusTestCase;
import org.codehaus.plexus.component.repository.exception.ComponentLookupException;

import java.io.File;

/**
* @author Edwin Punzalan
*/
public class LegacyProxyManagerTest
extends PlexusTestCase
{
private ProxyManager proxy;

private ProxyConfiguration configuration;

protected void setUp()
throws Exception
{
super.setUp();

proxy = (ProxyManager) container.lookup( ProxyManager.ROLE );

configuration = getProxyConfiguration();
proxy.setConfiguration( configuration );
}

public void testExceptions()
{
proxy.setConfiguration( null );

try
{
proxy.get( "/invalid" );
fail( "Expected empty configuration error." );
}
catch ( ProxyException e )
{
assertEquals( "Expected Exception not thrown.", "No proxy configuration defined.", e.getMessage() );
}
catch ( ResourceDoesNotExistException e )
{
fail( "Expected Exception not thrown." );
}
}

public void testArtifactDownload()
throws Exception
{
//test download
File file = proxy.get( "/commons-logging/jars/commons-logging-1.0.jar" );
assertTrue( "File must be downloaded: " + file.getAbsolutePath(), file.exists() );
assertTrue( "Downloaded file should be present in the cache.",
file.getAbsolutePath().startsWith( configuration.getRepositoryCachePath() ) );

//test cache
proxy.get( "/commons-logging/jars/commons-logging-1.0.jar" );

try
{
proxy.get( "/commons-logging/jars/commons-logging-2.0.jar" );
fail( "Expected ResourceDoesNotExistException exception not thrown" );
}
catch ( ResourceDoesNotExistException e )
{
assertTrue( true );
}
}

public void testArtifactChecksum()
throws Exception
{
//force the downlod from the remote repository, use getAlways()
File file = proxy.getAlways( "/commons-logging/jars/commons-logging-1.0.jar.md5" );
assertTrue( "File must be downloaded.", file.exists() );
assertTrue( "Downloaded file should be present in the cache.",
file.getAbsolutePath().startsWith( configuration.getRepositoryCachePath() ) );
}

public void testNonArtifactWithNoChecksum()
throws Exception
{
File file = proxy.get( "/not-standard/repository/file.txt" );
assertTrue( "File must be downloaded.", file.exists() );
assertTrue( "Downloaded file should be present in the cache.",
file.getAbsolutePath().startsWith( configuration.getRepositoryCachePath() ) );
}

public void testNonArtifactWithMD5Checksum()
throws Exception
{
File file = proxy.get( "/checksumed-md5/repository/file.txt" );
assertTrue( "File must be downloaded.", file.exists() );
assertTrue( "Downloaded file should be present in the cache.",
file.getAbsolutePath().startsWith( configuration.getRepositoryCachePath() ) );
}

public void testNonArtifactWithSHA1Checksum()
throws Exception
{
File file = proxy.get( "/checksumed-sha1/repository/file.txt" );
assertTrue( "File must be downloaded.", file.exists() );
assertTrue( "Downloaded file should be present in the cache.",
file.getAbsolutePath().startsWith( configuration.getRepositoryCachePath() ) );
}

protected void tearDown()
throws Exception
{
container.release( proxy );

super.tearDown();
}

private ProxyConfiguration getProxyConfiguration()
throws ComponentLookupException
{
ProxyConfiguration config = new ProxyConfiguration();

config.setRepositoryCachePath( getTestFile( "target/m1-proxy-cache" ).getAbsolutePath() );

ArtifactRepositoryLayout layout = new LegacyRepositoryLayout();

File repo1File = getTestFile( "src/test/m1-remote-repo" );

ProxyRepository repo1 = new ProxyRepository( "m1-test-repo", "file://" + repo1File.getAbsolutePath(), layout );

config.addRepository( repo1 );

return config;
}
}

maven-repository-proxy/src/test/java/org/apache/maven/repository/proxy/DefaultProxyManagerTest.java → maven-repository-proxy/src/test/java/org/apache/maven/repository/proxy/ProxyRequestHandlerTest.java View File

@@ -16,71 +16,46 @@ package org.apache.maven.repository.proxy;
* limitations under the License.
*/

import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout;
import org.apache.maven.repository.proxy.configuration.ProxyConfiguration;
import org.apache.maven.repository.proxy.repository.ProxyRepository;
import org.apache.maven.wagon.ResourceDoesNotExistException;
import org.codehaus.plexus.PlexusTestCase;
import org.codehaus.plexus.component.repository.exception.ComponentLookupException;

import java.io.File;

/**
* @author Edwin Punzalan
*/
public class DefaultProxyManagerTest
public class ProxyRequestHandlerTest
extends PlexusTestCase
{
private ProxyManager proxy;
private ProxyRequestHandler requestHandler;

private ProxyConfiguration configuration;
public void testdummy(){}

/* TODO!
protected void setUp()
throws Exception
{
super.setUp();

proxy = (ProxyManager) container.lookup( ProxyManager.ROLE );

configuration = getProxyConfiguration();
proxy.setConfiguration( configuration );
}

public void testExceptions()
{
proxy.setConfiguration( null );

try
{
proxy.get( "/invalid" );
fail( "Expected empty configuration error." );
}
catch ( ProxyException e )
{
assertEquals( "Expected Exception not thrown.", "No proxy configuration defined.", e.getMessage() );
}
catch ( ResourceDoesNotExistException e )
{
fail( "Expected Exception not thrown." );
}
requestHandler = (ProxyRequestHandler) container.lookup( ProxyRequestHandler.ROLE );
}

public void testArtifactDownload()
throws Exception
{
//test download
File file = proxy.get( "/commons-logging/commons-logging/1.0/commons-logging-1.0.jar" );
String s = "/commons-logging/commons-logging/1.0/commons-logging-1.0.jar";
File file = get( s );
assertTrue( "File must be downloaded.", file.exists() );
assertTrue( "Downloaded file should be present in the cache.",
file.getAbsolutePath().startsWith( configuration.getRepositoryCachePath() ) );
file.getAbsolutePath().startsWith( managedRepository.getBasedir() ) );

//test cache
proxy.get( "/commons-logging/commons-logging/1.0/commons-logging-1.0.jar" );
get( "/commons-logging/commons-logging/1.0/commons-logging-1.0.jar" );

try
{
proxy.get( "/commons-logging/commons-logging/2.0/commons-logging-2.0.jar" );
get( "/commons-logging/commons-logging/2.0/commons-logging-2.0.jar" );
fail( "Expected ResourceDoesNotExistException exception not thrown" );
}
catch ( ResourceDoesNotExistException e )
@@ -89,49 +64,47 @@ public class DefaultProxyManagerTest
}
}

private File get( String s )
throws ProxyException, ResourceDoesNotExistException
{
return requestHandler.get( s, proxiedRepositories, managedRepository );
}

public void testArtifactChecksum()
throws Exception
{
//force the downlod from the remote repository, use getAlways()
File file = proxy.getAlways( "/commons-logging/commons-logging/1.0/commons-logging-1.0.jar.md5" );
File file = requestHandler.getAlways( "/commons-logging/commons-logging/1.0/commons-logging-1.0.jar.md5" );
assertTrue( "File must be downloaded.", file.exists() );
assertTrue( "Downloaded file should be present in the cache.",
file.getAbsolutePath().startsWith( configuration.getRepositoryCachePath() ) );
file.getAbsolutePath().startsWith( managedRepository.getBasedir() ) );
}

public void testNonArtifactWithNoChecksum()
throws Exception
{
File file = proxy.get( "/not-standard/repository/file.txt" );
File file = get( "/not-standard/repository/file.txt" );
assertTrue( "File must be downloaded.", file.exists() );
assertTrue( "Downloaded file should be present in the cache.",
file.getAbsolutePath().startsWith( configuration.getRepositoryCachePath() ) );
file.getAbsolutePath().startsWith( managedRepository.getBasedir() ) );
}

public void testNonArtifactWithMD5Checksum()
throws Exception
{
File file = proxy.get( "/checksumed-md5/repository/file.txt" );
File file = get( "/checksumed-md5/repository/file.txt" );
assertTrue( "File must be downloaded.", file.exists() );
assertTrue( "Downloaded file should be present in the cache.",
file.getAbsolutePath().startsWith( configuration.getRepositoryCachePath() ) );
file.getAbsolutePath().startsWith( managedRepository.getBasedir() ) );
}

public void testNonArtifactWithSHA1Checksum()
throws Exception
{
File file = proxy.get( "/checksumed-sha1/repository/file.txt" );
File file = get( "/checksumed-sha1/repository/file.txt" );
assertTrue( "File must be downloaded.", file.exists() );
assertTrue( "Downloaded file should be present in the cache.",
file.getAbsolutePath().startsWith( configuration.getRepositoryCachePath() ) );
}

protected void tearDown()
throws Exception
{
container.release( proxy );

super.tearDown();
file.getAbsolutePath().startsWith( managedRepository.getBasedir() ) );
}

private ProxyConfiguration getProxyConfiguration()
@@ -139,7 +112,7 @@ public class DefaultProxyManagerTest
{
ProxyConfiguration config = new ProxyConfiguration();

config.setRepositoryCachePath( "target/proxy-cache" );
config.setRepositoryCachePath( "target/requestHandler-cache" );

ArtifactRepositoryLayout defLayout = new DefaultRepositoryLayout();

@@ -151,4 +124,5 @@ public class DefaultProxyManagerTest

return config;
}
*/
}

+ 0
- 86
maven-repository-proxy/src/test/java/org/apache/maven/repository/proxy/configuration/MavenProxyPropertyLoaderTest.java View File

@@ -1,86 +0,0 @@
package org.apache.maven.repository.proxy.configuration;

/*
* Copyright 2005-2006 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import org.apache.maven.repository.proxy.repository.ProxyRepository;
import org.codehaus.plexus.PlexusTestCase;
import org.codehaus.plexus.util.FileUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;


/**
* @author Edwin Punzalan
*/
public class MavenProxyPropertyLoaderTest
extends PlexusTestCase
{
private static final int DEFAULT_CACHE_PERIOD = 3600;

public void testLoadValidMavenProxyConfiguration()
throws ValidationException, IOException
{
MavenProxyPropertyLoader loader = new MavenProxyPropertyLoader();

//must create the test directory bec configuration is using relative path which varies
FileUtils.mkdir( "target/remote-repo1" );

try
{
File confFile = getTestFile( "src/test/conf/maven-proxy-complete.conf" );

ProxyConfiguration config = loader.load( new FileInputStream( confFile ) );

assertTrue( "cache path changed", config.getRepositoryCachePath().endsWith( "target" ) );

assertEquals( "Count repositories", 4, config.getRepositories().size() );

ProxyRepository repo = (ProxyRepository) config.getRepositories().get( 0 );
assertEquals( "Repository name not as expected", "local-repo", repo.getKey() );
assertEquals( "Repository url does not match its name", "file://target", repo.getUrl() );
assertEquals( "Repository cache period check failed", 0, repo.getCachePeriod() );
assertFalse( "Repository failure caching check failed", repo.isCacheFailures() );

repo = (ProxyRepository) config.getRepositories().get( 1 );
assertEquals( "Repository name not as expected", "www-ibiblio-org", repo.getKey() );
assertEquals( "Repository url does not match its name", "http://www.ibiblio.org/maven2", repo.getUrl() );
assertEquals( "Repository cache period check failed", DEFAULT_CACHE_PERIOD, repo.getCachePeriod() );
assertTrue( "Repository failure caching check failed", repo.isCacheFailures() );

repo = (ProxyRepository) config.getRepositories().get( 2 );
assertEquals( "Repository name not as expected", "dist-codehaus-org", repo.getKey() );
assertEquals( "Repository url does not match its name", "http://dist.codehaus.org", repo.getUrl() );
assertEquals( "Repository cache period check failed", DEFAULT_CACHE_PERIOD, repo.getCachePeriod() );
assertTrue( "Repository failure caching check failed", repo.isCacheFailures() );

repo = (ProxyRepository) config.getRepositories().get( 3 );
assertEquals( "Repository name not as expected", "private-example-com", repo.getKey() );
assertEquals( "Repository url does not match its name", "http://private.example.com/internal",
repo.getUrl() );
assertEquals( "Repository cache period check failed", DEFAULT_CACHE_PERIOD, repo.getCachePeriod() );
assertFalse( "Repository failure caching check failed", repo.isCacheFailures() );
}
finally
{
//make sure to delete the test directory after tests
FileUtils.deleteDirectory( "target/remote-repo1" );
}
}

}

+ 0
- 137
maven-repository-proxy/src/test/java/org/apache/maven/repository/proxy/configuration/ProxyConfigurationTest.java View File

@@ -1,137 +0,0 @@
package org.apache.maven.repository.proxy.configuration;
/*
* Copyright 2005-2006 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout;
import org.apache.maven.artifact.repository.layout.LegacyRepositoryLayout;
import org.apache.maven.repository.proxy.repository.ProxyRepository;
import org.apache.maven.wagon.proxy.ProxyInfo;
import org.codehaus.plexus.PlexusTestCase;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
public class ProxyConfigurationTest
extends PlexusTestCase
{
private ProxyConfiguration config;
private static final int DEFAULT_CACHE_PERIOD = 3600;
private static final int DEFAULT_PORT = 80;
protected void setUp()
throws Exception
{
super.setUp();
config = new ProxyConfiguration();
}
public void testRepositoryCache()
{
File cacheFile = new File( "target/proxy-cache" );
config.setRepositoryCachePath( cacheFile.getAbsolutePath() );
assertEquals( config.getRepositoryCachePath(), cacheFile.getAbsolutePath() );
}
public void testRepositories()
{
ArtifactRepositoryLayout defLayout = new DefaultRepositoryLayout();
ProxyRepository repo1 = new ProxyRepository( "repo1", "http://www.ibiblio.org/maven2", defLayout );
repo1.setCacheFailures( true );
repo1.setCachePeriod( 0 );
repo1.setHardfail( true );
config.addRepository( repo1 );
assertEquals( 1, config.getRepositories().size() );
ArtifactRepositoryLayout legacyLayout = new LegacyRepositoryLayout();
ProxyRepository repo2 = new ProxyRepository( "repo2", "http://www.ibiblio.org/maven", legacyLayout );
repo2.setCacheFailures( false );
repo2.setCachePeriod( DEFAULT_CACHE_PERIOD );
repo2.setProxied( true );
config.setHttpProxy( "some.local.proxy", DEFAULT_PORT, "username", "password" );
config.addRepository( repo2 );
assertEquals( 2, config.getRepositories().size() );
List repositories = config.getRepositories();
ProxyRepository repo = (ProxyRepository) repositories.get( 0 );
assertEquals( "repo1", repo.getId() );
assertEquals( "http://www.ibiblio.org/maven2", repo.getUrl() );
assertTrue( repo.isCacheFailures() );
assertTrue( repo.isHardfail() );
assertEquals( 0, repo.getCachePeriod() );
assertEquals( repo1, repo );
repo = (ProxyRepository) repositories.get( 1 );
assertEquals( "repo2", repo.getId() );
assertEquals( "http://www.ibiblio.org/maven", repo.getUrl() );
assertFalse( repo.isCacheFailures() );
assertTrue( repo.isHardfail() );
assertEquals( DEFAULT_CACHE_PERIOD, repo.getCachePeriod() );
assertEquals( repo2, repo );
assertTrue( repo.isProxied() );
ProxyInfo proxyInfo = config.getHttpProxy();
assertNotNull( proxyInfo );
assertEquals( "some.local.proxy", proxyInfo.getHost() );
assertEquals( DEFAULT_PORT, proxyInfo.getPort() );
assertEquals( "username", proxyInfo.getUserName() );
assertEquals( "password", proxyInfo.getPassword() );
try
{
repositories.add( new ProxyRepository( "repo", "url", defLayout ) );
fail( "Expected UnsupportedOperationException not thrown." );
}
catch ( UnsupportedOperationException e )
{
assertTrue( true );
}
repositories = new ArrayList();
repositories.add( repo1 );
repositories.add( repo2 );
config.setRepositories( repositories );
assertEquals( repositories, config.getRepositories() );
}
public void testHttpProxy()
throws Exception
{
config.setHttpProxy( "some.local.proxy", DEFAULT_PORT, "username", "password", "ntlmHost", "ntlmDomain" );
ProxyInfo proxyInfo = config.getHttpProxy();
assertEquals( "test proxy host", proxyInfo.getHost(), "some.local.proxy" );
assertEquals( DEFAULT_PORT, proxyInfo.getPort() );
assertEquals( "username", proxyInfo.getUserName() );
assertEquals( "password", proxyInfo.getPassword() );
assertEquals( "ntlmHost", proxyInfo.getNtlmHost() );
assertEquals( "ntlmDomain", proxyInfo.getNtlmDomain() );
}
protected void tearDown()
throws Exception
{
config = null;
super.tearDown();
}
}

+ 0
- 19
maven-repository-webapp/pom.xml View File

@@ -102,14 +102,6 @@
<build>
<finalName>maven-repository-webapp</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<!-- TODO! temporary until tests are fixed -->
<skip>true</skip>
</configuration>
</plugin>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
@@ -148,17 +140,6 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>clean</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-maven-plugin</artifactId>

+ 0
- 154
maven-repository-webapp/src/main/java/org/apache/maven/repository/proxy/web/action/RepositoryProxyAction.java View File

@@ -1,154 +0,0 @@
package org.apache.maven.repository.proxy.web.action;

/*
* Copyright 2005-2006 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import com.opensymphony.xwork.Action;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.maven.repository.proxy.ProxyException;
import org.apache.maven.repository.proxy.ProxyManager;
import org.apache.maven.repository.proxy.configuration.MavenProxyPropertyLoader;
import org.apache.maven.repository.proxy.configuration.ProxyConfiguration;
import org.apache.maven.repository.proxy.configuration.ValidationException;
import org.apache.maven.wagon.ResourceDoesNotExistException;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.MalformedURLException;

/**
* This is the Action class responsible for processing artifact request,
* relies on the RestfulActionMapper to map the artifact request to this action.
*
* @plexus.component role="com.opensymphony.xwork.Action" role-hint="org.apache.maven.repository.manager.web.action.RepositoryProxyAction"
*/
public class RepositoryProxyAction
implements Action
{
/**
* logger instance
*/
protected static final Log log = LogFactory.getLog( RepositoryProxyAction.class );

public static final String NOTFOUND = "notFound";

public static final String PROXYERROR = "proxyError";

/**
* file requested by the client,
* TODO: validate the requestd file using na interceptor
*/
private String requestedFile;

/**
* main proxy logic
*
* @plexus.requirement role="org.apache.maven.repository.proxy.ProxyManager"
*/
private ProxyManager repositoryProxyManager;

/**
* configuration for the ProxyManager
*
* @plexus.requirement
*/
private ProxyConfiguration proxyConfig;

/**
* the inputstream for the artifact file
*/
private FileInputStream artifactStream;

/**
* the cached artifact file
*/
private File cachedFile;

/**
* proxy configuration file
* TODO: recode the configuration part when Configuration is finalized
* TODO: this is only temporary
*/
private String configFile;

// setters and getters

public void setProxyManager( ProxyManager manager )
{
repositoryProxyManager = manager;
}

public void setRequestedFile( String reqFile )
{
requestedFile = reqFile;
}

public String getRequestedFile()
{
return requestedFile;
}

public FileInputStream getArtifactStream()
{
return artifactStream;
}

public File getCachedFile()
{
return cachedFile;
}

public void setConfigFile( String fileName )
{
configFile = fileName;
}

/**
* entry-point
*/
public String execute()
throws MalformedURLException, IOException, ValidationException
{
try
{
MavenProxyPropertyLoader loader = new MavenProxyPropertyLoader();
proxyConfig = loader.load( new FileInputStream( configFile ) );
repositoryProxyManager.setConfiguration( proxyConfig );
cachedFile = repositoryProxyManager.get( requestedFile );
artifactStream = new FileInputStream( cachedFile );
}
catch ( ResourceDoesNotExistException ex )
{
log.info( "[not found] " + ex.getMessage() );
return NOTFOUND;
}
catch ( ProxyException ex )
{
log.info( "[proxy error] " + ex.getMessage() );
return PROXYERROR;
}
catch ( FileNotFoundException ex )
{
log.info( "[not found] " + ex.getMessage() );
return NOTFOUND;
}

return SUCCESS;
}
}

+ 0
- 77
maven-repository-webapp/src/test/java/org/apache/maven/repository/proxy/web/action/test/RepositoryProxyActionTest.java View File

@@ -1,77 +0,0 @@
package org.apache.maven.repository.proxy.web.action.test;

/*
* Copyright 2005-2006 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import org.apache.maven.repository.proxy.web.action.RepositoryProxyAction;
import org.apache.maven.repository.proxy.web.action.test.stub.ProxyManagerStub;
import org.codehaus.plexus.PlexusTestCase;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.Properties;

public class RepositoryProxyActionTest
extends PlexusTestCase
{

/**
* test basic proxy operation
*
* @throws Exception
*/
public void testProxy()
throws Exception
{
String testDir = getBasedir() + "/target/test-classes/unit/proxy-test";
RepositoryProxyAction action = new RepositoryProxyAction();
ProxyManagerStub proxyManager = new ProxyManagerStub( testDir );
File cachedFile = proxyManager.get( "dummyFile" );

if ( !cachedFile.getParentFile().exists() )
{
assertTrue( "can not create test file", cachedFile.getParentFile().mkdirs() );
}

if ( !cachedFile.exists() )
{
assertTrue( "can not create test file", cachedFile.createNewFile() );
}

File tmpDir = getTestFile( "target/tmp-repo" );
tmpDir.mkdirs();

// TODO: configure manually, test the property loader elsewhere
Properties properties = new Properties();
properties.load( getClass().getResourceAsStream( "/unit/proxy-test/maven-proxy-complete.conf" ) );
properties.setProperty( "repo.local.store", tmpDir.getAbsolutePath() );
File tempFile = File.createTempFile( "test", "tmp" );
tempFile.deleteOnExit();
properties.store( new FileOutputStream( tempFile ), "" );

action.setConfigFile( tempFile.getAbsolutePath() );
action.setProxyManager( proxyManager );

String result = action.execute();
FileInputStream fileStream = action.getArtifactStream();

assertEquals( "proxy error", action.SUCCESS, result );
assertNotNull( "inputstream not set", fileStream );
assertNotNull( "cached file not set", action.getCachedFile() );
assertTrue( "proxy error", cachedFile.getPath().equals( action.getCachedFile().getPath() ) );
}
}

+ 0
- 58
maven-repository-webapp/src/test/java/org/apache/maven/repository/proxy/web/action/test/stub/ProxyManagerStub.java View File

@@ -1,58 +0,0 @@
package org.apache.maven.repository.proxy.web.action.test.stub;

/*
* Copyright 2005-2006 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import org.apache.maven.repository.proxy.ProxyManager;
import org.apache.maven.repository.proxy.configuration.ProxyConfiguration;

import java.io.File;

public class ProxyManagerStub
implements ProxyManager
{
String baseDir;

public ProxyManagerStub( String base )
{
baseDir = base;
}

public File get( String requestFile )
{
return new File( baseDir, "proxy-cache/test-0.0.jar" );
}

public File getRemoteFile( String reqFile )
{
return new File( baseDir, "proxy-chache/test-0.0.jar" );
}

public void setConfiguration( ProxyConfiguration config )
{
// do nothing
}

public ProxyConfiguration getConfiguration()
{
return null;
}

public File getAlways( String name )
{
return null;
}
}

+ 1
- 1
pom.xml View File

@@ -293,7 +293,7 @@
</reporting>
<profiles>
<profile>
<id>ciProfile</id>
<id>ci</id>
<activation>
<property>
<name>enableCiProfile</name>

Loading…
Cancel
Save