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