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         requireNonNull( session, "session cannot be null" );
206         requireNonNull( request, "request cannot be null" );
207         try
208         {
209             Utils.checkOffline( session, offlineController, request.getRepository() );
210         }
211         catch ( RepositoryOfflineException e )
212         {
213             throw new DeploymentException( "Cannot deploy while " + request.getRepository().getId() + " ("
214                 + request.getRepository().getUrl() + ") is in offline mode", e );
215         }
216 
217         try ( SyncContext syncContext = syncContextFactory.newInstance( session, false ) )
218         {
219             return deploy( syncContext, session, request );
220         }
221     }
222 
223     private DeployResult deploy( SyncContext syncContext, RepositorySystemSession session, DeployRequest request )
224         throws DeploymentException
225     {
226         DeployResult result = new DeployResult( request );
227 
228         RequestTrace trace = RequestTrace.newChild( request.getTrace(), request );
229 
230         RemoteRepository repository = request.getRepository();
231 
232         RepositoryConnector connector;
233         try
234         {
235             connector = repositoryConnectorProvider.newRepositoryConnector( session, repository );
236         }
237         catch ( NoRepositoryConnectorException e )
238         {
239             throw new DeploymentException( "Failed to deploy artifacts/metadata: " + e.getMessage(), e );
240         }
241 
242         try
243         {
244             List<? extends MetadataGenerator> generators = getMetadataGenerators( session, request );
245 
246             FileTransformerManager fileTransformerManager = session.getFileTransformerManager();
247 
248             List<ArtifactUpload> artifactUploads = new ArrayList<>();
249             List<MetadataUpload> metadataUploads = new ArrayList<>();
250             IdentityHashMap<Metadata, Object> processedMetadata = new IdentityHashMap<>();
251 
252             EventCatapult catapult = new EventCatapult( session, trace, repository, repositoryEventDispatcher );
253 
254             List<Artifact> artifacts = new ArrayList<>( request.getArtifacts() );
255 
256             List<Metadata> metadatas = Utils.prepareMetadata( generators, artifacts );
257 
258             syncContext.acquire( artifacts, Utils.combine( request.getMetadata(), metadatas ) );
259 
260             for ( Metadata metadata : metadatas )
261             {
262                 upload( metadataUploads, session, metadata, repository, connector, catapult );
263                 processedMetadata.put( metadata, null );
264             }
265 
266             for ( ListIterator<Artifact> iterator = artifacts.listIterator(); iterator.hasNext(); )
267             {
268                 Artifact artifact = iterator.next();
269 
270                 for ( MetadataGenerator generator : generators )
271                 {
272                     artifact = generator.transformArtifact( artifact );
273                 }
274 
275                 iterator.set( artifact );
276 
277                 Collection<FileTransformer> fileTransformers =
278                         fileTransformerManager.getTransformersForArtifact( artifact );
279                 if ( !fileTransformers.isEmpty() )
280                 {
281                     for ( FileTransformer fileTransformer : fileTransformers )
282                     {
283                         Artifact targetArtifact = fileTransformer.transformArtifact( artifact );
284 
285                         ArtifactUpload upload = new ArtifactUpload( targetArtifact, artifact.getFile(),
286                                 fileTransformer );
287                         upload.setTrace( trace );
288                         upload.setListener( new ArtifactUploadListener( catapult, upload ) );
289                         artifactUploads.add( upload );
290                     }
291                 }
292                 else
293                 {
294                     ArtifactUpload upload = new ArtifactUpload( artifact, artifact.getFile() );
295                     upload.setTrace( trace );
296                     upload.setListener( new ArtifactUploadListener( catapult, upload ) );
297                     artifactUploads.add( upload );
298                 }
299             }
300 
301             connector.put( artifactUploads, null );
302 
303             for ( ArtifactUpload upload : artifactUploads )
304             {
305                 if ( upload.getException() != null )
306                 {
307                     throw new DeploymentException( "Failed to deploy artifacts: " + upload.getException().getMessage(),
308                                                    upload.getException() );
309                 }
310                 result.addArtifact( upload.getArtifact() );
311             }
312 
313             metadatas = Utils.finishMetadata( generators, artifacts );
314 
315             syncContext.acquire( null, metadatas );
316 
317             for ( Metadata metadata : metadatas )
318             {
319                 upload( metadataUploads, session, metadata, repository, connector, catapult );
320                 processedMetadata.put( metadata, null );
321             }
322 
323             for ( Metadata metadata : request.getMetadata() )
324             {
325                 if ( !processedMetadata.containsKey( metadata ) )
326                 {
327                     upload( metadataUploads, session, metadata, repository, connector, catapult );
328                     processedMetadata.put( metadata, null );
329                 }
330             }
331 
332             connector.put( null, metadataUploads );
333 
334             for ( MetadataUpload upload : metadataUploads )
335             {
336                 if ( upload.getException() != null )
337                 {
338                     throw new DeploymentException( "Failed to deploy metadata: " + upload.getException().getMessage(),
339                                                    upload.getException() );
340                 }
341                 result.addMetadata( upload.getMetadata() );
342             }
343         }
344         finally
345         {
346             connector.close();
347         }
348 
349         return result;
350     }
351 
352     private List<? extends MetadataGenerator> getMetadataGenerators( RepositorySystemSession session,
353                                                                      DeployRequest request )
354     {
355         PrioritizedComponents<MetadataGeneratorFactory> factories =
356             Utils.sortMetadataGeneratorFactories( session, this.metadataFactories );
357 
358         List<MetadataGenerator> generators = new ArrayList<>();
359 
360         for ( PrioritizedComponent<MetadataGeneratorFactory> factory : factories.getEnabled() )
361         {
362             MetadataGenerator generator = factory.getComponent().newInstance( session, request );
363             if ( generator != null )
364             {
365                 generators.add( generator );
366             }
367         }
368 
369         return generators;
370     }
371 
372     private void upload( Collection<MetadataUpload> metadataUploads, RepositorySystemSession session,
373                          Metadata metadata, RemoteRepository repository, RepositoryConnector connector,
374                          EventCatapult catapult )
375         throws DeploymentException
376     {
377         LocalRepositoryManager lrm = session.getLocalRepositoryManager();
378         File basedir = lrm.getRepository().getBasedir();
379 
380         File dstFile = new File( basedir, lrm.getPathForRemoteMetadata( metadata, repository, "" ) );
381 
382         if ( metadata instanceof MergeableMetadata )
383         {
384             if ( !( (MergeableMetadata) metadata ).isMerged() )
385             {
386                 RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.METADATA_RESOLVING );
387                 event.setTrace( catapult.getTrace() );
388                 event.setMetadata( metadata );
389                 event.setRepository( repository );
390                 repositoryEventDispatcher.dispatch( event.build() );
391 
392                 event = new RepositoryEvent.Builder( session, EventType.METADATA_DOWNLOADING );
393                 event.setTrace( catapult.getTrace() );
394                 event.setMetadata( metadata );
395                 event.setRepository( repository );
396                 repositoryEventDispatcher.dispatch( event.build() );
397 
398                 RepositoryPolicy policy = getPolicy( session, repository, metadata.getNature() );
399                 MetadataDownload download = new MetadataDownload();
400                 download.setMetadata( metadata );
401                 download.setFile( dstFile );
402                 download.setChecksumPolicy( policy.getChecksumPolicy() );
403                 download.setListener( SafeTransferListener.wrap( session ) );
404                 download.setTrace( catapult.getTrace() );
405                 connector.get( null, Arrays.asList( download ) );
406 
407                 Exception error = download.getException();
408 
409                 if ( error instanceof MetadataNotFoundException )
410                 {
411                     dstFile.delete();
412                 }
413 
414                 event = new RepositoryEvent.Builder( session, EventType.METADATA_DOWNLOADED );
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                 event = new RepositoryEvent.Builder( session, EventType.METADATA_RESOLVED );
423                 event.setTrace( catapult.getTrace() );
424                 event.setMetadata( metadata );
425                 event.setRepository( repository );
426                 event.setException( error );
427                 event.setFile( dstFile );
428                 repositoryEventDispatcher.dispatch( event.build() );
429 
430                 if ( error != null && !( error instanceof MetadataNotFoundException ) )
431                 {
432                     throw new DeploymentException( "Failed to retrieve remote metadata " + metadata + ": "
433                         + error.getMessage(), error );
434                 }
435             }
436 
437             try
438             {
439                 ( (MergeableMetadata) metadata ).merge( dstFile, dstFile );
440             }
441             catch ( RepositoryException e )
442             {
443                 throw new DeploymentException( "Failed to update metadata " + metadata + ": " + e.getMessage(), e );
444             }
445         }
446         else
447         {
448             if ( metadata.getFile() == null )
449             {
450                 throw new DeploymentException( "Failed to update metadata " + metadata + ": No file attached." );
451             }
452             try
453             {
454                 fileProcessor.copy( metadata.getFile(), dstFile );
455             }
456             catch ( IOException e )
457             {
458                 throw new DeploymentException( "Failed to update metadata " + metadata + ": " + e.getMessage(), e );
459             }
460         }
461 
462         UpdateCheck<Metadata, MetadataTransferException> check = new UpdateCheck<>();
463         check.setItem( metadata );
464         check.setFile( dstFile );
465         check.setRepository( repository );
466         check.setAuthoritativeRepository( repository );
467         updateCheckManager.touchMetadata( session, check );
468 
469         MetadataUpload upload = new MetadataUpload( metadata, dstFile );
470         upload.setTrace( catapult.getTrace() );
471         upload.setListener( new MetadataUploadListener( catapult, upload ) );
472         metadataUploads.add( upload );
473     }
474 
475     private RepositoryPolicy getPolicy( RepositorySystemSession session, RemoteRepository repository,
476                                         Metadata.Nature nature )
477     {
478         boolean releases = !Metadata.Nature.SNAPSHOT.equals( nature );
479         boolean snapshots = !Metadata.Nature.RELEASE.equals( nature );
480         return remoteRepositoryManager.getPolicy( session, repository, releases, snapshots );
481     }
482 
483     static final class EventCatapult
484     {
485 
486         private final RepositorySystemSession session;
487 
488         private final RequestTrace trace;
489 
490         private final RemoteRepository repository;
491 
492         private final RepositoryEventDispatcher dispatcher;
493 
494         EventCatapult( RepositorySystemSession session, RequestTrace trace, RemoteRepository repository,
495                               RepositoryEventDispatcher dispatcher )
496         {
497             this.session = session;
498             this.trace = trace;
499             this.repository = repository;
500             this.dispatcher = dispatcher;
501         }
502 
503         public RepositorySystemSession getSession()
504         {
505             return session;
506         }
507 
508         public RequestTrace getTrace()
509         {
510             return trace;
511         }
512 
513         public void artifactDeploying( Artifact artifact, File file )
514         {
515             RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.ARTIFACT_DEPLOYING );
516             event.setTrace( trace );
517             event.setArtifact( artifact );
518             event.setRepository( repository );
519             event.setFile( file );
520 
521             dispatcher.dispatch( event.build() );
522         }
523 
524         public void artifactDeployed( Artifact artifact, File file, ArtifactTransferException exception )
525         {
526             RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.ARTIFACT_DEPLOYED );
527             event.setTrace( trace );
528             event.setArtifact( artifact );
529             event.setRepository( repository );
530             event.setFile( file );
531             event.setException( exception );
532 
533             dispatcher.dispatch( event.build() );
534         }
535 
536         public void metadataDeploying( Metadata metadata, File file )
537         {
538             RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.METADATA_DEPLOYING );
539             event.setTrace( trace );
540             event.setMetadata( metadata );
541             event.setRepository( repository );
542             event.setFile( file );
543 
544             dispatcher.dispatch( event.build() );
545         }
546 
547         public void metadataDeployed( Metadata metadata, File file, Exception exception )
548         {
549             RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.METADATA_DEPLOYED );
550             event.setTrace( trace );
551             event.setMetadata( metadata );
552             event.setRepository( repository );
553             event.setFile( file );
554             event.setException( exception );
555 
556             dispatcher.dispatch( event.build() );
557         }
558 
559     }
560 
561     static final class ArtifactUploadListener
562         extends SafeTransferListener
563     {
564 
565         private final EventCatapult catapult;
566 
567         private final ArtifactUpload transfer;
568 
569         ArtifactUploadListener( EventCatapult catapult, ArtifactUpload transfer )
570         {
571             super( catapult.getSession() );
572             this.catapult = catapult;
573             this.transfer = transfer;
574         }
575 
576         @Override
577         public void transferInitiated( TransferEvent event )
578             throws TransferCancelledException
579         {
580             super.transferInitiated( event );
581             requireNonNull( event, "event cannot be null" );
582             catapult.artifactDeploying( transfer.getArtifact(), transfer.getFile() );
583         }
584 
585         @Override
586         public void transferFailed( TransferEvent event )
587         {
588             super.transferFailed( event );
589             requireNonNull( event, "event cannot be null" );
590             catapult.artifactDeployed( transfer.getArtifact(), transfer.getFile(), transfer.getException() );
591         }
592 
593         @Override
594         public void transferSucceeded( TransferEvent event )
595         {
596             super.transferSucceeded( event );
597             requireNonNull( event, "event cannot be null" );
598             catapult.artifactDeployed( transfer.getArtifact(), transfer.getFile(), null );
599         }
600 
601     }
602 
603     static final class MetadataUploadListener
604         extends SafeTransferListener
605     {
606 
607         private final EventCatapult catapult;
608 
609         private final MetadataUpload transfer;
610 
611         MetadataUploadListener( EventCatapult catapult, MetadataUpload transfer )
612         {
613             super( catapult.getSession() );
614             this.catapult = catapult;
615             this.transfer = transfer;
616         }
617 
618         @Override
619         public void transferInitiated( TransferEvent event )
620             throws TransferCancelledException
621         {
622             super.transferInitiated( event );
623             requireNonNull( event, "event cannot be null" );
624             catapult.metadataDeploying( transfer.getMetadata(), transfer.getFile() );
625         }
626 
627         @Override
628         public void transferFailed( TransferEvent event )
629         {
630             super.transferFailed( event );
631             requireNonNull( event, "event cannot be null" );
632             catapult.metadataDeployed( transfer.getMetadata(), transfer.getFile(), transfer.getException() );
633         }
634 
635         @Override
636         public void transferSucceeded( TransferEvent event )
637         {
638             super.transferSucceeded( event );
639             requireNonNull( event, "event cannot be null" );
640             catapult.metadataDeployed( transfer.getMetadata(), transfer.getFile(), null );
641         }
642 
643     }
644 
645 }