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