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