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