123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595 |
- package org.apache.archiva.metadata.repository.storage.maven2;
-
- /*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.archiva.common.utils.VersionUtil;
- import org.apache.archiva.maven2.metadata.MavenMetadataReader;
- import org.apache.archiva.metadata.repository.storage.RepositoryPathTranslator;
- import org.apache.archiva.model.ArchivaRepositoryMetadata;
- import org.apache.archiva.model.SnapshotVersion;
- import org.apache.archiva.proxy.maven.WagonFactory;
- import org.apache.archiva.proxy.maven.WagonFactoryException;
- import org.apache.archiva.proxy.maven.WagonFactoryRequest;
- import org.apache.archiva.proxy.model.NetworkProxy;
- import org.apache.archiva.repository.ManagedRepository;
- import org.apache.archiva.repository.RemoteRepository;
- import org.apache.archiva.repository.RepositoryCredentials;
- import org.apache.archiva.repository.maven2.MavenSystemManager;
- import org.apache.archiva.repository.storage.StorageAsset;
- import org.apache.archiva.xml.XMLException;
- import org.apache.commons.lang.StringUtils;
- import org.apache.http.auth.UsernamePasswordCredentials;
- import org.apache.maven.model.Dependency;
- import org.apache.maven.model.Parent;
- import org.apache.maven.model.Repository;
- import org.apache.maven.model.building.FileModelSource;
- import org.apache.maven.model.building.ModelSource;
- import org.apache.maven.model.resolution.InvalidRepositoryException;
- import org.apache.maven.model.resolution.ModelResolver;
- import org.apache.maven.model.resolution.UnresolvableModelException;
- 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.authentication.AuthenticationInfo;
- import org.apache.maven.wagon.authorization.AuthorizationException;
- import org.apache.maven.wagon.proxy.ProxyInfo;
- import org.eclipse.aether.RepositorySystemSession;
- import org.eclipse.aether.artifact.Artifact;
- import org.eclipse.aether.artifact.DefaultArtifact;
- import org.eclipse.aether.impl.VersionRangeResolver;
- import org.eclipse.aether.resolution.VersionRangeRequest;
- import org.eclipse.aether.resolution.VersionRangeResolutionException;
- import org.eclipse.aether.resolution.VersionRangeResult;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
-
- import java.io.IOException;
- import java.nio.file.Files;
- import java.nio.file.Path;
- import java.nio.file.Paths;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
-
- public class RepositoryModelResolver
- implements ModelResolver
- {
-
- private final Map<String, NetworkProxy> networkProxyMap = new HashMap<>();
-
- private RepositorySystemSession session;
- private VersionRangeResolver versionRangeResolver;
-
- private StorageAsset basedir;
-
- private RepositoryPathTranslator pathTranslator;
-
- private WagonFactory wagonFactory;
-
- private List<RemoteRepository> remoteRepositories;
-
- private ManagedRepository targetRepository;
-
- private static final Logger log = LoggerFactory.getLogger( RepositoryModelResolver.class );
-
- private static final String METADATA_FILENAME = "maven-metadata.xml";
-
- private MavenSystemManager mavenSystemManager;
-
-
-
- private ManagedRepository managedRepository;
-
- public RepositoryModelResolver(StorageAsset basedir, RepositoryPathTranslator pathTranslator )
- {
- this.basedir = basedir;
-
- this.pathTranslator = pathTranslator;
- }
-
- public RepositoryModelResolver(ManagedRepository managedRepository, RepositoryPathTranslator pathTranslator,
- WagonFactory wagonFactory, List<RemoteRepository> remoteRepositories,
- Map<String, NetworkProxy> networkProxiesMap, ManagedRepository targetRepository,
- MavenSystemManager mavenSystemManager)
- {
- this( managedRepository.getAsset(""), pathTranslator );
-
- this.managedRepository = managedRepository;
-
- this.wagonFactory = wagonFactory;
-
- this.remoteRepositories = remoteRepositories;
-
- this.networkProxyMap.clear();
- this.networkProxyMap.putAll(networkProxiesMap);
-
- this.targetRepository = targetRepository;
-
- this.session = MavenSystemManager.newRepositorySystemSession( managedRepository.getAsset("").getFilePath().toString() );
-
- this.versionRangeResolver = mavenSystemManager.getLocator().getService(VersionRangeResolver.class);
-
- this.mavenSystemManager = mavenSystemManager;
- }
-
-
- @Override
- public ModelSource resolveModel( String groupId, String artifactId, String version )
- throws UnresolvableModelException
- {
- String filename = artifactId + "-" + version + ".pom";
- // TODO: we need to convert 1.0-20091120.112233-1 type paths to baseVersion for the below call - add a test
-
- StorageAsset model = pathTranslator.toFile( basedir, groupId, artifactId, version, filename );
-
- if ( !model.exists() )
- {
- /**
- *
- */
- // is a SNAPSHOT ? so we can try to find locally before asking remote repositories.
- if ( StringUtils.contains( version, VersionUtil.SNAPSHOT ) )
- {
- Path localSnapshotModel = findTimeStampedSnapshotPom( groupId, artifactId, version, model.getParent().getFilePath() );
- if ( localSnapshotModel != null )
- {
- return new FileModelSource( localSnapshotModel.toFile() );
- }
-
- }
-
- for ( RemoteRepository remoteRepository : remoteRepositories )
- {
- try
- {
- boolean success = getModelFromProxy( remoteRepository, groupId, artifactId, version, filename );
- if ( success && model.exists() )
- {
- log.info( "Model '{}' successfully retrieved from remote repository '{}'",
- model.getPath(), remoteRepository.getId() );
- break;
- }
- }
- catch ( ResourceDoesNotExistException e )
- {
- log.info(
- "An exception was caught while attempting to retrieve model '{}' from remote repository '{}'.Reason:{}",
- model.getPath(), remoteRepository.getId(), e.getMessage() );
- }
- catch ( Exception e )
- {
- log.warn(
- "An exception was caught while attempting to retrieve model '{}' from remote repository '{}'.Reason:{}",
- model.getPath(), remoteRepository.getId(), e.getMessage() );
-
- continue;
- }
- }
- }
-
- return new FileModelSource( model.getFilePath().toFile() );
- }
-
- public ModelSource resolveModel(Parent parent) throws UnresolvableModelException {
- try {
- Artifact artifact = new DefaultArtifact(parent.getGroupId(), parent.getArtifactId(), "", "pom", parent.getVersion());
- VersionRangeRequest versionRangeRequest;
- versionRangeRequest = new VersionRangeRequest(artifact, null, null);
- VersionRangeResult versionRangeResult = this.versionRangeResolver.resolveVersionRange(this.session, versionRangeRequest);
- if (versionRangeResult.getHighestVersion() == null) {
- throw new UnresolvableModelException(String.format("No versions matched the requested parent version range '%s'", parent.getVersion()), parent.getGroupId(), parent.getArtifactId(), parent.getVersion());
- } else if (versionRangeResult.getVersionConstraint() != null && versionRangeResult.getVersionConstraint().getRange() != null && versionRangeResult.getVersionConstraint().getRange().getUpperBound() == null) {
- throw new UnresolvableModelException(String.format("The requested parent version range '%s' does not specify an upper bound", parent.getVersion()), parent.getGroupId(), parent.getArtifactId(), parent.getVersion());
- } else {
- parent.setVersion(versionRangeResult.getHighestVersion().toString());
- return this.resolveModel(parent.getGroupId(), parent.getArtifactId(), parent.getVersion());
- }
- } catch ( VersionRangeResolutionException var5) {
- throw new UnresolvableModelException(var5.getMessage(), parent.getGroupId(), parent.getArtifactId(), parent.getVersion(), var5);
- }
- }
-
- public ModelSource resolveModel(Dependency dependency) throws UnresolvableModelException {
- try {
- Artifact artifact = new DefaultArtifact(dependency.getGroupId(), dependency.getArtifactId(), "", "pom", dependency.getVersion());
- VersionRangeRequest versionRangeRequest = new VersionRangeRequest(artifact, null, null);
- VersionRangeResult versionRangeResult = this.versionRangeResolver.resolveVersionRange(this.session, versionRangeRequest);
- if (versionRangeResult.getHighestVersion() == null) {
- throw new UnresolvableModelException(String.format("No versions matched the requested dependency version range '%s'", dependency.getVersion()), dependency.getGroupId(), dependency.getArtifactId(), dependency.getVersion());
- } else if (versionRangeResult.getVersionConstraint() != null && versionRangeResult.getVersionConstraint().getRange() != null && versionRangeResult.getVersionConstraint().getRange().getUpperBound() == null) {
- throw new UnresolvableModelException(String.format("The requested dependency version range '%s' does not specify an upper bound", dependency.getVersion()), dependency.getGroupId(), dependency.getArtifactId(), dependency.getVersion());
- } else {
- dependency.setVersion(versionRangeResult.getHighestVersion().toString());
- return this.resolveModel(dependency.getGroupId(), dependency.getArtifactId(), dependency.getVersion());
- }
- } catch (VersionRangeResolutionException var5) {
- throw new UnresolvableModelException(var5.getMessage(), dependency.getGroupId(), dependency.getArtifactId(), dependency.getVersion(), var5);
- }
- }
-
- protected Path findTimeStampedSnapshotPom( String groupId, String artifactId, String version,
- Path parentDirectory )
- {
-
- // reading metadata if there
- Path mavenMetadata = parentDirectory.resolve( METADATA_FILENAME );
- if ( Files.exists(mavenMetadata) )
- {
- try
- {
- ArchivaRepositoryMetadata archivaRepositoryMetadata = MavenMetadataReader.read( mavenMetadata);
- SnapshotVersion snapshotVersion = archivaRepositoryMetadata.getSnapshotVersion();
- if ( snapshotVersion != null )
- {
- String lastVersion = snapshotVersion.getTimestamp();
- int buildNumber = snapshotVersion.getBuildNumber();
- String snapshotPath =
- StringUtils.replaceChars( groupId, '.', '/' ) + '/' + artifactId + '/' + version + '/'
- + artifactId + '-' + StringUtils.remove( version, "-" + VersionUtil.SNAPSHOT ) + '-'
- + lastVersion + '-' + buildNumber + ".pom";
-
- log.debug( "use snapshot path {} for maven coordinate {}:{}:{}", snapshotPath, groupId, artifactId,
- version );
-
- StorageAsset model = basedir.resolve( snapshotPath );
- //model = pathTranslator.toFile( basedir, groupId, artifactId, lastVersion, filename );
- if ( model.exists() )
- {
- return model.getFilePath();
- }
- }
- }
- catch (XMLException e )
- {
- log.warn( "fail to read {}, {}", mavenMetadata.toAbsolutePath(), e.getCause() );
- }
- }
-
- return null;
- }
-
- @Override
- public void addRepository( Repository repository )
- throws InvalidRepositoryException
- {
- // we just ignore repositories outside of the current one for now
- // TODO: it'd be nice to look them up from Archiva's set, but we want to do that by URL / mapping, not just the
- // ID since they will rarely match
- }
-
- @Override
- public void addRepository( Repository repository, boolean b ) throws InvalidRepositoryException
- {
-
- }
-
- @Override
- public ModelResolver newCopy()
- {
- return new RepositoryModelResolver( managedRepository, pathTranslator, wagonFactory, remoteRepositories,
- networkProxyMap, targetRepository, mavenSystemManager);
- }
-
- // FIXME: we need to do some refactoring, we cannot re-use the proxy components of archiva-proxy in maven2-repository
- // because it's causing a cyclic dependency
- private boolean getModelFromProxy( RemoteRepository remoteRepository, String groupId, String artifactId,
- String version, String filename )
- throws AuthorizationException, TransferFailedException, ResourceDoesNotExistException, WagonFactoryException,
- XMLException, IOException
- {
- boolean success = false;
- Path tmpMd5 = null;
- Path tmpSha1 = null;
- Path tmpResource = null;
- String artifactPath = pathTranslator.toPath( groupId, artifactId, version, filename );
- Path resource = targetRepository.getAsset("").getFilePath().resolve( artifactPath );
-
- Path workingDirectory = createWorkingDirectory( targetRepository.getLocation().toString() );
- try
- {
- Wagon wagon = null;
- try
- {
- String protocol = getProtocol( remoteRepository.getLocation().toString() );
- final NetworkProxy networkProxy = this.networkProxyMap.get( remoteRepository.getId() );
-
- wagon = wagonFactory.getWagon(
- new WagonFactoryRequest( "wagon#" + protocol, remoteRepository.getExtraHeaders() ).networkProxy(
- networkProxy )
- );
-
- if ( wagon == null )
- {
- throw new RuntimeException( "Unsupported remote repository protocol: " + protocol );
- }
-
- boolean connected = connectToRepository( wagon, remoteRepository );
- if ( connected )
- {
- tmpResource = workingDirectory.resolve( filename );
-
- if ( VersionUtil.isSnapshot( version ) )
- {
- // get the metadata first!
- Path tmpMetadataResource = workingDirectory.resolve( METADATA_FILENAME );
-
- String metadataPath =
- StringUtils.substringBeforeLast( artifactPath, "/" ) + "/" + METADATA_FILENAME;
-
- wagon.get( addParameters( metadataPath, remoteRepository ), tmpMetadataResource.toFile() );
-
- log.debug( "Successfully downloaded metadata." );
-
- ArchivaRepositoryMetadata metadata = MavenMetadataReader.read( tmpMetadataResource );
-
- // re-adjust to timestamp if present, otherwise retain the original -SNAPSHOT filename
- SnapshotVersion snapshotVersion = metadata.getSnapshotVersion();
- String timestampVersion = version;
- if ( snapshotVersion != null )
- {
- timestampVersion = timestampVersion.substring( 0, timestampVersion.length()
- - 8 ); // remove SNAPSHOT from end
- timestampVersion = timestampVersion + snapshotVersion.getTimestamp() + "-"
- + snapshotVersion.getBuildNumber();
-
- filename = artifactId + "-" + timestampVersion + ".pom";
-
- artifactPath = pathTranslator.toPath( groupId, artifactId, version, filename );
-
- log.debug( "New artifactPath :{}", artifactPath );
- }
- }
-
- log.info( "Retrieving {} from {}", artifactPath, remoteRepository.getName() );
-
- wagon.get( addParameters( artifactPath, remoteRepository ), tmpResource.toFile() );
-
- log.debug( "Downloaded successfully." );
-
- tmpSha1 = transferChecksum( wagon, remoteRepository, artifactPath, tmpResource, workingDirectory,
- ".sha1" );
- tmpMd5 = transferChecksum( wagon, remoteRepository, artifactPath, tmpResource, workingDirectory,
- ".md5" );
- }
- }
- finally
- {
- if ( wagon != null )
- {
- try
- {
- wagon.disconnect();
- }
- catch ( ConnectionException e )
- {
- log.warn( "Unable to disconnect wagon.", e );
- }
- }
- }
-
- if ( resource != null )
- {
- synchronized ( resource.toAbsolutePath().toString().intern() )
- {
- Path directory = resource.getParent();
- moveFileIfExists( tmpMd5, directory );
- moveFileIfExists( tmpSha1, directory );
- moveFileIfExists( tmpResource, directory );
- success = true;
- }
- }
- }
- finally
- {
- org.apache.archiva.common.utils.FileUtils.deleteQuietly( workingDirectory );
- }
-
- // do we still need to execute the consumers?
-
- return success;
- }
-
- /**
- * Using wagon, connect to the remote repository.
- *
- * @param wagon the wagon instance to establish the connection on.
- * @return true if the connection was successful. false if not connected.
- */
- private boolean connectToRepository( Wagon wagon, RemoteRepository remoteRepository )
- {
- boolean connected;
-
- final NetworkProxy proxyConnector = this.networkProxyMap.get( remoteRepository.getId() );
- ProxyInfo networkProxy = null;
- if ( proxyConnector != null )
- {
- networkProxy = new ProxyInfo();
- networkProxy.setType( proxyConnector.getProtocol() );
- networkProxy.setHost( proxyConnector.getHost() );
- networkProxy.setPort( proxyConnector.getPort() );
- networkProxy.setUserName( proxyConnector.getUsername() );
- networkProxy.setPassword( proxyConnector.getPassword() );
-
- String msg = "Using network proxy " + networkProxy.getHost() + ":" + networkProxy.getPort()
- + " to connect to remote repository " + remoteRepository.getLocation();
- if ( networkProxy.getNonProxyHosts() != null )
- {
- msg += "; excluding hosts: " + networkProxy.getNonProxyHosts();
- }
-
- if ( StringUtils.isNotBlank( networkProxy.getUserName() ) )
- {
- msg += "; as user: " + networkProxy.getUserName();
- }
-
- log.debug( msg );
- }
-
- AuthenticationInfo authInfo = null;
- RepositoryCredentials creds = remoteRepository.getLoginCredentials();
- String username = "";
- String password = "";
- if (creds instanceof UsernamePasswordCredentials) {
- UsernamePasswordCredentials c = (UsernamePasswordCredentials) creds;
- username = c.getUserName();
- password = c.getPassword();
- }
-
- if ( StringUtils.isNotBlank( username ) && StringUtils.isNotBlank( password ) )
- {
- log.debug( "Using username {} to connect to remote repository {}", username, remoteRepository.getLocation() );
- authInfo = new AuthenticationInfo();
- authInfo.setUserName( username );
- authInfo.setPassword( password );
- }
-
- int timeoutInMilliseconds = ((int)remoteRepository.getTimeout().getSeconds())*1000;
- // FIXME olamy having 2 config values
- // Set timeout
- wagon.setReadTimeout( timeoutInMilliseconds );
- wagon.setTimeout( timeoutInMilliseconds );
-
- try
- {
- org.apache.maven.wagon.repository.Repository wagonRepository =
- new org.apache.maven.wagon.repository.Repository( remoteRepository.getId(), remoteRepository.getLocation().toString() );
- if ( networkProxy != null )
- {
- wagon.connect( wagonRepository, authInfo, networkProxy );
- }
- else
- {
- wagon.connect( wagonRepository, authInfo );
- }
- connected = true;
- }
- catch ( ConnectionException | AuthenticationException e )
- {
- log.error( "Could not connect to {}:{} ", remoteRepository.getName(), e.getMessage() );
- connected = false;
- }
-
- return connected;
- }
-
- /**
- *
- * @param wagon The wagon instance that should be connected.
- * @param remoteRepository The repository from where the checksum file should be retrieved
- * @param remotePath The remote path of the artifact (without extension)
- * @param resource The local artifact (without extension)
- * @param workingDir The working directory where the downloaded file should be placed to
- * @param ext The extension of th checksum file
- * @return The file where the data has been downloaded to.
- * @throws AuthorizationException
- * @throws TransferFailedException
- * @throws ResourceDoesNotExistException
- */
- private Path transferChecksum( final Wagon wagon, final RemoteRepository remoteRepository,
- final String remotePath, final Path resource,
- final Path workingDir, final String ext )
- throws AuthorizationException, TransferFailedException, ResourceDoesNotExistException
- {
- Path destFile = workingDir.resolve( resource.getFileName() + ext );
- String remoteChecksumPath = remotePath + ext;
-
- log.info( "Retrieving {} from {}", remoteChecksumPath, remoteRepository.getName() );
-
- wagon.get( addParameters( remoteChecksumPath, remoteRepository ), destFile.toFile() );
-
- log.debug( "Downloaded successfully." );
-
- return destFile;
- }
-
- private String getProtocol( String url )
- {
- String protocol = StringUtils.substringBefore( url, ":" );
-
- return protocol;
- }
-
- private Path createWorkingDirectory( String targetRepository )
- throws IOException
- {
- return Files.createTempDirectory( "temp" );
- }
-
- private void moveFileIfExists( Path fileToMove, Path directory )
- {
- if ( fileToMove != null && Files.exists(fileToMove) )
- {
- Path newLocation = directory.resolve( fileToMove.getFileName() );
- try {
- Files.deleteIfExists(newLocation);
- } catch (IOException e) {
- throw new RuntimeException(
- "Unable to overwrite existing target file: " + newLocation.toAbsolutePath(), e );
- }
-
- try {
- Files.createDirectories(newLocation.getParent());
- } catch (IOException e) {
- e.printStackTrace();
- }
- try {
- Files.move(fileToMove, newLocation );
- } catch (IOException e) {
- try {
- Files.copy(fileToMove, newLocation);
- } catch (IOException e1) {
- if (Files.exists(newLocation)) {
- log.error( "Tried to copy file {} to {} but file with this name already exists.",
- fileToMove.getFileName(), newLocation.toAbsolutePath() );
- } else {
- throw new RuntimeException(
- "Cannot copy tmp file " + fileToMove.toAbsolutePath() + " to its final location", e );
- }
- }
- } finally {
- org.apache.archiva.common.utils.FileUtils.deleteQuietly(fileToMove);
- }
- }
- }
-
- protected String addParameters( String path, RemoteRepository remoteRepository )
- {
- if ( remoteRepository.getExtraParameters().isEmpty() )
- {
- return path;
- }
-
- boolean question = false;
-
- StringBuilder res = new StringBuilder( path == null ? "" : path );
-
- for ( Map.Entry<String, String> entry : remoteRepository.getExtraParameters().entrySet() )
- {
- if ( !question )
- {
- res.append( '?' ).append( entry.getKey() ).append( '=' ).append( entry.getValue() );
- }
- }
-
- return res.toString();
- }
- }
|