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