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<>();
94  
95      private SyncContextFactory syncContextFactory;
96  
97      private OfflineController offlineController;
98  
99      public DefaultDeployer()
100     {
101         // enables default constructor
102     }
103 
104     @SuppressWarnings( "checkstyle:parameternumber" )
105     @Inject
106     DefaultDeployer( FileProcessor fileProcessor, RepositoryEventDispatcher repositoryEventDispatcher,
107                      RepositoryConnectorProvider repositoryConnectorProvider,
108                      RemoteRepositoryManager remoteRepositoryManager, UpdateCheckManager updateCheckManager,
109                      Set<MetadataGeneratorFactory> metadataFactories, SyncContextFactory syncContextFactory,
110                      OfflineController offlineController )
111     {
112         setFileProcessor( fileProcessor );
113         setRepositoryEventDispatcher( repositoryEventDispatcher );
114         setRepositoryConnectorProvider( repositoryConnectorProvider );
115         setRemoteRepositoryManager( remoteRepositoryManager );
116         setUpdateCheckManager( updateCheckManager );
117         setMetadataGeneratorFactories( metadataFactories );
118         setSyncContextFactory( syncContextFactory );
119         setOfflineController( offlineController );
120     }
121 
122     public void initService( ServiceLocator locator )
123     {
124         setFileProcessor( locator.getService( FileProcessor.class ) );
125         setRepositoryEventDispatcher( locator.getService( RepositoryEventDispatcher.class ) );
126         setRepositoryConnectorProvider( locator.getService( RepositoryConnectorProvider.class ) );
127         setRemoteRepositoryManager( locator.getService( RemoteRepositoryManager.class ) );
128         setUpdateCheckManager( locator.getService( UpdateCheckManager.class ) );
129         setMetadataGeneratorFactories( locator.getServices( MetadataGeneratorFactory.class ) );
130         setSyncContextFactory( locator.getService( SyncContextFactory.class ) );
131         setOfflineController( locator.getService( OfflineController.class ) );
132     }
133 
134     public DefaultDeployer setFileProcessor( FileProcessor fileProcessor )
135     {
136         this.fileProcessor = requireNonNull( fileProcessor, "file processor cannot be null" );
137         return this;
138     }
139 
140     public DefaultDeployer setRepositoryEventDispatcher( RepositoryEventDispatcher repositoryEventDispatcher )
141     {
142         this.repositoryEventDispatcher = requireNonNull(
143                 repositoryEventDispatcher, "repository event dispatcher cannot be null" );
144         return this;
145     }
146 
147     public DefaultDeployer setRepositoryConnectorProvider( RepositoryConnectorProvider repositoryConnectorProvider )
148     {
149         this.repositoryConnectorProvider = requireNonNull(
150                 repositoryConnectorProvider, "repository connector provider cannot be null" );
151         return this;
152     }
153 
154     public DefaultDeployer setRemoteRepositoryManager( RemoteRepositoryManager remoteRepositoryManager )
155     {
156         this.remoteRepositoryManager = requireNonNull(
157                 remoteRepositoryManager, "remote repository provider cannot be null" );
158         return this;
159     }
160 
161     public DefaultDeployer setUpdateCheckManager( UpdateCheckManager updateCheckManager )
162     {
163         this.updateCheckManager = requireNonNull( updateCheckManager, "update check manager cannot be null" );
164         return this;
165     }
166 
167     public DefaultDeployer addMetadataGeneratorFactory( MetadataGeneratorFactory factory )
168     {
169         metadataFactories.add( requireNonNull( factory, "metadata generator factory cannot be null" ) );
170         return this;
171     }
172 
173     public DefaultDeployer setMetadataGeneratorFactories( Collection<MetadataGeneratorFactory> metadataFactories )
174     {
175         if ( metadataFactories == null )
176         {
177             this.metadataFactories = new ArrayList<>();
178         }
179         else
180         {
181             this.metadataFactories = metadataFactories;
182         }
183         return this;
184     }
185 
186     public DefaultDeployer setSyncContextFactory( SyncContextFactory syncContextFactory )
187     {
188         this.syncContextFactory = requireNonNull( syncContextFactory, "sync context factory cannot be null" );
189         return this;
190     }
191 
192     public DefaultDeployer setOfflineController( OfflineController offlineController )
193     {
194         this.offlineController = requireNonNull( offlineController, "offline controller cannot be null" );
195         return this;
196     }
197 
198     public DeployResult deploy( RepositorySystemSession session, DeployRequest request )
199         throws DeploymentException
200     {
201         try
202         {
203             Utils.checkOffline( session, offlineController, request.getRepository() );
204         }
205         catch ( RepositoryOfflineException e )
206         {
207             throw new DeploymentException( "Cannot deploy while " + request.getRepository().getId() + " ("
208                 + request.getRepository().getUrl() + ") is in offline mode", e );
209         }
210 
211         try ( SyncContext syncContext = syncContextFactory.newInstance( session, false ) )
212         {
213             return deploy( syncContext, session, request );
214         }
215     }
216 
217     private DeployResult deploy( SyncContext syncContext, RepositorySystemSession session, DeployRequest request )
218         throws DeploymentException
219     {
220         DeployResult result = new DeployResult( request );
221 
222         RequestTrace trace = RequestTrace.newChild( request.getTrace(), request );
223 
224         RemoteRepository repository = request.getRepository();
225 
226         RepositoryConnector connector;
227         try
228         {
229             connector = repositoryConnectorProvider.newRepositoryConnector( session, repository );
230         }
231         catch ( NoRepositoryConnectorException e )
232         {
233             throw new DeploymentException( "Failed to deploy artifacts/metadata: " + e.getMessage(), e );
234         }
235 
236         try
237         {
238             List<? extends MetadataGenerator> generators = getMetadataGenerators( session, request );
239 
240             FileTransformerManager fileTransformerManager = session.getFileTransformerManager();
241 
242             List<ArtifactUpload> artifactUploads = new ArrayList<>();
243             List<MetadataUpload> metadataUploads = new ArrayList<>();
244             IdentityHashMap<Metadata, Object> processedMetadata = new IdentityHashMap<>();
245 
246             EventCatapult catapult = new EventCatapult( session, trace, repository, repositoryEventDispatcher );
247 
248             List<Artifact> artifacts = new ArrayList<>( request.getArtifacts() );
249 
250             List<Metadata> metadatas = Utils.prepareMetadata( generators, artifacts );
251 
252             syncContext.acquire( artifacts, Utils.combine( request.getMetadata(), metadatas ) );
253 
254             for ( Metadata metadata : metadatas )
255             {
256                 upload( metadataUploads, session, metadata, repository, connector, catapult );
257                 processedMetadata.put( metadata, null );
258             }
259 
260             for ( int i = 0; i < artifacts.size(); i++ )
261             {
262                 Artifact artifact = artifacts.get( i );
263 
264                 for ( MetadataGenerator generator : generators )
265                 {
266                     artifact = generator.transformArtifact( artifact );
267                 }
268 
269                 artifacts.set( i, artifact );
270 
271                 Collection<FileTransformer> fileTransformers =
272                         fileTransformerManager.getTransformersForArtifact( artifact );
273                 if ( !fileTransformers.isEmpty() )
274                 {
275                     for ( FileTransformer fileTransformer : fileTransformers )
276                     {
277                         Artifact targetArtifact = fileTransformer.transformArtifact( artifact );
278 
279                         ArtifactUpload upload = new ArtifactUpload( targetArtifact, artifact.getFile(),
280                                 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<>();
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                 RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.METADATA_RESOLVING );
381                 event.setTrace( catapult.getTrace() );
382                 event.setMetadata( metadata );
383                 event.setRepository( repository );
384                 repositoryEventDispatcher.dispatch( event.build() );
385 
386                 event = new RepositoryEvent.Builder( session, EventType.METADATA_DOWNLOADING );
387                 event.setTrace( catapult.getTrace() );
388                 event.setMetadata( metadata );
389                 event.setRepository( repository );
390                 repositoryEventDispatcher.dispatch( event.build() );
391 
392                 RepositoryPolicy policy = getPolicy( session, repository, metadata.getNature() );
393                 MetadataDownload download = new MetadataDownload();
394                 download.setMetadata( metadata );
395                 download.setFile( dstFile );
396                 download.setChecksumPolicy( policy.getChecksumPolicy() );
397                 download.setListener( SafeTransferListener.wrap( session ) );
398                 download.setTrace( catapult.getTrace() );
399                 connector.get( null, Arrays.asList( download ) );
400 
401                 Exception error = download.getException();
402 
403                 if ( error instanceof MetadataNotFoundException )
404                 {
405                     dstFile.delete();
406                 }
407 
408                 event = new RepositoryEvent.Builder( session, EventType.METADATA_DOWNLOADED );
409                 event.setTrace( catapult.getTrace() );
410                 event.setMetadata( metadata );
411                 event.setRepository( repository );
412                 event.setException( error );
413                 event.setFile( dstFile );
414                 repositoryEventDispatcher.dispatch( event.build() );
415 
416                 event = new RepositoryEvent.Builder( session, EventType.METADATA_RESOLVED );
417                 event.setTrace( catapult.getTrace() );
418                 event.setMetadata( metadata );
419                 event.setRepository( repository );
420                 event.setException( error );
421                 event.setFile( dstFile );
422                 repositoryEventDispatcher.dispatch( event.build() );
423 
424                 if ( error != null && !( error instanceof MetadataNotFoundException ) )
425                 {
426                     throw new DeploymentException( "Failed to retrieve remote metadata " + metadata + ": "
427                         + error.getMessage(), error );
428                 }
429             }
430 
431             try
432             {
433                 ( (MergeableMetadata) metadata ).merge( dstFile, dstFile );
434             }
435             catch ( RepositoryException e )
436             {
437                 throw new DeploymentException( "Failed to update metadata " + metadata + ": " + e.getMessage(), e );
438             }
439         }
440         else
441         {
442             if ( metadata.getFile() == null )
443             {
444                 throw new DeploymentException( "Failed to update metadata " + metadata + ": No file attached." );
445             }
446             try
447             {
448                 fileProcessor.copy( metadata.getFile(), dstFile );
449             }
450             catch ( IOException e )
451             {
452                 throw new DeploymentException( "Failed to update metadata " + metadata + ": " + e.getMessage(), e );
453             }
454         }
455 
456         UpdateCheck<Metadata, MetadataTransferException> check = new UpdateCheck<>();
457         check.setItem( metadata );
458         check.setFile( dstFile );
459         check.setRepository( repository );
460         check.setAuthoritativeRepository( repository );
461         updateCheckManager.touchMetadata( session, check );
462 
463         MetadataUpload upload = new MetadataUpload( metadata, dstFile );
464         upload.setTrace( catapult.getTrace() );
465         upload.setListener( new MetadataUploadListener( catapult, upload ) );
466         metadataUploads.add( upload );
467     }
468 
469     private RepositoryPolicy getPolicy( RepositorySystemSession session, RemoteRepository repository,
470                                         Metadata.Nature nature )
471     {
472         boolean releases = !Metadata.Nature.SNAPSHOT.equals( nature );
473         boolean snapshots = !Metadata.Nature.RELEASE.equals( nature );
474         return remoteRepositoryManager.getPolicy( session, repository, releases, snapshots );
475     }
476 
477     static final class EventCatapult
478     {
479 
480         private final RepositorySystemSession session;
481 
482         private final RequestTrace trace;
483 
484         private final RemoteRepository repository;
485 
486         private final RepositoryEventDispatcher dispatcher;
487 
488         EventCatapult( RepositorySystemSession session, RequestTrace trace, RemoteRepository repository,
489                               RepositoryEventDispatcher dispatcher )
490         {
491             this.session = session;
492             this.trace = trace;
493             this.repository = repository;
494             this.dispatcher = dispatcher;
495         }
496 
497         public RepositorySystemSession getSession()
498         {
499             return session;
500         }
501 
502         public RequestTrace getTrace()
503         {
504             return trace;
505         }
506 
507         public void artifactDeploying( Artifact artifact, File file )
508         {
509             RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.ARTIFACT_DEPLOYING );
510             event.setTrace( trace );
511             event.setArtifact( artifact );
512             event.setRepository( repository );
513             event.setFile( file );
514 
515             dispatcher.dispatch( event.build() );
516         }
517 
518         public void artifactDeployed( Artifact artifact, File file, ArtifactTransferException exception )
519         {
520             RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.ARTIFACT_DEPLOYED );
521             event.setTrace( trace );
522             event.setArtifact( artifact );
523             event.setRepository( repository );
524             event.setFile( file );
525             event.setException( exception );
526 
527             dispatcher.dispatch( event.build() );
528         }
529 
530         public void metadataDeploying( Metadata metadata, File file )
531         {
532             RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.METADATA_DEPLOYING );
533             event.setTrace( trace );
534             event.setMetadata( metadata );
535             event.setRepository( repository );
536             event.setFile( file );
537 
538             dispatcher.dispatch( event.build() );
539         }
540 
541         public void metadataDeployed( Metadata metadata, File file, Exception exception )
542         {
543             RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.METADATA_DEPLOYED );
544             event.setTrace( trace );
545             event.setMetadata( metadata );
546             event.setRepository( repository );
547             event.setFile( file );
548             event.setException( exception );
549 
550             dispatcher.dispatch( event.build() );
551         }
552 
553     }
554 
555     static final class ArtifactUploadListener
556         extends SafeTransferListener
557     {
558 
559         private final EventCatapult catapult;
560 
561         private final ArtifactUpload transfer;
562 
563         ArtifactUploadListener( EventCatapult catapult, ArtifactUpload transfer )
564         {
565             super( catapult.getSession() );
566             this.catapult = catapult;
567             this.transfer = transfer;
568         }
569 
570         @Override
571         public void transferInitiated( TransferEvent event )
572             throws TransferCancelledException
573         {
574             super.transferInitiated( event );
575             catapult.artifactDeploying( transfer.getArtifact(), transfer.getFile() );
576         }
577 
578         @Override
579         public void transferFailed( TransferEvent event )
580         {
581             super.transferFailed( event );
582             catapult.artifactDeployed( transfer.getArtifact(), transfer.getFile(), transfer.getException() );
583         }
584 
585         @Override
586         public void transferSucceeded( TransferEvent event )
587         {
588             super.transferSucceeded( event );
589             catapult.artifactDeployed( transfer.getArtifact(), transfer.getFile(), null );
590         }
591 
592     }
593 
594     static final class MetadataUploadListener
595         extends SafeTransferListener
596     {
597 
598         private final EventCatapult catapult;
599 
600         private final MetadataUpload transfer;
601 
602         MetadataUploadListener( EventCatapult catapult, MetadataUpload transfer )
603         {
604             super( catapult.getSession() );
605             this.catapult = catapult;
606             this.transfer = transfer;
607         }
608 
609         @Override
610         public void transferInitiated( TransferEvent event )
611             throws TransferCancelledException
612         {
613             super.transferInitiated( event );
614             catapult.metadataDeploying( transfer.getMetadata(), transfer.getFile() );
615         }
616 
617         @Override
618         public void transferFailed( TransferEvent event )
619         {
620             super.transferFailed( event );
621             catapult.metadataDeployed( transfer.getMetadata(), transfer.getFile(), transfer.getException() );
622         }
623 
624         @Override
625         public void transferSucceeded( TransferEvent event )
626         {
627             super.transferSucceeded( event );
628             catapult.metadataDeployed( transfer.getMetadata(), transfer.getFile(), null );
629         }
630 
631     }
632 
633 }