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