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
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
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 }