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