1 package org.apache.maven.shared.dependency.graph.internal.maven30;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.util.ArrayList;
23 import java.util.Collection;
24 import java.util.HashSet;
25 import java.util.Iterator;
26 import java.util.List;
27
28 import org.apache.maven.shared.dependency.graph.internal.maven30.ConflictResolver.ConflictContext;
29 import org.apache.maven.shared.dependency.graph.internal.maven30.ConflictResolver.ConflictItem;
30 import org.apache.maven.shared.dependency.graph.internal.maven30.ConflictResolver.VersionSelector;
31 import org.sonatype.aether.RepositoryException;
32 import org.sonatype.aether.collection.UnsolvableVersionConflictException;
33 import org.sonatype.aether.graph.DependencyFilter;
34 import org.sonatype.aether.graph.DependencyNode;
35 import org.sonatype.aether.util.graph.PathRecordingDependencyVisitor;
36 import org.sonatype.aether.version.Version;
37 import org.sonatype.aether.version.VersionConstraint;
38
39
40
41
42
43
44
45 public final class NearestVersionSelector
46 extends VersionSelector
47 {
48
49 @Override
50 public void selectVersion( ConflictContext context )
51 throws RepositoryException
52 {
53 ConflictGroup group = new ConflictGroup();
54 for ( ConflictItem item : context.getItems() )
55 {
56 DependencyNode node = item.getNode();
57 VersionConstraint constraint = node.getVersionConstraint();
58
59 boolean backtrack = false;
60 boolean hardConstraint = !constraint.getRanges().isEmpty();
61
62
63 if ( hardConstraint )
64 {
65 if ( group.constraints.add( constraint ) )
66 {
67 if ( group.winner != null && !constraint.containsVersion( group.winner.getNode().getVersion() ) )
68 {
69 backtrack = true;
70 }
71 }
72 }
73
74 if ( isAcceptable( group, node.getVersion() ) )
75 {
76 group.candidates.add( item );
77
78 if ( backtrack )
79 {
80 backtrack( group, context );
81 }
82 else if ( group.winner == null || isNearer( item, group.winner ) )
83 {
84 group.winner = item;
85 }
86 }
87 else if ( backtrack )
88 {
89 backtrack( group, context );
90 }
91 }
92 context.setWinner( group.winner );
93 }
94
95 private void backtrack( ConflictGroup group, ConflictContext context )
96 throws UnsolvableVersionConflictException
97 {
98 group.winner = null;
99
100 for ( Iterator<ConflictItem> it = group.candidates.iterator(); it.hasNext(); )
101 {
102 ConflictItem candidate = it.next();
103
104 if ( !isAcceptable( group, candidate.getNode().getVersion() ) )
105 {
106 it.remove();
107 }
108 else if ( group.winner == null || isNearer( candidate, group.winner ) )
109 {
110 group.winner = candidate;
111 }
112 }
113
114 if ( group.winner == null )
115 {
116 throw newFailure( context );
117 }
118 }
119
120 private boolean isAcceptable( ConflictGroup group, Version version )
121 {
122 for ( VersionConstraint constraint : group.constraints )
123 {
124 if ( !constraint.containsVersion( version ) )
125 {
126 return false;
127 }
128 }
129 return true;
130 }
131
132 private boolean isNearer( ConflictItem item1, ConflictItem item2 )
133 {
134 if ( item1.isSibling( item2 ) )
135 {
136 return item1.getNode().getVersion().compareTo( item2.getNode().getVersion() ) > 0;
137 }
138 else
139 {
140 return item1.getDepth() < item2.getDepth();
141 }
142 }
143
144 private UnsolvableVersionConflictException newFailure( final ConflictContext context )
145 {
146 DependencyFilter filter = new DependencyFilter()
147 {
148 public boolean accept( DependencyNode node, List<DependencyNode> parents )
149 {
150 return context.isIncluded( node );
151 }
152 };
153 PathRecordingDependencyVisitor visitor = new PathRecordingDependencyVisitor( filter );
154 context.getRoot().accept( visitor );
155 return new UnsolvableVersionConflictException( visitor.getPaths(), context.conflictId );
156
157 }
158
159 static final class ConflictGroup
160 {
161
162 final Collection<VersionConstraint> constraints;
163
164 final Collection<ConflictItem> candidates;
165
166 ConflictItem winner;
167
168 ConflictGroup()
169 {
170 constraints = new HashSet<VersionConstraint>();
171 candidates = new ArrayList<ConflictItem>( 64 );
172 }
173
174 @Override
175 public String toString()
176 {
177 return String.valueOf( winner );
178 }
179
180 }
181
182
183 }