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