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 org.apache.maven.artifact.Artifact;
23 import org.apache.maven.artifact.metadata.ArtifactMetadataRetrievalException;
24 import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
25 import org.apache.maven.artifact.metadata.ResolutionGroup;
26 import org.apache.maven.artifact.repository.ArtifactRepository;
27 import org.apache.maven.artifact.resolver.filter.AndArtifactFilter;
28 import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
29 import org.apache.maven.artifact.versioning.ArtifactVersion;
30 import org.apache.maven.artifact.versioning.ManagedVersionMap;
31 import org.apache.maven.artifact.versioning.OverConstrainedVersionException;
32 import org.apache.maven.artifact.versioning.VersionRange;
33
34 import java.util.ArrayList;
35 import java.util.Collections;
36 import java.util.Iterator;
37 import java.util.LinkedHashMap;
38 import java.util.LinkedHashSet;
39 import java.util.List;
40 import java.util.Map;
41 import java.util.Set;
42
43
44
45
46
47
48
49 public class DefaultArtifactCollector
50 implements ArtifactCollector
51 {
52 public ArtifactResolutionResult collect( Set artifacts, Artifact originatingArtifact,
53 ArtifactRepository localRepository, List remoteRepositories,
54 ArtifactMetadataSource source, ArtifactFilter filter, List listeners )
55 throws ArtifactResolutionException
56 {
57 return collect( artifacts, originatingArtifact, Collections.EMPTY_MAP, localRepository, remoteRepositories,
58 source, filter, listeners );
59 }
60
61 public ArtifactResolutionResult collect( Set artifacts, Artifact originatingArtifact, Map managedVersions,
62 ArtifactRepository localRepository, List remoteRepositories,
63 ArtifactMetadataSource source, ArtifactFilter filter, List listeners )
64 throws ArtifactResolutionException
65 {
66 Map resolvedArtifacts = new LinkedHashMap();
67
68 ResolutionNode root = new ResolutionNode( originatingArtifact, remoteRepositories );
69
70 root.addDependencies( artifacts, remoteRepositories, filter );
71
72 ManagedVersionMap versionMap = getManagedVersionsMap( originatingArtifact, managedVersions );
73
74 recurse( originatingArtifact, root, resolvedArtifacts, versionMap, localRepository, remoteRepositories, source, filter,
75 listeners );
76
77 Set set = new LinkedHashSet();
78
79 for ( Iterator i = resolvedArtifacts.values().iterator(); i.hasNext(); )
80 {
81 List nodes = (List) i.next();
82 for ( Iterator j = nodes.iterator(); j.hasNext(); )
83 {
84 ResolutionNode node = (ResolutionNode) j.next();
85 if ( !node.equals( root ) && node.isActive() )
86 {
87 Artifact artifact = node.getArtifact();
88
89 if ( node.filterTrail( filter ) )
90 {
91
92
93 if ( node.isChildOfRootNode() || !artifact.isOptional() )
94 {
95 artifact.setDependencyTrail( node.getDependencyTrail() );
96
97 set.add( node );
98 }
99 }
100 }
101 }
102 }
103
104 ArtifactResolutionResult result = new ArtifactResolutionResult();
105 result.setArtifactResolutionNodes( set );
106 return result;
107 }
108
109
110
111
112
113
114 private ManagedVersionMap getManagedVersionsMap( Artifact originatingArtifact, Map managedVersions )
115 {
116 ManagedVersionMap versionMap;
117 if ( managedVersions != null && managedVersions instanceof ManagedVersionMap )
118 {
119 versionMap = (ManagedVersionMap) managedVersions;
120 }
121 else
122 {
123 versionMap = new ManagedVersionMap( managedVersions );
124 }
125
126
127 Artifact managedOriginatingArtifact = (Artifact) versionMap.get( originatingArtifact.getDependencyConflictId() );
128 if ( managedOriginatingArtifact != null )
129 {
130
131
132 if ( managedVersions instanceof ManagedVersionMap )
133 {
134
135 versionMap = new ManagedVersionMap( managedVersions );
136 }
137 versionMap.remove( originatingArtifact.getDependencyConflictId() );
138 }
139
140 return versionMap;
141 }
142
143 private void recurse( Artifact originatingArtifact, ResolutionNode node, Map resolvedArtifacts, ManagedVersionMap managedVersions,
144 ArtifactRepository localRepository, List remoteRepositories, ArtifactMetadataSource source,
145 ArtifactFilter filter, List listeners )
146 throws CyclicDependencyException, ArtifactResolutionException, OverConstrainedVersionException
147 {
148 fireEvent( ResolutionListener.TEST_ARTIFACT, listeners, node );
149
150 Object key = node.getKey();
151
152
153
154 if ( managedVersions.containsKey( key ))
155 {
156 manageArtifact( node, managedVersions, listeners );
157 }
158
159 List previousNodes = (List) resolvedArtifacts.get( key );
160 if ( previousNodes != null )
161 {
162 for ( Iterator i = previousNodes.iterator(); i.hasNext(); )
163 {
164 ResolutionNode previous = (ResolutionNode) i.next();
165
166 if ( previous.isActive() )
167 {
168
169 VersionRange previousRange = previous.getArtifact().getVersionRange();
170 VersionRange currentRange = node.getArtifact().getVersionRange();
171
172 if ( previousRange != null && currentRange != null )
173 {
174
175
176 VersionRange newRange = previousRange.restrict( currentRange );
177
178 if ( newRange.isSelectedVersionKnown( previous.getArtifact() ) )
179 {
180 fireEvent( ResolutionListener.RESTRICT_RANGE, listeners, node, previous.getArtifact(),
181 newRange );
182 }
183 previous.getArtifact().setVersionRange( newRange );
184 node.getArtifact().setVersionRange( currentRange.restrict( previousRange ) );
185
186
187
188
189 ResolutionNode[] resetNodes = {previous, node};
190 for ( int j = 0; j < 2; j++ )
191 {
192 Artifact resetArtifact = resetNodes[j].getArtifact();
193
194
195
196
197 if ( resetArtifact.getVersion() == null && resetArtifact.getVersionRange() != null )
198 {
199
200
201 List versions = resetArtifact.getAvailableVersions();
202 if ( versions == null )
203 {
204 try
205 {
206 versions =
207 source.retrieveAvailableVersions( resetArtifact, localRepository,
208 remoteRepositories );
209 resetArtifact.setAvailableVersions( versions );
210 }
211 catch ( ArtifactMetadataRetrievalException e )
212 {
213 resetArtifact.setDependencyTrail( node.getDependencyTrail() );
214 throw new ArtifactResolutionException(
215 "Unable to get dependency information: " +
216 e.getMessage(), resetArtifact,
217 remoteRepositories, e );
218 }
219 }
220
221
222
223 ArtifactVersion selectedVersion = resetArtifact.getVersionRange().matchVersion( resetArtifact.getAvailableVersions() );
224 if (selectedVersion != null)
225 {
226 resetArtifact.selectVersion( selectedVersion.toString() );
227 }
228 else
229 {
230 throw new OverConstrainedVersionException(" Unable to find a version in "+ resetArtifact.getAvailableVersions()+" to match the range "+ resetArtifact.getVersionRange(), resetArtifact);
231 }
232
233 fireEvent( ResolutionListener.SELECT_VERSION_FROM_RANGE, listeners, resetNodes[j] );
234 }
235 }
236 }
237
238
239
240
241
242
243 ResolutionNode nearest;
244 ResolutionNode farthest;
245 if ( previous.getDepth() <= node.getDepth() )
246 {
247 nearest = previous;
248 farthest = node;
249 }
250 else
251 {
252 nearest = node;
253 farthest = previous;
254 }
255
256 if ( checkScopeUpdate( farthest, nearest, listeners ) )
257 {
258
259 nearest.disable();
260 farthest.getArtifact().setVersion( nearest.getArtifact().getVersion() );
261 fireEvent( ResolutionListener.OMIT_FOR_NEARER, listeners, nearest, farthest.getArtifact() );
262 }
263 else
264 {
265 farthest.disable();
266 fireEvent( ResolutionListener.OMIT_FOR_NEARER, listeners, farthest, nearest.getArtifact() );
267 }
268 }
269 }
270 }
271 else
272 {
273 previousNodes = new ArrayList();
274 resolvedArtifacts.put( key, previousNodes );
275 }
276 previousNodes.add( node );
277
278 if ( node.isActive() )
279 {
280 fireEvent( ResolutionListener.INCLUDE_ARTIFACT, listeners, node );
281 }
282
283
284 if ( node.isActive() && !Artifact.SCOPE_SYSTEM.equals( node.getArtifact().getScope() ) )
285 {
286 fireEvent( ResolutionListener.PROCESS_CHILDREN, listeners, node );
287
288 Artifact parentArtifact = node.getArtifact();
289
290 for ( Iterator i = node.getChildrenIterator(); i.hasNext(); )
291 {
292 ResolutionNode child = (ResolutionNode) i.next();
293
294
295 if ( !child.isResolved() && ( !child.getArtifact().isOptional() || child.isChildOfRootNode() ) )
296 {
297 Artifact artifact = child.getArtifact();
298 artifact.setDependencyTrail( node.getDependencyTrail() );
299
300 List childRemoteRepositories = child.getRemoteRepositories();
301 try
302 {
303 Object childKey;
304 do
305 {
306 childKey = child.getKey();
307
308 if ( managedVersions.containsKey( childKey ) )
309 {
310
311
312
313
314
315 manageArtifact( child, managedVersions, listeners );
316
317
318
319
320
321 Artifact ma = (Artifact) managedVersions.get( childKey );
322 ArtifactFilter managedExclusionFilter = ma.getDependencyFilter();
323 if ( null != managedExclusionFilter )
324 {
325 if ( null != artifact.getDependencyFilter() )
326 {
327 AndArtifactFilter aaf = new AndArtifactFilter();
328 aaf.add( artifact.getDependencyFilter() );
329 aaf.add( managedExclusionFilter );
330 artifact.setDependencyFilter( aaf );
331 }
332 else
333 {
334 artifact.setDependencyFilter( managedExclusionFilter );
335 }
336 }
337 }
338
339 if ( artifact.getVersion() == null )
340 {
341
342
343 ArtifactVersion version;
344 if ( artifact.isSelectedVersionKnown() )
345 {
346 version = artifact.getSelectedVersion();
347 }
348 else
349 {
350
351 List versions = artifact.getAvailableVersions();
352 if ( versions == null )
353 {
354 versions = source.retrieveAvailableVersions( artifact, localRepository,
355 childRemoteRepositories );
356 artifact.setAvailableVersions( versions );
357 }
358
359 Collections.sort( versions );
360
361 VersionRange versionRange = artifact.getVersionRange();
362
363 version = versionRange.matchVersion( versions );
364
365 if ( version == null )
366 {
367 if ( versions.isEmpty() )
368 {
369 throw new OverConstrainedVersionException(
370 "No versions are present in the repository for the artifact with a range " +
371 versionRange, artifact, childRemoteRepositories );
372 }
373
374 throw new OverConstrainedVersionException( "Couldn't find a version in " +
375 versions + " to match range " + versionRange, artifact,
376 childRemoteRepositories );
377 }
378 }
379
380
381
382
383 artifact.selectVersion( version.toString() );
384 fireEvent( ResolutionListener.SELECT_VERSION_FROM_RANGE, listeners, child );
385 }
386
387 Artifact relocated = source.retrieveRelocatedArtifact( artifact, localRepository, childRemoteRepositories );
388 if ( relocated != null && !artifact.equals( relocated ) )
389 {
390 relocated.setDependencyFilter( artifact.getDependencyFilter() );
391 artifact = relocated;
392 child.setArtifact( artifact );
393 }
394 }
395 while( !childKey.equals( child.getKey() ) );
396
397 if ( parentArtifact != null && parentArtifact.getDependencyFilter() != null && !parentArtifact.getDependencyFilter().include( artifact ) )
398 {
399
400
401
402
403
404 continue;
405 }
406
407 ResolutionGroup rGroup = source.retrieve( artifact, localRepository, childRemoteRepositories );
408
409
410
411 if ( rGroup == null )
412 {
413
414 continue;
415 }
416
417 child.addDependencies( rGroup.getArtifacts(), rGroup.getResolutionRepositories(), filter );
418
419 }
420 catch ( CyclicDependencyException e )
421 {
422
423
424 fireEvent( ResolutionListener.OMIT_FOR_CYCLE, listeners,
425 new ResolutionNode( e.getArtifact(), childRemoteRepositories, child ) );
426 }
427 catch ( ArtifactMetadataRetrievalException e )
428 {
429 artifact.setDependencyTrail( node.getDependencyTrail() );
430 throw new ArtifactResolutionException(
431 "Unable to get dependency information: " + e.getMessage(), artifact, childRemoteRepositories,
432 e );
433 }
434
435 recurse( originatingArtifact, child, resolvedArtifacts, managedVersions, localRepository, childRemoteRepositories, source,
436 filter, listeners );
437 }
438 }
439
440 fireEvent( ResolutionListener.FINISH_PROCESSING_CHILDREN, listeners, node );
441 }
442 }
443
444 private void manageArtifact( ResolutionNode node, ManagedVersionMap managedVersions, List listeners )
445 {
446 Artifact artifact = (Artifact) managedVersions.get( node.getKey() );
447
448
449
450
451
452
453
454
455 if ( artifact.getVersion() != null
456 && ( node.isChildOfRootNode() ? node.getArtifact().getVersion() == null : true ) )
457 {
458 fireEvent( ResolutionListener.MANAGE_ARTIFACT_VERSION, listeners, node, artifact );
459 node.getArtifact().setVersion( artifact.getVersion() );
460 }
461
462 if ( artifact.getScope() != null
463 && ( node.isChildOfRootNode() ? node.getArtifact().getScope() == null : true ) )
464 {
465 fireEvent( ResolutionListener.MANAGE_ARTIFACT_SCOPE, listeners, node, artifact );
466 node.getArtifact().setScope( artifact.getScope() );
467 }
468 }
469
470
471
472
473
474
475
476
477
478 boolean checkScopeUpdate( ResolutionNode farthest, ResolutionNode nearest, List listeners )
479 {
480 boolean updateScope = false;
481 Artifact farthestArtifact = farthest.getArtifact();
482 Artifact nearestArtifact = nearest.getArtifact();
483
484
485 if ( Artifact.SCOPE_RUNTIME.equals( farthestArtifact.getScope() ) && (
486 Artifact.SCOPE_TEST.equals( nearestArtifact.getScope() ) ||
487 Artifact.SCOPE_PROVIDED.equals( nearestArtifact.getScope() ) ) )
488 {
489 updateScope = true;
490 }
491
492
493 if ( Artifact.SCOPE_COMPILE.equals( farthestArtifact.getScope() ) &&
494 !Artifact.SCOPE_COMPILE.equals( nearestArtifact.getScope() ) )
495 {
496 updateScope = true;
497 }
498
499
500 if ( nearest.getDepth() < 2 && updateScope )
501 {
502 updateScope = false;
503
504 fireEvent( ResolutionListener.UPDATE_SCOPE_CURRENT_POM, listeners, nearest, farthestArtifact );
505 }
506
507 if ( updateScope )
508 {
509 fireEvent( ResolutionListener.UPDATE_SCOPE, listeners, nearest, farthestArtifact );
510
511
512
513
514 nearestArtifact.setScope( farthestArtifact.getScope() );
515 }
516
517 return updateScope;
518 }
519
520 private void fireEvent( int event, List listeners, ResolutionNode node )
521 {
522 fireEvent( event, listeners, node, null );
523 }
524
525 private void fireEvent( int event, List listeners, ResolutionNode node, Artifact replacement )
526 {
527 fireEvent( event, listeners, node, replacement, null );
528 }
529
530 private void fireEvent( int event, List listeners, ResolutionNode node, Artifact replacement,
531 VersionRange newRange )
532 {
533 for ( Iterator i = listeners.iterator(); i.hasNext(); )
534 {
535 ResolutionListener listener = (ResolutionListener) i.next();
536
537 switch ( event )
538 {
539 case ResolutionListener.TEST_ARTIFACT:
540 listener.testArtifact( node.getArtifact() );
541 break;
542 case ResolutionListener.PROCESS_CHILDREN:
543 listener.startProcessChildren( node.getArtifact() );
544 break;
545 case ResolutionListener.FINISH_PROCESSING_CHILDREN:
546 listener.endProcessChildren( node.getArtifact() );
547 break;
548 case ResolutionListener.INCLUDE_ARTIFACT:
549 listener.includeArtifact( node.getArtifact() );
550 break;
551 case ResolutionListener.OMIT_FOR_NEARER:
552 listener.omitForNearer( node.getArtifact(), replacement );
553 break;
554 case ResolutionListener.OMIT_FOR_CYCLE:
555 listener.omitForCycle( node.getArtifact() );
556 break;
557 case ResolutionListener.UPDATE_SCOPE:
558 listener.updateScope( node.getArtifact(), replacement.getScope() );
559 break;
560 case ResolutionListener.UPDATE_SCOPE_CURRENT_POM:
561 listener.updateScopeCurrentPom( node.getArtifact(), replacement.getScope() );
562 break;
563 case ResolutionListener.MANAGE_ARTIFACT_VERSION:
564 if (listener instanceof ResolutionListenerForDepMgmt) {
565 ResolutionListenerForDepMgmt asImpl = (ResolutionListenerForDepMgmt) listener;
566 asImpl.manageArtifactVersion( node.getArtifact(), replacement );
567 } else {
568 listener.manageArtifact( node.getArtifact(), replacement );
569 }
570 break;
571 case ResolutionListener.MANAGE_ARTIFACT_SCOPE:
572 if (listener instanceof ResolutionListenerForDepMgmt) {
573 ResolutionListenerForDepMgmt asImpl = (ResolutionListenerForDepMgmt) listener;
574 asImpl.manageArtifactScope( node.getArtifact(), replacement );
575 } else {
576 listener.manageArtifact( node.getArtifact(), replacement );
577 }
578 break;
579 case ResolutionListener.SELECT_VERSION_FROM_RANGE:
580 listener.selectVersionFromRange( node.getArtifact() );
581 break;
582 case ResolutionListener.RESTRICT_RANGE:
583 if ( node.getArtifact().getVersionRange().hasRestrictions() ||
584 replacement.getVersionRange().hasRestrictions() )
585 {
586 listener.restrictRange( node.getArtifact(), replacement, newRange );
587 }
588 break;
589 default:
590 throw new IllegalStateException( "Unknown event: " + event );
591 }
592 }
593 }
594
595 }