blob: 78c83ff4dcd81a6c67d0333ceae81646ecaa3733 [file] [log] [blame]
package org.eclipse.aether.internal.impl;
/*
* 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.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.IdentityHashMap;
import java.util.List;
import static java.util.Objects.requireNonNull;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Named;
import org.eclipse.aether.RepositoryEvent;
import org.eclipse.aether.RepositoryEvent.EventType;
import org.eclipse.aether.RepositoryException;
import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.RequestTrace;
import org.eclipse.aether.SyncContext;
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.deployment.DeployRequest;
import org.eclipse.aether.deployment.DeployResult;
import org.eclipse.aether.deployment.DeploymentException;
import org.eclipse.aether.impl.Deployer;
import org.eclipse.aether.impl.MetadataGenerator;
import org.eclipse.aether.impl.MetadataGeneratorFactory;
import org.eclipse.aether.impl.OfflineController;
import org.eclipse.aether.impl.RemoteRepositoryManager;
import org.eclipse.aether.impl.RepositoryConnectorProvider;
import org.eclipse.aether.impl.RepositoryEventDispatcher;
import org.eclipse.aether.impl.SyncContextFactory;
import org.eclipse.aether.impl.UpdateCheck;
import org.eclipse.aether.impl.UpdateCheckManager;
import org.eclipse.aether.metadata.MergeableMetadata;
import org.eclipse.aether.metadata.Metadata;
import org.eclipse.aether.repository.LocalRepositoryManager;
import org.eclipse.aether.repository.RemoteRepository;
import org.eclipse.aether.repository.RepositoryPolicy;
import org.eclipse.aether.spi.connector.ArtifactUpload;
import org.eclipse.aether.spi.connector.MetadataDownload;
import org.eclipse.aether.spi.connector.MetadataUpload;
import org.eclipse.aether.spi.connector.RepositoryConnector;
import org.eclipse.aether.spi.io.FileProcessor;
import org.eclipse.aether.spi.locator.Service;
import org.eclipse.aether.spi.locator.ServiceLocator;
import org.eclipse.aether.transfer.ArtifactTransferException;
import org.eclipse.aether.transfer.MetadataNotFoundException;
import org.eclipse.aether.transfer.MetadataTransferException;
import org.eclipse.aether.transfer.NoRepositoryConnectorException;
import org.eclipse.aether.transfer.RepositoryOfflineException;
import org.eclipse.aether.transfer.TransferCancelledException;
import org.eclipse.aether.transfer.TransferEvent;
import org.eclipse.aether.transform.FileTransformer;
import org.eclipse.aether.transform.FileTransformerManager;
/**
*/
@Named
public class DefaultDeployer
implements Deployer, Service
{
private FileProcessor fileProcessor;
private RepositoryEventDispatcher repositoryEventDispatcher;
private RepositoryConnectorProvider repositoryConnectorProvider;
private RemoteRepositoryManager remoteRepositoryManager;
private UpdateCheckManager updateCheckManager;
private Collection<MetadataGeneratorFactory> metadataFactories = new ArrayList<>();
private SyncContextFactory syncContextFactory;
private OfflineController offlineController;
public DefaultDeployer()
{
// enables default constructor
}
@SuppressWarnings( "checkstyle:parameternumber" )
@Inject
DefaultDeployer( FileProcessor fileProcessor, RepositoryEventDispatcher repositoryEventDispatcher,
RepositoryConnectorProvider repositoryConnectorProvider,
RemoteRepositoryManager remoteRepositoryManager, UpdateCheckManager updateCheckManager,
Set<MetadataGeneratorFactory> metadataFactories, SyncContextFactory syncContextFactory,
OfflineController offlineController )
{
setFileProcessor( fileProcessor );
setRepositoryEventDispatcher( repositoryEventDispatcher );
setRepositoryConnectorProvider( repositoryConnectorProvider );
setRemoteRepositoryManager( remoteRepositoryManager );
setUpdateCheckManager( updateCheckManager );
setMetadataGeneratorFactories( metadataFactories );
setSyncContextFactory( syncContextFactory );
setOfflineController( offlineController );
}
public void initService( ServiceLocator locator )
{
setFileProcessor( locator.getService( FileProcessor.class ) );
setRepositoryEventDispatcher( locator.getService( RepositoryEventDispatcher.class ) );
setRepositoryConnectorProvider( locator.getService( RepositoryConnectorProvider.class ) );
setRemoteRepositoryManager( locator.getService( RemoteRepositoryManager.class ) );
setUpdateCheckManager( locator.getService( UpdateCheckManager.class ) );
setMetadataGeneratorFactories( locator.getServices( MetadataGeneratorFactory.class ) );
setSyncContextFactory( locator.getService( SyncContextFactory.class ) );
setOfflineController( locator.getService( OfflineController.class ) );
}
public DefaultDeployer setFileProcessor( FileProcessor fileProcessor )
{
this.fileProcessor = requireNonNull( fileProcessor, "file processor cannot be null" );
return this;
}
public DefaultDeployer setRepositoryEventDispatcher( RepositoryEventDispatcher repositoryEventDispatcher )
{
this.repositoryEventDispatcher = requireNonNull(
repositoryEventDispatcher, "repository event dispatcher cannot be null" );
return this;
}
public DefaultDeployer setRepositoryConnectorProvider( RepositoryConnectorProvider repositoryConnectorProvider )
{
this.repositoryConnectorProvider = requireNonNull(
repositoryConnectorProvider, "repository connector provider cannot be null" );
return this;
}
public DefaultDeployer setRemoteRepositoryManager( RemoteRepositoryManager remoteRepositoryManager )
{
this.remoteRepositoryManager = requireNonNull(
remoteRepositoryManager, "remote repository provider cannot be null" );
return this;
}
public DefaultDeployer setUpdateCheckManager( UpdateCheckManager updateCheckManager )
{
this.updateCheckManager = requireNonNull( updateCheckManager, "update check manager cannot be null" );
return this;
}
public DefaultDeployer addMetadataGeneratorFactory( MetadataGeneratorFactory factory )
{
metadataFactories.add( requireNonNull( factory, "metadata generator factory cannot be null" ) );
return this;
}
public DefaultDeployer setMetadataGeneratorFactories( Collection<MetadataGeneratorFactory> metadataFactories )
{
if ( metadataFactories == null )
{
this.metadataFactories = new ArrayList<>();
}
else
{
this.metadataFactories = metadataFactories;
}
return this;
}
public DefaultDeployer setSyncContextFactory( SyncContextFactory syncContextFactory )
{
this.syncContextFactory = requireNonNull( syncContextFactory, "sync context factory cannot be null" );
return this;
}
public DefaultDeployer setOfflineController( OfflineController offlineController )
{
this.offlineController = requireNonNull( offlineController, "offline controller cannot be null" );
return this;
}
public DeployResult deploy( RepositorySystemSession session, DeployRequest request )
throws DeploymentException
{
try
{
Utils.checkOffline( session, offlineController, request.getRepository() );
}
catch ( RepositoryOfflineException e )
{
throw new DeploymentException( "Cannot deploy while " + request.getRepository().getId() + " ("
+ request.getRepository().getUrl() + ") is in offline mode", e );
}
try ( SyncContext syncContext = syncContextFactory.newInstance( session, false ) )
{
return deploy( syncContext, session, request );
}
}
private DeployResult deploy( SyncContext syncContext, RepositorySystemSession session, DeployRequest request )
throws DeploymentException
{
DeployResult result = new DeployResult( request );
RequestTrace trace = RequestTrace.newChild( request.getTrace(), request );
RemoteRepository repository = request.getRepository();
RepositoryConnector connector;
try
{
connector = repositoryConnectorProvider.newRepositoryConnector( session, repository );
}
catch ( NoRepositoryConnectorException e )
{
throw new DeploymentException( "Failed to deploy artifacts/metadata: " + e.getMessage(), e );
}
try
{
List<? extends MetadataGenerator> generators = getMetadataGenerators( session, request );
FileTransformerManager fileTransformerManager = session.getFileTransformerManager();
List<ArtifactUpload> artifactUploads = new ArrayList<>();
List<MetadataUpload> metadataUploads = new ArrayList<>();
IdentityHashMap<Metadata, Object> processedMetadata = new IdentityHashMap<>();
EventCatapult catapult = new EventCatapult( session, trace, repository, repositoryEventDispatcher );
List<Artifact> artifacts = new ArrayList<>( request.getArtifacts() );
List<Metadata> metadatas = Utils.prepareMetadata( generators, artifacts );
syncContext.acquire( artifacts, Utils.combine( request.getMetadata(), metadatas ) );
for ( Metadata metadata : metadatas )
{
upload( metadataUploads, session, metadata, repository, connector, catapult );
processedMetadata.put( metadata, null );
}
for ( int i = 0; i < artifacts.size(); i++ )
{
Artifact artifact = artifacts.get( i );
for ( MetadataGenerator generator : generators )
{
artifact = generator.transformArtifact( artifact );
}
artifacts.set( i, artifact );
Collection<FileTransformer> fileTransformers =
fileTransformerManager.getTransformersForArtifact( artifact );
if ( !fileTransformers.isEmpty() )
{
for ( FileTransformer fileTransformer : fileTransformers )
{
Artifact targetArtifact = fileTransformer.transformArtifact( artifact );
ArtifactUpload upload = new ArtifactUpload( targetArtifact, artifact.getFile(),
fileTransformer );
upload.setTrace( trace );
upload.setListener( new ArtifactUploadListener( catapult, upload ) );
artifactUploads.add( upload );
}
}
else
{
ArtifactUpload upload = new ArtifactUpload( artifact, artifact.getFile() );
upload.setTrace( trace );
upload.setListener( new ArtifactUploadListener( catapult, upload ) );
artifactUploads.add( upload );
}
}
connector.put( artifactUploads, null );
for ( ArtifactUpload upload : artifactUploads )
{
if ( upload.getException() != null )
{
throw new DeploymentException( "Failed to deploy artifacts: " + upload.getException().getMessage(),
upload.getException() );
}
result.addArtifact( upload.getArtifact() );
}
metadatas = Utils.finishMetadata( generators, artifacts );
syncContext.acquire( null, metadatas );
for ( Metadata metadata : metadatas )
{
upload( metadataUploads, session, metadata, repository, connector, catapult );
processedMetadata.put( metadata, null );
}
for ( Metadata metadata : request.getMetadata() )
{
if ( !processedMetadata.containsKey( metadata ) )
{
upload( metadataUploads, session, metadata, repository, connector, catapult );
processedMetadata.put( metadata, null );
}
}
connector.put( null, metadataUploads );
for ( MetadataUpload upload : metadataUploads )
{
if ( upload.getException() != null )
{
throw new DeploymentException( "Failed to deploy metadata: " + upload.getException().getMessage(),
upload.getException() );
}
result.addMetadata( upload.getMetadata() );
}
}
finally
{
connector.close();
}
return result;
}
private List<? extends MetadataGenerator> getMetadataGenerators( RepositorySystemSession session,
DeployRequest request )
{
PrioritizedComponents<MetadataGeneratorFactory> factories =
Utils.sortMetadataGeneratorFactories( session, this.metadataFactories );
List<MetadataGenerator> generators = new ArrayList<>();
for ( PrioritizedComponent<MetadataGeneratorFactory> factory : factories.getEnabled() )
{
MetadataGenerator generator = factory.getComponent().newInstance( session, request );
if ( generator != null )
{
generators.add( generator );
}
}
return generators;
}
private void upload( Collection<MetadataUpload> metadataUploads, RepositorySystemSession session,
Metadata metadata, RemoteRepository repository, RepositoryConnector connector,
EventCatapult catapult )
throws DeploymentException
{
LocalRepositoryManager lrm = session.getLocalRepositoryManager();
File basedir = lrm.getRepository().getBasedir();
File dstFile = new File( basedir, lrm.getPathForRemoteMetadata( metadata, repository, "" ) );
if ( metadata instanceof MergeableMetadata )
{
if ( !( (MergeableMetadata) metadata ).isMerged() )
{
RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.METADATA_RESOLVING );
event.setTrace( catapult.getTrace() );
event.setMetadata( metadata );
event.setRepository( repository );
repositoryEventDispatcher.dispatch( event.build() );
event = new RepositoryEvent.Builder( session, EventType.METADATA_DOWNLOADING );
event.setTrace( catapult.getTrace() );
event.setMetadata( metadata );
event.setRepository( repository );
repositoryEventDispatcher.dispatch( event.build() );
RepositoryPolicy policy = getPolicy( session, repository, metadata.getNature() );
MetadataDownload download = new MetadataDownload();
download.setMetadata( metadata );
download.setFile( dstFile );
download.setChecksumPolicy( policy.getChecksumPolicy() );
download.setListener( SafeTransferListener.wrap( session ) );
download.setTrace( catapult.getTrace() );
connector.get( null, Arrays.asList( download ) );
Exception error = download.getException();
if ( error instanceof MetadataNotFoundException )
{
dstFile.delete();
}
event = new RepositoryEvent.Builder( session, EventType.METADATA_DOWNLOADED );
event.setTrace( catapult.getTrace() );
event.setMetadata( metadata );
event.setRepository( repository );
event.setException( error );
event.setFile( dstFile );
repositoryEventDispatcher.dispatch( event.build() );
event = new RepositoryEvent.Builder( session, EventType.METADATA_RESOLVED );
event.setTrace( catapult.getTrace() );
event.setMetadata( metadata );
event.setRepository( repository );
event.setException( error );
event.setFile( dstFile );
repositoryEventDispatcher.dispatch( event.build() );
if ( error != null && !( error instanceof MetadataNotFoundException ) )
{
throw new DeploymentException( "Failed to retrieve remote metadata " + metadata + ": "
+ error.getMessage(), error );
}
}
try
{
( (MergeableMetadata) metadata ).merge( dstFile, dstFile );
}
catch ( RepositoryException e )
{
throw new DeploymentException( "Failed to update metadata " + metadata + ": " + e.getMessage(), e );
}
}
else
{
if ( metadata.getFile() == null )
{
throw new DeploymentException( "Failed to update metadata " + metadata + ": No file attached." );
}
try
{
fileProcessor.copy( metadata.getFile(), dstFile );
}
catch ( IOException e )
{
throw new DeploymentException( "Failed to update metadata " + metadata + ": " + e.getMessage(), e );
}
}
UpdateCheck<Metadata, MetadataTransferException> check = new UpdateCheck<>();
check.setItem( metadata );
check.setFile( dstFile );
check.setRepository( repository );
check.setAuthoritativeRepository( repository );
updateCheckManager.touchMetadata( session, check );
MetadataUpload upload = new MetadataUpload( metadata, dstFile );
upload.setTrace( catapult.getTrace() );
upload.setListener( new MetadataUploadListener( catapult, upload ) );
metadataUploads.add( upload );
}
private RepositoryPolicy getPolicy( RepositorySystemSession session, RemoteRepository repository,
Metadata.Nature nature )
{
boolean releases = !Metadata.Nature.SNAPSHOT.equals( nature );
boolean snapshots = !Metadata.Nature.RELEASE.equals( nature );
return remoteRepositoryManager.getPolicy( session, repository, releases, snapshots );
}
static final class EventCatapult
{
private final RepositorySystemSession session;
private final RequestTrace trace;
private final RemoteRepository repository;
private final RepositoryEventDispatcher dispatcher;
EventCatapult( RepositorySystemSession session, RequestTrace trace, RemoteRepository repository,
RepositoryEventDispatcher dispatcher )
{
this.session = session;
this.trace = trace;
this.repository = repository;
this.dispatcher = dispatcher;
}
public RepositorySystemSession getSession()
{
return session;
}
public RequestTrace getTrace()
{
return trace;
}
public void artifactDeploying( Artifact artifact, File file )
{
RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.ARTIFACT_DEPLOYING );
event.setTrace( trace );
event.setArtifact( artifact );
event.setRepository( repository );
event.setFile( file );
dispatcher.dispatch( event.build() );
}
public void artifactDeployed( Artifact artifact, File file, ArtifactTransferException exception )
{
RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.ARTIFACT_DEPLOYED );
event.setTrace( trace );
event.setArtifact( artifact );
event.setRepository( repository );
event.setFile( file );
event.setException( exception );
dispatcher.dispatch( event.build() );
}
public void metadataDeploying( Metadata metadata, File file )
{
RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.METADATA_DEPLOYING );
event.setTrace( trace );
event.setMetadata( metadata );
event.setRepository( repository );
event.setFile( file );
dispatcher.dispatch( event.build() );
}
public void metadataDeployed( Metadata metadata, File file, Exception exception )
{
RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.METADATA_DEPLOYED );
event.setTrace( trace );
event.setMetadata( metadata );
event.setRepository( repository );
event.setFile( file );
event.setException( exception );
dispatcher.dispatch( event.build() );
}
}
static final class ArtifactUploadListener
extends SafeTransferListener
{
private final EventCatapult catapult;
private final ArtifactUpload transfer;
ArtifactUploadListener( EventCatapult catapult, ArtifactUpload transfer )
{
super( catapult.getSession() );
this.catapult = catapult;
this.transfer = transfer;
}
@Override
public void transferInitiated( TransferEvent event )
throws TransferCancelledException
{
super.transferInitiated( event );
catapult.artifactDeploying( transfer.getArtifact(), transfer.getFile() );
}
@Override
public void transferFailed( TransferEvent event )
{
super.transferFailed( event );
catapult.artifactDeployed( transfer.getArtifact(), transfer.getFile(), transfer.getException() );
}
@Override
public void transferSucceeded( TransferEvent event )
{
super.transferSucceeded( event );
catapult.artifactDeployed( transfer.getArtifact(), transfer.getFile(), null );
}
}
static final class MetadataUploadListener
extends SafeTransferListener
{
private final EventCatapult catapult;
private final MetadataUpload transfer;
MetadataUploadListener( EventCatapult catapult, MetadataUpload transfer )
{
super( catapult.getSession() );
this.catapult = catapult;
this.transfer = transfer;
}
@Override
public void transferInitiated( TransferEvent event )
throws TransferCancelledException
{
super.transferInitiated( event );
catapult.metadataDeploying( transfer.getMetadata(), transfer.getFile() );
}
@Override
public void transferFailed( TransferEvent event )
{
super.transferFailed( event );
catapult.metadataDeployed( transfer.getMetadata(), transfer.getFile(), transfer.getException() );
}
@Override
public void transferSucceeded( TransferEvent event )
{
super.transferSucceeded( event );
catapult.metadataDeployed( transfer.getMetadata(), transfer.getFile(), null );
}
}
}