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