001package org.eclipse.aether.internal.impl; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import java.io.File; 023import java.io.IOException; 024import java.util.ArrayList; 025import java.util.Arrays; 026import java.util.Collection; 027import java.util.IdentityHashMap; 028import java.util.List; 029import static java.util.Objects.requireNonNull; 030 031import java.util.ListIterator; 032import java.util.Set; 033 034import javax.inject.Inject; 035import javax.inject.Named; 036import javax.inject.Singleton; 037 038import org.eclipse.aether.RepositoryEvent; 039import org.eclipse.aether.RepositoryEvent.EventType; 040import org.eclipse.aether.RepositoryException; 041import org.eclipse.aether.RepositorySystemSession; 042import org.eclipse.aether.RequestTrace; 043import org.eclipse.aether.SyncContext; 044import org.eclipse.aether.artifact.Artifact; 045import org.eclipse.aether.deployment.DeployRequest; 046import org.eclipse.aether.deployment.DeployResult; 047import org.eclipse.aether.deployment.DeploymentException; 048import org.eclipse.aether.impl.Deployer; 049import org.eclipse.aether.impl.MetadataGenerator; 050import org.eclipse.aether.impl.MetadataGeneratorFactory; 051import org.eclipse.aether.impl.OfflineController; 052import org.eclipse.aether.impl.RemoteRepositoryManager; 053import org.eclipse.aether.impl.RepositoryConnectorProvider; 054import org.eclipse.aether.impl.RepositoryEventDispatcher; 055import org.eclipse.aether.spi.synccontext.SyncContextFactory; 056import org.eclipse.aether.impl.UpdateCheck; 057import org.eclipse.aether.impl.UpdateCheckManager; 058import org.eclipse.aether.metadata.MergeableMetadata; 059import org.eclipse.aether.metadata.Metadata; 060import org.eclipse.aether.repository.LocalRepositoryManager; 061import org.eclipse.aether.repository.RemoteRepository; 062import org.eclipse.aether.repository.RepositoryPolicy; 063import org.eclipse.aether.spi.connector.ArtifactUpload; 064import org.eclipse.aether.spi.connector.MetadataDownload; 065import org.eclipse.aether.spi.connector.MetadataUpload; 066import org.eclipse.aether.spi.connector.RepositoryConnector; 067import org.eclipse.aether.spi.io.FileProcessor; 068import org.eclipse.aether.spi.locator.Service; 069import org.eclipse.aether.spi.locator.ServiceLocator; 070import org.eclipse.aether.transfer.ArtifactTransferException; 071import org.eclipse.aether.transfer.MetadataNotFoundException; 072import org.eclipse.aether.transfer.MetadataTransferException; 073import org.eclipse.aether.transfer.NoRepositoryConnectorException; 074import org.eclipse.aether.transfer.RepositoryOfflineException; 075import org.eclipse.aether.transfer.TransferCancelledException; 076import org.eclipse.aether.transfer.TransferEvent; 077import org.eclipse.aether.transform.FileTransformer; 078import org.eclipse.aether.transform.FileTransformerManager; 079 080/** 081 */ 082@Singleton 083@Named 084public class DefaultDeployer 085 implements Deployer, Service 086{ 087 private FileProcessor fileProcessor; 088 089 private RepositoryEventDispatcher repositoryEventDispatcher; 090 091 private RepositoryConnectorProvider repositoryConnectorProvider; 092 093 private RemoteRepositoryManager remoteRepositoryManager; 094 095 private UpdateCheckManager updateCheckManager; 096 097 private Collection<MetadataGeneratorFactory> metadataFactories = new ArrayList<>(); 098 099 private SyncContextFactory syncContextFactory; 100 101 private OfflineController offlineController; 102 103 public DefaultDeployer() 104 { 105 // enables default constructor 106 } 107 108 @SuppressWarnings( "checkstyle:parameternumber" ) 109 @Inject 110 DefaultDeployer( FileProcessor fileProcessor, RepositoryEventDispatcher repositoryEventDispatcher, 111 RepositoryConnectorProvider repositoryConnectorProvider, 112 RemoteRepositoryManager remoteRepositoryManager, UpdateCheckManager updateCheckManager, 113 Set<MetadataGeneratorFactory> metadataFactories, SyncContextFactory syncContextFactory, 114 OfflineController offlineController ) 115 { 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 { 128 setFileProcessor( locator.getService( FileProcessor.class ) ); 129 setRepositoryEventDispatcher( locator.getService( RepositoryEventDispatcher.class ) ); 130 setRepositoryConnectorProvider( locator.getService( RepositoryConnectorProvider.class ) ); 131 setRemoteRepositoryManager( locator.getService( RemoteRepositoryManager.class ) ); 132 setUpdateCheckManager( locator.getService( UpdateCheckManager.class ) ); 133 setMetadataGeneratorFactories( locator.getServices( MetadataGeneratorFactory.class ) ); 134 setSyncContextFactory( locator.getService( SyncContextFactory.class ) ); 135 setOfflineController( locator.getService( OfflineController.class ) ); 136 } 137 138 public DefaultDeployer setFileProcessor( FileProcessor fileProcessor ) 139 { 140 this.fileProcessor = requireNonNull( fileProcessor, "file processor cannot be null" ); 141 return this; 142 } 143 144 public DefaultDeployer setRepositoryEventDispatcher( RepositoryEventDispatcher repositoryEventDispatcher ) 145 { 146 this.repositoryEventDispatcher = requireNonNull( 147 repositoryEventDispatcher, "repository event dispatcher cannot be null" ); 148 return this; 149 } 150 151 public DefaultDeployer setRepositoryConnectorProvider( RepositoryConnectorProvider repositoryConnectorProvider ) 152 { 153 this.repositoryConnectorProvider = requireNonNull( 154 repositoryConnectorProvider, "repository connector provider cannot be null" ); 155 return this; 156 } 157 158 public DefaultDeployer setRemoteRepositoryManager( RemoteRepositoryManager remoteRepositoryManager ) 159 { 160 this.remoteRepositoryManager = requireNonNull( 161 remoteRepositoryManager, "remote repository provider cannot be null" ); 162 return this; 163 } 164 165 public DefaultDeployer setUpdateCheckManager( UpdateCheckManager updateCheckManager ) 166 { 167 this.updateCheckManager = requireNonNull( updateCheckManager, "update check manager cannot be null" ); 168 return this; 169 } 170 171 public DefaultDeployer addMetadataGeneratorFactory( MetadataGeneratorFactory factory ) 172 { 173 metadataFactories.add( requireNonNull( factory, "metadata generator factory cannot be null" ) ); 174 return this; 175 } 176 177 public DefaultDeployer setMetadataGeneratorFactories( Collection<MetadataGeneratorFactory> metadataFactories ) 178 { 179 if ( metadataFactories == null ) 180 { 181 this.metadataFactories = new ArrayList<>(); 182 } 183 else 184 { 185 this.metadataFactories = metadataFactories; 186 } 187 return this; 188 } 189 190 public DefaultDeployer setSyncContextFactory( SyncContextFactory syncContextFactory ) 191 { 192 this.syncContextFactory = requireNonNull( syncContextFactory, "sync context factory cannot be null" ); 193 return this; 194 } 195 196 public DefaultDeployer setOfflineController( OfflineController offlineController ) 197 { 198 this.offlineController = requireNonNull( offlineController, "offline controller cannot be null" ); 199 return this; 200 } 201 202 public DeployResult deploy( RepositorySystemSession session, DeployRequest request ) 203 throws DeploymentException 204 { 205 requireNonNull( session, "session cannot be null" ); 206 requireNonNull( request, "request cannot be null" ); 207 try 208 { 209 Utils.checkOffline( session, offlineController, request.getRepository() ); 210 } 211 catch ( RepositoryOfflineException e ) 212 { 213 throw new DeploymentException( "Cannot deploy while " + request.getRepository().getId() + " (" 214 + request.getRepository().getUrl() + ") is in offline mode", e ); 215 } 216 217 try ( SyncContext syncContext = syncContextFactory.newInstance( session, false ) ) 218 { 219 return deploy( syncContext, session, request ); 220 } 221 } 222 223 private DeployResult deploy( SyncContext syncContext, RepositorySystemSession session, DeployRequest request ) 224 throws DeploymentException 225 { 226 DeployResult result = new DeployResult( request ); 227 228 RequestTrace trace = RequestTrace.newChild( request.getTrace(), request ); 229 230 RemoteRepository repository = request.getRepository(); 231 232 RepositoryConnector connector; 233 try 234 { 235 connector = repositoryConnectorProvider.newRepositoryConnector( session, repository ); 236 } 237 catch ( NoRepositoryConnectorException e ) 238 { 239 throw new DeploymentException( "Failed to deploy artifacts/metadata: " + e.getMessage(), e ); 240 } 241 242 try 243 { 244 List<? extends MetadataGenerator> generators = getMetadataGenerators( session, request ); 245 246 FileTransformerManager fileTransformerManager = session.getFileTransformerManager(); 247 248 List<ArtifactUpload> artifactUploads = new ArrayList<>(); 249 List<MetadataUpload> metadataUploads = new ArrayList<>(); 250 IdentityHashMap<Metadata, Object> processedMetadata = new IdentityHashMap<>(); 251 252 EventCatapult catapult = new EventCatapult( session, trace, repository, repositoryEventDispatcher ); 253 254 List<Artifact> artifacts = new ArrayList<>( request.getArtifacts() ); 255 256 List<Metadata> metadatas = Utils.prepareMetadata( generators, artifacts ); 257 258 syncContext.acquire( artifacts, Utils.combine( request.getMetadata(), metadatas ) ); 259 260 for ( Metadata metadata : metadatas ) 261 { 262 upload( metadataUploads, session, metadata, repository, connector, catapult ); 263 processedMetadata.put( metadata, null ); 264 } 265 266 for ( ListIterator<Artifact> iterator = artifacts.listIterator(); iterator.hasNext(); ) 267 { 268 Artifact artifact = iterator.next(); 269 270 for ( MetadataGenerator generator : generators ) 271 { 272 artifact = generator.transformArtifact( artifact ); 273 } 274 275 iterator.set( artifact ); 276 277 Collection<FileTransformer> fileTransformers = 278 fileTransformerManager.getTransformersForArtifact( artifact ); 279 if ( !fileTransformers.isEmpty() ) 280 { 281 for ( FileTransformer fileTransformer : fileTransformers ) 282 { 283 Artifact targetArtifact = fileTransformer.transformArtifact( artifact ); 284 285 ArtifactUpload upload = new ArtifactUpload( targetArtifact, artifact.getFile(), 286 fileTransformer ); 287 upload.setTrace( trace ); 288 upload.setListener( new ArtifactUploadListener( catapult, upload ) ); 289 artifactUploads.add( upload ); 290 } 291 } 292 else 293 { 294 ArtifactUpload upload = new ArtifactUpload( artifact, artifact.getFile() ); 295 upload.setTrace( trace ); 296 upload.setListener( new ArtifactUploadListener( catapult, upload ) ); 297 artifactUploads.add( upload ); 298 } 299 } 300 301 connector.put( artifactUploads, null ); 302 303 for ( ArtifactUpload upload : artifactUploads ) 304 { 305 if ( upload.getException() != null ) 306 { 307 throw new DeploymentException( "Failed to deploy artifacts: " + upload.getException().getMessage(), 308 upload.getException() ); 309 } 310 result.addArtifact( upload.getArtifact() ); 311 } 312 313 metadatas = Utils.finishMetadata( generators, artifacts ); 314 315 syncContext.acquire( null, metadatas ); 316 317 for ( Metadata metadata : metadatas ) 318 { 319 upload( metadataUploads, session, metadata, repository, connector, catapult ); 320 processedMetadata.put( metadata, null ); 321 } 322 323 for ( Metadata metadata : request.getMetadata() ) 324 { 325 if ( !processedMetadata.containsKey( metadata ) ) 326 { 327 upload( metadataUploads, session, metadata, repository, connector, catapult ); 328 processedMetadata.put( metadata, null ); 329 } 330 } 331 332 connector.put( null, metadataUploads ); 333 334 for ( MetadataUpload upload : metadataUploads ) 335 { 336 if ( upload.getException() != null ) 337 { 338 throw new DeploymentException( "Failed to deploy metadata: " + upload.getException().getMessage(), 339 upload.getException() ); 340 } 341 result.addMetadata( upload.getMetadata() ); 342 } 343 } 344 finally 345 { 346 connector.close(); 347 } 348 349 return result; 350 } 351 352 private List<? extends MetadataGenerator> getMetadataGenerators( RepositorySystemSession session, 353 DeployRequest request ) 354 { 355 PrioritizedComponents<MetadataGeneratorFactory> factories = 356 Utils.sortMetadataGeneratorFactories( session, this.metadataFactories ); 357 358 List<MetadataGenerator> generators = new ArrayList<>(); 359 360 for ( PrioritizedComponent<MetadataGeneratorFactory> factory : factories.getEnabled() ) 361 { 362 MetadataGenerator generator = factory.getComponent().newInstance( session, request ); 363 if ( generator != null ) 364 { 365 generators.add( generator ); 366 } 367 } 368 369 return generators; 370 } 371 372 private void upload( Collection<MetadataUpload> metadataUploads, RepositorySystemSession session, 373 Metadata metadata, RemoteRepository repository, RepositoryConnector connector, 374 EventCatapult catapult ) 375 throws DeploymentException 376 { 377 LocalRepositoryManager lrm = session.getLocalRepositoryManager(); 378 File basedir = lrm.getRepository().getBasedir(); 379 380 File dstFile = new File( basedir, lrm.getPathForRemoteMetadata( metadata, repository, "" ) ); 381 382 if ( metadata instanceof MergeableMetadata ) 383 { 384 if ( !( (MergeableMetadata) metadata ).isMerged() ) 385 { 386 RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.METADATA_RESOLVING ); 387 event.setTrace( catapult.getTrace() ); 388 event.setMetadata( metadata ); 389 event.setRepository( repository ); 390 repositoryEventDispatcher.dispatch( event.build() ); 391 392 event = new RepositoryEvent.Builder( session, EventType.METADATA_DOWNLOADING ); 393 event.setTrace( catapult.getTrace() ); 394 event.setMetadata( metadata ); 395 event.setRepository( repository ); 396 repositoryEventDispatcher.dispatch( event.build() ); 397 398 RepositoryPolicy policy = getPolicy( session, repository, metadata.getNature() ); 399 MetadataDownload download = new MetadataDownload(); 400 download.setMetadata( metadata ); 401 download.setFile( dstFile ); 402 download.setChecksumPolicy( policy.getChecksumPolicy() ); 403 download.setListener( SafeTransferListener.wrap( session ) ); 404 download.setTrace( catapult.getTrace() ); 405 connector.get( null, Arrays.asList( download ) ); 406 407 Exception error = download.getException(); 408 409 if ( error instanceof MetadataNotFoundException ) 410 { 411 dstFile.delete(); 412 } 413 414 event = new RepositoryEvent.Builder( session, EventType.METADATA_DOWNLOADED ); 415 event.setTrace( catapult.getTrace() ); 416 event.setMetadata( metadata ); 417 event.setRepository( repository ); 418 event.setException( error ); 419 event.setFile( dstFile ); 420 repositoryEventDispatcher.dispatch( event.build() ); 421 422 event = new RepositoryEvent.Builder( session, EventType.METADATA_RESOLVED ); 423 event.setTrace( catapult.getTrace() ); 424 event.setMetadata( metadata ); 425 event.setRepository( repository ); 426 event.setException( error ); 427 event.setFile( dstFile ); 428 repositoryEventDispatcher.dispatch( event.build() ); 429 430 if ( error != null && !( error instanceof MetadataNotFoundException ) ) 431 { 432 throw new DeploymentException( "Failed to retrieve remote metadata " + metadata + ": " 433 + error.getMessage(), error ); 434 } 435 } 436 437 try 438 { 439 ( (MergeableMetadata) metadata ).merge( dstFile, dstFile ); 440 } 441 catch ( RepositoryException e ) 442 { 443 throw new DeploymentException( "Failed to update metadata " + metadata + ": " + e.getMessage(), e ); 444 } 445 } 446 else 447 { 448 if ( metadata.getFile() == null ) 449 { 450 throw new DeploymentException( "Failed to update metadata " + metadata + ": No file attached." ); 451 } 452 try 453 { 454 fileProcessor.copy( metadata.getFile(), dstFile ); 455 } 456 catch ( IOException e ) 457 { 458 throw new DeploymentException( "Failed to update metadata " + metadata + ": " + e.getMessage(), e ); 459 } 460 } 461 462 UpdateCheck<Metadata, MetadataTransferException> check = new UpdateCheck<>(); 463 check.setItem( metadata ); 464 check.setFile( dstFile ); 465 check.setRepository( repository ); 466 check.setAuthoritativeRepository( repository ); 467 updateCheckManager.touchMetadata( session, check ); 468 469 MetadataUpload upload = new MetadataUpload( metadata, dstFile ); 470 upload.setTrace( catapult.getTrace() ); 471 upload.setListener( new MetadataUploadListener( catapult, upload ) ); 472 metadataUploads.add( upload ); 473 } 474 475 private RepositoryPolicy getPolicy( RepositorySystemSession session, RemoteRepository repository, 476 Metadata.Nature nature ) 477 { 478 boolean releases = !Metadata.Nature.SNAPSHOT.equals( nature ); 479 boolean snapshots = !Metadata.Nature.RELEASE.equals( nature ); 480 return remoteRepositoryManager.getPolicy( session, repository, releases, snapshots ); 481 } 482 483 static final class EventCatapult 484 { 485 486 private final RepositorySystemSession session; 487 488 private final RequestTrace trace; 489 490 private final RemoteRepository repository; 491 492 private final RepositoryEventDispatcher dispatcher; 493 494 EventCatapult( RepositorySystemSession session, RequestTrace trace, RemoteRepository repository, 495 RepositoryEventDispatcher dispatcher ) 496 { 497 this.session = session; 498 this.trace = trace; 499 this.repository = repository; 500 this.dispatcher = dispatcher; 501 } 502 503 public RepositorySystemSession getSession() 504 { 505 return session; 506 } 507 508 public RequestTrace getTrace() 509 { 510 return trace; 511 } 512 513 public void artifactDeploying( Artifact artifact, File file ) 514 { 515 RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.ARTIFACT_DEPLOYING ); 516 event.setTrace( trace ); 517 event.setArtifact( artifact ); 518 event.setRepository( repository ); 519 event.setFile( file ); 520 521 dispatcher.dispatch( event.build() ); 522 } 523 524 public void artifactDeployed( Artifact artifact, File file, ArtifactTransferException exception ) 525 { 526 RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.ARTIFACT_DEPLOYED ); 527 event.setTrace( trace ); 528 event.setArtifact( artifact ); 529 event.setRepository( repository ); 530 event.setFile( file ); 531 event.setException( exception ); 532 533 dispatcher.dispatch( event.build() ); 534 } 535 536 public void metadataDeploying( Metadata metadata, File file ) 537 { 538 RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.METADATA_DEPLOYING ); 539 event.setTrace( trace ); 540 event.setMetadata( metadata ); 541 event.setRepository( repository ); 542 event.setFile( file ); 543 544 dispatcher.dispatch( event.build() ); 545 } 546 547 public void metadataDeployed( Metadata metadata, File file, Exception exception ) 548 { 549 RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.METADATA_DEPLOYED ); 550 event.setTrace( trace ); 551 event.setMetadata( metadata ); 552 event.setRepository( repository ); 553 event.setFile( file ); 554 event.setException( exception ); 555 556 dispatcher.dispatch( event.build() ); 557 } 558 559 } 560 561 static final class ArtifactUploadListener 562 extends SafeTransferListener 563 { 564 565 private final EventCatapult catapult; 566 567 private final ArtifactUpload transfer; 568 569 ArtifactUploadListener( EventCatapult catapult, ArtifactUpload transfer ) 570 { 571 super( catapult.getSession() ); 572 this.catapult = catapult; 573 this.transfer = transfer; 574 } 575 576 @Override 577 public void transferInitiated( TransferEvent event ) 578 throws TransferCancelledException 579 { 580 super.transferInitiated( event ); 581 requireNonNull( event, "event cannot be null" ); 582 catapult.artifactDeploying( transfer.getArtifact(), transfer.getFile() ); 583 } 584 585 @Override 586 public void transferFailed( TransferEvent event ) 587 { 588 super.transferFailed( event ); 589 requireNonNull( event, "event cannot be null" ); 590 catapult.artifactDeployed( transfer.getArtifact(), transfer.getFile(), transfer.getException() ); 591 } 592 593 @Override 594 public void transferSucceeded( TransferEvent event ) 595 { 596 super.transferSucceeded( event ); 597 requireNonNull( event, "event cannot be null" ); 598 catapult.artifactDeployed( transfer.getArtifact(), transfer.getFile(), null ); 599 } 600 601 } 602 603 static final class MetadataUploadListener 604 extends SafeTransferListener 605 { 606 607 private final EventCatapult catapult; 608 609 private final MetadataUpload transfer; 610 611 MetadataUploadListener( EventCatapult catapult, MetadataUpload transfer ) 612 { 613 super( catapult.getSession() ); 614 this.catapult = catapult; 615 this.transfer = transfer; 616 } 617 618 @Override 619 public void transferInitiated( TransferEvent event ) 620 throws TransferCancelledException 621 { 622 super.transferInitiated( event ); 623 requireNonNull( event, "event cannot be null" ); 624 catapult.metadataDeploying( transfer.getMetadata(), transfer.getFile() ); 625 } 626 627 @Override 628 public void transferFailed( TransferEvent event ) 629 { 630 super.transferFailed( event ); 631 requireNonNull( event, "event cannot be null" ); 632 catapult.metadataDeployed( transfer.getMetadata(), transfer.getFile(), transfer.getException() ); 633 } 634 635 @Override 636 public void transferSucceeded( TransferEvent event ) 637 { 638 super.transferSucceeded( event ); 639 requireNonNull( event, "event cannot be null" ); 640 catapult.metadataDeployed( transfer.getMetadata(), transfer.getFile(), null ); 641 } 642 643 } 644 645}