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 try 206 { 207 Utils.checkOffline( session, offlineController, request.getRepository() ); 208 } 209 catch ( RepositoryOfflineException e ) 210 { 211 throw new DeploymentException( "Cannot deploy while " + request.getRepository().getId() + " (" 212 + request.getRepository().getUrl() + ") is in offline mode", e ); 213 } 214 215 try ( SyncContext syncContext = syncContextFactory.newInstance( session, false ) ) 216 { 217 return deploy( syncContext, session, request ); 218 } 219 } 220 221 private DeployResult deploy( SyncContext syncContext, RepositorySystemSession session, DeployRequest request ) 222 throws DeploymentException 223 { 224 DeployResult result = new DeployResult( request ); 225 226 RequestTrace trace = RequestTrace.newChild( request.getTrace(), request ); 227 228 RemoteRepository repository = request.getRepository(); 229 230 RepositoryConnector connector; 231 try 232 { 233 connector = repositoryConnectorProvider.newRepositoryConnector( session, repository ); 234 } 235 catch ( NoRepositoryConnectorException e ) 236 { 237 throw new DeploymentException( "Failed to deploy artifacts/metadata: " + e.getMessage(), e ); 238 } 239 240 try 241 { 242 List<? extends MetadataGenerator> generators = getMetadataGenerators( session, request ); 243 244 FileTransformerManager fileTransformerManager = session.getFileTransformerManager(); 245 246 List<ArtifactUpload> artifactUploads = new ArrayList<>(); 247 List<MetadataUpload> metadataUploads = new ArrayList<>(); 248 IdentityHashMap<Metadata, Object> processedMetadata = new IdentityHashMap<>(); 249 250 EventCatapult catapult = new EventCatapult( session, trace, repository, repositoryEventDispatcher ); 251 252 List<Artifact> artifacts = new ArrayList<>( request.getArtifacts() ); 253 254 List<Metadata> metadatas = Utils.prepareMetadata( generators, artifacts ); 255 256 syncContext.acquire( artifacts, Utils.combine( request.getMetadata(), metadatas ) ); 257 258 for ( Metadata metadata : metadatas ) 259 { 260 upload( metadataUploads, session, metadata, repository, connector, catapult ); 261 processedMetadata.put( metadata, null ); 262 } 263 264 for ( ListIterator<Artifact> iterator = artifacts.listIterator(); iterator.hasNext(); ) 265 { 266 Artifact artifact = iterator.next(); 267 268 for ( MetadataGenerator generator : generators ) 269 { 270 artifact = generator.transformArtifact( artifact ); 271 } 272 273 iterator.set( artifact ); 274 275 Collection<FileTransformer> fileTransformers = 276 fileTransformerManager.getTransformersForArtifact( artifact ); 277 if ( !fileTransformers.isEmpty() ) 278 { 279 for ( FileTransformer fileTransformer : fileTransformers ) 280 { 281 Artifact targetArtifact = fileTransformer.transformArtifact( artifact ); 282 283 ArtifactUpload upload = new ArtifactUpload( targetArtifact, artifact.getFile(), 284 fileTransformer ); 285 upload.setTrace( trace ); 286 upload.setListener( new ArtifactUploadListener( catapult, upload ) ); 287 artifactUploads.add( upload ); 288 } 289 } 290 else 291 { 292 ArtifactUpload upload = new ArtifactUpload( artifact, artifact.getFile() ); 293 upload.setTrace( trace ); 294 upload.setListener( new ArtifactUploadListener( catapult, upload ) ); 295 artifactUploads.add( upload ); 296 } 297 } 298 299 connector.put( artifactUploads, null ); 300 301 for ( ArtifactUpload upload : artifactUploads ) 302 { 303 if ( upload.getException() != null ) 304 { 305 throw new DeploymentException( "Failed to deploy artifacts: " + upload.getException().getMessage(), 306 upload.getException() ); 307 } 308 result.addArtifact( upload.getArtifact() ); 309 } 310 311 metadatas = Utils.finishMetadata( generators, artifacts ); 312 313 syncContext.acquire( null, metadatas ); 314 315 for ( Metadata metadata : metadatas ) 316 { 317 upload( metadataUploads, session, metadata, repository, connector, catapult ); 318 processedMetadata.put( metadata, null ); 319 } 320 321 for ( Metadata metadata : request.getMetadata() ) 322 { 323 if ( !processedMetadata.containsKey( metadata ) ) 324 { 325 upload( metadataUploads, session, metadata, repository, connector, catapult ); 326 processedMetadata.put( metadata, null ); 327 } 328 } 329 330 connector.put( null, metadataUploads ); 331 332 for ( MetadataUpload upload : metadataUploads ) 333 { 334 if ( upload.getException() != null ) 335 { 336 throw new DeploymentException( "Failed to deploy metadata: " + upload.getException().getMessage(), 337 upload.getException() ); 338 } 339 result.addMetadata( upload.getMetadata() ); 340 } 341 } 342 finally 343 { 344 connector.close(); 345 } 346 347 return result; 348 } 349 350 private List<? extends MetadataGenerator> getMetadataGenerators( RepositorySystemSession session, 351 DeployRequest request ) 352 { 353 PrioritizedComponents<MetadataGeneratorFactory> factories = 354 Utils.sortMetadataGeneratorFactories( session, this.metadataFactories ); 355 356 List<MetadataGenerator> generators = new ArrayList<>(); 357 358 for ( PrioritizedComponent<MetadataGeneratorFactory> factory : factories.getEnabled() ) 359 { 360 MetadataGenerator generator = factory.getComponent().newInstance( session, request ); 361 if ( generator != null ) 362 { 363 generators.add( generator ); 364 } 365 } 366 367 return generators; 368 } 369 370 private void upload( Collection<MetadataUpload> metadataUploads, RepositorySystemSession session, 371 Metadata metadata, RemoteRepository repository, RepositoryConnector connector, 372 EventCatapult catapult ) 373 throws DeploymentException 374 { 375 LocalRepositoryManager lrm = session.getLocalRepositoryManager(); 376 File basedir = lrm.getRepository().getBasedir(); 377 378 File dstFile = new File( basedir, lrm.getPathForRemoteMetadata( metadata, repository, "" ) ); 379 380 if ( metadata instanceof MergeableMetadata ) 381 { 382 if ( !( (MergeableMetadata) metadata ).isMerged() ) 383 { 384 RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.METADATA_RESOLVING ); 385 event.setTrace( catapult.getTrace() ); 386 event.setMetadata( metadata ); 387 event.setRepository( repository ); 388 repositoryEventDispatcher.dispatch( event.build() ); 389 390 event = new RepositoryEvent.Builder( session, EventType.METADATA_DOWNLOADING ); 391 event.setTrace( catapult.getTrace() ); 392 event.setMetadata( metadata ); 393 event.setRepository( repository ); 394 repositoryEventDispatcher.dispatch( event.build() ); 395 396 RepositoryPolicy policy = getPolicy( session, repository, metadata.getNature() ); 397 MetadataDownload download = new MetadataDownload(); 398 download.setMetadata( metadata ); 399 download.setFile( dstFile ); 400 download.setChecksumPolicy( policy.getChecksumPolicy() ); 401 download.setListener( SafeTransferListener.wrap( session ) ); 402 download.setTrace( catapult.getTrace() ); 403 connector.get( null, Arrays.asList( download ) ); 404 405 Exception error = download.getException(); 406 407 if ( error instanceof MetadataNotFoundException ) 408 { 409 dstFile.delete(); 410 } 411 412 event = 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 if ( error != null && !( error instanceof MetadataNotFoundException ) ) 429 { 430 throw new DeploymentException( "Failed to retrieve remote metadata " + metadata + ": " 431 + error.getMessage(), error ); 432 } 433 } 434 435 try 436 { 437 ( (MergeableMetadata) metadata ).merge( dstFile, dstFile ); 438 } 439 catch ( RepositoryException e ) 440 { 441 throw new DeploymentException( "Failed to update metadata " + metadata + ": " + e.getMessage(), e ); 442 } 443 } 444 else 445 { 446 if ( metadata.getFile() == null ) 447 { 448 throw new DeploymentException( "Failed to update metadata " + metadata + ": No file attached." ); 449 } 450 try 451 { 452 fileProcessor.copy( metadata.getFile(), dstFile ); 453 } 454 catch ( IOException e ) 455 { 456 throw new DeploymentException( "Failed to update metadata " + metadata + ": " + e.getMessage(), e ); 457 } 458 } 459 460 UpdateCheck<Metadata, MetadataTransferException> check = new UpdateCheck<>(); 461 check.setItem( metadata ); 462 check.setFile( dstFile ); 463 check.setRepository( repository ); 464 check.setAuthoritativeRepository( repository ); 465 updateCheckManager.touchMetadata( session, check ); 466 467 MetadataUpload upload = new MetadataUpload( metadata, dstFile ); 468 upload.setTrace( catapult.getTrace() ); 469 upload.setListener( new MetadataUploadListener( catapult, upload ) ); 470 metadataUploads.add( upload ); 471 } 472 473 private RepositoryPolicy getPolicy( RepositorySystemSession session, RemoteRepository repository, 474 Metadata.Nature nature ) 475 { 476 boolean releases = !Metadata.Nature.SNAPSHOT.equals( nature ); 477 boolean snapshots = !Metadata.Nature.RELEASE.equals( nature ); 478 return remoteRepositoryManager.getPolicy( session, repository, releases, snapshots ); 479 } 480 481 static final class EventCatapult 482 { 483 484 private final RepositorySystemSession session; 485 486 private final RequestTrace trace; 487 488 private final RemoteRepository repository; 489 490 private final RepositoryEventDispatcher dispatcher; 491 492 EventCatapult( RepositorySystemSession session, RequestTrace trace, RemoteRepository repository, 493 RepositoryEventDispatcher dispatcher ) 494 { 495 this.session = session; 496 this.trace = trace; 497 this.repository = repository; 498 this.dispatcher = dispatcher; 499 } 500 501 public RepositorySystemSession getSession() 502 { 503 return session; 504 } 505 506 public RequestTrace getTrace() 507 { 508 return trace; 509 } 510 511 public void artifactDeploying( Artifact artifact, File file ) 512 { 513 RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.ARTIFACT_DEPLOYING ); 514 event.setTrace( trace ); 515 event.setArtifact( artifact ); 516 event.setRepository( repository ); 517 event.setFile( file ); 518 519 dispatcher.dispatch( event.build() ); 520 } 521 522 public void artifactDeployed( Artifact artifact, File file, ArtifactTransferException exception ) 523 { 524 RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.ARTIFACT_DEPLOYED ); 525 event.setTrace( trace ); 526 event.setArtifact( artifact ); 527 event.setRepository( repository ); 528 event.setFile( file ); 529 event.setException( exception ); 530 531 dispatcher.dispatch( event.build() ); 532 } 533 534 public void metadataDeploying( Metadata metadata, File file ) 535 { 536 RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.METADATA_DEPLOYING ); 537 event.setTrace( trace ); 538 event.setMetadata( metadata ); 539 event.setRepository( repository ); 540 event.setFile( file ); 541 542 dispatcher.dispatch( event.build() ); 543 } 544 545 public void metadataDeployed( Metadata metadata, File file, Exception exception ) 546 { 547 RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.METADATA_DEPLOYED ); 548 event.setTrace( trace ); 549 event.setMetadata( metadata ); 550 event.setRepository( repository ); 551 event.setFile( file ); 552 event.setException( exception ); 553 554 dispatcher.dispatch( event.build() ); 555 } 556 557 } 558 559 static final class ArtifactUploadListener 560 extends SafeTransferListener 561 { 562 563 private final EventCatapult catapult; 564 565 private final ArtifactUpload transfer; 566 567 ArtifactUploadListener( EventCatapult catapult, ArtifactUpload transfer ) 568 { 569 super( catapult.getSession() ); 570 this.catapult = catapult; 571 this.transfer = transfer; 572 } 573 574 @Override 575 public void transferInitiated( TransferEvent event ) 576 throws TransferCancelledException 577 { 578 super.transferInitiated( event ); 579 catapult.artifactDeploying( transfer.getArtifact(), transfer.getFile() ); 580 } 581 582 @Override 583 public void transferFailed( TransferEvent event ) 584 { 585 super.transferFailed( event ); 586 catapult.artifactDeployed( transfer.getArtifact(), transfer.getFile(), transfer.getException() ); 587 } 588 589 @Override 590 public void transferSucceeded( TransferEvent event ) 591 { 592 super.transferSucceeded( event ); 593 catapult.artifactDeployed( transfer.getArtifact(), transfer.getFile(), null ); 594 } 595 596 } 597 598 static final class MetadataUploadListener 599 extends SafeTransferListener 600 { 601 602 private final EventCatapult catapult; 603 604 private final MetadataUpload transfer; 605 606 MetadataUploadListener( EventCatapult catapult, MetadataUpload transfer ) 607 { 608 super( catapult.getSession() ); 609 this.catapult = catapult; 610 this.transfer = transfer; 611 } 612 613 @Override 614 public void transferInitiated( TransferEvent event ) 615 throws TransferCancelledException 616 { 617 super.transferInitiated( event ); 618 catapult.metadataDeploying( transfer.getMetadata(), transfer.getFile() ); 619 } 620 621 @Override 622 public void transferFailed( TransferEvent event ) 623 { 624 super.transferFailed( event ); 625 catapult.metadataDeployed( transfer.getMetadata(), transfer.getFile(), transfer.getException() ); 626 } 627 628 @Override 629 public void transferSucceeded( TransferEvent event ) 630 { 631 super.transferSucceeded( event ); 632 catapult.metadataDeployed( transfer.getMetadata(), transfer.getFile(), null ); 633 } 634 635 } 636 637}