diff options
Diffstat (limited to 'framework/src/maven/apache-maven-3.3.3/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/DefaultRepositoryMetadataManager.java')
-rw-r--r-- | framework/src/maven/apache-maven-3.3.3/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/DefaultRepositoryMetadataManager.java | 558 |
1 files changed, 558 insertions, 0 deletions
diff --git a/framework/src/maven/apache-maven-3.3.3/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/DefaultRepositoryMetadataManager.java b/framework/src/maven/apache-maven-3.3.3/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/DefaultRepositoryMetadataManager.java new file mode 100644 index 00000000..e7937134 --- /dev/null +++ b/framework/src/maven/apache-maven-3.3.3/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/DefaultRepositoryMetadataManager.java @@ -0,0 +1,558 @@ +package org.apache.maven.artifact.repository.metadata; + +/* + * 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 java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.Reader; +import java.io.Writer; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.maven.artifact.metadata.ArtifactMetadata; +import org.apache.maven.artifact.repository.ArtifactRepository; +import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy; +import org.apache.maven.artifact.repository.DefaultRepositoryRequest; +import org.apache.maven.artifact.repository.RepositoryRequest; +import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Reader; +import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Writer; +import org.apache.maven.repository.legacy.UpdateCheckManager; +import org.apache.maven.repository.legacy.WagonManager; +import org.apache.maven.wagon.ResourceDoesNotExistException; +import org.apache.maven.wagon.TransferFailedException; +import org.codehaus.plexus.component.annotations.Component; +import org.codehaus.plexus.component.annotations.Requirement; +import org.codehaus.plexus.logging.AbstractLogEnabled; +import org.codehaus.plexus.util.IOUtil; +import org.codehaus.plexus.util.ReaderFactory; +import org.codehaus.plexus.util.WriterFactory; +import org.codehaus.plexus.util.xml.pull.XmlPullParserException; + +/** + * @author Jason van Zyl + */ +@Component( role = RepositoryMetadataManager.class ) +public class DefaultRepositoryMetadataManager + extends AbstractLogEnabled + implements RepositoryMetadataManager +{ + @Requirement + private WagonManager wagonManager; + + @Requirement + private UpdateCheckManager updateCheckManager; + + public void resolve( RepositoryMetadata metadata, List<ArtifactRepository> remoteRepositories, + ArtifactRepository localRepository ) + throws RepositoryMetadataResolutionException + { + RepositoryRequest request = new DefaultRepositoryRequest(); + request.setLocalRepository( localRepository ); + request.setRemoteRepositories( remoteRepositories ); + resolve( metadata, request ); + } + + public void resolve( RepositoryMetadata metadata, RepositoryRequest request ) + throws RepositoryMetadataResolutionException + { + ArtifactRepository localRepo = request.getLocalRepository(); + List<ArtifactRepository> remoteRepositories = request.getRemoteRepositories(); + + if ( !request.isOffline() ) + { + Date localCopyLastModified = null; + if ( metadata.getBaseVersion() != null ) + { + localCopyLastModified = getLocalCopyLastModified( localRepo, metadata ); + } + + for ( ArtifactRepository repository : remoteRepositories ) + { + ArtifactRepositoryPolicy policy = metadata.getPolicy( repository ); + + File file = + new File( localRepo.getBasedir(), localRepo.pathOfLocalRepositoryMetadata( metadata, repository ) ); + boolean update; + + if ( !policy.isEnabled() ) + { + update = false; + + if ( getLogger().isDebugEnabled() ) + { + getLogger().debug( + "Skipping update check for " + metadata.getKey() + " (" + file + + ") from disabled repository " + repository.getId() + " (" + + repository.getUrl() + ")" ); + } + } + else if ( request.isForceUpdate() ) + { + update = true; + } + else if ( localCopyLastModified != null && !policy.checkOutOfDate( localCopyLastModified ) ) + { + update = false; + + if ( getLogger().isDebugEnabled() ) + { + getLogger().debug( + "Skipping update check for " + metadata.getKey() + " (" + file + + ") from repository " + repository.getId() + " (" + repository.getUrl() + + ") in favor of local copy" ); + } + } + else + { + update = updateCheckManager.isUpdateRequired( metadata, repository, file ); + } + + if ( update ) + { + getLogger().info( metadata.getKey() + ": checking for updates from " + repository.getId() ); + try + { + wagonManager.getArtifactMetadata( metadata, repository, file, policy.getChecksumPolicy() ); + } + catch ( ResourceDoesNotExistException e ) + { + getLogger().debug( metadata + " could not be found on repository: " + repository.getId() ); + + // delete the local copy so the old details aren't used. + if ( file.exists() ) + { + if ( !file.delete() ) + { + // sleep for 10ms just in case this is windows holding a file lock + try + { + Thread.sleep( 10 ); + } + catch ( InterruptedException ie ) + { + // ignore + } + file.delete(); // if this fails, forget about it + } + } + } + catch ( TransferFailedException e ) + { + getLogger().warn( metadata + " could not be retrieved from repository: " + repository.getId() + + " due to an error: " + e.getMessage() ); + getLogger().debug( "Exception", e ); + } + finally + { + updateCheckManager.touch( metadata, repository, file ); + } + } + + // TODO: should this be inside the above check? + // touch file so that this is not checked again until interval has passed + if ( file.exists() ) + { + file.setLastModified( System.currentTimeMillis() ); + } + } + } + + try + { + mergeMetadata( metadata, remoteRepositories, localRepo ); + } + catch ( RepositoryMetadataStoreException e ) + { + throw new RepositoryMetadataResolutionException( "Unable to store local copy of metadata: " + + e.getMessage(), e ); + } + } + + private Date getLocalCopyLastModified( ArtifactRepository localRepository, RepositoryMetadata metadata ) + { + String metadataPath = localRepository.pathOfLocalRepositoryMetadata( metadata, localRepository ); + File metadataFile = new File( localRepository.getBasedir(), metadataPath ); + return metadataFile.isFile() ? new Date( metadataFile.lastModified() ) : null; + } + + private void mergeMetadata( RepositoryMetadata metadata, List<ArtifactRepository> remoteRepositories, + ArtifactRepository localRepository ) + throws RepositoryMetadataStoreException + { + // TODO: currently this is first wins, but really we should take the latest by comparing either the + // snapshot timestamp, or some other timestamp later encoded into the metadata. + // TODO: this needs to be repeated here so the merging doesn't interfere with the written metadata + // - we'd be much better having a pristine input, and an ongoing metadata for merging instead + + Map<ArtifactRepository, Metadata> previousMetadata = new HashMap<ArtifactRepository, Metadata>(); + ArtifactRepository selected = null; + for ( ArtifactRepository repository : remoteRepositories ) + { + ArtifactRepositoryPolicy policy = metadata.getPolicy( repository ); + + if ( policy.isEnabled() && loadMetadata( metadata, repository, localRepository, previousMetadata ) ) + { + metadata.setRepository( repository ); + selected = repository; + } + } + if ( loadMetadata( metadata, localRepository, localRepository, previousMetadata ) ) + { + metadata.setRepository( null ); + selected = localRepository; + } + + updateSnapshotMetadata( metadata, previousMetadata, selected, localRepository ); + } + + private void updateSnapshotMetadata( RepositoryMetadata metadata, + Map<ArtifactRepository, Metadata> previousMetadata, + ArtifactRepository selected, ArtifactRepository localRepository ) + throws RepositoryMetadataStoreException + { + // TODO: this could be a lot nicer... should really be in the snapshot transformation? + if ( metadata.isSnapshot() ) + { + Metadata prevMetadata = metadata.getMetadata(); + + for ( ArtifactRepository repository : previousMetadata.keySet() ) + { + Metadata m = previousMetadata.get( repository ); + if ( repository.equals( selected ) ) + { + if ( m.getVersioning() == null ) + { + m.setVersioning( new Versioning() ); + } + + if ( m.getVersioning().getSnapshot() == null ) + { + m.getVersioning().setSnapshot( new Snapshot() ); + } + } + else + { + if ( ( m.getVersioning() != null ) && ( m.getVersioning().getSnapshot() != null ) + && m.getVersioning().getSnapshot().isLocalCopy() ) + { + m.getVersioning().getSnapshot().setLocalCopy( false ); + metadata.setMetadata( m ); + metadata.storeInLocalRepository( localRepository, repository ); + } + } + } + + metadata.setMetadata( prevMetadata ); + } + } + + private boolean loadMetadata( RepositoryMetadata repoMetadata, ArtifactRepository remoteRepository, + ArtifactRepository localRepository, Map<ArtifactRepository, + Metadata> previousMetadata ) + { + boolean setRepository = false; + + File metadataFile = + new File( localRepository.getBasedir(), localRepository.pathOfLocalRepositoryMetadata( repoMetadata, + remoteRepository ) ); + + if ( metadataFile.exists() ) + { + Metadata metadata; + + try + { + metadata = readMetadata( metadataFile ); + } + catch ( RepositoryMetadataReadException e ) + { + if ( getLogger().isDebugEnabled() ) + { + getLogger().warn( e.getMessage(), e ); + } + else + { + getLogger().warn( e.getMessage() ); + } + return setRepository; + } + + if ( repoMetadata.isSnapshot() && ( previousMetadata != null ) ) + { + previousMetadata.put( remoteRepository, metadata ); + } + + if ( repoMetadata.getMetadata() != null ) + { + setRepository = repoMetadata.getMetadata().merge( metadata ); + } + else + { + repoMetadata.setMetadata( metadata ); + setRepository = true; + } + } + return setRepository; + } + + /** @todo share with DefaultPluginMappingManager. */ + protected Metadata readMetadata( File mappingFile ) + throws RepositoryMetadataReadException + { + Metadata result; + + Reader reader = null; + try + { + reader = ReaderFactory.newXmlReader( mappingFile ); + + MetadataXpp3Reader mappingReader = new MetadataXpp3Reader(); + + result = mappingReader.read( reader, false ); + } + catch ( FileNotFoundException e ) + { + throw new RepositoryMetadataReadException( "Cannot read metadata from '" + mappingFile + "'", e ); + } + catch ( IOException e ) + { + throw new RepositoryMetadataReadException( "Cannot read metadata from '" + mappingFile + "': " + + e.getMessage(), e ); + } + catch ( XmlPullParserException e ) + { + throw new RepositoryMetadataReadException( "Cannot read metadata from '" + mappingFile + "': " + + e.getMessage(), e ); + } + finally + { + IOUtil.close( reader ); + } + + return result; + } + + /** + * Ensures the last updated timestamp of the specified metadata does not refer to the future and fixes the local + * metadata if necessary to allow proper merging/updating of metadata during deployment. + */ + private void fixTimestamp( File metadataFile, Metadata metadata, Metadata reference ) + { + boolean changed = false; + + if ( metadata != null && reference != null ) + { + Versioning versioning = metadata.getVersioning(); + Versioning versioningRef = reference.getVersioning(); + if ( versioning != null && versioningRef != null ) + { + String lastUpdated = versioning.getLastUpdated(); + String now = versioningRef.getLastUpdated(); + if ( lastUpdated != null && now != null && now.compareTo( lastUpdated ) < 0 ) + { + getLogger().warn( + "The last updated timestamp in " + metadataFile + " refers to the future (now = " + + now + ", lastUpdated = " + lastUpdated + + "). Please verify that the clocks of all" + + " deploying machines are reasonably synchronized." ); + versioning.setLastUpdated( now ); + changed = true; + } + } + } + + if ( changed ) + { + getLogger().debug( "Repairing metadata in " + metadataFile ); + + Writer writer = null; + try + { + writer = WriterFactory.newXmlWriter( metadataFile ); + new MetadataXpp3Writer().write( writer, metadata ); + } + catch ( IOException e ) + { + String msg = "Could not write fixed metadata to " + metadataFile + ": " + e.getMessage(); + if ( getLogger().isDebugEnabled() ) + { + getLogger().warn( msg, e ); + } + else + { + getLogger().warn( msg ); + } + } + finally + { + IOUtil.close( writer ); + } + } + } + + public void resolveAlways( RepositoryMetadata metadata, ArtifactRepository localRepository, + ArtifactRepository remoteRepository ) + throws RepositoryMetadataResolutionException + { + File file; + try + { + file = getArtifactMetadataFromDeploymentRepository( metadata, localRepository, remoteRepository ); + } + catch ( TransferFailedException e ) + { + throw new RepositoryMetadataResolutionException( metadata + " could not be retrieved from repository: " + + remoteRepository.getId() + " due to an error: " + e.getMessage(), e ); + } + + try + { + if ( file.exists() ) + { + Metadata prevMetadata = readMetadata( file ); + metadata.setMetadata( prevMetadata ); + } + } + catch ( RepositoryMetadataReadException e ) + { + throw new RepositoryMetadataResolutionException( e.getMessage(), e ); + } + } + + private File getArtifactMetadataFromDeploymentRepository( ArtifactMetadata metadata, + ArtifactRepository localRepo, + ArtifactRepository remoteRepository ) + throws TransferFailedException + { + File file = + new File( localRepo.getBasedir(), localRepo.pathOfLocalRepositoryMetadata( metadata, remoteRepository ) ); + + try + { + wagonManager.getArtifactMetadataFromDeploymentRepository( metadata, remoteRepository, file, + ArtifactRepositoryPolicy.CHECKSUM_POLICY_WARN ); + } + catch ( ResourceDoesNotExistException e ) + { + getLogger().info( metadata + " could not be found on repository: " + remoteRepository.getId() + + ", so will be created" ); + + // delete the local copy so the old details aren't used. + if ( file.exists() ) + { + if ( !file.delete() ) + { + // sleep for 10ms just in case this is windows holding a file lock + try + { + Thread.sleep( 10 ); + } + catch ( InterruptedException ie ) + { + // ignore + } + file.delete(); // if this fails, forget about it + } + } + } + finally + { + if ( metadata instanceof RepositoryMetadata ) + { + updateCheckManager.touch( (RepositoryMetadata) metadata, remoteRepository, file ); + } + } + return file; + } + + public void deploy( ArtifactMetadata metadata, ArtifactRepository localRepository, + ArtifactRepository deploymentRepository ) + throws RepositoryMetadataDeploymentException + { + File file; + if ( metadata instanceof RepositoryMetadata ) + { + getLogger().info( "Retrieving previous metadata from " + deploymentRepository.getId() ); + try + { + file = getArtifactMetadataFromDeploymentRepository( metadata, localRepository, deploymentRepository ); + } + catch ( TransferFailedException e ) + { + throw new RepositoryMetadataDeploymentException( metadata + " could not be retrieved from repository: " + + deploymentRepository.getId() + " due to an error: " + e.getMessage(), e ); + } + + if ( file.isFile() ) + { + try + { + fixTimestamp( file, readMetadata( file ), ( (RepositoryMetadata) metadata ).getMetadata() ); + } + catch ( RepositoryMetadataReadException e ) + { + // will be reported via storeInlocalRepository + } + } + } + else + { + // It's a POM - we don't need to retrieve it first + file = + new File( localRepository.getBasedir(), + localRepository.pathOfLocalRepositoryMetadata( metadata, deploymentRepository ) ); + } + + try + { + metadata.storeInLocalRepository( localRepository, deploymentRepository ); + } + catch ( RepositoryMetadataStoreException e ) + { + throw new RepositoryMetadataDeploymentException( "Error installing metadata: " + e.getMessage(), e ); + } + + try + { + wagonManager.putArtifactMetadata( file, metadata, deploymentRepository ); + } + catch ( TransferFailedException e ) + { + throw new RepositoryMetadataDeploymentException( "Error while deploying metadata: " + e.getMessage(), e ); + } + } + + public void install( ArtifactMetadata metadata, ArtifactRepository localRepository ) + throws RepositoryMetadataInstallationException + { + try + { + metadata.storeInLocalRepository( localRepository, localRepository ); + } + catch ( RepositoryMetadataStoreException e ) + { + throw new RepositoryMetadataInstallationException( "Error installing metadata: " + e.getMessage(), e ); + } + } + +} |