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.IOException;
26 import java.nio.file.Files;
27 import java.nio.file.Path;
28 import java.util.ArrayList;
29 import java.util.Collection;
30 import java.util.Collections;
31 import java.util.HashMap;
32 import java.util.IdentityHashMap;
33 import java.util.List;
34 import java.util.ListIterator;
35 import java.util.Map;
36
37 import org.eclipse.aether.RepositoryEvent;
38 import org.eclipse.aether.RepositoryEvent.EventType;
39 import org.eclipse.aether.RepositoryException;
40 import org.eclipse.aether.RepositorySystemSession;
41 import org.eclipse.aether.RequestTrace;
42 import org.eclipse.aether.SyncContext;
43 import org.eclipse.aether.artifact.Artifact;
44 import org.eclipse.aether.deployment.DeployRequest;
45 import org.eclipse.aether.deployment.DeployResult;
46 import org.eclipse.aether.deployment.DeploymentException;
47 import org.eclipse.aether.impl.Deployer;
48 import org.eclipse.aether.impl.MetadataGenerator;
49 import org.eclipse.aether.impl.MetadataGeneratorFactory;
50 import org.eclipse.aether.impl.OfflineController;
51 import org.eclipse.aether.impl.RemoteRepositoryManager;
52 import org.eclipse.aether.impl.RepositoryConnectorProvider;
53 import org.eclipse.aether.impl.RepositoryEventDispatcher;
54 import org.eclipse.aether.impl.UpdateCheck;
55 import org.eclipse.aether.impl.UpdateCheckManager;
56 import org.eclipse.aether.metadata.MergeableMetadata;
57 import org.eclipse.aether.metadata.Metadata;
58 import org.eclipse.aether.repository.LocalRepositoryManager;
59 import org.eclipse.aether.repository.RemoteRepository;
60 import org.eclipse.aether.repository.RepositoryPolicy;
61 import org.eclipse.aether.spi.artifact.generator.ArtifactGenerator;
62 import org.eclipse.aether.spi.artifact.generator.ArtifactGeneratorFactory;
63 import org.eclipse.aether.spi.artifact.transformer.ArtifactTransformer;
64 import org.eclipse.aether.spi.connector.ArtifactUpload;
65 import org.eclipse.aether.spi.connector.MetadataDownload;
66 import org.eclipse.aether.spi.connector.MetadataUpload;
67 import org.eclipse.aether.spi.connector.RepositoryConnector;
68 import org.eclipse.aether.spi.io.PathProcessor;
69 import org.eclipse.aether.spi.synccontext.SyncContextFactory;
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.slf4j.Logger;
78 import org.slf4j.LoggerFactory;
79
80 import static java.util.Objects.requireNonNull;
81
82
83
84 @Singleton
85 @Named
86 public class DefaultDeployer implements Deployer {
87 private final Logger logger = LoggerFactory.getLogger(getClass());
88
89 private final PathProcessor pathProcessor;
90
91 private final RepositoryEventDispatcher repositoryEventDispatcher;
92
93 private final RepositoryConnectorProvider repositoryConnectorProvider;
94
95 private final RemoteRepositoryManager remoteRepositoryManager;
96
97 private final UpdateCheckManager updateCheckManager;
98
99 private final Map<String, ArtifactGeneratorFactory> artifactFactories;
100
101 private final Map<String, MetadataGeneratorFactory> metadataFactories;
102
103 private final Map<String, ArtifactTransformer> artifactTransformers;
104
105 private final SyncContextFactory syncContextFactory;
106
107 private final OfflineController offlineController;
108
109 @SuppressWarnings("checkstyle:parameternumber")
110 @Inject
111 public DefaultDeployer(
112 PathProcessor pathProcessor,
113 RepositoryEventDispatcher repositoryEventDispatcher,
114 RepositoryConnectorProvider repositoryConnectorProvider,
115 RemoteRepositoryManager remoteRepositoryManager,
116 UpdateCheckManager updateCheckManager,
117 Map<String, ArtifactGeneratorFactory> artifactFactories,
118 Map<String, MetadataGeneratorFactory> metadataFactories,
119 Map<String, ArtifactTransformer> artifactTransformers,
120 SyncContextFactory syncContextFactory,
121 OfflineController offlineController) {
122 this.pathProcessor = requireNonNull(pathProcessor, "path processor cannot be null");
123 this.repositoryEventDispatcher =
124 requireNonNull(repositoryEventDispatcher, "repository event dispatcher cannot be null");
125 this.repositoryConnectorProvider =
126 requireNonNull(repositoryConnectorProvider, "repository connector provider cannot be null");
127 this.remoteRepositoryManager =
128 requireNonNull(remoteRepositoryManager, "remote repository provider cannot be null");
129 this.updateCheckManager = requireNonNull(updateCheckManager, "update check manager cannot be null");
130 this.artifactFactories = Collections.unmodifiableMap(artifactFactories);
131 this.metadataFactories = Collections.unmodifiableMap(metadataFactories);
132 this.artifactTransformers = Collections.unmodifiableMap(artifactTransformers);
133 this.syncContextFactory = requireNonNull(syncContextFactory, "sync context factory cannot be null");
134 this.offlineController = requireNonNull(offlineController, "offline controller cannot be null");
135 }
136
137 @Override
138 public DeployResult deploy(RepositorySystemSession session, DeployRequest request) throws DeploymentException {
139 requireNonNull(session, "session cannot be null");
140 requireNonNull(request, "request cannot be null");
141 try {
142 Utils.checkOffline(session, offlineController, request.getRepository());
143 } catch (RepositoryOfflineException e) {
144 throw new DeploymentException(
145 "Cannot deploy while " + request.getRepository().getId() + " ("
146 + request.getRepository().getUrl() + ") is in offline mode",
147 e);
148 }
149
150 for (ArtifactTransformer transformer : artifactTransformers.values()) {
151 request = transformer.transformDeployArtifacts(session, request);
152 }
153 try (SyncContext syncContext = syncContextFactory.newInstance(session, true)) {
154 return deploy(syncContext, session, request);
155 }
156 }
157
158 private DeployResult deploy(SyncContext syncContext, RepositorySystemSession session, DeployRequest request)
159 throws DeploymentException {
160 DeployResult result = new DeployResult(request);
161
162 RequestTrace trace = RequestTrace.newChild(request.getTrace(), request);
163
164 RemoteRepository repository = request.getRepository();
165
166 RepositoryConnector connector;
167 try {
168 connector = repositoryConnectorProvider.newRepositoryConnector(session, repository);
169 } catch (NoRepositoryConnectorException e) {
170 throw new DeploymentException("Failed to deploy artifacts/metadata: " + e.getMessage(), e);
171 }
172
173 List<Artifact> artifacts = new ArrayList<>(request.getArtifacts());
174 List<? extends ArtifactGenerator> artifactGenerators =
175 Utils.getArtifactGenerators(session, artifactFactories, request);
176 try {
177 List<Artifact> generatedArtifacts = new ArrayList<>();
178 for (ArtifactGenerator artifactGenerator : artifactGenerators) {
179 Collection<? extends Artifact> generated = artifactGenerator.generate(generatedArtifacts);
180 for (Artifact generatedArtifact : generated) {
181 Map<String, String> properties = new HashMap<>(generatedArtifact.getProperties());
182 properties.put(
183 ArtifactGeneratorFactory.ARTIFACT_GENERATOR_ID,
184 requireNonNull(artifactGenerator.generatorId(), "generatorId"));
185 Artifact ga = generatedArtifact.setProperties(properties);
186 generatedArtifacts.add(ga);
187 }
188 }
189 artifacts.addAll(generatedArtifacts);
190
191 List<? extends MetadataGenerator> metadataGenerators =
192 Utils.getMetadataGenerators(session, metadataFactories, request);
193
194 List<ArtifactUpload> artifactUploads = new ArrayList<>();
195 List<MetadataUpload> metadataUploads = new ArrayList<>();
196 IdentityHashMap<Metadata, Object> processedMetadata = new IdentityHashMap<>();
197
198 EventCatapult catapult = new EventCatapult(session, trace, repository, repositoryEventDispatcher);
199
200 List<Metadata> metadatas = Utils.prepareMetadata(metadataGenerators, artifacts);
201
202 syncContext.acquire(artifacts, Utils.combine(request.getMetadata(), metadatas));
203
204 for (Metadata metadata : metadatas) {
205 upload(metadataUploads, session, metadata, repository, connector, catapult);
206 processedMetadata.put(metadata, null);
207 }
208
209 for (ListIterator<Artifact> iterator = artifacts.listIterator(); iterator.hasNext(); ) {
210 Artifact artifact = iterator.next();
211
212 for (MetadataGenerator generator : metadataGenerators) {
213 artifact = generator.transformArtifact(artifact);
214 }
215
216 iterator.set(artifact);
217
218 ArtifactUpload upload = new ArtifactUpload(artifact, artifact.getPath());
219 upload.setTrace(trace);
220 upload.setListener(new ArtifactUploadListener(catapult, upload));
221 artifactUploads.add(upload);
222 }
223
224 connector.put(artifactUploads, null);
225
226 for (ArtifactUpload upload : artifactUploads) {
227 if (upload.getException() != null) {
228 throw new DeploymentException(
229 "Failed to deploy artifacts: "
230 + upload.getException().getMessage(),
231 upload.getException());
232 }
233 if (upload.getArtifact().getProperty(ArtifactGeneratorFactory.ARTIFACT_GENERATOR_ID, null) == null) {
234 result.addArtifact(upload.getArtifact());
235 }
236 }
237
238 metadatas = Utils.finishMetadata(metadataGenerators, artifacts);
239
240 syncContext.acquire(null, metadatas);
241
242 for (Metadata metadata : metadatas) {
243 upload(metadataUploads, session, metadata, repository, connector, catapult);
244 processedMetadata.put(metadata, null);
245 }
246
247 for (Metadata metadata : request.getMetadata()) {
248 if (!processedMetadata.containsKey(metadata)) {
249 upload(metadataUploads, session, metadata, repository, connector, catapult);
250 processedMetadata.put(metadata, null);
251 }
252 }
253
254 connector.put(null, metadataUploads);
255
256 for (MetadataUpload upload : metadataUploads) {
257 if (upload.getException() != null) {
258 throw new DeploymentException(
259 "Failed to deploy metadata: "
260 + upload.getException().getMessage(),
261 upload.getException());
262 }
263 result.addMetadata(upload.getMetadata());
264 }
265 } finally {
266 connector.close();
267 for (ArtifactGenerator artifactGenerator : artifactGenerators) {
268 try {
269 artifactGenerator.close();
270 } catch (Exception e) {
271 logger.warn("ArtifactGenerator close failure: {}", artifactGenerator.generatorId(), e);
272 }
273 }
274 }
275
276 return result;
277 }
278
279 private void upload(
280 Collection<MetadataUpload> metadataUploads,
281 RepositorySystemSession session,
282 Metadata metadata,
283 RemoteRepository repository,
284 RepositoryConnector connector,
285 EventCatapult catapult)
286 throws DeploymentException {
287 LocalRepositoryManager lrm = session.getLocalRepositoryManager();
288 Path dstPath = lrm.getAbsolutePathForRemoteMetadata(metadata, repository, "");
289
290 if (metadata instanceof MergeableMetadata) {
291 if (!((MergeableMetadata) metadata).isMerged()) {
292 RepositoryEvent.Builder event = new RepositoryEvent.Builder(session, EventType.METADATA_RESOLVING);
293 event.setTrace(catapult.getTrace());
294 event.setMetadata(metadata);
295 event.setRepository(repository);
296 repositoryEventDispatcher.dispatch(event.build());
297
298 event = new RepositoryEvent.Builder(session, EventType.METADATA_DOWNLOADING);
299 event.setTrace(catapult.getTrace());
300 event.setMetadata(metadata);
301 event.setRepository(repository);
302 repositoryEventDispatcher.dispatch(event.build());
303
304 RepositoryPolicy policy = getPolicy(session, repository, metadata.getNature());
305 MetadataDownload download = new MetadataDownload();
306 download.setMetadata(metadata);
307 download.setPath(dstPath);
308 download.setChecksumPolicy(policy.getChecksumPolicy());
309 download.setListener(SafeTransferListener.wrap(session));
310 download.setTrace(catapult.getTrace());
311 connector.get(null, Collections.singletonList(download));
312
313 Exception error = download.getException();
314
315 if (error instanceof MetadataNotFoundException) {
316 try {
317 Files.deleteIfExists(dstPath);
318 } catch (IOException e) {
319 throw new DeploymentException(
320 "Failed to delete cached metadata " + metadata + ": " + e.getMessage(), e);
321 }
322 }
323
324 event = new RepositoryEvent.Builder(session, EventType.METADATA_DOWNLOADED);
325 event.setTrace(catapult.getTrace());
326 event.setMetadata(metadata);
327 event.setRepository(repository);
328 event.setException(error);
329 event.setPath(dstPath);
330 repositoryEventDispatcher.dispatch(event.build());
331
332 event = new RepositoryEvent.Builder(session, EventType.METADATA_RESOLVED);
333 event.setTrace(catapult.getTrace());
334 event.setMetadata(metadata);
335 event.setRepository(repository);
336 event.setException(error);
337 event.setPath(dstPath);
338 repositoryEventDispatcher.dispatch(event.build());
339
340 if (error != null && !(error instanceof MetadataNotFoundException)) {
341 throw new DeploymentException(
342 "Failed to retrieve remote metadata " + metadata + ": " + error.getMessage(), error);
343 }
344 }
345
346 try {
347 ((MergeableMetadata) metadata).merge(dstPath, dstPath);
348 } catch (RepositoryException e) {
349 throw new DeploymentException("Failed to update metadata " + metadata + ": " + e.getMessage(), e);
350 }
351 } else {
352 if (metadata.getPath() == null) {
353 throw new DeploymentException("Failed to update metadata " + metadata + ": No file attached.");
354 }
355 try {
356 pathProcessor.copy(metadata.getPath(), dstPath);
357 } catch (IOException e) {
358 throw new DeploymentException("Failed to update metadata " + metadata + ": " + e.getMessage(), e);
359 }
360 }
361
362 UpdateCheck<Metadata, MetadataTransferException> check = new UpdateCheck<>();
363 check.setItem(metadata);
364 check.setPath(dstPath);
365 check.setRepository(repository);
366 check.setAuthoritativeRepository(repository);
367 updateCheckManager.touchMetadata(session, check);
368
369 MetadataUpload upload = new MetadataUpload(metadata, dstPath);
370 upload.setTrace(catapult.getTrace());
371 upload.setListener(new MetadataUploadListener(catapult, upload));
372 metadataUploads.add(upload);
373 }
374
375 private RepositoryPolicy getPolicy(
376 RepositorySystemSession session, RemoteRepository repository, Metadata.Nature nature) {
377 boolean releases = !Metadata.Nature.SNAPSHOT.equals(nature);
378 boolean snapshots = !Metadata.Nature.RELEASE.equals(nature);
379 return remoteRepositoryManager.getPolicy(session, repository, releases, snapshots);
380 }
381
382 static final class EventCatapult {
383
384 private final RepositorySystemSession session;
385
386 private final RequestTrace trace;
387
388 private final RemoteRepository repository;
389
390 private final RepositoryEventDispatcher dispatcher;
391
392 EventCatapult(
393 RepositorySystemSession session,
394 RequestTrace trace,
395 RemoteRepository repository,
396 RepositoryEventDispatcher dispatcher) {
397 this.session = session;
398 this.trace = trace;
399 this.repository = repository;
400 this.dispatcher = dispatcher;
401 }
402
403 public RepositorySystemSession getSession() {
404 return session;
405 }
406
407 public RequestTrace getTrace() {
408 return trace;
409 }
410
411 public void artifactDeploying(Artifact artifact, Path path) {
412 RepositoryEvent.Builder event = new RepositoryEvent.Builder(session, EventType.ARTIFACT_DEPLOYING);
413 event.setTrace(trace);
414 event.setArtifact(artifact);
415 event.setRepository(repository);
416 event.setPath(path);
417
418 dispatcher.dispatch(event.build());
419 }
420
421 public void artifactDeployed(Artifact artifact, Path path, ArtifactTransferException exception) {
422 RepositoryEvent.Builder event = new RepositoryEvent.Builder(session, EventType.ARTIFACT_DEPLOYED);
423 event.setTrace(trace);
424 event.setArtifact(artifact);
425 event.setRepository(repository);
426 event.setPath(path);
427 event.setException(exception);
428
429 dispatcher.dispatch(event.build());
430 }
431
432 public void metadataDeploying(Metadata metadata, Path path) {
433 RepositoryEvent.Builder event = new RepositoryEvent.Builder(session, EventType.METADATA_DEPLOYING);
434 event.setTrace(trace);
435 event.setMetadata(metadata);
436 event.setRepository(repository);
437 event.setPath(path);
438
439 dispatcher.dispatch(event.build());
440 }
441
442 public void metadataDeployed(Metadata metadata, Path path, Exception exception) {
443 RepositoryEvent.Builder event = new RepositoryEvent.Builder(session, EventType.METADATA_DEPLOYED);
444 event.setTrace(trace);
445 event.setMetadata(metadata);
446 event.setRepository(repository);
447 event.setPath(path);
448 event.setException(exception);
449
450 dispatcher.dispatch(event.build());
451 }
452 }
453
454 static final class ArtifactUploadListener extends SafeTransferListener {
455
456 private final EventCatapult catapult;
457
458 private final ArtifactUpload transfer;
459
460 ArtifactUploadListener(EventCatapult catapult, ArtifactUpload transfer) {
461 super(catapult.getSession());
462 this.catapult = catapult;
463 this.transfer = transfer;
464 }
465
466 @Override
467 public void transferInitiated(TransferEvent event) throws TransferCancelledException {
468 super.transferInitiated(event);
469 requireNonNull(event, "event cannot be null");
470 catapult.artifactDeploying(transfer.getArtifact(), transfer.getPath());
471 }
472
473 @Override
474 public void transferFailed(TransferEvent event) {
475 super.transferFailed(event);
476 requireNonNull(event, "event cannot be null");
477 catapult.artifactDeployed(transfer.getArtifact(), transfer.getPath(), transfer.getException());
478 }
479
480 @Override
481 public void transferSucceeded(TransferEvent event) {
482 super.transferSucceeded(event);
483 requireNonNull(event, "event cannot be null");
484 catapult.artifactDeployed(transfer.getArtifact(), transfer.getPath(), null);
485 }
486 }
487
488 static final class MetadataUploadListener extends SafeTransferListener {
489
490 private final EventCatapult catapult;
491
492 private final MetadataUpload transfer;
493
494 MetadataUploadListener(EventCatapult catapult, MetadataUpload transfer) {
495 super(catapult.getSession());
496 this.catapult = catapult;
497 this.transfer = transfer;
498 }
499
500 @Override
501 public void transferInitiated(TransferEvent event) throws TransferCancelledException {
502 super.transferInitiated(event);
503 requireNonNull(event, "event cannot be null");
504 catapult.metadataDeploying(transfer.getMetadata(), transfer.getPath());
505 }
506
507 @Override
508 public void transferFailed(TransferEvent event) {
509 super.transferFailed(event);
510 requireNonNull(event, "event cannot be null");
511 catapult.metadataDeployed(transfer.getMetadata(), transfer.getPath(), transfer.getException());
512 }
513
514 @Override
515 public void transferSucceeded(TransferEvent event) {
516 super.transferSucceeded(event);
517 requireNonNull(event, "event cannot be null");
518 catapult.metadataDeployed(transfer.getMetadata(), transfer.getPath(), null);
519 }
520 }
521 }