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