From 93dcc426469c4fb4289e6888a91d74541978af28 Mon Sep 17 00:00:00 2001 From: "Edwin L. Punzalan" Date: Tue, 31 Jan 2006 02:13:38 +0000 Subject: [PATCH] Added proxy module git-svn-id: https://svn.apache.org/repos/asf/maven/repository-manager/trunk@373670 13f79535-47bb-0310-9956-ffa450edef68 --- maven-repository-proxy/pom.xml | 37 ++ .../repository/proxy/DefaultProxyManager.java | 338 ++++++++++++++++++ .../repository/proxy/ProxyException.java | 18 + .../maven/repository/proxy/ProxyManager.java | 20 ++ .../configuration/ProxyConfiguration.java | 76 ++++ .../repository/proxy/files/Checksum.java | 36 ++ .../files/DefaultRepositoryFileManager.java | 95 +++++ .../proxy/repository/ProxyRepository.java | 38 ++ pom.xml | 1 + 9 files changed, 659 insertions(+) create mode 100644 maven-repository-proxy/pom.xml create mode 100644 maven-repository-proxy/src/main/java/org/apache/maven/repository/proxy/DefaultProxyManager.java create mode 100644 maven-repository-proxy/src/main/java/org/apache/maven/repository/proxy/ProxyException.java create mode 100644 maven-repository-proxy/src/main/java/org/apache/maven/repository/proxy/ProxyManager.java create mode 100644 maven-repository-proxy/src/main/java/org/apache/maven/repository/proxy/configuration/ProxyConfiguration.java create mode 100644 maven-repository-proxy/src/main/java/org/apache/maven/repository/proxy/files/Checksum.java create mode 100644 maven-repository-proxy/src/main/java/org/apache/maven/repository/proxy/files/DefaultRepositoryFileManager.java create mode 100644 maven-repository-proxy/src/main/java/org/apache/maven/repository/proxy/repository/ProxyRepository.java diff --git a/maven-repository-proxy/pom.xml b/maven-repository-proxy/pom.xml new file mode 100644 index 000000000..a6201714b --- /dev/null +++ b/maven-repository-proxy/pom.xml @@ -0,0 +1,37 @@ + + + + + org.apache.maven.repository + maven-repository-manager + 1.0-SNAPSHOT + + 4.0.0 + maven-repository-proxy + Maven Repository Proxy + + + org.apache.maven + maven-artifact + + + org.apache.maven + maven-artifact-manager + + + diff --git a/maven-repository-proxy/src/main/java/org/apache/maven/repository/proxy/DefaultProxyManager.java b/maven-repository-proxy/src/main/java/org/apache/maven/repository/proxy/DefaultProxyManager.java new file mode 100644 index 000000000..b1a6e637c --- /dev/null +++ b/maven-repository-proxy/src/main/java/org/apache/maven/repository/proxy/DefaultProxyManager.java @@ -0,0 +1,338 @@ +package org.apache.maven.repository.proxy; + +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.repository.proxy.configuration.ProxyConfiguration; +import org.apache.maven.repository.proxy.files.DefaultRepositoryFileManager; +import org.apache.maven.repository.proxy.files.Checksum; +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.util.FileUtils; + +import java.io.File; +import java.io.IOException; +import java.security.NoSuchAlgorithmException; +import java.util.Iterator; + +/** + * @author Edwin Punzalan + */ +public class DefaultProxyManager + //implements ProxyManager +{ + /* @plexus.requirement */ + private WagonManager wagon; + + private ProxyConfiguration config; + + public DefaultProxyManager( ProxyConfiguration configuration ) + { + config = configuration; + } + + public File get( String path ) + throws ProxyException + { + String cachePath = config.getRepositoryCachePath(); + File cachedFile = new File( cachePath, path ); + if ( !cachedFile.exists() ) + { + getRemoteFile( path ); + } + return cachedFile; + } + + public File getRemoteFile( String path ) + throws ProxyException + { + try + { + if ( path.indexOf( "/jars/" ) >= 0 ) + { + //@todo maven 1 repo request + throw new ProxyException( "Maven 1 repository requests not yet supported." ); + } + else if ( path.indexOf( "/poms/" ) >= 0 ) + { + //@todo maven 1 repo request + throw new ProxyException( "Maven 1 repository requests not yet supported." ); + } + else + { + //maven 2 repo request + Object obj = new DefaultRepositoryFileManager().getRequestedObjectFromPath( path ); + + if ( obj == null ) + { + //right now, only metadata is known to fit here + return getRepositoryFile( path ); + } + else if ( obj instanceof Checksum ) + { + return getRepositoryFile( path, false ); + } + else if ( obj instanceof Artifact ) + { + Artifact artifact = (Artifact) obj; + return getArtifactFile( artifact ); + } + else + { + throw new ProxyException( "Could not hande repository object: " + obj.getClass() ); + } + } + } + catch( TransferFailedException e ) + { + throw new ProxyException( e.getMessage(), e ); + } + catch( ResourceDoesNotExistException e) + { + throw new ProxyException( e.getMessage(), e ); + } + } + + private File getArtifactFile( Artifact artifact ) + throws TransferFailedException, ResourceDoesNotExistException + { + ArtifactRepository repoCache = config.getRepositoryCache(); + + File artifactFile = new File( repoCache.getBasedir(), repoCache.pathOf( artifact ) ); + + if ( !artifactFile.exists() ) + { + wagon.getArtifact( artifact, config.getRepositories() ); + artifactFile = artifact.getFile(); + } + + return artifactFile; + } + + private File getRepositoryFile( String path ) + throws ProxyException + { + return getRepositoryFile( path, true ); + } + + private File getRepositoryFile( String path, boolean useChecksum ) + throws ProxyException + { + ArtifactRepository cache = config.getRepositoryCache(); + File target = new File( cache.getBasedir(), path ); + + for( Iterator repositories = config.getRepositories().iterator(); repositories.hasNext(); ) + { + ProxyRepository repository = (ProxyRepository) repositories.next(); + + try + { + Wagon wagon = this.wagon.getWagon( repository.getProtocol() ); + + //@todo configure wagon + + ChecksumObserver listener = null; + try + { + listener = repository.getChecksumObserver(); + + if ( listener != null ) + { + wagon.addTransferListener( listener ); + } + } + catch ( NoSuchAlgorithmException e ) + { + System.out.println( "Skipping checksum validation for unsupported algorithm: " + + repository.getChecksum() ); + } + + if ( connectToRepository( wagon, repository ) ) + { + File temp = new File( target.getAbsolutePath() + ".tmp" ); + temp.deleteOnExit(); + + int tries = 0; + boolean success = false; + + while( !success ) + { + tries++; + + wagon.get( path, temp ); + + if ( useChecksum ) + { + success = doChecksumCheck( listener, repository, path, wagon ); + } + else + { + success = true; + } + + if ( tries > 1 && !success ) + { + throw new ProxyException( "Checksum failures occurred while downloading " + path ); + } + } + disconnectWagon( wagon ); + + return target; + } + //try next repository + } + catch ( TransferFailedException e ) + { + System.out.println( "Skipping repository " + repository.getUrl() + + ": " + e.getMessage() ); + } + catch ( ResourceDoesNotExistException e ) + { + //do nothing, file not found in this repository + } + catch ( AuthorizationException e ) + { + System.out.println( "Skipping repository " + repository.getUrl() + + ": " + e.getMessage() ); + } + catch ( UnsupportedProtocolException e ) + { + System.out.println( "Skipping repository " + repository.getUrl() + + ": no wagon configured for protocol " + repository.getProtocol() ); + } + } + + throw new ProxyException( "Could not find " + path + " in any of the repositories." ); + } + + private boolean connectToRepository( Wagon wagon, ProxyRepository repository ) + { + boolean connected = false; + try + { + wagon.connect( repository ); + connected = true; + } + catch ( ConnectionException e ) + { + System.out.println( "Could not connect to " + repository.getId() + ": " + e.getMessage() ); + } + catch ( AuthenticationException e ) + { + System.out.println( "Could not connect to " + repository.getId() + ": " + e.getMessage() ); + } + + return connected; + } + + private boolean doChecksumCheck( ChecksumObserver listener, ProxyRepository repository, String path, Wagon wagon ) + //throws ChecksumFailedException + { + boolean success = false; + + try + { + String checksumExt = repository.getChecksum().getFileExtension(); + String remotePath = path + "." + checksumExt; + File checksumFile = new File( config.getRepositoryCache().getBasedir(), remotePath ); + + verifyChecksum( listener.getActualChecksum(), checksumFile, remotePath, checksumExt, wagon ); + + wagon.removeTransferListener( listener ); + + success = true; + } + catch ( ChecksumFailedException e ) + { + System.out.println( "*** CHECKSUM FAILED - " + e.getMessage() + " - RETRYING" ); + } + + return success; + } + + private void verifyChecksum( String actualChecksum, File destination, String remotePath, + String checksumFileExtension, Wagon wagon ) + throws ChecksumFailedException + { + try + { + File tempDestination = new File( destination.getAbsolutePath() + ".tmp" ); + tempDestination.deleteOnExit(); + + File tempChecksumFile = new File( tempDestination + checksumFileExtension + ".tmp" ); + tempChecksumFile.deleteOnExit(); + + wagon.get( remotePath + checksumFileExtension, tempChecksumFile ); + + String expectedChecksum = FileUtils.fileRead( tempChecksumFile ); + + // remove whitespaces at the end + expectedChecksum = expectedChecksum.trim(); + + // check for 'MD5 (name) = CHECKSUM' + if ( expectedChecksum.startsWith( "MD5" ) ) + { + int lastSpacePos = expectedChecksum.lastIndexOf( ' ' ); + expectedChecksum = expectedChecksum.substring( lastSpacePos + 1 ); + } + else + { + // remove everything after the first space (if available) + int spacePos = expectedChecksum.indexOf( ' ' ); + + if ( spacePos != -1 ) + { + expectedChecksum = expectedChecksum.substring( 0, spacePos ); + } + } + + if ( expectedChecksum.equals( actualChecksum ) ) + { + File checksumFile = new File( destination + checksumFileExtension ); + if ( checksumFile.exists() ) checksumFile.delete(); + FileUtils.copyFile( tempChecksumFile, checksumFile ); + } + else + { + throw new ChecksumFailedException( "Checksum failed on download: local = '" + actualChecksum + + "'; remote = '" + expectedChecksum + "'" ); + } + } + catch ( TransferFailedException e ) + { + System.out.println( "Skipping checksum validation for " + remotePath + ": " + e.getMessage() ); + } + catch ( ResourceDoesNotExistException e ) + { + System.out.println( "Skipping checksum validation for " + remotePath + ": " + e.getMessage() ); + } + catch ( AuthorizationException e ) + { + System.out.println( "Skipping checksum validation for " + remotePath + ": " + e.getMessage() ); + } + catch ( IOException e ) + { + throw new ChecksumFailedException( "Invalid checksum file", e ); + } + } + + private void disconnectWagon( Wagon wagon ) + { + try + { + wagon.disconnect(); + } + catch ( ConnectionException e ) + { + System.err.println( "Problem disconnecting from wagon - ignoring: " + e.getMessage() ); + } + } +} diff --git a/maven-repository-proxy/src/main/java/org/apache/maven/repository/proxy/ProxyException.java b/maven-repository-proxy/src/main/java/org/apache/maven/repository/proxy/ProxyException.java new file mode 100644 index 000000000..92ac871c4 --- /dev/null +++ b/maven-repository-proxy/src/main/java/org/apache/maven/repository/proxy/ProxyException.java @@ -0,0 +1,18 @@ +package org.apache.maven.repository.proxy; + +/** + * @author Edwin Punzalan + */ +public class ProxyException + extends Exception +{ + public ProxyException( String message ) + { + super( message ); + } + + public ProxyException( String message, Throwable t ) + { + super( message, t ); + } +} diff --git a/maven-repository-proxy/src/main/java/org/apache/maven/repository/proxy/ProxyManager.java b/maven-repository-proxy/src/main/java/org/apache/maven/repository/proxy/ProxyManager.java new file mode 100644 index 000000000..3c582aa4c --- /dev/null +++ b/maven-repository-proxy/src/main/java/org/apache/maven/repository/proxy/ProxyManager.java @@ -0,0 +1,20 @@ +package org.apache.maven.repository.proxy; + +import org.apache.maven.artifact.Artifact; +import org.apache.maven.wagon.ResourceDoesNotExistException; +import org.apache.maven.wagon.TransferFailedException; + +import java.io.IOException; +import java.io.InputStream; +import java.io.File; + +/** + * @author Edwin Punzalan + */ +public interface ProxyManager +{ + File getArtifactFile( Artifact artifact ) + throws TransferFailedException, ResourceDoesNotExistException, IOException; + InputStream getArtifactAsStream( Artifact artifact ) + throws TransferFailedException, ResourceDoesNotExistException, IOException; +} diff --git a/maven-repository-proxy/src/main/java/org/apache/maven/repository/proxy/configuration/ProxyConfiguration.java b/maven-repository-proxy/src/main/java/org/apache/maven/repository/proxy/configuration/ProxyConfiguration.java new file mode 100644 index 000000000..990e15480 --- /dev/null +++ b/maven-repository-proxy/src/main/java/org/apache/maven/repository/proxy/configuration/ProxyConfiguration.java @@ -0,0 +1,76 @@ +package org.apache.maven.repository.proxy.configuration; + +import org.apache.maven.artifact.repository.ArtifactRepository; +import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy; +import org.apache.maven.artifact.repository.ArtifactRepositoryFactory; +import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout; +import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout; +import org.apache.maven.repository.proxy.repository.ProxyRepository; + +import java.util.ArrayList; +import java.util.List; +import java.util.Collections; + +/** + * @plexus.component role="org.apache.maven.repository.proxy.configuration.ProxyConfiguration" + * + * @author Edwin Punzalan + */ +public class ProxyConfiguration +{ + public static final String ROLE = ProxyConfiguration.class.getName(); + + /** @plexus.requirement */ + private ArtifactRepositoryFactory artifactRepositoryFactory; + + private boolean browsable; + private ArtifactRepository repoCache; + private ArrayList repositories = new ArrayList(); + + public void setBrowsable( boolean browsable ) + { + this.browsable = browsable; + } + + public boolean isBrowsable() + { + return browsable; + } + + public void setRepositoryCachePath( String repoCachePath ) + { + ArtifactRepositoryPolicy standardPolicy; + standardPolicy = new ArtifactRepositoryPolicy( true, ArtifactRepositoryPolicy.UPDATE_POLICY_ALWAYS, + ArtifactRepositoryPolicy.CHECKSUM_POLICY_IGNORE ); + + ArtifactRepositoryLayout layout = new DefaultRepositoryLayout(); + + repoCache = artifactRepositoryFactory.createArtifactRepository( "localCache", repoCachePath, layout, + standardPolicy, standardPolicy ); + } + + public ArtifactRepository getRepositoryCache( ) + { + return repoCache; + } + + public String getRepositoryCachePath() + { + return repoCache.getBasedir(); + } + + public void addRepository( ProxyRepository repository ) + { + repositories.add( repository ); + } + + public List getRepositories() + { + return Collections.unmodifiableList( repositories ); + } + + public void setRepositories( ArrayList repositories ) + { + this.repositories = repositories; + } +} diff --git a/maven-repository-proxy/src/main/java/org/apache/maven/repository/proxy/files/Checksum.java b/maven-repository-proxy/src/main/java/org/apache/maven/repository/proxy/files/Checksum.java new file mode 100644 index 000000000..458848899 --- /dev/null +++ b/maven-repository-proxy/src/main/java/org/apache/maven/repository/proxy/files/Checksum.java @@ -0,0 +1,36 @@ +package org.apache.maven.repository.proxy.files; + +/** + * @author Edwin Punzalan + */ +public class Checksum +{ + private String algorithm; + + public Checksum( String algorithm ) + { + this.setAlgorithm( algorithm ); + } + + public String getFileExtension() + { + if ( "MD5".equals( algorithm ) ) + { + return "md5"; + } + else + { + return "sha1"; + } + } + + public String getAlgorithm() + { + return algorithm; + } + + public void setAlgorithm( String algorithm ) + { + this.algorithm = algorithm; + } +} diff --git a/maven-repository-proxy/src/main/java/org/apache/maven/repository/proxy/files/DefaultRepositoryFileManager.java b/maven-repository-proxy/src/main/java/org/apache/maven/repository/proxy/files/DefaultRepositoryFileManager.java new file mode 100644 index 000000000..f3317735c --- /dev/null +++ b/maven-repository-proxy/src/main/java/org/apache/maven/repository/proxy/files/DefaultRepositoryFileManager.java @@ -0,0 +1,95 @@ +package org.apache.maven.repository.proxy.files; + +import org.apache.maven.artifact.Artifact; +import org.apache.maven.artifact.factory.ArtifactFactory; + +import java.util.ArrayList; +import java.util.List; +import java.util.StringTokenizer; + +/** + * @author Edwin Punzalan + */ +public class DefaultRepositoryFileManager +{ + /* @plexus.requirement */ + private ArtifactFactory factory; + + public Object getRequestedObjectFromPath( String path ) + { + if ( path.endsWith( ".pom" ) ) + { + return getArtifactFromPath( path ); + } + else if ( path.endsWith( "ar" ) ) + { + return getArtifactFromPath( path ); + } + else if ( path.endsWith( ".md5" ) ) + { + return new Checksum( "MD5" ); + } + else if ( path.endsWith( ".sha1" ) ) + { + return new Checksum( "SHA-1" ); + } + else + { + //@todo handle metadata file requests + return null; + } + } + + private Artifact getArtifactFromPath( String path ) + { + List pathInfo = getReversedPathInfo( path ); + String filename = getPathToken( pathInfo ); + String version = getPathToken( pathInfo ); + String artifactId = getPathToken( pathInfo ); + String groupId = ""; + while ( pathInfo.size() > 0 ) + { + if ( groupId.length() == 0 ) + { + groupId = "." + groupId; + } + else + { + groupId = getPathToken( pathInfo ) + "." + groupId; + } + } + + return factory.createBuildArtifact( groupId, artifactId, version, getFileExtension( filename ) ); + } + + private List getReversedPathInfo( String path ) + { + List reversedPath = new ArrayList(); + + StringTokenizer tokenizer = new StringTokenizer( path, "/" ); + while( tokenizer.hasMoreTokens() ) + { + reversedPath.add( 0, tokenizer.nextToken() ); + } + + return reversedPath; + } + + private String getPathToken( List path ) + { + if ( path.size() > 0 ) + { + return (String) path.remove( 0 ); + } + else + { + return null; + } + } + + private String getFileExtension( String filename ) + { + int idx = filename.lastIndexOf( '.' ); + return filename.substring( idx + 1 ); + } +} diff --git a/maven-repository-proxy/src/main/java/org/apache/maven/repository/proxy/repository/ProxyRepository.java b/maven-repository-proxy/src/main/java/org/apache/maven/repository/proxy/repository/ProxyRepository.java new file mode 100644 index 000000000..d0e833952 --- /dev/null +++ b/maven-repository-proxy/src/main/java/org/apache/maven/repository/proxy/repository/ProxyRepository.java @@ -0,0 +1,38 @@ +package org.apache.maven.repository.proxy.repository; + +import org.apache.maven.artifact.repository.DefaultArtifactRepository; +import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout; +import org.apache.maven.wagon.observers.ChecksumObserver; +import org.apache.maven.repository.proxy.files.Checksum; + +import java.security.NoSuchAlgorithmException; + +/** + * @author Edwin Punzalan + */ +public class ProxyRepository + extends DefaultArtifactRepository +{ + private Checksum checksum; + + public ProxyRepository( String id, String url, ArtifactRepositoryLayout layout ) + { + super( id, url, layout ); + } + + public void setChecksum( String algorithm ) + { + this.checksum = new Checksum( algorithm ); + } + + public Checksum getChecksum() + { + return checksum; + } + + public ChecksumObserver getChecksumObserver() + throws NoSuchAlgorithmException + { + return new ChecksumObserver( checksum.getAlgorithm() ); + } +} diff --git a/pom.xml b/pom.xml index 7358f2a29..21b792983 100644 --- a/pom.xml +++ b/pom.xml @@ -137,6 +137,7 @@ maven-repository-indexer maven-repository-utils maven-repository-webapp + maven-repository-proxy -- 2.39.5