1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.aether.util.graph.transformer;
20
21 import java.util.Collection;
22 import java.util.Collections;
23 import java.util.HashMap;
24 import java.util.HashSet;
25 import java.util.IdentityHashMap;
26 import java.util.Map;
27 import java.util.Set;
28
29 import org.eclipse.aether.RepositoryException;
30 import org.eclipse.aether.artifact.Artifact;
31 import org.eclipse.aether.collection.DependencyGraphTransformationContext;
32 import org.eclipse.aether.collection.DependencyGraphTransformer;
33 import org.eclipse.aether.graph.Dependency;
34 import org.eclipse.aether.graph.DependencyNode;
35
36 import static java.util.Objects.requireNonNull;
37
38
39
40
41
42
43
44 public final class ConflictMarker implements DependencyGraphTransformer {
45
46
47
48
49
50
51
52 public DependencyNode transformGraph(DependencyNode node, DependencyGraphTransformationContext context)
53 throws RepositoryException {
54 requireNonNull(node, "node cannot be null");
55 requireNonNull(context, "context cannot be null");
56 @SuppressWarnings("unchecked")
57 Map<String, Object> stats = (Map<String, Object>) context.get(TransformationContextKeys.STATS);
58 long time1 = System.nanoTime();
59
60 Map<DependencyNode, Object> nodes = new IdentityHashMap<>(1024);
61 Map<Object, ConflictGroup> groups = new HashMap<>(1024);
62
63 analyze(node, nodes, groups, new int[] {0});
64
65 long time2 = System.nanoTime();
66
67 Map<DependencyNode, Object> conflictIds = mark(nodes.keySet(), groups);
68
69 context.put(TransformationContextKeys.CONFLICT_IDS, conflictIds);
70
71 if (stats != null) {
72 long time3 = System.nanoTime();
73 stats.put("ConflictMarker.analyzeTime", time2 - time1);
74 stats.put("ConflictMarker.markTime", time3 - time2);
75 stats.put("ConflictMarker.nodeCount", nodes.size());
76 }
77
78 return node;
79 }
80
81 private void analyze(
82 DependencyNode node, Map<DependencyNode, Object> nodes, Map<Object, ConflictGroup> groups, int[] counter) {
83 if (nodes.put(node, Boolean.TRUE) != null) {
84 return;
85 }
86
87 Set<Object> keys = getKeys(node);
88 if (!keys.isEmpty()) {
89 ConflictGroup group = null;
90 boolean fixMappings = false;
91
92 for (Object key : keys) {
93 ConflictGroup g = groups.get(key);
94
95 if (group != g) {
96 if (group == null) {
97 Set<Object> newKeys = merge(g.keys, keys);
98 if (newKeys == g.keys) {
99 group = g;
100 break;
101 } else {
102 group = new ConflictGroup(newKeys, counter[0]++);
103 fixMappings = true;
104 }
105 } else if (g == null) {
106 fixMappings = true;
107 } else {
108 Set<Object> newKeys = merge(g.keys, group.keys);
109 if (newKeys == g.keys) {
110 group = g;
111 fixMappings = false;
112 break;
113 } else if (newKeys != group.keys) {
114 group = new ConflictGroup(newKeys, counter[0]++);
115 fixMappings = true;
116 }
117 }
118 }
119 }
120
121 if (group == null) {
122 group = new ConflictGroup(keys, counter[0]++);
123 fixMappings = true;
124 }
125 if (fixMappings) {
126 for (Object key : group.keys) {
127 groups.put(key, group);
128 }
129 }
130 }
131
132 for (DependencyNode child : node.getChildren()) {
133 analyze(child, nodes, groups, counter);
134 }
135 }
136
137 private Set<Object> merge(Set<Object> keys1, Set<Object> keys2) {
138 int size1 = keys1.size();
139 int size2 = keys2.size();
140
141 if (size1 < size2) {
142 if (keys2.containsAll(keys1)) {
143 return keys2;
144 }
145 } else {
146 if (keys1.containsAll(keys2)) {
147 return keys1;
148 }
149 }
150
151 Set<Object> keys = new HashSet<>();
152 keys.addAll(keys1);
153 keys.addAll(keys2);
154 return keys;
155 }
156
157 private Set<Object> getKeys(DependencyNode node) {
158 Set<Object> keys;
159
160 Dependency dependency = node.getDependency();
161
162 if (dependency == null) {
163 keys = Collections.emptySet();
164 } else {
165 Object key = toKey(dependency.getArtifact());
166
167 if (node.getRelocations().isEmpty() && node.getAliases().isEmpty()) {
168 keys = Collections.singleton(key);
169 } else {
170 keys = new HashSet<>();
171 keys.add(key);
172
173 for (Artifact relocation : node.getRelocations()) {
174 key = toKey(relocation);
175 keys.add(key);
176 }
177
178 for (Artifact alias : node.getAliases()) {
179 key = toKey(alias);
180 keys.add(key);
181 }
182 }
183 }
184
185 return keys;
186 }
187
188 private Map<DependencyNode, Object> mark(Collection<DependencyNode> nodes, Map<Object, ConflictGroup> groups) {
189 Map<DependencyNode, Object> conflictIds = new IdentityHashMap<>(nodes.size() + 1);
190
191 for (DependencyNode node : nodes) {
192 Dependency dependency = node.getDependency();
193 if (dependency != null) {
194 Object key = toKey(dependency.getArtifact());
195 conflictIds.put(node, groups.get(key).index);
196 }
197 }
198
199 return conflictIds;
200 }
201
202 private static Object toKey(Artifact artifact) {
203 return new Key(artifact);
204 }
205
206 static class ConflictGroup {
207
208 final Set<Object> keys;
209
210 final int index;
211
212 ConflictGroup(Set<Object> keys, int index) {
213 this.keys = keys;
214 this.index = index;
215 }
216
217 @Override
218 public String toString() {
219 return String.valueOf(keys);
220 }
221 }
222
223 static class Key {
224
225 private final Artifact artifact;
226
227 Key(Artifact artifact) {
228 this.artifact = artifact;
229 }
230
231 @Override
232 public boolean equals(Object obj) {
233 if (obj == this) {
234 return true;
235 } else if (!(obj instanceof Key)) {
236 return false;
237 }
238 Key that = (Key) obj;
239 return artifact.getArtifactId().equals(that.artifact.getArtifactId())
240 && artifact.getGroupId().equals(that.artifact.getGroupId())
241 && artifact.getExtension().equals(that.artifact.getExtension())
242 && artifact.getClassifier().equals(that.artifact.getClassifier());
243 }
244
245 @Override
246 public int hashCode() {
247 int hash = 17;
248 hash = hash * 31 + artifact.getArtifactId().hashCode();
249 hash = hash * 31 + artifact.getGroupId().hashCode();
250 hash = hash * 31 + artifact.getClassifier().hashCode();
251 hash = hash * 31 + artifact.getExtension().hashCode();
252 return hash;
253 }
254
255 @Override
256 public String toString() {
257 return artifact.getGroupId()
258 + ':'
259 + artifact.getArtifactId()
260 + ':'
261 + artifact.getClassifier()
262 + ':'
263 + artifact.getExtension();
264 }
265 }
266 }