1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.aether.internal.impl;
20
21 import javax.inject.Inject;
22 import javax.inject.Named;
23 import javax.inject.Singleton;
24
25 import java.io.File;
26 import java.io.IOException;
27 import java.util.ArrayList;
28 import java.util.Collection;
29 import java.util.Collections;
30 import java.util.IdentityHashMap;
31 import java.util.List;
32 import java.util.ListIterator;
33 import java.util.Set;
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.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.synccontext.SyncContextFactory;
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 import static java.util.Objects.requireNonNull;
78
79
80
81 @Singleton
82 @Named
83 public class DefaultDeployer implements Deployer, Service {
84 private FileProcessor fileProcessor;
85
86 private RepositoryEventDispatcher repositoryEventDispatcher;
87
88 private RepositoryConnectorProvider repositoryConnectorProvider;
89
90 private RemoteRepositoryManager remoteRepositoryManager;
91
92 private UpdateCheckManager updateCheckManager;
93
94 private Collection<MetadataGeneratorFactory> metadataFactories = new ArrayList<>();
95
96 private SyncContextFactory syncContextFactory;
97
98 private OfflineController offlineController;
99
100 @Deprecated
101 public DefaultDeployer() {
102
103 }
104
105 @SuppressWarnings("checkstyle:parameternumber")
106 @Inject
107 public DefaultDeployer(
108 FileProcessor fileProcessor,
109 RepositoryEventDispatcher repositoryEventDispatcher,
110 RepositoryConnectorProvider repositoryConnectorProvider,
111 RemoteRepositoryManager remoteRepositoryManager,
112 UpdateCheckManager updateCheckManager,
113 Set<MetadataGeneratorFactory> metadataFactories,
114 SyncContextFactory syncContextFactory,
115 OfflineController offlineController) {
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 setFileProcessor(locator.getService(FileProcessor.class));
128 setRepositoryEventDispatcher(locator.getService(RepositoryEventDispatcher.class));
129 setRepositoryConnectorProvider(locator.getService(RepositoryConnectorProvider.class));
130 setRemoteRepositoryManager(locator.getService(RemoteRepositoryManager.class));
131 setUpdateCheckManager(locator.getService(UpdateCheckManager.class));
132 setMetadataGeneratorFactories(locator.getServices(MetadataGeneratorFactory.class));
133 setSyncContextFactory(locator.getService(SyncContextFactory.class));
134 setOfflineController(locator.getService(OfflineController.class));
135 }
136
137 public DefaultDeployer setFileProcessor(FileProcessor fileProcessor) {
138 this.fileProcessor = requireNonNull(fileProcessor, "file processor cannot be null");
139 return this;
140 }
141
142 public DefaultDeployer setRepositoryEventDispatcher(RepositoryEventDispatcher repositoryEventDispatcher) {
143 this.repositoryEventDispatcher =
144 requireNonNull(repositoryEventDispatcher, "repository event dispatcher cannot be null");
145 return this;
146 }
147
148 public DefaultDeployer setRepositoryConnectorProvider(RepositoryConnectorProvider repositoryConnectorProvider) {
149 this.repositoryConnectorProvider =
150 requireNonNull(repositoryConnectorProvider, "repository connector provider cannot be null");
151 return this;
152 }
153
154 public DefaultDeployer setRemoteRepositoryManager(RemoteRepositoryManager remoteRepositoryManager) {
155 this.remoteRepositoryManager =
156 requireNonNull(remoteRepositoryManager, "remote repository provider cannot be null");
157 return this;
158 }
159
160 public DefaultDeployer setUpdateCheckManager(UpdateCheckManager updateCheckManager) {
161 this.updateCheckManager = requireNonNull(updateCheckManager, "update check manager cannot be null");
162 return this;
163 }
164
165 public DefaultDeployer addMetadataGeneratorFactory(MetadataGeneratorFactory factory) {
166 metadataFactories.add(requireNonNull(factory, "metadata generator factory cannot be null"));
167 return this;
168 }
169
170 public DefaultDeployer setMetadataGeneratorFactories(Collection<MetadataGeneratorFactory> metadataFactories) {
171 if (metadataFactories == null) {
172 this.metadataFactories = new ArrayList<>();
173 } else {
174 this.metadataFactories = metadataFactories;
175 }
176 return this;
177 }
178
179 public DefaultDeployer setSyncContextFactory(SyncContextFactory syncContextFactory) {
180 this.syncContextFactory = requireNonNull(syncContextFactory, "sync context factory cannot be null");
181 return this;
182 }
183
184 public DefaultDeployer setOfflineController(OfflineController offlineController) {
185 this.offlineController = requireNonNull(offlineController, "offline controller cannot be null");
186 return this;
187 }
188
189 public DeployResult deploy(RepositorySystemSession session, DeployRequest request) throws DeploymentException {
190 requireNonNull(session, "session cannot be null");
191 requireNonNull(request, "request cannot be null");
192 try {
193 Utils.checkOffline(session, offlineController, request.getRepository());
194 } catch (RepositoryOfflineException e) {
195 throw new DeploymentException(
196 "Cannot deploy while " + request.getRepository().getId() + " ("
197 + request.getRepository().getUrl() + ") is in offline mode",
198 e);
199 }
200
201 try (SyncContext syncContext = syncContextFactory.newInstance(session, true)) {
202 return deploy(syncContext, session, request);
203 }
204 }
205
206 private DeployResult deploy(SyncContext syncContext, RepositorySystemSession session, DeployRequest request)
207 throws DeploymentException {
208 DeployResult result = new DeployResult(request);
209
210 RequestTrace trace = RequestTrace.newChild(request.getTrace(), request);
211
212 RemoteRepository repository = request.getRepository();
213
214 RepositoryConnector connector;
215 try {
216 connector = repositoryConnectorProvider.newRepositoryConnector(session, repository);
217 } catch (NoRepositoryConnectorException e) {
218 throw new DeploymentException("Failed to deploy artifacts/metadata: " + e.getMessage(), e);
219 }
220
221 try {
222 List<? extends MetadataGenerator> generators = getMetadataGenerators(session, request);
223
224 FileTransformerManager fileTransformerManager = session.getFileTransformerManager();
225
226 List<ArtifactUpload> artifactUploads = new ArrayList<>();
227 List<MetadataUpload> metadataUploads = new ArrayList<>();
228 IdentityHashMap<Metadata, Object> processedMetadata = new IdentityHashMap<>();
229
230 EventCatapult catapult = new EventCatapult(session, trace, repository, repositoryEventDispatcher);
231
232 List<Artifact> artifacts = new ArrayList<>(request.getArtifacts());
233
234 List<Metadata> metadatas = Utils.prepareMetadata(generators, artifacts);
235
236 syncContext.acquire(artifacts, Utils.combine(request.getMetadata(), metadatas));
237
238 for (Metadata metadata : metadatas) {
239 upload(metadataUploads, session, metadata, repository, connector, catapult);
240 processedMetadata.put(metadata, null);
241 }
242
243 for (ListIterator<Artifact> iterator = artifacts.listIterator(); iterator.hasNext(); ) {
244 Artifact artifact = iterator.next();
245
246 for (MetadataGenerator generator : generators) {
247 artifact = generator.transformArtifact(artifact);
248 }
249
250 iterator.set(artifact);
251
252 Collection<FileTransformer> fileTransformers =
253 fileTransformerManager.getTransformersForArtifact(artifact);
254 if (!fileTransformers.isEmpty()) {
255 for (FileTransformer fileTransformer : fileTransformers) {
256 Artifact targetArtifact = fileTransformer.transformArtifact(artifact);
257
258 ArtifactUpload upload = new ArtifactUpload(targetArtifact, artifact.getFile(), fileTransformer);
259 upload.setTrace(trace);
260 upload.setListener(new ArtifactUploadListener(catapult, upload));
261 artifactUploads.add(upload);
262 }
263 } else {
264 ArtifactUpload upload = new ArtifactUpload(artifact, artifact.getFile());
265 upload.setTrace(trace);
266 upload.setListener(new ArtifactUploadListener(catapult, upload));
267 artifactUploads.add(upload);
268 }
269 }
270
271 connector.put(artifactUploads, null);
272
273 for (ArtifactUpload upload : artifactUploads) {
274 if (upload.getException() != null) {
275 throw new DeploymentException(
276 "Failed to deploy artifacts: "
277 + upload.getException().getMessage(),
278 upload.getException());
279 }
280 result.addArtifact(upload.getArtifact());
281 }
282
283 metadatas = Utils.finishMetadata(generators, artifacts);
284
285 syncContext.acquire(null, metadatas);
286
287 for (Metadata metadata : metadatas) {
288 upload(metadataUploads, session, metadata, repository, connector, catapult);
289 processedMetadata.put(metadata, null);
290 }
291
292 for (Metadata metadata : request.getMetadata()) {
293 if (!processedMetadata.containsKey(metadata)) {
294 upload(metadataUploads, session, metadata, repository, connector, catapult);
295 processedMetadata.put(metadata, null);
296 }
297 }
298
299 connector.put(null, metadataUploads);
300
301 for (MetadataUpload upload : metadataUploads) {
302 if (upload.getException() != null) {
303 throw new DeploymentException(
304 "Failed to deploy metadata: "
305 + upload.getException().getMessage(),
306 upload.getException());
307 }
308 result.addMetadata(upload.getMetadata());
309 }
310 } finally {
311 connector.close();
312 }
313
314 return result;
315 }
316
317 private List<? extends MetadataGenerator> getMetadataGenerators(
318 RepositorySystemSession session, DeployRequest request) {
319 PrioritizedComponents<MetadataGeneratorFactory> factories =
320 Utils.sortMetadataGeneratorFactories(session, this.metadataFactories);
321
322 List<MetadataGenerator> generators = new ArrayList<>();
323
324 for (PrioritizedComponent<MetadataGeneratorFactory> factory : factories.getEnabled()) {
325 MetadataGenerator generator = factory.getComponent().newInstance(session, request);
326 if (generator != null) {
327 generators.add(generator);
328 }
329 }
330
331 return generators;
332 }
333
334 private void upload(
335 Collection<MetadataUpload> metadataUploads,
336 RepositorySystemSession session,
337 Metadata metadata,
338 RemoteRepository repository,
339 RepositoryConnector connector,
340 EventCatapult catapult)
341 throws DeploymentException {
342 LocalRepositoryManager lrm = session.getLocalRepositoryManager();
343 File basedir = lrm.getRepository().getBasedir();
344
345 File dstFile = new File(basedir, lrm.getPathForRemoteMetadata(metadata, repository, ""));
346
347 if (metadata instanceof MergeableMetadata) {
348 if (!((MergeableMetadata) metadata).isMerged()) {
349 RepositoryEvent.Builder event = new RepositoryEvent.Builder(session, EventType.METADATA_RESOLVING);
350 event.setTrace(catapult.getTrace());
351 event.setMetadata(metadata);
352 event.setRepository(repository);
353 repositoryEventDispatcher.dispatch(event.build());
354
355 event = new RepositoryEvent.Builder(session, EventType.METADATA_DOWNLOADING);
356 event.setTrace(catapult.getTrace());
357 event.setMetadata(metadata);
358 event.setRepository(repository);
359 repositoryEventDispatcher.dispatch(event.build());
360
361 RepositoryPolicy policy = getPolicy(session, repository, metadata.getNature());
362 MetadataDownload download = new MetadataDownload();
363 download.setMetadata(metadata);
364 download.setFile(dstFile);
365 download.setChecksumPolicy(policy.getChecksumPolicy());
366 download.setListener(SafeTransferListener.wrap(session));
367 download.setTrace(catapult.getTrace());
368 connector.get(null, Collections.singletonList(download));
369
370 Exception error = download.getException();
371
372 if (error instanceof MetadataNotFoundException) {
373 dstFile.delete();
374 }
375
376 event = new RepositoryEvent.Builder(session, EventType.METADATA_DOWNLOADED);
377 event.setTrace(catapult.getTrace());
378 event.setMetadata(metadata);
379 event.setRepository(repository);
380 event.setException(error);
381 event.setFile(dstFile);
382 repositoryEventDispatcher.dispatch(event.build());
383
384 event = new RepositoryEvent.Builder(session, EventType.METADATA_RESOLVED);
385 event.setTrace(catapult.getTrace());
386 event.setMetadata(metadata);
387 event.setRepository(repository);
388 event.setException(error);
389 event.setFile(dstFile);
390 repositoryEventDispatcher.dispatch(event.build());
391
392 if (error != null && !(error instanceof MetadataNotFoundException)) {
393 throw new DeploymentException(
394 "Failed to retrieve remote metadata " + metadata + ": " + error.getMessage(), error);
395 }
396 }
397
398 try {
399 ((MergeableMetadata) metadata).merge(dstFile, dstFile);
400 } catch (RepositoryException e) {
401 throw new DeploymentException("Failed to update metadata " + metadata + ": " + e.getMessage(), e);
402 }
403 } else {
404 if (metadata.getFile() == null) {
405 throw new DeploymentException("Failed to update metadata " + metadata + ": No file attached.");
406 }
407 try {
408 fileProcessor.copy(metadata.getFile(), dstFile);
409 } catch (IOException e) {
410 throw new DeploymentException("Failed to update metadata " + metadata + ": " + e.getMessage(), e);
411 }
412 }
413
414 UpdateCheck<Metadata, MetadataTransferException> check = new UpdateCheck<>();
415 check.setItem(metadata);
416 check.setFile(dstFile);
417 check.setRepository(repository);
418 check.setAuthoritativeRepository(repository);
419 updateCheckManager.touchMetadata(session, check);
420
421 MetadataUpload upload = new MetadataUpload(metadata, dstFile);
422 upload.setTrace(catapult.getTrace());
423 upload.setListener(new MetadataUploadListener(catapult, upload));
424 metadataUploads.add(upload);
425 }
426
427 private RepositoryPolicy getPolicy(
428 RepositorySystemSession session, RemoteRepository repository, Metadata.Nature nature) {
429 boolean releases = !Metadata.Nature.SNAPSHOT.equals(nature);
430 boolean snapshots = !Metadata.Nature.RELEASE.equals(nature);
431 return remoteRepositoryManager.getPolicy(session, repository, releases, snapshots);
432 }
433
434 static final class EventCatapult {
435
436 private final RepositorySystemSession session;
437
438 private final RequestTrace trace;
439
440 private final RemoteRepository repository;
441
442 private final RepositoryEventDispatcher dispatcher;
443
444 EventCatapult(
445 RepositorySystemSession session,
446 RequestTrace trace,
447 RemoteRepository repository,
448 RepositoryEventDispatcher dispatcher) {
449 this.session = session;
450 this.trace = trace;
451 this.repository = repository;
452 this.dispatcher = dispatcher;
453 }
454
455 public RepositorySystemSession getSession() {
456 return session;
457 }
458
459 public RequestTrace getTrace() {
460 return trace;
461 }
462
463 public void artifactDeploying(Artifact artifact, File file) {
464 RepositoryEvent.Builder event = new RepositoryEvent.Builder(session, EventType.ARTIFACT_DEPLOYING);
465 event.setTrace(trace);
466 event.setArtifact(artifact);
467 event.setRepository(repository);
468 event.setFile(file);
469
470 dispatcher.dispatch(event.build());
471 }
472
473 public void artifactDeployed(Artifact artifact, File file, ArtifactTransferException exception) {
474 RepositoryEvent.Builder event = new RepositoryEvent.Builder(session, EventType.ARTIFACT_DEPLOYED);
475 event.setTrace(trace);
476 event.setArtifact(artifact);
477 event.setRepository(repository);
478 event.setFile(file);
479 event.setException(exception);
480
481 dispatcher.dispatch(event.build());
482 }
483
484 public void metadataDeploying(Metadata metadata, File file) {
485 RepositoryEvent.Builder event = new RepositoryEvent.Builder(session, EventType.METADATA_DEPLOYING);
486 event.setTrace(trace);
487 event.setMetadata(metadata);
488 event.setRepository(repository);
489 event.setFile(file);
490
491 dispatcher.dispatch(event.build());
492 }
493
494 public void metadataDeployed(Metadata metadata, File file, Exception exception) {
495 RepositoryEvent.Builder event = new RepositoryEvent.Builder(session, EventType.METADATA_DEPLOYED);
496 event.setTrace(trace);
497 event.setMetadata(metadata);
498 event.setRepository(repository);
499 event.setFile(file);
500 event.setException(exception);
501
502 dispatcher.dispatch(event.build());
503 }
504 }
505
506 static final class ArtifactUploadListener extends SafeTransferListener {
507
508 private final EventCatapult catapult;
509
510 private final ArtifactUpload transfer;
511
512 ArtifactUploadListener(EventCatapult catapult, ArtifactUpload transfer) {
513 super(catapult.getSession());
514 this.catapult = catapult;
515 this.transfer = transfer;
516 }
517
518 @Override
519 public void transferInitiated(TransferEvent event) throws TransferCancelledException {
520 super.transferInitiated(event);
521 requireNonNull(event, "event cannot be null");
522 catapult.artifactDeploying(transfer.getArtifact(), transfer.getFile());
523 }
524
525 @Override
526 public void transferFailed(TransferEvent event) {
527 super.transferFailed(event);
528 requireNonNull(event, "event cannot be null");
529 catapult.artifactDeployed(transfer.getArtifact(), transfer.getFile(), transfer.getException());
530 }
531
532 @Override
533 public void transferSucceeded(TransferEvent event) {
534 super.transferSucceeded(event);
535 requireNonNull(event, "event cannot be null");
536 catapult.artifactDeployed(transfer.getArtifact(), transfer.getFile(), null);
537 }
538 }
539
540 static final class MetadataUploadListener extends SafeTransferListener {
541
542 private final EventCatapult catapult;
543
544 private final MetadataUpload transfer;
545
546 MetadataUploadListener(EventCatapult catapult, MetadataUpload transfer) {
547 super(catapult.getSession());
548 this.catapult = catapult;
549 this.transfer = transfer;
550 }
551
552 @Override
553 public void transferInitiated(TransferEvent event) throws TransferCancelledException {
554 super.transferInitiated(event);
555 requireNonNull(event, "event cannot be null");
556 catapult.metadataDeploying(transfer.getMetadata(), transfer.getFile());
557 }
558
559 @Override
560 public void transferFailed(TransferEvent event) {
561 super.transferFailed(event);
562 requireNonNull(event, "event cannot be null");
563 catapult.metadataDeployed(transfer.getMetadata(), transfer.getFile(), transfer.getException());
564 }
565
566 @Override
567 public void transferSucceeded(TransferEvent event) {
568 super.transferSucceeded(event);
569 requireNonNull(event, "event cannot be null");
570 catapult.metadataDeployed(transfer.getMetadata(), transfer.getFile(), null);
571 }
572 }
573 }