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