View Javadoc
1   package org.eclipse.aether.internal.impl;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   * 
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   * 
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.File;
23  import java.io.IOException;
24  import java.util.ArrayList;
25  import java.util.Arrays;
26  import java.util.Collection;
27  import java.util.IdentityHashMap;
28  import java.util.List;
29  import static java.util.Objects.requireNonNull;
30  import java.util.Set;
31  
32  import javax.inject.Inject;
33  import javax.inject.Named;
34  
35  import org.eclipse.aether.RepositoryEvent;
36  import org.eclipse.aether.RepositoryEvent.EventType;
37  import org.eclipse.aether.RepositoryException;
38  import org.eclipse.aether.RepositorySystemSession;
39  import org.eclipse.aether.RequestTrace;
40  import org.eclipse.aether.SyncContext;
41  import org.eclipse.aether.artifact.Artifact;
42  import org.eclipse.aether.deployment.DeployRequest;
43  import org.eclipse.aether.deployment.DeployResult;
44  import org.eclipse.aether.deployment.DeploymentException;
45  import org.eclipse.aether.impl.Deployer;
46  import org.eclipse.aether.impl.MetadataGenerator;
47  import org.eclipse.aether.impl.MetadataGeneratorFactory;
48  import org.eclipse.aether.impl.OfflineController;
49  import org.eclipse.aether.impl.RemoteRepositoryManager;
50  import org.eclipse.aether.impl.RepositoryConnectorProvider;
51  import org.eclipse.aether.impl.RepositoryEventDispatcher;
52  import org.eclipse.aether.impl.SyncContextFactory;
53  import org.eclipse.aether.impl.UpdateCheck;
54  import org.eclipse.aether.impl.UpdateCheckManager;
55  import org.eclipse.aether.metadata.MergeableMetadata;
56  import org.eclipse.aether.metadata.Metadata;
57  import org.eclipse.aether.repository.LocalRepositoryManager;
58  import org.eclipse.aether.repository.RemoteRepository;
59  import org.eclipse.aether.repository.RepositoryPolicy;
60  import org.eclipse.aether.spi.connector.ArtifactUpload;
61  import org.eclipse.aether.spi.connector.MetadataDownload;
62  import org.eclipse.aether.spi.connector.MetadataUpload;
63  import org.eclipse.aether.spi.connector.RepositoryConnector;
64  import org.eclipse.aether.spi.io.FileProcessor;
65  import org.eclipse.aether.spi.locator.Service;
66  import org.eclipse.aether.spi.locator.ServiceLocator;
67  import org.eclipse.aether.transfer.ArtifactTransferException;
68  import org.eclipse.aether.transfer.MetadataNotFoundException;
69  import org.eclipse.aether.transfer.MetadataTransferException;
70  import org.eclipse.aether.transfer.NoRepositoryConnectorException;
71  import org.eclipse.aether.transfer.RepositoryOfflineException;
72  import org.eclipse.aether.transfer.TransferCancelledException;
73  import org.eclipse.aether.transfer.TransferEvent;
74  import org.eclipse.aether.transform.FileTransformer;
75  import org.eclipse.aether.transform.FileTransformerManager;
76  
77  /**
78   */
79  @Named
80  public class DefaultDeployer
81      implements Deployer, Service
82  {
83      private FileProcessor fileProcessor;
84  
85      private RepositoryEventDispatcher repositoryEventDispatcher;
86  
87      private RepositoryConnectorProvider repositoryConnectorProvider;
88  
89      private RemoteRepositoryManager remoteRepositoryManager;
90  
91      private UpdateCheckManager updateCheckManager;
92  
93      private Collection<MetadataGeneratorFactory> metadataFactories = new ArrayList<MetadataGeneratorFactory>();
94  
95      private SyncContextFactory syncContextFactory;
96  
97      private OfflineController offlineController;
98  
99      public DefaultDeployer()
100     {
101         // enables default constructor
102     }
103 
104     @Inject
105     DefaultDeployer( FileProcessor fileProcessor, RepositoryEventDispatcher repositoryEventDispatcher,
106                      RepositoryConnectorProvider repositoryConnectorProvider,
107                      RemoteRepositoryManager remoteRepositoryManager, UpdateCheckManager updateCheckManager,
108                      Set<MetadataGeneratorFactory> metadataFactories, SyncContextFactory syncContextFactory,
109                      OfflineController offlineController )
110     {
111         setFileProcessor( fileProcessor );
112         setRepositoryEventDispatcher( repositoryEventDispatcher );
113         setRepositoryConnectorProvider( repositoryConnectorProvider );
114         setRemoteRepositoryManager( remoteRepositoryManager );
115         setUpdateCheckManager( updateCheckManager );
116         setMetadataGeneratorFactories( metadataFactories );
117         setSyncContextFactory( syncContextFactory );
118         setOfflineController( offlineController );
119     }
120 
121     public void initService( ServiceLocator locator )
122     {
123         setFileProcessor( locator.getService( FileProcessor.class ) );
124         setRepositoryEventDispatcher( locator.getService( RepositoryEventDispatcher.class ) );
125         setRepositoryConnectorProvider( locator.getService( RepositoryConnectorProvider.class ) );
126         setRemoteRepositoryManager( locator.getService( RemoteRepositoryManager.class ) );
127         setUpdateCheckManager( locator.getService( UpdateCheckManager.class ) );
128         setMetadataGeneratorFactories( locator.getServices( MetadataGeneratorFactory.class ) );
129         setSyncContextFactory( locator.getService( SyncContextFactory.class ) );
130         setOfflineController( locator.getService( OfflineController.class ) );
131     }
132 
133     public DefaultDeployer setFileProcessor( FileProcessor fileProcessor )
134     {
135         this.fileProcessor = requireNonNull( fileProcessor, "file processor cannot be null" );
136         return this;
137     }
138 
139     public DefaultDeployer setRepositoryEventDispatcher( RepositoryEventDispatcher repositoryEventDispatcher )
140     {
141         this.repositoryEventDispatcher = requireNonNull( repositoryEventDispatcher, "repository event dispatcher cannot be null" );
142         return this;
143     }
144 
145     public DefaultDeployer setRepositoryConnectorProvider( RepositoryConnectorProvider repositoryConnectorProvider )
146     {
147         this.repositoryConnectorProvider = requireNonNull( repositoryConnectorProvider, "repository connector provider cannot be null" );
148         return this;
149     }
150 
151     public DefaultDeployer setRemoteRepositoryManager( RemoteRepositoryManager remoteRepositoryManager )
152     {
153         this.remoteRepositoryManager = requireNonNull( remoteRepositoryManager, "remote repository provider cannot be null" );
154         return this;
155     }
156 
157     public DefaultDeployer setUpdateCheckManager( UpdateCheckManager updateCheckManager )
158     {
159         this.updateCheckManager = requireNonNull( updateCheckManager, "update check manager cannot be null" );
160         return this;
161     }
162 
163     public DefaultDeployer addMetadataGeneratorFactory( MetadataGeneratorFactory factory )
164     {
165         metadataFactories.add( requireNonNull( factory, "metadata generator factory cannot be null" ) );
166         return this;
167     }
168 
169     public DefaultDeployer setMetadataGeneratorFactories( Collection<MetadataGeneratorFactory> metadataFactories )
170     {
171         if ( metadataFactories == null )
172         {
173             this.metadataFactories = new ArrayList<MetadataGeneratorFactory>();
174         }
175         else
176         {
177             this.metadataFactories = metadataFactories;
178         }
179         return this;
180     }
181 
182     public DefaultDeployer setSyncContextFactory( SyncContextFactory syncContextFactory )
183     {
184         this.syncContextFactory = requireNonNull( syncContextFactory, "sync context factory cannot be null" );
185         return this;
186     }
187 
188     public DefaultDeployer setOfflineController( OfflineController offlineController )
189     {
190         this.offlineController = requireNonNull( offlineController, "offline controller cannot be null" );
191         return this;
192     }
193 
194     public DeployResult deploy( RepositorySystemSession session, DeployRequest request )
195         throws DeploymentException
196     {
197         try
198         {
199             Utils.checkOffline( session, offlineController, request.getRepository() );
200         }
201         catch ( RepositoryOfflineException e )
202         {
203             throw new DeploymentException( "Cannot deploy while " + request.getRepository().getId() + " ("
204                 + request.getRepository().getUrl() + ") is in offline mode", e );
205         }
206 
207         SyncContext syncContext = syncContextFactory.newInstance( session, false );
208 
209         try
210         {
211             return deploy( syncContext, session, request );
212         }
213         finally
214         {
215             syncContext.close();
216         }
217     }
218 
219     private DeployResult deploy( SyncContext syncContext, RepositorySystemSession session, DeployRequest request )
220         throws DeploymentException
221     {
222         DeployResult result = new DeployResult( request );
223 
224         RequestTrace trace = RequestTrace.newChild( request.getTrace(), request );
225 
226         RemoteRepository repository = request.getRepository();
227 
228         RepositoryConnector connector;
229         try
230         {
231             connector = repositoryConnectorProvider.newRepositoryConnector( session, repository );
232         }
233         catch ( NoRepositoryConnectorException e )
234         {
235             throw new DeploymentException( "Failed to deploy artifacts/metadata: " + e.getMessage(), e );
236         }
237 
238         try
239         {
240             List<? extends MetadataGenerator> generators = getMetadataGenerators( session, request );
241 
242             FileTransformerManager fileTransformerManager = session.getFileTransformerManager();
243 
244             List<ArtifactUpload> artifactUploads = new ArrayList<ArtifactUpload>();
245             List<MetadataUpload> metadataUploads = new ArrayList<MetadataUpload>();
246             IdentityHashMap<Metadata, Object> processedMetadata = new IdentityHashMap<Metadata, Object>();
247 
248             EventCatapult catapult = new EventCatapult( session, trace, repository, repositoryEventDispatcher );
249 
250             List<Artifact> artifacts = new ArrayList<Artifact>( request.getArtifacts() );
251 
252             List<Metadata> metadatas = Utils.prepareMetadata( generators, artifacts );
253 
254             syncContext.acquire( artifacts, Utils.combine( request.getMetadata(), metadatas ) );
255 
256             for ( Metadata metadata : metadatas )
257             {
258                 upload( metadataUploads, session, metadata, repository, connector, catapult );
259                 processedMetadata.put( metadata, null );
260             }
261 
262             for ( int i = 0; i < artifacts.size(); i++ )
263             {
264                 Artifact artifact = artifacts.get( i );
265 
266                 for ( MetadataGenerator generator : generators )
267                 {
268                     artifact = generator.transformArtifact( artifact );
269                 }
270 
271                 artifacts.set( i, artifact );
272 
273                 Collection<FileTransformer> fileTransformers = fileTransformerManager.getTransformersForArtifact( artifact );
274                 if ( !fileTransformers.isEmpty() )
275                 {
276                     for ( FileTransformer fileTransformer : fileTransformers )
277                     {
278                         Artifact targetArtifact = fileTransformer.transformArtifact( artifact );
279 
280                         ArtifactUpload upload = new ArtifactUpload( targetArtifact, artifact.getFile(), fileTransformer );
281                         upload.setTrace( trace );
282                         upload.setListener( new ArtifactUploadListener( catapult, upload ) );
283                         artifactUploads.add( upload );
284                     }
285                 }
286                 else
287                 {
288                     ArtifactUpload upload = new ArtifactUpload( artifact, artifact.getFile() );
289                     upload.setTrace( trace );
290                     upload.setListener( new ArtifactUploadListener( catapult, upload ) );
291                     artifactUploads.add( upload );
292                 }
293             }
294 
295             connector.put( artifactUploads, null );
296 
297             for ( ArtifactUpload upload : artifactUploads )
298             {
299                 if ( upload.getException() != null )
300                 {
301                     throw new DeploymentException( "Failed to deploy artifacts: " + upload.getException().getMessage(),
302                                                    upload.getException() );
303                 }
304                 result.addArtifact( upload.getArtifact() );
305             }
306 
307             metadatas = Utils.finishMetadata( generators, artifacts );
308 
309             syncContext.acquire( null, metadatas );
310 
311             for ( Metadata metadata : metadatas )
312             {
313                 upload( metadataUploads, session, metadata, repository, connector, catapult );
314                 processedMetadata.put( metadata, null );
315             }
316 
317             for ( Metadata metadata : request.getMetadata() )
318             {
319                 if ( !processedMetadata.containsKey( metadata ) )
320                 {
321                     upload( metadataUploads, session, metadata, repository, connector, catapult );
322                     processedMetadata.put( metadata, null );
323                 }
324             }
325 
326             connector.put( null, metadataUploads );
327 
328             for ( MetadataUpload upload : metadataUploads )
329             {
330                 if ( upload.getException() != null )
331                 {
332                     throw new DeploymentException( "Failed to deploy metadata: " + upload.getException().getMessage(),
333                                                    upload.getException() );
334                 }
335                 result.addMetadata( upload.getMetadata() );
336             }
337         }
338         finally
339         {
340             connector.close();
341         }
342 
343         return result;
344     }
345 
346     private List<? extends MetadataGenerator> getMetadataGenerators( RepositorySystemSession session,
347                                                                      DeployRequest request )
348     {
349         PrioritizedComponents<MetadataGeneratorFactory> factories =
350             Utils.sortMetadataGeneratorFactories( session, this.metadataFactories );
351 
352         List<MetadataGenerator> generators = new ArrayList<MetadataGenerator>();
353 
354         for ( PrioritizedComponent<MetadataGeneratorFactory> factory : factories.getEnabled() )
355         {
356             MetadataGenerator generator = factory.getComponent().newInstance( session, request );
357             if ( generator != null )
358             {
359                 generators.add( generator );
360             }
361         }
362 
363         return generators;
364     }
365 
366     private void upload( Collection<MetadataUpload> metadataUploads, RepositorySystemSession session,
367                          Metadata metadata, RemoteRepository repository, RepositoryConnector connector,
368                          EventCatapult catapult )
369         throws DeploymentException
370     {
371         LocalRepositoryManager lrm = session.getLocalRepositoryManager();
372         File basedir = lrm.getRepository().getBasedir();
373 
374         File dstFile = new File( basedir, lrm.getPathForRemoteMetadata( metadata, repository, "" ) );
375 
376         if ( metadata instanceof MergeableMetadata )
377         {
378             if ( !( (MergeableMetadata) metadata ).isMerged() )
379             {
380                 {
381                     RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.METADATA_RESOLVING );
382                     event.setTrace( catapult.getTrace() );
383                     event.setMetadata( metadata );
384                     event.setRepository( repository );
385                     repositoryEventDispatcher.dispatch( event.build() );
386 
387                     event = new RepositoryEvent.Builder( session, EventType.METADATA_DOWNLOADING );
388                     event.setTrace( catapult.getTrace() );
389                     event.setMetadata( metadata );
390                     event.setRepository( repository );
391                     repositoryEventDispatcher.dispatch( event.build() );
392                 }
393 
394                 RepositoryPolicy policy = getPolicy( session, repository, metadata.getNature() );
395                 MetadataDownload download = new MetadataDownload();
396                 download.setMetadata( metadata );
397                 download.setFile( dstFile );
398                 download.setChecksumPolicy( policy.getChecksumPolicy() );
399                 download.setListener( SafeTransferListener.wrap( session ) );
400                 download.setTrace( catapult.getTrace() );
401                 connector.get( null, Arrays.asList( download ) );
402 
403                 Exception error = download.getException();
404 
405                 if ( error instanceof MetadataNotFoundException )
406                 {
407                     dstFile.delete();
408                 }
409 
410                 {
411                     RepositoryEvent.Builder event =
412                         new RepositoryEvent.Builder( session, EventType.METADATA_DOWNLOADED );
413                     event.setTrace( catapult.getTrace() );
414                     event.setMetadata( metadata );
415                     event.setRepository( repository );
416                     event.setException( error );
417                     event.setFile( dstFile );
418                     repositoryEventDispatcher.dispatch( event.build() );
419 
420                     event = new RepositoryEvent.Builder( session, EventType.METADATA_RESOLVED );
421                     event.setTrace( catapult.getTrace() );
422                     event.setMetadata( metadata );
423                     event.setRepository( repository );
424                     event.setException( error );
425                     event.setFile( dstFile );
426                     repositoryEventDispatcher.dispatch( event.build() );
427                 }
428 
429                 if ( error != null && !( error instanceof MetadataNotFoundException ) )
430                 {
431                     throw new DeploymentException( "Failed to retrieve remote metadata " + metadata + ": "
432                         + error.getMessage(), error );
433                 }
434             }
435 
436             try
437             {
438                 ( (MergeableMetadata) metadata ).merge( dstFile, dstFile );
439             }
440             catch ( RepositoryException e )
441             {
442                 throw new DeploymentException( "Failed to update metadata " + metadata + ": " + e.getMessage(), e );
443             }
444         }
445         else
446         {
447             if ( metadata.getFile() == null )
448             {
449                 throw new DeploymentException( "Failed to update metadata " + metadata + ": No file attached." );
450             }
451             try
452             {
453                 fileProcessor.copy( metadata.getFile(), dstFile );
454             }
455             catch ( IOException e )
456             {
457                 throw new DeploymentException( "Failed to update metadata " + metadata + ": " + e.getMessage(), e );
458             }
459         }
460 
461         UpdateCheck<Metadata, MetadataTransferException> check = new UpdateCheck<Metadata, MetadataTransferException>();
462         check.setItem( metadata );
463         check.setFile( dstFile );
464         check.setRepository( repository );
465         check.setAuthoritativeRepository( repository );
466         updateCheckManager.touchMetadata( session, check );
467 
468         MetadataUpload upload = new MetadataUpload( metadata, dstFile );
469         upload.setTrace( catapult.getTrace() );
470         upload.setListener( new MetadataUploadListener( catapult, upload ) );
471         metadataUploads.add( upload );
472     }
473 
474     private RepositoryPolicy getPolicy( RepositorySystemSession session, RemoteRepository repository,
475                                         Metadata.Nature nature )
476     {
477         boolean releases = !Metadata.Nature.SNAPSHOT.equals( nature );
478         boolean snapshots = !Metadata.Nature.RELEASE.equals( nature );
479         return remoteRepositoryManager.getPolicy( session, repository, releases, snapshots );
480     }
481 
482     static final class EventCatapult
483     {
484 
485         private final RepositorySystemSession session;
486 
487         private final RequestTrace trace;
488 
489         private final RemoteRepository repository;
490 
491         private final RepositoryEventDispatcher dispatcher;
492 
493         EventCatapult( RepositorySystemSession session, RequestTrace trace, RemoteRepository repository,
494                               RepositoryEventDispatcher dispatcher )
495         {
496             this.session = session;
497             this.trace = trace;
498             this.repository = repository;
499             this.dispatcher = dispatcher;
500         }
501 
502         public RepositorySystemSession getSession()
503         {
504             return session;
505         }
506 
507         public RequestTrace getTrace()
508         {
509             return trace;
510         }
511 
512         public void artifactDeploying( Artifact artifact, File file )
513         {
514             RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.ARTIFACT_DEPLOYING );
515             event.setTrace( trace );
516             event.setArtifact( artifact );
517             event.setRepository( repository );
518             event.setFile( file );
519 
520             dispatcher.dispatch( event.build() );
521         }
522 
523         public void artifactDeployed( Artifact artifact, File file, ArtifactTransferException exception )
524         {
525             RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.ARTIFACT_DEPLOYED );
526             event.setTrace( trace );
527             event.setArtifact( artifact );
528             event.setRepository( repository );
529             event.setFile( file );
530             event.setException( exception );
531 
532             dispatcher.dispatch( event.build() );
533         }
534 
535         public void metadataDeploying( Metadata metadata, File file )
536         {
537             RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.METADATA_DEPLOYING );
538             event.setTrace( trace );
539             event.setMetadata( metadata );
540             event.setRepository( repository );
541             event.setFile( file );
542 
543             dispatcher.dispatch( event.build() );
544         }
545 
546         public void metadataDeployed( Metadata metadata, File file, Exception exception )
547         {
548             RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.METADATA_DEPLOYED );
549             event.setTrace( trace );
550             event.setMetadata( metadata );
551             event.setRepository( repository );
552             event.setFile( file );
553             event.setException( exception );
554 
555             dispatcher.dispatch( event.build() );
556         }
557 
558     }
559 
560     static final class ArtifactUploadListener
561         extends SafeTransferListener
562     {
563 
564         private final EventCatapult catapult;
565 
566         private final ArtifactUpload transfer;
567 
568         ArtifactUploadListener( EventCatapult catapult, ArtifactUpload transfer )
569         {
570             super( catapult.getSession() );
571             this.catapult = catapult;
572             this.transfer = transfer;
573         }
574 
575         @Override
576         public void transferInitiated( TransferEvent event )
577             throws TransferCancelledException
578         {
579             super.transferInitiated( event );
580             catapult.artifactDeploying( transfer.getArtifact(), transfer.getFile() );
581         }
582 
583         @Override
584         public void transferFailed( TransferEvent event )
585         {
586             super.transferFailed( event );
587             catapult.artifactDeployed( transfer.getArtifact(), transfer.getFile(), transfer.getException() );
588         }
589 
590         @Override
591         public void transferSucceeded( TransferEvent event )
592         {
593             super.transferSucceeded( event );
594             catapult.artifactDeployed( transfer.getArtifact(), transfer.getFile(), null );
595         }
596 
597     }
598 
599     static final class MetadataUploadListener
600         extends SafeTransferListener
601     {
602 
603         private final EventCatapult catapult;
604 
605         private final MetadataUpload transfer;
606 
607         MetadataUploadListener( EventCatapult catapult, MetadataUpload transfer )
608         {
609             super( catapult.getSession() );
610             this.catapult = catapult;
611             this.transfer = transfer;
612         }
613 
614         @Override
615         public void transferInitiated( TransferEvent event )
616             throws TransferCancelledException
617         {
618             super.transferInitiated( event );
619             catapult.metadataDeploying( transfer.getMetadata(), transfer.getFile() );
620         }
621 
622         @Override
623         public void transferFailed( TransferEvent event )
624         {
625             super.transferFailed( event );
626             catapult.metadataDeployed( transfer.getMetadata(), transfer.getFile(), transfer.getException() );
627         }
628 
629         @Override
630         public void transferSucceeded( TransferEvent event )
631         {
632             super.transferSucceeded( event );
633             catapult.metadataDeployed( transfer.getMetadata(), transfer.getFile(), null );
634         }
635 
636     }
637 
638 }