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( artifacts, originatingArtifact, Collections.<String, Artifact>emptyMap(), localRepository,
262 remoteRepositories, source, filter );
263
264 }
265
266 public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact,
267 Map<String, Artifact> managedVersions,
268 ArtifactRepository localRepository,
269 List<ArtifactRepository> remoteRepositories,
270 ArtifactMetadataSource source )
271 throws ArtifactResolutionException,
272 ArtifactNotFoundException
273 {
274 return resolveTransitively( artifacts, originatingArtifact, managedVersions, localRepository,
275 remoteRepositories, source, null );
276 }
277
278 public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact,
279 Map<String, Artifact> managedVersions,
280 ArtifactRepository localRepository,
281 List<ArtifactRepository> remoteRepositories,
282 ArtifactMetadataSource source, ArtifactFilter filter )
283 throws ArtifactResolutionException,
284 ArtifactNotFoundException
285 {
286 return resolveTransitively( artifacts, originatingArtifact, managedVersions, localRepository,
287 remoteRepositories, source, filter, null );
288 }
289
290 public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact,
291 List<ArtifactRepository> remoteRepositories,
292 ArtifactRepository localRepository,
293 ArtifactMetadataSource source )
294 throws ArtifactResolutionException,
295 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,
306 ArtifactNotFoundException
307 {
308 return resolveTransitively( artifacts, originatingArtifact, Collections.<String, Artifact>emptyMap(), localRepository,
309 remoteRepositories, source, null, listeners );
310 }
311
312 public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact,
313 Map<String, Artifact> managedVersions,
314 ArtifactRepository localRepository,
315 List<ArtifactRepository> remoteRepositories,
316 ArtifactMetadataSource source, ArtifactFilter filter,
317 List<ResolutionListener> listeners )
318 throws ArtifactResolutionException,
319 ArtifactNotFoundException
320 {
321 return resolveTransitively( artifacts, originatingArtifact, managedVersions, localRepository,
322 remoteRepositories, source, filter, listeners, null );
323 }
324
325 public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact,
326 Map<String, Artifact> managedVersions,
327 ArtifactRepository localRepository,
328 List<ArtifactRepository> remoteRepositories,
329 ArtifactMetadataSource source, ArtifactFilter filter,
330 List<ResolutionListener> listeners,
331 List<ConflictResolver> conflictResolvers )
332 throws ArtifactResolutionException,
333 ArtifactNotFoundException
334 {
335 ArtifactResolutionRequest request = new ArtifactResolutionRequest().
336 setArtifact( originatingArtifact ).
337 setResolveRoot( false ).
338
339 setArtifactDependencies( artifacts ).
340 setManagedVersionMap( managedVersions ).
341 setLocalRepository( localRepository ).
342 setRemoteRepositories( remoteRepositories ).
343 setCollectionFilter( filter ).
344 setListeners( listeners );
345
346 injectSession2( request, legacySupport.getSession() );
347
348 return resolveWithExceptions( request );
349 }
350
351 public ArtifactResolutionResult resolveWithExceptions( ArtifactResolutionRequest request )
352 throws ArtifactResolutionException, ArtifactNotFoundException
353 {
354 ArtifactResolutionResult result = resolve( request );
355
356
357
358
359
360 resolutionErrorHandler.throwErrors( request, result );
361
362 return result;
363 }
364
365
366
367
368
369 public ArtifactResolutionResult resolve( ArtifactResolutionRequest request )
370 {
371 Artifact rootArtifact = request.getArtifact();
372 Set<Artifact> artifacts = request.getArtifactDependencies();
373 Map<String, Artifact> managedVersions = request.getManagedVersionMap();
374 List<ResolutionListener> listeners = request.getListeners();
375 ArtifactFilter collectionFilter = request.getCollectionFilter();
376 ArtifactFilter resolutionFilter = request.getResolutionFilter();
377 RepositorySystemSession session = getSession( request.getLocalRepository() );
378
379
380
381 if ( source == null )
382 {
383 try
384 {
385 source = container.lookup( ArtifactMetadataSource.class );
386 }
387 catch ( ComponentLookupException e )
388 {
389
390 }
391 }
392
393 if ( listeners == null )
394 {
395 listeners = new ArrayList<>();
396
397 if ( logger.isDebugEnabled() )
398 {
399 listeners.add( new DebugResolutionListener( logger ) );
400 }
401
402 listeners.add( new WarningResolutionListener( logger ) );
403 }
404
405 ArtifactResolutionResult result = new ArtifactResolutionResult();
406
407
408
409
410
411
412 if ( request.isResolveRoot() )
413 {
414 try
415 {
416 resolve( rootArtifact, request.getRemoteRepositories(), session );
417 }
418 catch ( ArtifactResolutionException e )
419 {
420 result.addErrorArtifactException( e );
421 return result;
422 }
423 catch ( ArtifactNotFoundException e )
424 {
425 result.addMissingArtifact( request.getArtifact() );
426 return result;
427 }
428 }
429
430 ArtifactResolutionRequest collectionRequest = request;
431
432 if ( request.isResolveTransitively() )
433 {
434 MetadataResolutionRequest metadataRequest = new DefaultMetadataResolutionRequest( request );
435
436 metadataRequest.setArtifact( rootArtifact );
437 metadataRequest.setResolveManagedVersions( managedVersions == null );
438
439 try
440 {
441 ResolutionGroup resolutionGroup = source.retrieve( metadataRequest );
442
443 if ( managedVersions == null )
444 {
445 managedVersions = resolutionGroup.getManagedVersions();
446 }
447
448 Set<Artifact> directArtifacts = resolutionGroup.getArtifacts();
449
450 if ( artifacts == null || artifacts.isEmpty() )
451 {
452 artifacts = directArtifacts;
453 }
454 else
455 {
456 List<Artifact> allArtifacts = new ArrayList<>();
457 allArtifacts.addAll( artifacts );
458 allArtifacts.addAll( directArtifacts );
459
460 Map<String, Artifact> mergedArtifacts = new LinkedHashMap<>();
461 for ( Artifact artifact : allArtifacts )
462 {
463 String conflictId = artifact.getDependencyConflictId();
464 if ( !mergedArtifacts.containsKey( conflictId ) )
465 {
466 mergedArtifacts.put( conflictId, artifact );
467 }
468 }
469
470 artifacts = new LinkedHashSet<>( mergedArtifacts.values() );
471 }
472
473 collectionRequest = new ArtifactResolutionRequest( request );
474 collectionRequest.setServers( request.getServers() );
475 collectionRequest.setMirrors( request.getMirrors() );
476 collectionRequest.setProxies( request.getProxies() );
477 collectionRequest.setRemoteRepositories( resolutionGroup.getResolutionRepositories() );
478 }
479 catch ( ArtifactMetadataRetrievalException e )
480 {
481 ArtifactResolutionException are =
482 new ArtifactResolutionException( "Unable to get dependency information for " + rootArtifact.getId()
483 + ": " + e.getMessage(), rootArtifact, metadataRequest.getRemoteRepositories(), e );
484 result.addMetadataResolutionException( are );
485 return result;
486 }
487 }
488
489 if ( artifacts == null || artifacts.isEmpty() )
490 {
491 if ( request.isResolveRoot() )
492 {
493 result.addArtifact( rootArtifact );
494 }
495 return result;
496 }
497
498
499 result = artifactCollector.collect( artifacts, rootArtifact, managedVersions, collectionRequest, source,
500 collectionFilter, listeners, null );
501
502
503
504
505
506 if ( result.hasMetadataResolutionExceptions() || result.hasVersionRangeViolations()
507 || result.hasCircularDependencyExceptions() )
508 {
509 logger.info( "Failure detected." );
510 return result;
511 }
512
513 if ( result.getArtifactResolutionNodes() != null )
514 {
515 ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
516
517 CountDownLatch latch = new CountDownLatch( result.getArtifactResolutionNodes().size() );
518
519 for ( ResolutionNode node : result.getArtifactResolutionNodes() )
520 {
521 Artifact artifact = node.getArtifact();
522
523 if ( resolutionFilter == null || resolutionFilter.include( artifact ) )
524 {
525 executor.execute( new ResolveTask( classLoader, latch, artifact, session,
526 node.getRemoteRepositories(), result ) );
527 }
528 else
529 {
530 latch.countDown();
531 }
532 }
533 try
534 {
535 latch.await();
536 }
537 catch ( InterruptedException e )
538 {
539 result.addErrorArtifactException( new ArtifactResolutionException( "Resolution interrupted",
540 rootArtifact, e ) );
541 }
542 }
543
544
545
546 if ( request.isResolveRoot() )
547 {
548
549 Set<Artifact> allArtifacts = new LinkedHashSet<>();
550 allArtifacts.add( rootArtifact );
551 allArtifacts.addAll( result.getArtifacts() );
552 result.setArtifacts( allArtifacts );
553 }
554
555 return result;
556 }
557
558 public void resolve( Artifact artifact, List<ArtifactRepository> remoteRepositories,
559 ArtifactRepository localRepository )
560 throws ArtifactResolutionException, ArtifactNotFoundException
561 {
562 resolve( artifact, remoteRepositories, localRepository, null );
563 }
564
565
566
567
568 static final class DaemonThreadCreator
569 implements ThreadFactory
570 {
571 static final String THREADGROUP_NAME = "org.apache.maven.artifact.resolver.DefaultArtifactResolver";
572
573 static final ThreadGroup GROUP = new ThreadGroup( THREADGROUP_NAME );
574
575 static final AtomicInteger THREAD_NUMBER = new AtomicInteger( 1 );
576
577 public Thread newThread( Runnable r )
578 {
579 Thread newThread = new Thread( GROUP, r, "resolver-" + THREAD_NUMBER.getAndIncrement() );
580 newThread.setDaemon( true );
581 newThread.setContextClassLoader( null );
582 return newThread;
583 }
584 }
585
586 private class ResolveTask
587 implements Runnable
588 {
589
590 private final ClassLoader classLoader;
591
592 private final CountDownLatch latch;
593
594 private final Artifact artifact;
595
596 private final RepositorySystemSession session;
597
598 private final List<ArtifactRepository> remoteRepositories;
599
600 private final ArtifactResolutionResult result;
601
602 public ResolveTask( ClassLoader classLoader, CountDownLatch latch, Artifact artifact,
603 RepositorySystemSession session, List<ArtifactRepository> remoteRepositories,
604 ArtifactResolutionResult result )
605 {
606 this.classLoader = classLoader;
607 this.latch = latch;
608 this.artifact = artifact;
609 this.session = session;
610 this.remoteRepositories = remoteRepositories;
611 this.result = result;
612 }
613
614 public void run()
615 {
616 ClassLoader old = Thread.currentThread().getContextClassLoader();
617 try
618 {
619 Thread.currentThread().setContextClassLoader( classLoader );
620 resolve( artifact, remoteRepositories, session );
621 }
622 catch ( ArtifactNotFoundException anfe )
623 {
624
625
626
627 synchronized ( result )
628 {
629 result.addMissingArtifact( artifact );
630 }
631 }
632 catch ( ArtifactResolutionException e )
633 {
634
635
636
637 synchronized ( result )
638 {
639 result.addErrorArtifactException( e );
640 }
641 }
642 finally
643 {
644 latch.countDown();
645 Thread.currentThread().setContextClassLoader( old );
646
647 }
648 }
649
650 }
651
652 @Override
653 public void dispose()
654 {
655 if ( executor instanceof ExecutorService )
656 {
657 ( (ExecutorService) executor ).shutdownNow();
658 }
659 }
660
661 }