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.EMPTY_MAP, 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.EMPTY_MAP, 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 return result;
510 }
511
512 if ( result.getArtifactResolutionNodes() != null )
513 {
514 ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
515
516 CountDownLatch latch = new CountDownLatch( result.getArtifactResolutionNodes().size() );
517
518 for ( ResolutionNode node : result.getArtifactResolutionNodes() )
519 {
520 Artifact artifact = node.getArtifact();
521
522 if ( resolutionFilter == null || resolutionFilter.include( artifact ) )
523 {
524 executor.execute( new ResolveTask( classLoader, latch, artifact, session,
525 node.getRemoteRepositories(), result ) );
526 }
527 else
528 {
529 latch.countDown();
530 }
531 }
532 try
533 {
534 latch.await();
535 }
536 catch ( InterruptedException e )
537 {
538 result.addErrorArtifactException( new ArtifactResolutionException( "Resolution interrupted",
539 rootArtifact, e ) );
540 }
541 }
542
543
544
545 if ( request.isResolveRoot() )
546 {
547
548 Set<Artifact> allArtifacts = new LinkedHashSet<>();
549 allArtifacts.add( rootArtifact );
550 allArtifacts.addAll( result.getArtifacts() );
551 result.setArtifacts( allArtifacts );
552 }
553
554 return result;
555 }
556
557 public void resolve( Artifact artifact, List<ArtifactRepository> remoteRepositories,
558 ArtifactRepository localRepository )
559 throws ArtifactResolutionException, ArtifactNotFoundException
560 {
561 resolve( artifact, remoteRepositories, localRepository, null );
562 }
563
564
565
566
567 static final class DaemonThreadCreator
568 implements ThreadFactory
569 {
570 static final String THREADGROUP_NAME = "org.apache.maven.artifact.resolver.DefaultArtifactResolver";
571
572 static final ThreadGroup GROUP = new ThreadGroup( THREADGROUP_NAME );
573
574 static final AtomicInteger THREAD_NUMBER = new AtomicInteger( 1 );
575
576 public Thread newThread( Runnable r )
577 {
578 Thread newThread = new Thread( GROUP, r, "resolver-" + THREAD_NUMBER.getAndIncrement() );
579 newThread.setDaemon( true );
580 newThread.setContextClassLoader( null );
581 return newThread;
582 }
583 }
584
585 private class ResolveTask
586 implements Runnable
587 {
588
589 private final ClassLoader classLoader;
590
591 private final CountDownLatch latch;
592
593 private final Artifact artifact;
594
595 private final RepositorySystemSession session;
596
597 private final List<ArtifactRepository> remoteRepositories;
598
599 private final ArtifactResolutionResult result;
600
601 public ResolveTask( ClassLoader classLoader, CountDownLatch latch, Artifact artifact,
602 RepositorySystemSession session, List<ArtifactRepository> remoteRepositories,
603 ArtifactResolutionResult result )
604 {
605 this.classLoader = classLoader;
606 this.latch = latch;
607 this.artifact = artifact;
608 this.session = session;
609 this.remoteRepositories = remoteRepositories;
610 this.result = result;
611 }
612
613 public void run()
614 {
615 ClassLoader old = Thread.currentThread().getContextClassLoader();
616 try
617 {
618 Thread.currentThread().setContextClassLoader( classLoader );
619 resolve( artifact, remoteRepositories, session );
620 }
621 catch ( ArtifactNotFoundException anfe )
622 {
623
624
625
626 synchronized ( result )
627 {
628 result.addMissingArtifact( artifact );
629 }
630 }
631 catch ( ArtifactResolutionException e )
632 {
633
634
635
636 synchronized ( result )
637 {
638 result.addErrorArtifactException( e );
639 }
640 }
641 finally
642 {
643 latch.countDown();
644 Thread.currentThread().setContextClassLoader( old );
645
646 }
647 }
648
649 }
650
651 @Override
652 public void dispose()
653 {
654 if ( executor instanceof ExecutorService )
655 {
656 ( (ExecutorService) executor ).shutdownNow();
657 }
658 }
659
660 }