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