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