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