001package org.apache.maven.artifact.resolver; 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.util.ArrayList; 024import java.util.Collections; 025import java.util.LinkedHashMap; 026import java.util.LinkedHashSet; 027import java.util.List; 028import java.util.Map; 029import java.util.Set; 030import java.util.concurrent.CountDownLatch; 031import java.util.concurrent.Executor; 032import java.util.concurrent.ExecutorService; 033import java.util.concurrent.LinkedBlockingQueue; 034import java.util.concurrent.ThreadFactory; 035import java.util.concurrent.ThreadPoolExecutor; 036import java.util.concurrent.TimeUnit; 037import java.util.concurrent.atomic.AtomicInteger; 038import java.util.regex.Matcher; 039 040import org.apache.maven.RepositoryUtils; 041import org.apache.maven.artifact.Artifact; 042import org.apache.maven.artifact.factory.ArtifactFactory; 043import org.apache.maven.artifact.metadata.ArtifactMetadataRetrievalException; 044import org.apache.maven.artifact.metadata.ArtifactMetadataSource; 045import org.apache.maven.artifact.metadata.ResolutionGroup; 046import org.apache.maven.artifact.repository.ArtifactRepository; 047import org.apache.maven.artifact.repository.LegacyLocalRepositoryManager; 048import org.apache.maven.artifact.repository.RepositoryRequest; 049import org.apache.maven.artifact.repository.metadata.Snapshot; 050import org.apache.maven.artifact.repository.metadata.SnapshotArtifactRepositoryMetadata; 051import org.apache.maven.artifact.resolver.filter.ArtifactFilter; 052import org.apache.maven.execution.MavenSession; 053import org.apache.maven.plugin.LegacySupport; 054import org.apache.maven.repository.legacy.metadata.DefaultMetadataResolutionRequest; 055import org.apache.maven.repository.legacy.metadata.MetadataResolutionRequest; 056import org.apache.maven.repository.legacy.resolver.conflict.ConflictResolver; 057import org.apache.maven.wagon.events.TransferListener; 058import org.codehaus.plexus.PlexusContainer; 059import org.codehaus.plexus.component.annotations.Component; 060import org.codehaus.plexus.component.annotations.Requirement; 061import org.codehaus.plexus.component.repository.exception.ComponentLookupException; 062import org.codehaus.plexus.logging.Logger; 063import org.eclipse.aether.RepositorySystem; 064import org.eclipse.aether.RepositorySystemSession; 065import org.eclipse.aether.repository.LocalRepositoryManager; 066import org.eclipse.aether.resolution.ArtifactRequest; 067import org.eclipse.aether.resolution.ArtifactResult; 068 069/** 070 * @author Jason van Zyl 071 */ 072@Component( role = ArtifactResolver.class ) 073public class DefaultArtifactResolver 074 implements ArtifactResolver 075{ 076 @Requirement 077 private Logger logger; 078 079 @Requirement 080 protected ArtifactFactory artifactFactory; 081 082 @Requirement 083 private ArtifactCollector artifactCollector; 084 085 @Requirement 086 private ResolutionErrorHandler resolutionErrorHandler; 087 088 @Requirement 089 private ArtifactMetadataSource source; 090 091 @Requirement 092 private PlexusContainer container; 093 094 @Requirement 095 private LegacySupport legacySupport; 096 097 @Requirement 098 private RepositorySystem repoSystem; 099 100 private final Executor executor; 101 102 public DefaultArtifactResolver() 103 { 104 int threads = Integer.getInteger( "maven.artifact.threads", 5 ); 105 if ( threads <= 1 ) 106 { 107 executor = new Executor() 108 { 109 public void execute( Runnable command ) 110 { 111 command.run(); 112 } 113 }; 114 } 115 else 116 { 117 executor = 118 new ThreadPoolExecutor( threads, threads, 3, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), 119 new DaemonThreadCreator() ); 120 } 121 } 122 123 @Override 124 protected void finalize() 125 throws Throwable 126 { 127 if ( executor instanceof ExecutorService ) 128 { 129 ( (ExecutorService) executor ).shutdown(); 130 } 131 } 132 133 private RepositorySystemSession getSession( ArtifactRepository localRepository ) 134 { 135 return LegacyLocalRepositoryManager.overlay( localRepository, legacySupport.getRepositorySession(), repoSystem ); 136 } 137 138 private void injectSession1( RepositoryRequest request, MavenSession session ) 139 { 140 if ( session != null ) 141 { 142 request.setOffline( session.isOffline() ); 143 request.setForceUpdate( session.getRequest().isUpdateSnapshots() ); 144 } 145 } 146 147 private void injectSession2( ArtifactResolutionRequest request, MavenSession session ) 148 { 149 injectSession1( request, session ); 150 151 if ( session != null ) 152 { 153 request.setServers( session.getRequest().getServers() ); 154 request.setMirrors( session.getRequest().getMirrors() ); 155 request.setProxies( session.getRequest().getProxies() ); 156 } 157 } 158 159 public void resolve( Artifact artifact, List<ArtifactRepository> remoteRepositories, 160 ArtifactRepository localRepository, TransferListener resolutionListener ) 161 throws ArtifactResolutionException, ArtifactNotFoundException 162 { 163 resolve( artifact, remoteRepositories, getSession( localRepository ) ); 164 } 165 166 public void resolveAlways( Artifact artifact, List<ArtifactRepository> remoteRepositories, 167 ArtifactRepository localRepository ) 168 throws ArtifactResolutionException, ArtifactNotFoundException 169 { 170 resolve( artifact, remoteRepositories, getSession( localRepository ) ); 171 } 172 173 private void resolve( Artifact artifact, List<ArtifactRepository> remoteRepositories, 174 RepositorySystemSession session ) 175 throws ArtifactResolutionException, ArtifactNotFoundException 176 { 177 if ( artifact == null ) 178 { 179 return; 180 } 181 182 if ( Artifact.SCOPE_SYSTEM.equals( artifact.getScope() ) ) 183 { 184 File systemFile = artifact.getFile(); 185 186 if ( systemFile == null ) 187 { 188 throw new ArtifactNotFoundException( "System artifact: " + artifact + " has no file attached", artifact ); 189 } 190 191 if ( !systemFile.exists() ) 192 { 193 throw new ArtifactNotFoundException( "System artifact: " + artifact + " not found in path: " + systemFile, artifact ); 194 } 195 196 if ( !systemFile.isFile() ) 197 { 198 throw new ArtifactNotFoundException( "System artifact: " + artifact + " is not a file: " + systemFile, artifact ); 199 } 200 201 artifact.setResolved( true ); 202 203 return; 204 } 205 206 if ( !artifact.isResolved() ) 207 { 208 ArtifactResult result; 209 210 try 211 { 212 ArtifactRequest artifactRequest = new ArtifactRequest(); 213 artifactRequest.setArtifact( RepositoryUtils.toArtifact( artifact ) ); 214 artifactRequest.setRepositories( RepositoryUtils.toRepos( remoteRepositories ) ); 215 216 // Maven 2.x quirk: an artifact always points at the local repo, regardless whether resolved or not 217 LocalRepositoryManager lrm = session.getLocalRepositoryManager(); 218 String path = lrm.getPathForLocalArtifact( artifactRequest.getArtifact() ); 219 artifact.setFile( new File( lrm.getRepository().getBasedir(), path ) ); 220 221 result = repoSystem.resolveArtifact( session, artifactRequest ); 222 } 223 catch ( org.eclipse.aether.resolution.ArtifactResolutionException e ) 224 { 225 if ( e.getCause() instanceof org.eclipse.aether.transfer.ArtifactNotFoundException ) 226 { 227 throw new ArtifactNotFoundException( e.getMessage(), artifact, remoteRepositories, e ); 228 } 229 else 230 { 231 throw new ArtifactResolutionException( e.getMessage(), artifact, remoteRepositories, e ); 232 } 233 } 234 235 artifact.selectVersion( result.getArtifact().getVersion() ); 236 artifact.setFile( result.getArtifact().getFile() ); 237 artifact.setResolved( true ); 238 239 if ( artifact.isSnapshot() ) 240 { 241 Matcher matcher = Artifact.VERSION_FILE_PATTERN.matcher( artifact.getVersion() ); 242 if ( matcher.matches() ) 243 { 244 Snapshot snapshot = new Snapshot(); 245 snapshot.setTimestamp( matcher.group( 2 ) ); 246 try 247 { 248 snapshot.setBuildNumber( Integer.parseInt( matcher.group( 3 ) ) ); 249 artifact.addMetadata( new SnapshotArtifactRepositoryMetadata( artifact, snapshot ) ); 250 } 251 catch ( NumberFormatException e ) 252 { 253 logger.warn( "Invalid artifact version " + artifact.getVersion() + ": " + e.getMessage() ); 254 } 255 } 256 } 257 } 258 } 259 260 public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact, 261 ArtifactRepository localRepository, 262 List<ArtifactRepository> remoteRepositories, 263 ArtifactMetadataSource source, ArtifactFilter filter ) 264 throws ArtifactResolutionException, ArtifactNotFoundException 265 { 266 return resolveTransitively( artifacts, originatingArtifact, Collections.EMPTY_MAP, localRepository, 267 remoteRepositories, source, filter ); 268 269 } 270 271 public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact, 272 Map managedVersions, ArtifactRepository localRepository, 273 List<ArtifactRepository> remoteRepositories, 274 ArtifactMetadataSource source ) 275 throws ArtifactResolutionException, ArtifactNotFoundException 276 { 277 return resolveTransitively( artifacts, originatingArtifact, managedVersions, localRepository, 278 remoteRepositories, source, null ); 279 } 280 281 public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact, 282 Map managedVersions, ArtifactRepository localRepository, 283 List<ArtifactRepository> remoteRepositories, 284 ArtifactMetadataSource source, ArtifactFilter filter ) 285 throws ArtifactResolutionException, ArtifactNotFoundException 286 { 287 return resolveTransitively( artifacts, originatingArtifact, managedVersions, localRepository, 288 remoteRepositories, source, filter, null ); 289 } 290 291 public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact, 292 List<ArtifactRepository> remoteRepositories, 293 ArtifactRepository localRepository, 294 ArtifactMetadataSource source ) 295 throws ArtifactResolutionException, ArtifactNotFoundException 296 { 297 return resolveTransitively( artifacts, originatingArtifact, localRepository, remoteRepositories, source, null ); 298 } 299 300 public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact, 301 List<ArtifactRepository> remoteRepositories, 302 ArtifactRepository localRepository, 303 ArtifactMetadataSource source, 304 List<ResolutionListener> listeners ) 305 throws ArtifactResolutionException, ArtifactNotFoundException 306 { 307 return resolveTransitively( artifacts, originatingArtifact, Collections.EMPTY_MAP, localRepository, 308 remoteRepositories, source, null, listeners ); 309 } 310 311 public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact, 312 Map managedVersions, ArtifactRepository localRepository, 313 List<ArtifactRepository> remoteRepositories, 314 ArtifactMetadataSource source, ArtifactFilter filter, 315 List<ResolutionListener> listeners ) 316 throws ArtifactResolutionException, ArtifactNotFoundException 317 { 318 return resolveTransitively( artifacts, originatingArtifact, managedVersions, localRepository, 319 remoteRepositories, source, filter, listeners, null ); 320 } 321 322 public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact, 323 Map managedVersions, ArtifactRepository localRepository, 324 List<ArtifactRepository> remoteRepositories, 325 ArtifactMetadataSource source, ArtifactFilter filter, 326 List<ResolutionListener> listeners, 327 List<ConflictResolver> conflictResolvers ) 328 throws ArtifactResolutionException, ArtifactNotFoundException 329 { 330 ArtifactResolutionRequest request = new ArtifactResolutionRequest() 331 .setArtifact( originatingArtifact ) 332 .setResolveRoot( false ) 333 // This is required by the surefire plugin 334 .setArtifactDependencies( artifacts ) 335 .setManagedVersionMap( managedVersions ) 336 .setLocalRepository( localRepository ) 337 .setRemoteRepositories( remoteRepositories ) 338 .setCollectionFilter( filter ) 339 .setListeners( listeners ); 340 341 injectSession2( request, legacySupport.getSession() ); 342 343 return resolveWithExceptions( request ); 344 } 345 346 public ArtifactResolutionResult resolveWithExceptions( ArtifactResolutionRequest request ) 347 throws ArtifactResolutionException, ArtifactNotFoundException 348 { 349 ArtifactResolutionResult result = resolve( request ); 350 351 // We have collected all the problems so let's mimic the way the old code worked and just blow up right here. 352 // That's right lets just let it rip right here and send a big incomprehensible blob of text at unsuspecting 353 // users. Bad dog! 354 355 resolutionErrorHandler.throwErrors( request, result ); 356 357 return result; 358 } 359 360 // ------------------------------------------------------------------------ 361 // 362 // ------------------------------------------------------------------------ 363 364 public ArtifactResolutionResult resolve( ArtifactResolutionRequest request ) 365 { 366 Artifact rootArtifact = request.getArtifact(); 367 Set<Artifact> artifacts = request.getArtifactDependencies(); 368 Map<String, Artifact> managedVersions = request.getManagedVersionMap(); 369 List<ResolutionListener> listeners = request.getListeners(); 370 ArtifactFilter collectionFilter = request.getCollectionFilter(); 371 ArtifactFilter resolutionFilter = request.getResolutionFilter(); 372 RepositorySystemSession session = getSession( request.getLocalRepository() ); 373 374 //TODO: hack because metadata isn't generated in m2e correctly and i want to run the maven i have in the workspace 375 if ( source == null ) 376 { 377 try 378 { 379 source = container.lookup( ArtifactMetadataSource.class ); 380 } 381 catch ( ComponentLookupException e ) 382 { 383 // won't happen 384 } 385 } 386 387 if ( listeners == null ) 388 { 389 listeners = new ArrayList<ResolutionListener>(); 390 391 if ( logger.isDebugEnabled() ) 392 { 393 listeners.add( new DebugResolutionListener( logger ) ); 394 } 395 396 listeners.add( new WarningResolutionListener( logger ) ); 397 } 398 399 ArtifactResolutionResult result = new ArtifactResolutionResult(); 400 401 // The root artifact may, or may not be resolved so we need to check before we attempt to resolve. 402 // This is often an artifact like a POM that is taken from disk and we already have hold of the 403 // file reference. But this may be a Maven Plugin that we need to resolve from a remote repository 404 // as well as its dependencies. 405 406 if ( request.isResolveRoot() /* && rootArtifact.getFile() == null */ ) 407 { 408 try 409 { 410 resolve( rootArtifact, request.getRemoteRepositories(), session ); 411 } 412 catch ( ArtifactResolutionException e ) 413 { 414 result.addErrorArtifactException( e ); 415 return result; 416 } 417 catch ( ArtifactNotFoundException e ) 418 { 419 result.addMissingArtifact( request.getArtifact() ); 420 return result; 421 } 422 } 423 424 ArtifactResolutionRequest collectionRequest = request; 425 426 if ( request.isResolveTransitively() ) 427 { 428 MetadataResolutionRequest metadataRequest = new DefaultMetadataResolutionRequest( request ); 429 430 metadataRequest.setArtifact( rootArtifact ); 431 metadataRequest.setResolveManagedVersions( managedVersions == null ); 432 433 try 434 { 435 ResolutionGroup resolutionGroup = source.retrieve( metadataRequest ); 436 437 if ( managedVersions == null ) 438 { 439 managedVersions = resolutionGroup.getManagedVersions(); 440 } 441 442 Set<Artifact> directArtifacts = resolutionGroup.getArtifacts(); 443 444 if ( artifacts == null || artifacts.isEmpty() ) 445 { 446 artifacts = directArtifacts; 447 } 448 else 449 { 450 List<Artifact> allArtifacts = new ArrayList<Artifact>(); 451 allArtifacts.addAll( artifacts ); 452 allArtifacts.addAll( directArtifacts ); 453 454 Map<String, Artifact> mergedArtifacts = new LinkedHashMap<String, Artifact>(); 455 for ( Artifact artifact : allArtifacts ) 456 { 457 String conflictId = artifact.getDependencyConflictId(); 458 if ( !mergedArtifacts.containsKey( conflictId ) ) 459 { 460 mergedArtifacts.put( conflictId, artifact ); 461 } 462 } 463 464 artifacts = new LinkedHashSet<Artifact>( mergedArtifacts.values() ); 465 } 466 467 collectionRequest = new ArtifactResolutionRequest( request ); 468 collectionRequest.setServers( request.getServers() ); 469 collectionRequest.setMirrors( request.getMirrors() ); 470 collectionRequest.setProxies( request.getProxies() ); 471 collectionRequest.setRemoteRepositories( resolutionGroup.getResolutionRepositories() ); 472 } 473 catch ( ArtifactMetadataRetrievalException e ) 474 { 475 ArtifactResolutionException are = 476 new ArtifactResolutionException( "Unable to get dependency information for " + rootArtifact.getId() 477 + ": " + e.getMessage(), rootArtifact, metadataRequest.getRemoteRepositories(), e ); 478 result.addMetadataResolutionException( are ); 479 return result; 480 } 481 } 482 483 if ( artifacts == null || artifacts.isEmpty() ) 484 { 485 if ( request.isResolveRoot() ) 486 { 487 result.addArtifact( rootArtifact ); 488 } 489 return result; 490 } 491 492 // After the collection we will have the artifact object in the result but they will not be resolved yet. 493 result = 494 artifactCollector.collect( artifacts, rootArtifact, managedVersions, collectionRequest, source, 495 collectionFilter, listeners, null ); 496 497 // We have metadata retrieval problems, or there are cycles that have been detected 498 // so we give this back to the calling code and let them deal with this information 499 // appropriately. 500 501 if ( result.hasMetadataResolutionExceptions() || result.hasVersionRangeViolations() || result.hasCircularDependencyExceptions() ) 502 { 503 return result; 504 } 505 506 if ( result.getArtifactResolutionNodes() != null ) 507 { 508 ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); 509 510 CountDownLatch latch = new CountDownLatch( result.getArtifactResolutionNodes().size() ); 511 512 for ( ResolutionNode node : result.getArtifactResolutionNodes() ) 513 { 514 Artifact artifact = node.getArtifact(); 515 516 if ( resolutionFilter == null || resolutionFilter.include( artifact ) ) 517 { 518 executor.execute( new ResolveTask( classLoader, latch, artifact, session, 519 node.getRemoteRepositories(), result ) ); 520 } 521 else 522 { 523 latch.countDown(); 524 } 525 } 526 try 527 { 528 latch.await(); 529 } 530 catch ( InterruptedException e ) 531 { 532 result.addErrorArtifactException( new ArtifactResolutionException( "Resolution interrupted", 533 rootArtifact, e ) ); 534 } 535 } 536 537 // We want to send the root artifact back in the result but we need to do this after the other dependencies 538 // have been resolved. 539 if ( request.isResolveRoot() ) 540 { 541 // Add the root artifact (as the first artifact to retain logical order of class path!) 542 Set<Artifact> allArtifacts = new LinkedHashSet<Artifact>(); 543 allArtifacts.add( rootArtifact ); 544 allArtifacts.addAll( result.getArtifacts() ); 545 result.setArtifacts( allArtifacts ); 546 } 547 548 return result; 549 } 550 551 public void resolve( Artifact artifact, List<ArtifactRepository> remoteRepositories, ArtifactRepository localRepository ) 552 throws ArtifactResolutionException, ArtifactNotFoundException 553 { 554 resolve( artifact, remoteRepositories, localRepository, null ); 555 } 556 557 /** 558 * ThreadCreator for creating daemon threads with fixed ThreadGroup-name. 559 */ 560 static final class DaemonThreadCreator 561 implements ThreadFactory 562 { 563 static final String THREADGROUP_NAME = "org.apache.maven.artifact.resolver.DefaultArtifactResolver"; 564 565 static final ThreadGroup GROUP = new ThreadGroup( THREADGROUP_NAME ); 566 567 static final AtomicInteger THREAD_NUMBER = new AtomicInteger( 1 ); 568 569 public Thread newThread( Runnable r ) 570 { 571 Thread newThread = new Thread( GROUP, r, "resolver-" + THREAD_NUMBER.getAndIncrement() ); 572 newThread.setDaemon( true ); 573 return newThread; 574 } 575 } 576 577 private class ResolveTask 578 implements Runnable 579 { 580 581 private final ClassLoader classLoader; 582 583 private final CountDownLatch latch; 584 585 private final Artifact artifact; 586 587 private final RepositorySystemSession session; 588 589 private final List<ArtifactRepository> remoteRepositories; 590 591 private final ArtifactResolutionResult result; 592 593 public ResolveTask( ClassLoader classLoader, CountDownLatch latch, Artifact artifact, RepositorySystemSession session, 594 List<ArtifactRepository> remoteRepositories, ArtifactResolutionResult result ) 595 { 596 this.classLoader = classLoader; 597 this.latch = latch; 598 this.artifact = artifact; 599 this.session = session; 600 this.remoteRepositories = remoteRepositories; 601 this.result = result; 602 } 603 604 public void run() 605 { 606 ClassLoader old = Thread.currentThread().getContextClassLoader(); 607 try 608 { 609 Thread.currentThread().setContextClassLoader( classLoader ); 610 resolve( artifact, remoteRepositories, session ); 611 } 612 catch ( ArtifactNotFoundException anfe ) 613 { 614 // These are cases where the artifact just isn't present in any of the remote repositories 615 // because it wasn't deployed, or it was deployed in the wrong place. 616 617 synchronized ( result ) 618 { 619 result.addMissingArtifact( artifact ); 620 } 621 } 622 catch ( ArtifactResolutionException e ) 623 { 624 // This is really a wagon TransferFailedException so something went wrong after we successfully 625 // retrieved the metadata. 626 627 synchronized ( result ) 628 { 629 result.addErrorArtifactException( e ); 630 } 631 } 632 finally 633 { 634 latch.countDown(); 635 Thread.currentThread().setContextClassLoader( old ); 636 637 } 638 } 639 640 } 641 642}