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 List childRemoteRepositories = child.getRemoteRepositories();
299 try
300 {
301 Object childKey;
302 do
303 {
304 childKey = child.getKey();
305
306 if ( managedVersions.containsKey( childKey ) )
307 {
308
309
310
311
312
313 manageArtifact( child, managedVersions, listeners );
314
315
316
317
318
319 Artifact ma = (Artifact) managedVersions.get( childKey );
320 ArtifactFilter managedExclusionFilter = ma.getDependencyFilter();
321 if ( null != managedExclusionFilter )
322 {
323 if ( null != artifact.getDependencyFilter() )
324 {
325 AndArtifactFilter aaf = new AndArtifactFilter();
326 aaf.add( artifact.getDependencyFilter() );
327 aaf.add( managedExclusionFilter );
328 artifact.setDependencyFilter( aaf );
329 }
330 else
331 {
332 artifact.setDependencyFilter( managedExclusionFilter );
333 }
334 }
335 }
336
337 if ( artifact.getVersion() == null )
338 {
339
340
341 ArtifactVersion version;
342 if ( artifact.isSelectedVersionKnown() )
343 {
344 version = artifact.getSelectedVersion();
345 }
346 else
347 {
348
349 List versions = artifact.getAvailableVersions();
350 if ( versions == null )
351 {
352 versions = source.retrieveAvailableVersions( artifact, localRepository,
353 childRemoteRepositories );
354 artifact.setAvailableVersions( versions );
355 }
356
357 Collections.sort( versions );
358
359 VersionRange versionRange = artifact.getVersionRange();
360
361 version = versionRange.matchVersion( versions );
362
363 if ( version == null )
364 {
365
366 artifact.setDependencyTrail( node.getDependencyTrail() );
367
368 if ( versions.isEmpty() )
369 {
370 throw new OverConstrainedVersionException(
371 "No versions are present in the repository for the artifact with a range " +
372 versionRange, artifact, childRemoteRepositories );
373 }
374
375 throw new OverConstrainedVersionException( "Couldn't find a version in " +
376 versions + " to match range " + versionRange, artifact,
377 childRemoteRepositories );
378 }
379 }
380
381
382
383
384 artifact.selectVersion( version.toString() );
385 fireEvent( ResolutionListener.SELECT_VERSION_FROM_RANGE, listeners, child );
386 }
387
388 Artifact relocated = source.retrieveRelocatedArtifact( artifact, localRepository, childRemoteRepositories );
389 if ( relocated != null && !artifact.equals( relocated ) )
390 {
391 relocated.setDependencyFilter( artifact.getDependencyFilter() );
392 artifact = relocated;
393 child.setArtifact( artifact );
394 }
395 }
396 while( !childKey.equals( child.getKey() ) );
397
398 if ( parentArtifact != null && parentArtifact.getDependencyFilter() != null && !parentArtifact.getDependencyFilter().include( artifact ) )
399 {
400
401
402
403
404
405 continue;
406 }
407
408 artifact.setDependencyTrail( node.getDependencyTrail() );
409 ResolutionGroup rGroup = source.retrieve( artifact, localRepository, childRemoteRepositories );
410
411
412
413 if ( rGroup == null )
414 {
415
416 continue;
417 }
418
419 child.addDependencies( rGroup.getArtifacts(), rGroup.getResolutionRepositories(), filter );
420
421 }
422 catch ( CyclicDependencyException e )
423 {
424
425
426 fireEvent( ResolutionListener.OMIT_FOR_CYCLE, listeners,
427 new ResolutionNode( e.getArtifact(), childRemoteRepositories, child ) );
428 }
429 catch ( ArtifactMetadataRetrievalException e )
430 {
431 artifact.setDependencyTrail( node.getDependencyTrail() );
432 throw new ArtifactResolutionException(
433 "Unable to get dependency information: " + e.getMessage(), artifact, childRemoteRepositories,
434 e );
435 }
436
437 recurse( originatingArtifact, child, resolvedArtifacts, managedVersions, localRepository, childRemoteRepositories, source,
438 filter, listeners );
439 }
440 }
441
442 fireEvent( ResolutionListener.FINISH_PROCESSING_CHILDREN, listeners, node );
443 }
444 }
445
446 private void manageArtifact( ResolutionNode node, ManagedVersionMap managedVersions, List listeners )
447 {
448 Artifact artifact = (Artifact) managedVersions.get( node.getKey() );
449
450
451
452
453
454
455
456
457 if ( artifact.getVersion() != null
458 && ( node.isChildOfRootNode() ? node.getArtifact().getVersion() == null : true ) )
459 {
460 fireEvent( ResolutionListener.MANAGE_ARTIFACT_VERSION, listeners, node, artifact );
461 node.getArtifact().setVersion( artifact.getVersion() );
462 }
463
464 if ( artifact.getScope() != null
465 && ( node.isChildOfRootNode() ? node.getArtifact().getScope() == null : true ) )
466 {
467 fireEvent( ResolutionListener.MANAGE_ARTIFACT_SCOPE, listeners, node, artifact );
468 node.getArtifact().setScope( artifact.getScope() );
469 }
470 }
471
472
473
474
475
476
477
478
479
480 boolean checkScopeUpdate( ResolutionNode farthest, ResolutionNode nearest, List listeners )
481 {
482 boolean updateScope = false;
483 Artifact farthestArtifact = farthest.getArtifact();
484 Artifact nearestArtifact = nearest.getArtifact();
485
486
487 if ( Artifact.SCOPE_RUNTIME.equals( farthestArtifact.getScope() ) && (
488 Artifact.SCOPE_TEST.equals( nearestArtifact.getScope() ) ||
489 Artifact.SCOPE_PROVIDED.equals( nearestArtifact.getScope() ) ) )
490 {
491 updateScope = true;
492 }
493
494
495 if ( Artifact.SCOPE_COMPILE.equals( farthestArtifact.getScope() ) &&
496 !Artifact.SCOPE_COMPILE.equals( nearestArtifact.getScope() ) )
497 {
498 updateScope = true;
499 }
500
501
502 if ( nearest.getDepth() < 2 && updateScope )
503 {
504 updateScope = false;
505
506 fireEvent( ResolutionListener.UPDATE_SCOPE_CURRENT_POM, listeners, nearest, farthestArtifact );
507 }
508
509 if ( updateScope )
510 {
511 fireEvent( ResolutionListener.UPDATE_SCOPE, listeners, nearest, farthestArtifact );
512
513
514
515
516 nearestArtifact.setScope( farthestArtifact.getScope() );
517 }
518
519 return updateScope;
520 }
521
522 private void fireEvent( int event, List listeners, ResolutionNode node )
523 {
524 fireEvent( event, listeners, node, null );
525 }
526
527 private void fireEvent( int event, List listeners, ResolutionNode node, Artifact replacement )
528 {
529 fireEvent( event, listeners, node, replacement, null );
530 }
531
532 private void fireEvent( int event, List listeners, ResolutionNode node, Artifact replacement,
533 VersionRange newRange )
534 {
535 for ( Iterator i = listeners.iterator(); i.hasNext(); )
536 {
537 ResolutionListener listener = (ResolutionListener) i.next();
538
539 switch ( event )
540 {
541 case ResolutionListener.TEST_ARTIFACT:
542 listener.testArtifact( node.getArtifact() );
543 break;
544 case ResolutionListener.PROCESS_CHILDREN:
545 listener.startProcessChildren( node.getArtifact() );
546 break;
547 case ResolutionListener.FINISH_PROCESSING_CHILDREN:
548 listener.endProcessChildren( node.getArtifact() );
549 break;
550 case ResolutionListener.INCLUDE_ARTIFACT:
551 listener.includeArtifact( node.getArtifact() );
552 break;
553 case ResolutionListener.OMIT_FOR_NEARER:
554 listener.omitForNearer( node.getArtifact(), replacement );
555 break;
556 case ResolutionListener.OMIT_FOR_CYCLE:
557 listener.omitForCycle( node.getArtifact() );
558 break;
559 case ResolutionListener.UPDATE_SCOPE:
560 listener.updateScope( node.getArtifact(), replacement.getScope() );
561 break;
562 case ResolutionListener.UPDATE_SCOPE_CURRENT_POM:
563 listener.updateScopeCurrentPom( node.getArtifact(), replacement.getScope() );
564 break;
565 case ResolutionListener.MANAGE_ARTIFACT_VERSION:
566 if (listener instanceof ResolutionListenerForDepMgmt) {
567 ResolutionListenerForDepMgmt asImpl = (ResolutionListenerForDepMgmt) listener;
568 asImpl.manageArtifactVersion( node.getArtifact(), replacement );
569 } else {
570 listener.manageArtifact( node.getArtifact(), replacement );
571 }
572 break;
573 case ResolutionListener.MANAGE_ARTIFACT_SCOPE:
574 if (listener instanceof ResolutionListenerForDepMgmt) {
575 ResolutionListenerForDepMgmt asImpl = (ResolutionListenerForDepMgmt) listener;
576 asImpl.manageArtifactScope( node.getArtifact(), replacement );
577 } else {
578 listener.manageArtifact( node.getArtifact(), replacement );
579 }
580 break;
581 case ResolutionListener.SELECT_VERSION_FROM_RANGE:
582 listener.selectVersionFromRange( node.getArtifact() );
583 break;
584 case ResolutionListener.RESTRICT_RANGE:
585 if ( node.getArtifact().getVersionRange().hasRestrictions() ||
586 replacement.getVersionRange().hasRestrictions() )
587 {
588 listener.restrictRange( node.getArtifact(), replacement, newRange );
589 }
590 break;
591 default:
592 throw new IllegalStateException( "Unknown event: " + event );
593 }
594 }
595 }
596
597 }