1 package org.apache.maven.artifact.resolver;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.File;
23 import java.util.ArrayList;
24 import java.util.Collections;
25 import java.util.LinkedHashMap;
26 import java.util.LinkedHashSet;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Set;
30 import java.util.concurrent.CountDownLatch;
31 import java.util.concurrent.Executor;
32 import java.util.concurrent.ExecutorService;
33 import java.util.concurrent.LinkedBlockingQueue;
34 import java.util.concurrent.ThreadFactory;
35 import java.util.concurrent.ThreadPoolExecutor;
36 import java.util.concurrent.TimeUnit;
37 import java.util.concurrent.atomic.AtomicInteger;
38 import java.util.regex.Matcher;
39
40 import org.apache.maven.RepositoryUtils;
41 import org.apache.maven.artifact.Artifact;
42 import org.apache.maven.artifact.factory.ArtifactFactory;
43 import org.apache.maven.artifact.metadata.ArtifactMetadataRetrievalException;
44 import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
45 import org.apache.maven.artifact.metadata.ResolutionGroup;
46 import org.apache.maven.artifact.repository.ArtifactRepository;
47 import org.apache.maven.artifact.repository.LegacyLocalRepositoryManager;
48 import org.apache.maven.artifact.repository.RepositoryRequest;
49 import org.apache.maven.artifact.repository.metadata.Snapshot;
50 import org.apache.maven.artifact.repository.metadata.SnapshotArtifactRepositoryMetadata;
51 import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
52 import org.apache.maven.execution.MavenSession;
53 import org.apache.maven.plugin.LegacySupport;
54 import org.apache.maven.repository.legacy.metadata.DefaultMetadataResolutionRequest;
55 import org.apache.maven.repository.legacy.metadata.MetadataResolutionRequest;
56 import org.apache.maven.repository.legacy.resolver.conflict.ConflictResolver;
57 import org.apache.maven.wagon.events.TransferListener;
58 import org.codehaus.plexus.PlexusContainer;
59 import org.codehaus.plexus.component.annotations.Component;
60 import org.codehaus.plexus.component.annotations.Requirement;
61 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
62 import org.codehaus.plexus.logging.Logger;
63 import org.codehaus.plexus.personality.plexus.lifecycle.phase.Disposable;
64 import org.eclipse.aether.RepositorySystem;
65 import org.eclipse.aether.RepositorySystemSession;
66 import org.eclipse.aether.repository.LocalRepositoryManager;
67 import org.eclipse.aether.resolution.ArtifactRequest;
68 import org.eclipse.aether.resolution.ArtifactResult;
69
70
71
72
73 @Component( role = ArtifactResolver.class )
74 public class DefaultArtifactResolver
75 implements ArtifactResolver, Disposable
76 {
77 @Requirement
78 private Logger logger;
79
80 @Requirement
81 protected ArtifactFactory artifactFactory;
82
83 @Requirement
84 private ArtifactCollector artifactCollector;
85
86 @Requirement
87 private ResolutionErrorHandler resolutionErrorHandler;
88
89 @Requirement
90 private ArtifactMetadataSource source;
91
92 @Requirement
93 private PlexusContainer container;
94
95 @Requirement
96 private LegacySupport legacySupport;
97
98 @Requirement
99 private RepositorySystem repoSystem;
100
101 private final Executor executor;
102
103 public DefaultArtifactResolver()
104 {
105 int threads = Integer.getInteger( "maven.artifact.threads", 5 );
106 if ( threads <= 1 )
107 {
108 executor = new Executor()
109 {
110 public void execute( Runnable command )
111 {
112 command.run();
113 }
114 };
115 }
116 else
117 {
118 executor = new ThreadPoolExecutor( threads, threads, 3, TimeUnit.SECONDS,
119 new LinkedBlockingQueue<Runnable>(), new DaemonThreadCreator() );
120 }
121 }
122
123 private RepositorySystemSession getSession( ArtifactRepository localRepository )
124 {
125 return LegacyLocalRepositoryManager.overlay( localRepository, legacySupport.getRepositorySession(),
126 repoSystem );
127 }
128
129 private void injectSession1( RepositoryRequest request, MavenSession session )
130 {
131 if ( session != null )
132 {
133 request.setOffline( session.isOffline() );
134 request.setForceUpdate( session.getRequest().isUpdateSnapshots() );
135 }
136 }
137
138 private void injectSession2( ArtifactResolutionRequest request, MavenSession session )
139 {
140 injectSession1( request, session );
141
142 if ( session != null )
143 {
144 request.setServers( session.getRequest().getServers() );
145 request.setMirrors( session.getRequest().getMirrors() );
146 request.setProxies( session.getRequest().getProxies() );
147 }
148 }
149
150 public void resolve( Artifact artifact, List<ArtifactRepository> remoteRepositories,
151 ArtifactRepository localRepository, TransferListener resolutionListener )
152 throws ArtifactResolutionException, ArtifactNotFoundException
153 {
154 resolve( artifact, remoteRepositories, getSession( localRepository ) );
155 }
156
157 public void resolveAlways( Artifact artifact, List<ArtifactRepository> remoteRepositories,
158 ArtifactRepository localRepository )
159 throws ArtifactResolutionException, ArtifactNotFoundException
160 {
161 resolve( artifact, remoteRepositories, getSession( localRepository ) );
162 }
163
164 private void resolve( Artifact artifact, List<ArtifactRepository> remoteRepositories,
165 RepositorySystemSession session )
166 throws ArtifactResolutionException, ArtifactNotFoundException
167 {
168 if ( artifact == null )
169 {
170 return;
171 }
172
173 if ( Artifact.SCOPE_SYSTEM.equals( artifact.getScope() ) )
174 {
175 File systemFile = artifact.getFile();
176
177 if ( systemFile == null )
178 {
179 throw new ArtifactNotFoundException( "System artifact: " + artifact + " has no file attached",
180 artifact );
181 }
182
183 if ( !systemFile.exists() )
184 {
185 throw new ArtifactNotFoundException( "System artifact: " + artifact + " not found in path: "
186 + systemFile, artifact );
187 }
188
189 if ( !systemFile.isFile() )
190 {
191 throw new ArtifactNotFoundException( "System artifact: " + artifact + " is not a file: " + systemFile,
192 artifact );
193 }
194
195 artifact.setResolved( true );
196
197 return;
198 }
199
200 if ( !artifact.isResolved() )
201 {
202 ArtifactResult result;
203
204 try
205 {
206 ArtifactRequest artifactRequest = new ArtifactRequest();
207 artifactRequest.setArtifact( RepositoryUtils.toArtifact( artifact ) );
208 artifactRequest.setRepositories( RepositoryUtils.toRepos( remoteRepositories ) );
209
210
211 LocalRepositoryManager lrm = session.getLocalRepositoryManager();
212 String path = lrm.getPathForLocalArtifact( artifactRequest.getArtifact() );
213 artifact.setFile( new File( lrm.getRepository().getBasedir(), path ) );
214
215 result = repoSystem.resolveArtifact( session, artifactRequest );
216 }
217 catch ( org.eclipse.aether.resolution.ArtifactResolutionException e )
218 {
219 if ( e.getCause() instanceof org.eclipse.aether.transfer.ArtifactNotFoundException )
220 {
221 throw new ArtifactNotFoundException( e.getMessage(), artifact, remoteRepositories, e );
222 }
223 else
224 {
225 throw new ArtifactResolutionException( e.getMessage(), artifact, remoteRepositories, e );
226 }
227 }
228
229 artifact.selectVersion( result.getArtifact().getVersion() );
230 artifact.setFile( result.getArtifact().getFile() );
231 artifact.setResolved( true );
232
233 if ( artifact.isSnapshot() )
234 {
235 Matcher matcher = Artifact.VERSION_FILE_PATTERN.matcher( artifact.getVersion() );
236 if ( matcher.matches() )
237 {
238 Snapshot snapshot = new Snapshot();
239 snapshot.setTimestamp( matcher.group( 2 ) );
240 try
241 {
242 snapshot.setBuildNumber( Integer.parseInt( matcher.group( 3 ) ) );
243 artifact.addMetadata( new SnapshotArtifactRepositoryMetadata( artifact, snapshot ) );
244 }
245 catch ( NumberFormatException e )
246 {
247 logger.warn( "Invalid artifact version " + artifact.getVersion() + ": " + e.getMessage() );
248 }
249 }
250 }
251 }
252 }
253
254 public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact,
255 ArtifactRepository localRepository,
256 List<ArtifactRepository> remoteRepositories,
257 ArtifactMetadataSource source, ArtifactFilter filter )
258 throws ArtifactResolutionException,
259 ArtifactNotFoundException
260 {
261 return resolveTransitively(
262 artifacts, originatingArtifact, Collections.<String, Artifact>emptyMap(), localRepository,
263 remoteRepositories, source, filter );
264
265 }
266
267 public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact,
268 Map<String, Artifact> managedVersions,
269 ArtifactRepository localRepository,
270 List<ArtifactRepository> remoteRepositories,
271 ArtifactMetadataSource source )
272 throws ArtifactResolutionException,
273 ArtifactNotFoundException
274 {
275 return resolveTransitively( artifacts, originatingArtifact, managedVersions, localRepository,
276 remoteRepositories, source, null );
277 }
278
279 public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact,
280 Map<String, Artifact> managedVersions,
281 ArtifactRepository localRepository,
282 List<ArtifactRepository> remoteRepositories,
283 ArtifactMetadataSource source, ArtifactFilter filter )
284 throws ArtifactResolutionException,
285 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,
296 ArtifactNotFoundException
297 {
298 return resolveTransitively( artifacts, originatingArtifact, localRepository, remoteRepositories, source, null );
299 }
300
301 public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact,
302 List<ArtifactRepository> remoteRepositories,
303 ArtifactRepository localRepository,
304 ArtifactMetadataSource source,
305 List<ResolutionListener> listeners )
306 throws ArtifactResolutionException,
307 ArtifactNotFoundException
308 {
309 return resolveTransitively(
310 artifacts, originatingArtifact, Collections.<String, Artifact>emptyMap(), localRepository,
311 remoteRepositories, source, null, listeners );
312 }
313
314 @SuppressWarnings( "checkstyle:parameternumber" )
315 public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact,
316 Map<String, Artifact> managedVersions,
317 ArtifactRepository localRepository,
318 List<ArtifactRepository> remoteRepositories,
319 ArtifactMetadataSource source, ArtifactFilter filter,
320 List<ResolutionListener> listeners )
321 throws ArtifactResolutionException,
322 ArtifactNotFoundException
323 {
324 return resolveTransitively( artifacts, originatingArtifact, managedVersions, localRepository,
325 remoteRepositories, source, filter, listeners, null );
326 }
327
328 @SuppressWarnings( "checkstyle:parameternumber" )
329 public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact,
330 Map<String, Artifact> managedVersions,
331 ArtifactRepository localRepository,
332 List<ArtifactRepository> remoteRepositories,
333 ArtifactMetadataSource source, ArtifactFilter filter,
334 List<ResolutionListener> listeners,
335 List<ConflictResolver> conflictResolvers )
336 throws ArtifactResolutionException,
337 ArtifactNotFoundException
338 {
339 ArtifactResolutionRequest request = new ArtifactResolutionRequest().
340 setArtifact( originatingArtifact ).
341 setResolveRoot( false ).
342
343 setArtifactDependencies( artifacts ).
344 setManagedVersionMap( managedVersions ).
345 setLocalRepository( localRepository ).
346 setRemoteRepositories( remoteRepositories ).
347 setCollectionFilter( filter ).
348 setListeners( listeners );
349
350 injectSession2( request, legacySupport.getSession() );
351
352 return resolveWithExceptions( request );
353 }
354
355 public ArtifactResolutionResult resolveWithExceptions( ArtifactResolutionRequest request )
356 throws ArtifactResolutionException, ArtifactNotFoundException
357 {
358 ArtifactResolutionResult result = resolve( request );
359
360
361
362
363
364 resolutionErrorHandler.throwErrors( request, result );
365
366 return result;
367 }
368
369
370
371
372
373 @SuppressWarnings( "checkstyle:methodlength" )
374 public ArtifactResolutionResult resolve( ArtifactResolutionRequest request )
375 {
376 Artifact rootArtifact = request.getArtifact();
377 Set<Artifact> artifacts = request.getArtifactDependencies();
378 Map<String, Artifact> managedVersions = request.getManagedVersionMap();
379 List<ResolutionListener> listeners = request.getListeners();
380 ArtifactFilter collectionFilter = request.getCollectionFilter();
381 ArtifactFilter resolutionFilter = request.getResolutionFilter();
382 RepositorySystemSession session = getSession( request.getLocalRepository() );
383
384
385
386 if ( source == null )
387 {
388 try
389 {
390 source = container.lookup( ArtifactMetadataSource.class );
391 }
392 catch ( ComponentLookupException e )
393 {
394
395 }
396 }
397
398 if ( listeners == null )
399 {
400 listeners = new ArrayList<>();
401
402 if ( logger.isDebugEnabled() )
403 {
404 listeners.add( new DebugResolutionListener( logger ) );
405 }
406
407 listeners.add( new WarningResolutionListener( logger ) );
408 }
409
410 ArtifactResolutionResult result = new ArtifactResolutionResult();
411
412
413
414
415
416
417 if ( request.isResolveRoot() )
418 {
419 try
420 {
421 resolve( rootArtifact, request.getRemoteRepositories(), session );
422 }
423 catch ( ArtifactResolutionException e )
424 {
425 result.addErrorArtifactException( e );
426 return result;
427 }
428 catch ( ArtifactNotFoundException e )
429 {
430 result.addMissingArtifact( request.getArtifact() );
431 return result;
432 }
433 }
434
435 ArtifactResolutionRequest collectionRequest = request;
436
437 if ( request.isResolveTransitively() )
438 {
439 MetadataResolutionRequest metadataRequest = new DefaultMetadataResolutionRequest( request );
440
441 metadataRequest.setArtifact( rootArtifact );
442 metadataRequest.setResolveManagedVersions( managedVersions == null );
443
444 try
445 {
446 ResolutionGroup resolutionGroup = source.retrieve( metadataRequest );
447
448 if ( managedVersions == null )
449 {
450 managedVersions = resolutionGroup.getManagedVersions();
451 }
452
453 Set<Artifact> directArtifacts = resolutionGroup.getArtifacts();
454
455 if ( artifacts == null || artifacts.isEmpty() )
456 {
457 artifacts = directArtifacts;
458 }
459 else
460 {
461 List<Artifact> allArtifacts = new ArrayList<>();
462 allArtifacts.addAll( artifacts );
463 allArtifacts.addAll( directArtifacts );
464
465 Map<String, Artifact> mergedArtifacts = new LinkedHashMap<>();
466 for ( Artifact artifact : allArtifacts )
467 {
468 String conflictId = artifact.getDependencyConflictId();
469 if ( !mergedArtifacts.containsKey( conflictId ) )
470 {
471 mergedArtifacts.put( conflictId, artifact );
472 }
473 }
474
475 artifacts = new LinkedHashSet<>( mergedArtifacts.values() );
476 }
477
478 collectionRequest = new ArtifactResolutionRequest( request );
479 collectionRequest.setServers( request.getServers() );
480 collectionRequest.setMirrors( request.getMirrors() );
481 collectionRequest.setProxies( request.getProxies() );
482 collectionRequest.setRemoteRepositories( resolutionGroup.getResolutionRepositories() );
483 }
484 catch ( ArtifactMetadataRetrievalException e )
485 {
486 ArtifactResolutionException are =
487 new ArtifactResolutionException( "Unable to get dependency information for " + rootArtifact.getId()
488 + ": " + e.getMessage(), rootArtifact, metadataRequest.getRemoteRepositories(), e );
489 result.addMetadataResolutionException( are );
490 return result;
491 }
492 }
493
494 if ( artifacts == null || artifacts.isEmpty() )
495 {
496 if ( request.isResolveRoot() )
497 {
498 result.addArtifact( rootArtifact );
499 }
500 return result;
501 }
502
503
504 result = artifactCollector.collect( artifacts, rootArtifact, managedVersions, collectionRequest, source,
505 collectionFilter, listeners, null );
506
507
508
509
510
511 if ( result.hasMetadataResolutionExceptions() || result.hasVersionRangeViolations()
512 || result.hasCircularDependencyExceptions() )
513 {
514 logger.info( "Failure detected." );
515 return result;
516 }
517
518 if ( result.getArtifactResolutionNodes() != null )
519 {
520 ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
521
522 CountDownLatch latch = new CountDownLatch( result.getArtifactResolutionNodes().size() );
523
524 for ( ResolutionNode node : result.getArtifactResolutionNodes() )
525 {
526 Artifact artifact = node.getArtifact();
527
528 if ( resolutionFilter == null || resolutionFilter.include( artifact ) )
529 {
530 executor.execute( new ResolveTask( classLoader, latch, artifact, session,
531 node.getRemoteRepositories(), result ) );
532 }
533 else
534 {
535 latch.countDown();
536 }
537 }
538 try
539 {
540 latch.await();
541 }
542 catch ( InterruptedException e )
543 {
544 result.addErrorArtifactException( new ArtifactResolutionException( "Resolution interrupted",
545 rootArtifact, e ) );
546 }
547 }
548
549
550
551 if ( request.isResolveRoot() )
552 {
553
554 Set<Artifact> allArtifacts = new LinkedHashSet<>();
555 allArtifacts.add( rootArtifact );
556 allArtifacts.addAll( result.getArtifacts() );
557 result.setArtifacts( allArtifacts );
558 }
559
560 return result;
561 }
562
563 public void resolve( Artifact artifact, List<ArtifactRepository> remoteRepositories,
564 ArtifactRepository localRepository )
565 throws ArtifactResolutionException, ArtifactNotFoundException
566 {
567 resolve( artifact, remoteRepositories, localRepository, null );
568 }
569
570
571
572
573 static final class DaemonThreadCreator
574 implements ThreadFactory
575 {
576 static final String THREADGROUP_NAME = "org.apache.maven.artifact.resolver.DefaultArtifactResolver";
577
578 static final ThreadGroup GROUP = new ThreadGroup( THREADGROUP_NAME );
579
580 static final AtomicInteger THREAD_NUMBER = new AtomicInteger( 1 );
581
582 public Thread newThread( Runnable r )
583 {
584 Thread newThread = new Thread( GROUP, r, "resolver-" + THREAD_NUMBER.getAndIncrement() );
585 newThread.setDaemon( true );
586 newThread.setContextClassLoader( null );
587 return newThread;
588 }
589 }
590
591 private class ResolveTask
592 implements Runnable
593 {
594
595 private final ClassLoader classLoader;
596
597 private final CountDownLatch latch;
598
599 private final Artifact artifact;
600
601 private final RepositorySystemSession session;
602
603 private final List<ArtifactRepository> remoteRepositories;
604
605 private final ArtifactResolutionResult result;
606
607 ResolveTask( ClassLoader classLoader, CountDownLatch latch, Artifact artifact,
608 RepositorySystemSession session, List<ArtifactRepository> remoteRepositories,
609 ArtifactResolutionResult result )
610 {
611 this.classLoader = classLoader;
612 this.latch = latch;
613 this.artifact = artifact;
614 this.session = session;
615 this.remoteRepositories = remoteRepositories;
616 this.result = result;
617 }
618
619 public void run()
620 {
621 ClassLoader old = Thread.currentThread().getContextClassLoader();
622 try
623 {
624 Thread.currentThread().setContextClassLoader( classLoader );
625 resolve( artifact, remoteRepositories, session );
626 }
627 catch ( ArtifactNotFoundException anfe )
628 {
629
630
631
632 synchronized ( result )
633 {
634 result.addMissingArtifact( artifact );
635 }
636 }
637 catch ( ArtifactResolutionException e )
638 {
639
640
641
642 synchronized ( result )
643 {
644 result.addErrorArtifactException( e );
645 }
646 }
647 finally
648 {
649 latch.countDown();
650 Thread.currentThread().setContextClassLoader( old );
651
652 }
653 }
654
655 }
656
657 @Override
658 public void dispose()
659 {
660 if ( executor instanceof ExecutorService )
661 {
662 ( (ExecutorService) executor ).shutdownNow();
663 }
664 }
665
666 }