001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.eclipse.aether.internal.impl; 020 021import javax.inject.Inject; 022import javax.inject.Named; 023import javax.inject.Singleton; 024 025import java.io.File; 026import java.io.IOException; 027import java.util.ArrayList; 028import java.util.Collection; 029import java.util.Collections; 030import java.util.IdentityHashMap; 031import java.util.List; 032import java.util.ListIterator; 033import java.util.Map; 034 035import org.eclipse.aether.RepositoryEvent; 036import org.eclipse.aether.RepositoryEvent.EventType; 037import org.eclipse.aether.RepositoryException; 038import org.eclipse.aether.RepositorySystemSession; 039import org.eclipse.aether.RequestTrace; 040import org.eclipse.aether.SyncContext; 041import org.eclipse.aether.artifact.Artifact; 042import org.eclipse.aether.deployment.DeployRequest; 043import org.eclipse.aether.deployment.DeployResult; 044import org.eclipse.aether.deployment.DeploymentException; 045import org.eclipse.aether.impl.Deployer; 046import org.eclipse.aether.impl.MetadataGenerator; 047import org.eclipse.aether.impl.MetadataGeneratorFactory; 048import org.eclipse.aether.impl.OfflineController; 049import org.eclipse.aether.impl.RemoteRepositoryManager; 050import org.eclipse.aether.impl.RepositoryConnectorProvider; 051import org.eclipse.aether.impl.RepositoryEventDispatcher; 052import org.eclipse.aether.impl.UpdateCheck; 053import org.eclipse.aether.impl.UpdateCheckManager; 054import org.eclipse.aether.metadata.MergeableMetadata; 055import org.eclipse.aether.metadata.Metadata; 056import org.eclipse.aether.repository.LocalRepositoryManager; 057import org.eclipse.aether.repository.RemoteRepository; 058import org.eclipse.aether.repository.RepositoryPolicy; 059import org.eclipse.aether.spi.connector.ArtifactUpload; 060import org.eclipse.aether.spi.connector.MetadataDownload; 061import org.eclipse.aether.spi.connector.MetadataUpload; 062import org.eclipse.aether.spi.connector.RepositoryConnector; 063import org.eclipse.aether.spi.io.FileProcessor; 064import org.eclipse.aether.spi.synccontext.SyncContextFactory; 065import org.eclipse.aether.transfer.ArtifactTransferException; 066import org.eclipse.aether.transfer.MetadataNotFoundException; 067import org.eclipse.aether.transfer.MetadataTransferException; 068import org.eclipse.aether.transfer.NoRepositoryConnectorException; 069import org.eclipse.aether.transfer.RepositoryOfflineException; 070import org.eclipse.aether.transfer.TransferCancelledException; 071import org.eclipse.aether.transfer.TransferEvent; 072 073import static java.util.Objects.requireNonNull; 074 075/** 076 */ 077@Singleton 078@Named 079public class DefaultDeployer implements Deployer { 080 private final FileProcessor fileProcessor; 081 082 private final RepositoryEventDispatcher repositoryEventDispatcher; 083 084 private final RepositoryConnectorProvider repositoryConnectorProvider; 085 086 private final RemoteRepositoryManager remoteRepositoryManager; 087 088 private final UpdateCheckManager updateCheckManager; 089 090 private final Map<String, MetadataGeneratorFactory> metadataFactories; 091 092 private final SyncContextFactory syncContextFactory; 093 094 private final OfflineController offlineController; 095 096 @SuppressWarnings("checkstyle:parameternumber") 097 @Inject 098 public DefaultDeployer( 099 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}