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.eclipse.aether.RepositorySystem;
64 import org.eclipse.aether.RepositorySystemSession;
65 import org.eclipse.aether.repository.LocalRepositoryManager;
66 import org.eclipse.aether.resolution.ArtifactRequest;
67 import org.eclipse.aether.resolution.ArtifactResult;
68
69
70
71
72 @Component( role = ArtifactResolver.class )
73 public class DefaultArtifactResolver
74 implements ArtifactResolver
75 {
76 @Requirement
77 private Logger logger;
78
79 @Requirement
80 protected ArtifactFactory artifactFactory;
81
82 @Requirement
83 private ArtifactCollector artifactCollector;
84
85 @Requirement
86 private ResolutionErrorHandler resolutionErrorHandler;
87
88 @Requirement
89 private ArtifactMetadataSource source;
90
91 @Requirement
92 private PlexusContainer container;
93
94 @Requirement
95 private LegacySupport legacySupport;
96
97 @Requirement
98 private RepositorySystem repoSystem;
99
100 private final Executor executor;
101
102 public DefaultArtifactResolver()
103 {
104 int threads = Integer.getInteger( "maven.artifact.threads", 5 );
105 if ( threads <= 1 )
106 {
107 executor = new Executor()
108 {
109 public void execute( Runnable command )
110 {
111 command.run();
112 }
113 };
114 }
115 else
116 {
117 executor =
118 new ThreadPoolExecutor( threads, threads, 3, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(),
119 new DaemonThreadCreator() );
120 }
121 }
122
123 @Override
124 protected void finalize()
125 throws Throwable
126 {
127 if ( executor instanceof ExecutorService )
128 {
129 ( (ExecutorService) executor ).shutdown();
130 }
131 }
132
133 private RepositorySystemSession getSession( ArtifactRepository localRepository )
134 {
135 return LegacyLocalRepositoryManager.overlay( localRepository, legacySupport.getRepositorySession(), repoSystem );
136 }
137
138 private void injectSession1( RepositoryRequest request, MavenSession session )
139 {
140 if ( session != null )
141 {
142 request.setOffline( session.isOffline() );
143 request.setForceUpdate( session.getRequest().isUpdateSnapshots() );
144 }
145 }
146
147 private void injectSession2( ArtifactResolutionRequest request, MavenSession session )
148 {
149 injectSession1( request, session );
150
151 if ( session != null )
152 {
153 request.setServers( session.getRequest().getServers() );
154 request.setMirrors( session.getRequest().getMirrors() );
155 request.setProxies( session.getRequest().getProxies() );
156 }
157 }
158
159 public void resolve( Artifact artifact, List<ArtifactRepository> remoteRepositories,
160 ArtifactRepository localRepository, TransferListener resolutionListener )
161 throws ArtifactResolutionException, ArtifactNotFoundException
162 {
163 resolve( artifact, remoteRepositories, getSession( localRepository ) );
164 }
165
166 public void resolveAlways( Artifact artifact, List<ArtifactRepository> remoteRepositories,
167 ArtifactRepository localRepository )
168 throws ArtifactResolutionException, ArtifactNotFoundException
169 {
170 resolve( artifact, remoteRepositories, getSession( localRepository ) );
171 }
172
173 private void resolve( Artifact artifact, List<ArtifactRepository> remoteRepositories,
174 RepositorySystemSession session )
175 throws ArtifactResolutionException, ArtifactNotFoundException
176 {
177 if ( artifact == null )
178 {
179 return;
180 }
181
182 if ( Artifact.SCOPE_SYSTEM.equals( artifact.getScope() ) )
183 {
184 File systemFile = artifact.getFile();
185
186 if ( systemFile == null )
187 {
188 throw new ArtifactNotFoundException( "System artifact: " + artifact + " has no file attached", artifact );
189 }
190
191 if ( !systemFile.exists() )
192 {
193 throw new ArtifactNotFoundException( "System artifact: " + artifact + " not found in path: " + systemFile, artifact );
194 }
195
196 if ( !systemFile.isFile() )
197 {
198 throw new ArtifactNotFoundException( "System artifact: " + artifact + " is not a file: " + systemFile, artifact );
199 }
200
201 artifact.setResolved( true );
202
203 return;
204 }
205
206 if ( !artifact.isResolved() )
207 {
208 ArtifactResult result;
209
210 try
211 {
212 ArtifactRequest artifactRequest = new ArtifactRequest();
213 artifactRequest.setArtifact( RepositoryUtils.toArtifact( artifact ) );
214 artifactRequest.setRepositories( RepositoryUtils.toRepos( remoteRepositories ) );
215
216
217 LocalRepositoryManager lrm = session.getLocalRepositoryManager();
218 String path = lrm.getPathForLocalArtifact( artifactRequest.getArtifact() );
219 artifact.setFile( new File( lrm.getRepository().getBasedir(), path ) );
220
221 result = repoSystem.resolveArtifact( session, artifactRequest );
222 }
223 catch ( org.eclipse.aether.resolution.ArtifactResolutionException e )
224 {
225 if ( e.getCause() instanceof org.eclipse.aether.transfer.ArtifactNotFoundException )
226 {
227 throw new ArtifactNotFoundException( e.getMessage(), artifact, remoteRepositories, e );
228 }
229 else
230 {
231 throw new ArtifactResolutionException( e.getMessage(), artifact, remoteRepositories, e );
232 }
233 }
234
235 artifact.selectVersion( result.getArtifact().getVersion() );
236 artifact.setFile( result.getArtifact().getFile() );
237 artifact.setResolved( true );
238
239 if ( artifact.isSnapshot() )
240 {
241 Matcher matcher = Artifact.VERSION_FILE_PATTERN.matcher( artifact.getVersion() );
242 if ( matcher.matches() )
243 {
244 Snapshot snapshot = new Snapshot();
245 snapshot.setTimestamp( matcher.group( 2 ) );
246 try
247 {
248 snapshot.setBuildNumber( Integer.parseInt( matcher.group( 3 ) ) );
249 artifact.addMetadata( new SnapshotArtifactRepositoryMetadata( artifact, snapshot ) );
250 }
251 catch ( NumberFormatException e )
252 {
253 logger.warn( "Invalid artifact version " + artifact.getVersion() + ": " + e.getMessage() );
254 }
255 }
256 }
257 }
258 }
259
260 public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact,
261 ArtifactRepository localRepository,
262 List<ArtifactRepository> remoteRepositories,
263 ArtifactMetadataSource source, ArtifactFilter filter )
264 throws ArtifactResolutionException, ArtifactNotFoundException
265 {
266 return resolveTransitively( artifacts, originatingArtifact, Collections.EMPTY_MAP, localRepository,
267 remoteRepositories, source, filter );
268
269 }
270
271 public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact,
272 Map managedVersions, ArtifactRepository localRepository,
273 List<ArtifactRepository> remoteRepositories,
274 ArtifactMetadataSource source )
275 throws ArtifactResolutionException, ArtifactNotFoundException
276 {
277 return resolveTransitively( artifacts, originatingArtifact, managedVersions, localRepository,
278 remoteRepositories, source, null );
279 }
280
281 public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact,
282 Map managedVersions, ArtifactRepository localRepository,
283 List<ArtifactRepository> remoteRepositories,
284 ArtifactMetadataSource source, ArtifactFilter filter )
285 throws ArtifactResolutionException, 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, 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, ArtifactNotFoundException
306 {
307 return resolveTransitively( artifacts, originatingArtifact, Collections.EMPTY_MAP, localRepository,
308 remoteRepositories, source, null, listeners );
309 }
310
311 public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact,
312 Map managedVersions, ArtifactRepository localRepository,
313 List<ArtifactRepository> remoteRepositories,
314 ArtifactMetadataSource source, ArtifactFilter filter,
315 List<ResolutionListener> listeners )
316 throws ArtifactResolutionException, ArtifactNotFoundException
317 {
318 return resolveTransitively( artifacts, originatingArtifact, managedVersions, localRepository,
319 remoteRepositories, source, filter, listeners, null );
320 }
321
322 public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact,
323 Map managedVersions, ArtifactRepository localRepository,
324 List<ArtifactRepository> remoteRepositories,
325 ArtifactMetadataSource source, ArtifactFilter filter,
326 List<ResolutionListener> listeners,
327 List<ConflictResolver> conflictResolvers )
328 throws ArtifactResolutionException, ArtifactNotFoundException
329 {
330 ArtifactResolutionRequest request = new ArtifactResolutionRequest()
331 .setArtifact( originatingArtifact )
332 .setResolveRoot( false )
333
334 .setArtifactDependencies( artifacts )
335 .setManagedVersionMap( managedVersions )
336 .setLocalRepository( localRepository )
337 .setRemoteRepositories( remoteRepositories )
338 .setCollectionFilter( filter )
339 .setListeners( listeners );
340
341 injectSession2( request, legacySupport.getSession() );
342
343 return resolveWithExceptions( request );
344 }
345
346 public ArtifactResolutionResult resolveWithExceptions( ArtifactResolutionRequest request )
347 throws ArtifactResolutionException, ArtifactNotFoundException
348 {
349 ArtifactResolutionResult result = resolve( request );
350
351
352
353
354
355 resolutionErrorHandler.throwErrors( request, result );
356
357 return result;
358 }
359
360
361
362
363
364 public ArtifactResolutionResult resolve( ArtifactResolutionRequest request )
365 {
366 Artifact rootArtifact = request.getArtifact();
367 Set<Artifact> artifacts = request.getArtifactDependencies();
368 Map<String, Artifact> managedVersions = request.getManagedVersionMap();
369 List<ResolutionListener> listeners = request.getListeners();
370 ArtifactFilter collectionFilter = request.getCollectionFilter();
371 ArtifactFilter resolutionFilter = request.getResolutionFilter();
372 RepositorySystemSession session = getSession( request.getLocalRepository() );
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<ResolutionListener>();
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<Artifact>();
451 allArtifacts.addAll( artifacts );
452 allArtifacts.addAll( directArtifacts );
453
454 Map<String, Artifact> mergedArtifacts = new LinkedHashMap<String, Artifact>();
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<Artifact>( 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 =
494 artifactCollector.collect( artifacts, rootArtifact, managedVersions, collectionRequest, source,
495 collectionFilter, listeners, null );
496
497
498
499
500
501 if ( result.hasMetadataResolutionExceptions() || result.hasVersionRangeViolations() || 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<Artifact>();
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, ArtifactRepository localRepository )
552 throws ArtifactResolutionException, ArtifactNotFoundException
553 {
554 resolve( artifact, remoteRepositories, localRepository, null );
555 }
556
557
558
559
560 static final class DaemonThreadCreator
561 implements ThreadFactory
562 {
563 static final String THREADGROUP_NAME = "org.apache.maven.artifact.resolver.DefaultArtifactResolver";
564
565 static final ThreadGroup GROUP = new ThreadGroup( THREADGROUP_NAME );
566
567 static final AtomicInteger THREAD_NUMBER = new AtomicInteger( 1 );
568
569 public Thread newThread( Runnable r )
570 {
571 Thread newThread = new Thread( GROUP, r, "resolver-" + THREAD_NUMBER.getAndIncrement() );
572 newThread.setDaemon( true );
573 return newThread;
574 }
575 }
576
577 private class ResolveTask
578 implements Runnable
579 {
580
581 private final ClassLoader classLoader;
582
583 private final CountDownLatch latch;
584
585 private final Artifact artifact;
586
587 private final RepositorySystemSession session;
588
589 private final List<ArtifactRepository> remoteRepositories;
590
591 private final ArtifactResolutionResult result;
592
593 public ResolveTask( ClassLoader classLoader, CountDownLatch latch, Artifact artifact, RepositorySystemSession session,
594 List<ArtifactRepository> remoteRepositories, ArtifactResolutionResult result )
595 {
596 this.classLoader = classLoader;
597 this.latch = latch;
598 this.artifact = artifact;
599 this.session = session;
600 this.remoteRepositories = remoteRepositories;
601 this.result = result;
602 }
603
604 public void run()
605 {
606 ClassLoader old = Thread.currentThread().getContextClassLoader();
607 try
608 {
609 Thread.currentThread().setContextClassLoader( classLoader );
610 resolve( artifact, remoteRepositories, session );
611 }
612 catch ( ArtifactNotFoundException anfe )
613 {
614
615
616
617 synchronized ( result )
618 {
619 result.addMissingArtifact( artifact );
620 }
621 }
622 catch ( ArtifactResolutionException e )
623 {
624
625
626
627 synchronized ( result )
628 {
629 result.addErrorArtifactException( e );
630 }
631 }
632 finally
633 {
634 latch.countDown();
635 Thread.currentThread().setContextClassLoader( old );
636
637 }
638 }
639
640 }
641
642 }