1 package org.apache.maven.artifact.resolver;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 import java.io.File;
19 import java.util.ArrayList;
20 import java.util.Collections;
21 import java.util.LinkedHashMap;
22 import java.util.LinkedHashSet;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.Set;
26 import java.util.concurrent.CountDownLatch;
27 import java.util.concurrent.Executor;
28 import java.util.concurrent.ExecutorService;
29 import java.util.concurrent.LinkedBlockingQueue;
30 import java.util.concurrent.ThreadFactory;
31 import java.util.concurrent.ThreadPoolExecutor;
32 import java.util.concurrent.TimeUnit;
33 import java.util.concurrent.atomic.AtomicInteger;
34 import java.util.regex.Matcher;
35
36 import org.apache.maven.RepositoryUtils;
37 import org.apache.maven.artifact.Artifact;
38 import org.apache.maven.artifact.factory.ArtifactFactory;
39 import org.apache.maven.artifact.metadata.ArtifactMetadataRetrievalException;
40 import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
41 import org.apache.maven.artifact.metadata.ResolutionGroup;
42 import org.apache.maven.artifact.repository.ArtifactRepository;
43 import org.apache.maven.artifact.repository.LegacyLocalRepositoryManager;
44 import org.apache.maven.artifact.repository.RepositoryRequest;
45 import org.apache.maven.artifact.repository.metadata.Snapshot;
46 import org.apache.maven.artifact.repository.metadata.SnapshotArtifactRepositoryMetadata;
47 import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
48 import org.apache.maven.execution.MavenSession;
49 import org.apache.maven.plugin.LegacySupport;
50 import org.apache.maven.repository.legacy.metadata.DefaultMetadataResolutionRequest;
51 import org.apache.maven.repository.legacy.metadata.MetadataResolutionRequest;
52 import org.apache.maven.repository.legacy.resolver.conflict.ConflictResolver;
53 import org.apache.maven.wagon.events.TransferListener;
54 import org.codehaus.plexus.PlexusContainer;
55 import org.codehaus.plexus.component.annotations.Component;
56 import org.codehaus.plexus.component.annotations.Requirement;
57 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
58 import org.codehaus.plexus.logging.Logger;
59 import org.sonatype.aether.RepositorySystem;
60 import org.sonatype.aether.RepositorySystemSession;
61 import org.sonatype.aether.repository.LocalRepositoryManager;
62 import org.sonatype.aether.resolution.ArtifactRequest;
63 import org.sonatype.aether.resolution.ArtifactResult;
64
65
66
67
68 @Component(role = ArtifactResolver.class)
69 public class DefaultArtifactResolver
70 implements ArtifactResolver
71 {
72 @Requirement
73 private Logger logger;
74
75 @Requirement
76 protected ArtifactFactory artifactFactory;
77
78 @Requirement
79 private ArtifactCollector artifactCollector;
80
81 @Requirement
82 private ResolutionErrorHandler resolutionErrorHandler;
83
84 @Requirement
85 private ArtifactMetadataSource source;
86
87 @Requirement
88 private PlexusContainer container;
89
90 @Requirement
91 private LegacySupport legacySupport;
92
93 @Requirement
94 private RepositorySystem repoSystem;
95
96 private final Executor executor;
97
98 public DefaultArtifactResolver()
99 {
100 int threads = Integer.getInteger( "maven.artifact.threads", 5 ).intValue();
101 if ( threads <= 1 )
102 {
103 executor = new Executor()
104 {
105 public void execute( Runnable command )
106 {
107 command.run();
108 }
109 };
110 }
111 else
112 {
113 executor =
114 new ThreadPoolExecutor( threads, threads, 3, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), new DaemonThreadCreator());
115 }
116 }
117
118 @Override
119 protected void finalize()
120 throws Throwable
121 {
122 if ( executor instanceof ExecutorService )
123 {
124 ( (ExecutorService) executor ).shutdown();
125 }
126 }
127
128 private RepositorySystemSession getSession( ArtifactRepository localRepository )
129 {
130 return LegacyLocalRepositoryManager.overlay( localRepository, legacySupport.getRepositorySession(), repoSystem );
131 }
132
133 private void injectSession1( RepositoryRequest request, MavenSession session )
134 {
135 if ( session != null )
136 {
137 request.setOffline( session.isOffline() );
138 request.setForceUpdate( session.getRequest().isUpdateSnapshots() );
139 }
140 }
141
142 private void injectSession2( ArtifactResolutionRequest request, MavenSession session )
143 {
144 injectSession1( request, session );
145
146 if ( session != null )
147 {
148 request.setServers( session.getRequest().getServers() );
149 request.setMirrors( session.getRequest().getMirrors() );
150 request.setProxies( session.getRequest().getProxies() );
151 }
152 }
153
154 public void resolve( Artifact artifact, List<ArtifactRepository> remoteRepositories, ArtifactRepository localRepository, TransferListener resolutionListener )
155 throws ArtifactResolutionException, ArtifactNotFoundException
156 {
157 resolve( artifact, remoteRepositories, getSession( localRepository ) );
158 }
159
160 public void resolveAlways( Artifact artifact, List<ArtifactRepository> remoteRepositories, ArtifactRepository localRepository )
161 throws ArtifactResolutionException, ArtifactNotFoundException
162 {
163 resolve( artifact, remoteRepositories, getSession( localRepository ) );
164 }
165
166 private void resolve( Artifact artifact, List<ArtifactRepository> remoteRepositories, RepositorySystemSession session )
167 throws ArtifactResolutionException, ArtifactNotFoundException
168 {
169 if ( artifact == null )
170 {
171 return;
172 }
173
174 if ( Artifact.SCOPE_SYSTEM.equals( artifact.getScope() ) )
175 {
176 File systemFile = artifact.getFile();
177
178 if ( systemFile == null )
179 {
180 throw new ArtifactNotFoundException( "System artifact: " + artifact + " has no file attached", artifact );
181 }
182
183 if ( !systemFile.exists() )
184 {
185 throw new ArtifactNotFoundException( "System artifact: " + artifact + " not found in path: " + systemFile, artifact );
186 }
187
188 if ( !systemFile.isFile() )
189 {
190 throw new ArtifactNotFoundException( "System artifact: " + artifact + " is not a file: " + systemFile, artifact );
191 }
192
193 artifact.setResolved( true );
194
195 return;
196 }
197
198 if ( !artifact.isResolved() )
199 {
200 ArtifactResult result;
201
202 try
203 {
204 ArtifactRequest artifactRequest = new ArtifactRequest();
205 artifactRequest.setArtifact( RepositoryUtils.toArtifact( artifact ) );
206 artifactRequest.setRepositories( RepositoryUtils.toRepos( remoteRepositories ) );
207
208
209 LocalRepositoryManager lrm = session.getLocalRepositoryManager();
210 String path = lrm.getPathForLocalArtifact( artifactRequest.getArtifact() );
211 artifact.setFile( new File( lrm.getRepository().getBasedir(), path ) );
212
213 result = repoSystem.resolveArtifact( session, artifactRequest );
214 }
215 catch ( org.sonatype.aether.resolution.ArtifactResolutionException e )
216 {
217 if ( e.getCause() instanceof org.sonatype.aether.transfer.ArtifactNotFoundException )
218 {
219 throw new ArtifactNotFoundException( e.getMessage(), artifact, remoteRepositories, e );
220 }
221 else
222 {
223 throw new ArtifactResolutionException( e.getMessage(), artifact, remoteRepositories, e );
224 }
225 }
226
227 artifact.selectVersion( result.getArtifact().getVersion() );
228 artifact.setFile( result.getArtifact().getFile() );
229 artifact.setResolved( true );
230
231 if ( artifact.isSnapshot() )
232 {
233 Matcher matcher = Artifact.VERSION_FILE_PATTERN.matcher( artifact.getVersion() );
234 if ( matcher.matches() )
235 {
236 Snapshot snapshot = new Snapshot();
237 snapshot.setTimestamp( matcher.group( 2 ) );
238 try
239 {
240 snapshot.setBuildNumber( Integer.parseInt( matcher.group( 3 ) ) );
241 artifact.addMetadata( new SnapshotArtifactRepositoryMetadata( artifact, snapshot ) );
242 }
243 catch ( NumberFormatException e )
244 {
245 logger.warn( "Invalid artifact version " + artifact.getVersion() + ": " + e.getMessage() );
246 }
247 }
248 }
249 }
250 }
251
252 public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact, ArtifactRepository localRepository, List<ArtifactRepository> remoteRepositories,
253 ArtifactMetadataSource source, ArtifactFilter filter )
254 throws ArtifactResolutionException, ArtifactNotFoundException
255 {
256 return resolveTransitively( artifacts, originatingArtifact, Collections.EMPTY_MAP, localRepository, remoteRepositories, source, filter );
257
258 }
259
260 public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact, Map managedVersions, ArtifactRepository localRepository,
261 List<ArtifactRepository> remoteRepositories, ArtifactMetadataSource source )
262 throws ArtifactResolutionException, ArtifactNotFoundException
263 {
264 return resolveTransitively( artifacts, originatingArtifact, managedVersions, localRepository, remoteRepositories, source, null );
265 }
266
267 public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact, Map managedVersions, ArtifactRepository localRepository,
268 List<ArtifactRepository> remoteRepositories, ArtifactMetadataSource source, ArtifactFilter filter )
269 throws ArtifactResolutionException, ArtifactNotFoundException
270 {
271 return resolveTransitively( artifacts, originatingArtifact, managedVersions, localRepository, remoteRepositories, source, filter, null );
272 }
273
274 public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact, List<ArtifactRepository> remoteRepositories, ArtifactRepository localRepository,
275 ArtifactMetadataSource source )
276 throws ArtifactResolutionException, ArtifactNotFoundException
277 {
278 return resolveTransitively( artifacts, originatingArtifact, localRepository, remoteRepositories, source, null );
279 }
280
281 public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact, List<ArtifactRepository> remoteRepositories, ArtifactRepository localRepository,
282 ArtifactMetadataSource source, List<ResolutionListener> listeners )
283 throws ArtifactResolutionException, ArtifactNotFoundException
284 {
285 return resolveTransitively( artifacts, originatingArtifact, Collections.EMPTY_MAP, localRepository,
286 remoteRepositories, source, null, listeners );
287 }
288
289 public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact, Map managedVersions, ArtifactRepository localRepository,
290 List<ArtifactRepository> remoteRepositories, ArtifactMetadataSource source, ArtifactFilter filter, List<ResolutionListener> listeners )
291 throws ArtifactResolutionException, ArtifactNotFoundException
292 {
293 return resolveTransitively( artifacts, originatingArtifact, managedVersions, localRepository, remoteRepositories, source, filter, listeners, null );
294 }
295
296 public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact, Map managedVersions, ArtifactRepository localRepository,
297 List<ArtifactRepository> remoteRepositories, ArtifactMetadataSource source, ArtifactFilter filter, List<ResolutionListener> listeners,
298 List<ConflictResolver> conflictResolvers )
299 throws ArtifactResolutionException, ArtifactNotFoundException
300 {
301 ArtifactResolutionRequest request = new ArtifactResolutionRequest()
302 .setArtifact( originatingArtifact )
303 .setResolveRoot( false )
304
305 .setArtifactDependencies( artifacts )
306 .setManagedVersionMap( managedVersions )
307 .setLocalRepository( localRepository )
308 .setRemoteRepositories( remoteRepositories )
309 .setCollectionFilter( filter )
310 .setListeners( listeners );
311
312 injectSession2( request, legacySupport.getSession() );
313
314 return resolveWithExceptions( request );
315 }
316
317 public ArtifactResolutionResult resolveWithExceptions( ArtifactResolutionRequest request )
318 throws ArtifactResolutionException, ArtifactNotFoundException
319 {
320 ArtifactResolutionResult result = resolve( request );
321
322
323
324
325
326 resolutionErrorHandler.throwErrors( request, result );
327
328 return result;
329 }
330
331
332
333
334
335 public ArtifactResolutionResult resolve( ArtifactResolutionRequest request )
336 {
337 Artifact rootArtifact = request.getArtifact();
338 Set<Artifact> artifacts = request.getArtifactDependencies();
339 Map managedVersions = request.getManagedVersionMap();
340 List<ResolutionListener> listeners = request.getListeners();
341 ArtifactFilter collectionFilter = request.getCollectionFilter();
342 ArtifactFilter resolutionFilter = request.getResolutionFilter();
343 RepositorySystemSession session = getSession( request.getLocalRepository() );
344
345
346 if ( source == null )
347 {
348 try
349 {
350 source = container.lookup( ArtifactMetadataSource.class );
351 }
352 catch ( ComponentLookupException e )
353 {
354
355 }
356 }
357
358 if ( listeners == null )
359 {
360 listeners = new ArrayList<ResolutionListener>();
361
362 if ( logger.isDebugEnabled() )
363 {
364 listeners.add( new DebugResolutionListener( logger ) );
365 }
366
367 listeners.add( new WarningResolutionListener( logger ) );
368 }
369
370 ArtifactResolutionResult result = new ArtifactResolutionResult();
371
372
373
374
375
376
377 if ( request.isResolveRoot()
378 {
379 try
380 {
381 resolve( rootArtifact, request.getRemoteRepositories(), session );
382 }
383 catch ( ArtifactResolutionException e )
384 {
385 result.addErrorArtifactException( e );
386 return result;
387 }
388 catch ( ArtifactNotFoundException e )
389 {
390 result.addMissingArtifact( request.getArtifact() );
391 return result;
392 }
393 }
394
395 ArtifactResolutionRequest collectionRequest = request;
396
397 if ( request.isResolveTransitively() )
398 {
399 MetadataResolutionRequest metadataRequest = new DefaultMetadataResolutionRequest( request );
400
401 metadataRequest.setArtifact( rootArtifact );
402 metadataRequest.setResolveManagedVersions( managedVersions == null );
403
404 try
405 {
406 ResolutionGroup resolutionGroup = source.retrieve( metadataRequest );
407
408 if ( managedVersions == null )
409 {
410 managedVersions = resolutionGroup.getManagedVersions();
411 }
412
413 Set<Artifact> directArtifacts = resolutionGroup.getArtifacts();
414
415 if ( artifacts == null || artifacts.isEmpty() )
416 {
417 artifacts = directArtifacts;
418 }
419 else
420 {
421 List<Artifact> allArtifacts = new ArrayList<Artifact>();
422 allArtifacts.addAll( artifacts );
423 allArtifacts.addAll( directArtifacts );
424
425 Map<String, Artifact> mergedArtifacts = new LinkedHashMap<String, Artifact>();
426 for ( Artifact artifact : allArtifacts )
427 {
428 String conflictId = artifact.getDependencyConflictId();
429 if ( !mergedArtifacts.containsKey( conflictId ) )
430 {
431 mergedArtifacts.put( conflictId, artifact );
432 }
433 }
434
435 artifacts = new LinkedHashSet<Artifact>( mergedArtifacts.values() );
436 }
437
438 collectionRequest = new ArtifactResolutionRequest( request );
439 collectionRequest.setServers( request.getServers() );
440 collectionRequest.setMirrors( request.getMirrors() );
441 collectionRequest.setProxies( request.getProxies() );
442 collectionRequest.setRemoteRepositories( resolutionGroup.getResolutionRepositories() );
443 }
444 catch ( ArtifactMetadataRetrievalException e )
445 {
446 ArtifactResolutionException are =
447 new ArtifactResolutionException( "Unable to get dependency information for " + rootArtifact.getId()
448 + ": " + e.getMessage(), rootArtifact, metadataRequest.getRemoteRepositories(), e );
449 result.addMetadataResolutionException( are );
450 return result;
451 }
452 }
453
454 if ( artifacts == null || artifacts.isEmpty() )
455 {
456 if ( request.isResolveRoot() )
457 {
458 result.addArtifact( rootArtifact );
459 }
460 return result;
461 }
462
463
464 result =
465 artifactCollector.collect( artifacts, rootArtifact, managedVersions, collectionRequest, source,
466 collectionFilter, listeners, null );
467
468
469
470
471
472 if ( result.hasMetadataResolutionExceptions() || result.hasVersionRangeViolations() || result.hasCircularDependencyExceptions() )
473 {
474 return result;
475 }
476
477 if ( result.getArtifactResolutionNodes() != null )
478 {
479 ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
480
481 CountDownLatch latch = new CountDownLatch( result.getArtifactResolutionNodes().size() );
482
483 for ( ResolutionNode node : result.getArtifactResolutionNodes() )
484 {
485 Artifact artifact = node.getArtifact();
486
487 if ( resolutionFilter == null || resolutionFilter.include( artifact ) )
488 {
489 executor.execute( new ResolveTask( classLoader, latch, artifact, session,
490 node.getRemoteRepositories(), result ) );
491 }
492 else
493 {
494 latch.countDown();
495 }
496 }
497 try
498 {
499 latch.await();
500 }
501 catch ( InterruptedException e )
502 {
503 result.addErrorArtifactException( new ArtifactResolutionException( "Resolution interrupted",
504 rootArtifact, e ) );
505 }
506 }
507
508
509
510 if ( request.isResolveRoot() )
511 {
512
513 Set<Artifact> allArtifacts = new LinkedHashSet<Artifact>();
514 allArtifacts.add( rootArtifact );
515 allArtifacts.addAll( result.getArtifacts() );
516 result.setArtifacts( allArtifacts );
517 }
518
519 return result;
520 }
521
522 public void resolve( Artifact artifact, List<ArtifactRepository> remoteRepositories, ArtifactRepository localRepository )
523 throws ArtifactResolutionException, ArtifactNotFoundException
524 {
525 resolve( artifact, remoteRepositories, localRepository, null );
526 }
527
528
529
530
531 final static class DaemonThreadCreator
532 implements ThreadFactory
533 {
534 static final String THREADGROUP_NAME = "org.apache.maven.artifact.resolver.DefaultArtifactResolver";
535
536 final static ThreadGroup group = new ThreadGroup( THREADGROUP_NAME );
537
538 final static AtomicInteger threadNumber = new AtomicInteger( 1 );
539
540 public Thread newThread( Runnable r )
541 {
542 Thread newThread = new Thread( group, r, "resolver-" + threadNumber.getAndIncrement() );
543 newThread.setDaemon( true );
544 return newThread;
545 }
546 }
547
548 private class ResolveTask
549 implements Runnable
550 {
551
552 private final ClassLoader classLoader;
553
554 private final CountDownLatch latch;
555
556 private final Artifact artifact;
557
558 private final RepositorySystemSession session;
559
560 private final List<ArtifactRepository> remoteRepositories;
561
562 private final ArtifactResolutionResult result;
563
564 public ResolveTask( ClassLoader classLoader, CountDownLatch latch, Artifact artifact, RepositorySystemSession session,
565 List<ArtifactRepository> remoteRepositories, ArtifactResolutionResult result )
566 {
567 this.classLoader = classLoader;
568 this.latch = latch;
569 this.artifact = artifact;
570 this.session = session;
571 this.remoteRepositories = remoteRepositories;
572 this.result = result;
573 }
574
575 public void run()
576 {
577 try
578 {
579 Thread.currentThread().setContextClassLoader( classLoader );
580 resolve( artifact, remoteRepositories, session );
581 }
582 catch ( ArtifactNotFoundException anfe )
583 {
584
585
586
587 synchronized ( result )
588 {
589 result.addMissingArtifact( artifact );
590 }
591 }
592 catch ( ArtifactResolutionException e )
593 {
594
595
596
597 synchronized ( result )
598 {
599 result.addErrorArtifactException( e );
600 }
601 }
602 finally
603 {
604 latch.countDown();
605 }
606 }
607
608 }
609
610 }