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 =
336 new ArtifactResolutionRequest().setArtifact( originatingArtifact ).setResolveRoot( false )
337
338 .setArtifactDependencies( artifacts ).setManagedVersionMap( managedVersions ).setLocalRepository( localRepository ).setRemoteRepositories( remoteRepositories ).setCollectionFilter( filter ).setListeners( listeners );
339
340 injectSession2( request, legacySupport.getSession() );
341
342 return resolveWithExceptions( request );
343 }
344
345 public ArtifactResolutionResult resolveWithExceptions( ArtifactResolutionRequest request )
346 throws ArtifactResolutionException, ArtifactNotFoundException
347 {
348 ArtifactResolutionResult result = resolve( request );
349
350
351
352
353
354 resolutionErrorHandler.throwErrors( request, result );
355
356 return result;
357 }
358
359
360
361
362
363 public ArtifactResolutionResult resolve( ArtifactResolutionRequest request )
364 {
365 Artifact rootArtifact = request.getArtifact();
366 Set<Artifact> artifacts = request.getArtifactDependencies();
367 Map<String, Artifact> managedVersions = request.getManagedVersionMap();
368 List<ResolutionListener> listeners = request.getListeners();
369 ArtifactFilter collectionFilter = request.getCollectionFilter();
370 ArtifactFilter resolutionFilter = request.getResolutionFilter();
371 RepositorySystemSession session = getSession( request.getLocalRepository() );
372
373
374
375 if ( source == null )
376 {
377 try
378 {
379 source = container.lookup( ArtifactMetadataSource.class );
380 }
381 catch ( ComponentLookupException e )
382 {
383
384 }
385 }
386
387 if ( listeners == null )
388 {
389 listeners = new ArrayList<>();
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
402
403
404
405
406 if ( request.isResolveRoot() )
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<>();
451 allArtifacts.addAll( artifacts );
452 allArtifacts.addAll( directArtifacts );
453
454 Map<String, Artifact> mergedArtifacts = new LinkedHashMap<>();
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<>( 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
493 result = artifactCollector.collect( artifacts, rootArtifact, managedVersions, collectionRequest, source,
494 collectionFilter, listeners, null );
495
496
497
498
499
500 if ( result.hasMetadataResolutionExceptions() || result.hasVersionRangeViolations()
501 || 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
538
539 if ( request.isResolveRoot() )
540 {
541
542 Set<Artifact> allArtifacts = new LinkedHashSet<>();
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,
552 ArtifactRepository localRepository )
553 throws ArtifactResolutionException, ArtifactNotFoundException
554 {
555 resolve( artifact, remoteRepositories, localRepository, null );
556 }
557
558
559
560
561 static final class DaemonThreadCreator
562 implements ThreadFactory
563 {
564 static final String THREADGROUP_NAME = "org.apache.maven.artifact.resolver.DefaultArtifactResolver";
565
566 static final ThreadGroup GROUP = new ThreadGroup( THREADGROUP_NAME );
567
568 static final AtomicInteger THREAD_NUMBER = new AtomicInteger( 1 );
569
570 public Thread newThread( Runnable r )
571 {
572 Thread newThread = new Thread( GROUP, r, "resolver-" + THREAD_NUMBER.getAndIncrement() );
573 newThread.setDaemon( true );
574 newThread.setContextClassLoader( null );
575 return newThread;
576 }
577 }
578
579 private class ResolveTask
580 implements Runnable
581 {
582
583 private final ClassLoader classLoader;
584
585 private final CountDownLatch latch;
586
587 private final Artifact artifact;
588
589 private final RepositorySystemSession session;
590
591 private final List<ArtifactRepository> remoteRepositories;
592
593 private final ArtifactResolutionResult result;
594
595 public ResolveTask( ClassLoader classLoader, CountDownLatch latch, Artifact artifact,
596 RepositorySystemSession session, List<ArtifactRepository> remoteRepositories,
597 ArtifactResolutionResult result )
598 {
599 this.classLoader = classLoader;
600 this.latch = latch;
601 this.artifact = artifact;
602 this.session = session;
603 this.remoteRepositories = remoteRepositories;
604 this.result = result;
605 }
606
607 public void run()
608 {
609 ClassLoader old = Thread.currentThread().getContextClassLoader();
610 try
611 {
612 Thread.currentThread().setContextClassLoader( classLoader );
613 resolve( artifact, remoteRepositories, session );
614 }
615 catch ( ArtifactNotFoundException anfe )
616 {
617
618
619
620 synchronized ( result )
621 {
622 result.addMissingArtifact( artifact );
623 }
624 }
625 catch ( ArtifactResolutionException e )
626 {
627
628
629
630 synchronized ( result )
631 {
632 result.addErrorArtifactException( e );
633 }
634 }
635 finally
636 {
637 latch.countDown();
638 Thread.currentThread().setContextClassLoader( old );
639
640 }
641 }
642
643 }
644
645 @Override
646 public void dispose()
647 {
648 if ( executor instanceof ExecutorService )
649 {
650 ( (ExecutorService) executor ).shutdownNow();
651 }
652 }
653
654 }