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.ArrayList;
22 import java.util.Arrays;
23 import java.util.Collection;
24 import java.util.Collections;
25 import java.util.HashMap;
26 import java.util.HashSet;
27 import java.util.IdentityHashMap;
28 import java.util.Iterator;
29 import java.util.List;
30 import java.util.ListIterator;
31 import java.util.Map;
32 import java.util.Objects;
33
34 import org.eclipse.aether.ConfigurationProperties;
35 import org.eclipse.aether.RepositoryException;
36 import org.eclipse.aether.RepositorySystemSession;
37 import org.eclipse.aether.artifact.Artifact;
38 import org.eclipse.aether.collection.DependencyGraphTransformationContext;
39 import org.eclipse.aether.collection.DependencyGraphTransformer;
40 import org.eclipse.aether.graph.DefaultDependencyNode;
41 import org.eclipse.aether.graph.Dependency;
42 import org.eclipse.aether.graph.DependencyNode;
43 import org.eclipse.aether.util.artifact.ArtifactIdUtils;
44
45 import static java.util.Objects.requireNonNull;
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67 public final class ConflictResolver implements DependencyGraphTransformer {
68
69
70
71
72
73
74
75
76
77
78
79 public static final String CONFIG_PROP_VERBOSE = ConfigurationProperties.PREFIX_AETHER + "conflictResolver.verbose";
80
81
82
83
84
85
86 public enum Verbosity {
87
88
89
90
91
92 NONE,
93
94
95
96
97
98
99
100
101 STANDARD,
102
103
104
105
106
107
108
109 FULL
110 }
111
112
113
114
115
116
117
118
119
120
121
122 private static Verbosity getVerbosity(RepositorySystemSession session) {
123 final Object verbosityValue = session.getConfigProperties().get(CONFIG_PROP_VERBOSE);
124 if (verbosityValue instanceof Boolean) {
125 return (Boolean) verbosityValue ? Verbosity.STANDARD : Verbosity.NONE;
126 } else if (verbosityValue instanceof String) {
127 return Boolean.parseBoolean(verbosityValue.toString()) ? Verbosity.STANDARD : Verbosity.NONE;
128 } else if (verbosityValue instanceof Verbosity) {
129 return (Verbosity) verbosityValue;
130 } else if (verbosityValue != null) {
131 throw new IllegalArgumentException("Unsupported Verbosity configuration: " + verbosityValue);
132 }
133 return Verbosity.NONE;
134 }
135
136
137
138
139
140 public static final String NODE_DATA_WINNER = "conflict.winner";
141
142
143
144
145
146 public static final String NODE_DATA_ORIGINAL_SCOPE = "conflict.originalScope";
147
148
149
150
151
152 public static final String NODE_DATA_ORIGINAL_OPTIONALITY = "conflict.originalOptionality";
153
154 private final VersionSelector versionSelector;
155
156 private final ScopeSelector scopeSelector;
157
158 private final ScopeDeriver scopeDeriver;
159
160 private final OptionalitySelector optionalitySelector;
161
162
163
164
165
166
167
168
169
170 public ConflictResolver(
171 VersionSelector versionSelector,
172 ScopeSelector scopeSelector,
173 OptionalitySelector optionalitySelector,
174 ScopeDeriver scopeDeriver) {
175 this.versionSelector = requireNonNull(versionSelector, "version selector cannot be null");
176 this.scopeSelector = requireNonNull(scopeSelector, "scope selector cannot be null");
177 this.optionalitySelector = requireNonNull(optionalitySelector, "optionality selector cannot be null");
178 this.scopeDeriver = requireNonNull(scopeDeriver, "scope deriver cannot be null");
179 }
180
181 public DependencyNode transformGraph(DependencyNode node, DependencyGraphTransformationContext context)
182 throws RepositoryException {
183 requireNonNull(node, "node cannot be null");
184 requireNonNull(context, "context cannot be null");
185 List<?> sortedConflictIds = (List<?>) context.get(TransformationContextKeys.SORTED_CONFLICT_IDS);
186 if (sortedConflictIds == null) {
187 ConflictIdSorter sorter = new ConflictIdSorter();
188 sorter.transformGraph(node, context);
189
190 sortedConflictIds = (List<?>) context.get(TransformationContextKeys.SORTED_CONFLICT_IDS);
191 }
192
193 @SuppressWarnings("unchecked")
194 Map<String, Object> stats = (Map<String, Object>) context.get(TransformationContextKeys.STATS);
195 long time1 = System.nanoTime();
196
197 @SuppressWarnings("unchecked")
198 Collection<Collection<?>> conflictIdCycles =
199 (Collection<Collection<?>>) context.get(TransformationContextKeys.CYCLIC_CONFLICT_IDS);
200 if (conflictIdCycles == null) {
201 throw new RepositoryException("conflict id cycles have not been identified");
202 }
203
204 Map<?, ?> conflictIds = (Map<?, ?>) context.get(TransformationContextKeys.CONFLICT_IDS);
205 if (conflictIds == null) {
206 throw new RepositoryException("conflict groups have not been identified");
207 }
208
209 Map<Object, Collection<Object>> cyclicPredecessors = new HashMap<>();
210 for (Collection<?> cycle : conflictIdCycles) {
211 for (Object conflictId : cycle) {
212 Collection<Object> predecessors = cyclicPredecessors.computeIfAbsent(conflictId, k -> new HashSet<>());
213 predecessors.addAll(cycle);
214 }
215 }
216
217 State state = new State(node, conflictIds, sortedConflictIds.size(), context);
218 for (Iterator<?> it = sortedConflictIds.iterator(); it.hasNext(); ) {
219 Object conflictId = it.next();
220
221
222 state.prepare(conflictId, cyclicPredecessors.get(conflictId));
223
224
225 gatherConflictItems(node, state);
226
227
228 state.finish();
229
230
231 if (!state.items.isEmpty()) {
232 ConflictContext ctx = state.conflictCtx;
233 state.versionSelector.selectVersion(ctx);
234 if (ctx.winner == null) {
235 throw new RepositoryException("conflict resolver did not select winner among " + state.items);
236 }
237 DependencyNode winner = ctx.winner.node;
238
239 state.scopeSelector.selectScope(ctx);
240 if (Verbosity.NONE != state.verbosity) {
241 winner.setData(
242 NODE_DATA_ORIGINAL_SCOPE, winner.getDependency().getScope());
243 }
244 winner.setScope(ctx.scope);
245
246 state.optionalitySelector.selectOptionality(ctx);
247 if (Verbosity.NONE != state.verbosity) {
248 winner.setData(
249 NODE_DATA_ORIGINAL_OPTIONALITY,
250 winner.getDependency().isOptional());
251 }
252 winner.setOptional(ctx.optional);
253
254 removeLosers(state);
255 }
256
257
258 state.winner();
259
260
261 if (!it.hasNext() && !conflictIdCycles.isEmpty() && state.conflictCtx.winner != null) {
262 DependencyNode winner = state.conflictCtx.winner.node;
263 state.prepare(state, null);
264 gatherConflictItems(winner, state);
265 }
266 }
267
268 if (stats != null) {
269 long time2 = System.nanoTime();
270 stats.put("ConflictResolver.totalTime", time2 - time1);
271 stats.put("ConflictResolver.conflictItemCount", state.totalConflictItems);
272 }
273
274 return node;
275 }
276
277 private boolean gatherConflictItems(DependencyNode node, State state) throws RepositoryException {
278 Object conflictId = state.conflictIds.get(node);
279 if (state.currentId.equals(conflictId)) {
280
281 state.add(node);
282
283 } else if (state.loser(node, conflictId)) {
284
285 return false;
286 } else if (state.push(node, conflictId)) {
287
288 for (Iterator<DependencyNode> it = node.getChildren().iterator(); it.hasNext(); ) {
289 DependencyNode child = it.next();
290 if (!gatherConflictItems(child, state)) {
291 it.remove();
292 }
293 }
294 state.pop();
295 }
296 return true;
297 }
298
299 private static void removeLosers(State state) {
300 ConflictItem winner = state.conflictCtx.winner;
301 String winnerArtifactId = ArtifactIdUtils.toId(winner.node.getArtifact());
302 List<DependencyNode> previousParent = null;
303 ListIterator<DependencyNode> childIt = null;
304 HashSet<String> toRemoveIds = new HashSet<>();
305 for (ConflictItem item : state.items) {
306 if (item == winner) {
307 continue;
308 }
309 if (item.parent != previousParent) {
310 childIt = item.parent.listIterator();
311 previousParent = item.parent;
312 }
313 while (childIt.hasNext()) {
314 DependencyNode child = childIt.next();
315 if (child == item.node) {
316
317 if (Verbosity.NONE == state.verbosity) {
318 childIt.remove();
319 break;
320 }
321
322
323 if (Verbosity.STANDARD == state.verbosity) {
324 String childArtifactId = ArtifactIdUtils.toId(child.getArtifact());
325
326
327
328
329
330
331
332
333
334
335
336
337
338 if (!Objects.equals(winnerArtifactId, childArtifactId)) {
339 toRemoveIds.add(childArtifactId);
340 }
341 }
342
343
344 DependencyNode loser = new DefaultDependencyNode(child);
345 loser.setData(NODE_DATA_WINNER, winner.node);
346 loser.setData(
347 NODE_DATA_ORIGINAL_SCOPE, loser.getDependency().getScope());
348 loser.setData(
349 NODE_DATA_ORIGINAL_OPTIONALITY,
350 loser.getDependency().isOptional());
351 loser.setScope(item.getScopes().iterator().next());
352 loser.setChildren(Collections.emptyList());
353 childIt.set(loser);
354 item.node = loser;
355 break;
356 }
357 }
358 }
359
360
361 if (Verbosity.STANDARD == state.verbosity && !toRemoveIds.isEmpty()) {
362 previousParent = null;
363 for (ConflictItem item : state.items) {
364 if (item == winner) {
365 continue;
366 }
367 if (item.parent != previousParent) {
368 childIt = item.parent.listIterator();
369 previousParent = item.parent;
370 }
371 while (childIt.hasNext()) {
372 DependencyNode child = childIt.next();
373 if (child == item.node) {
374 String childArtifactId = ArtifactIdUtils.toId(child.getArtifact());
375 if (toRemoveIds.contains(childArtifactId)
376 && relatedSiblingsCount(child.getArtifact(), item.parent) > 1) {
377 childIt.remove();
378 }
379 break;
380 }
381 }
382 }
383 }
384
385
386
387 }
388
389 private static long relatedSiblingsCount(Artifact artifact, List<DependencyNode> parent) {
390 String ga = artifact.getGroupId() + ":" + artifact.getArtifactId();
391 return parent.stream()
392 .map(DependencyNode::getArtifact)
393 .filter(a -> ga.equals(a.getGroupId() + ":" + a.getArtifactId()))
394 .count();
395 }
396
397 static final class NodeInfo {
398
399
400
401
402 int minDepth;
403
404
405
406
407
408
409 Object derivedScopes;
410
411
412
413
414
415
416 int derivedOptionalities;
417
418
419
420
421
422 List<ConflictItem> children;
423
424 static final int CHANGE_SCOPE = 0x01;
425
426 static final int CHANGE_OPTIONAL = 0x02;
427
428 private static final int OPT_FALSE = 0x01;
429
430 private static final int OPT_TRUE = 0x02;
431
432 NodeInfo(int depth, String derivedScope, boolean optional) {
433 minDepth = depth;
434 derivedScopes = derivedScope;
435 derivedOptionalities = optional ? OPT_TRUE : OPT_FALSE;
436 }
437
438 @SuppressWarnings("unchecked")
439 int update(int depth, String derivedScope, boolean optional) {
440 if (depth < minDepth) {
441 minDepth = depth;
442 }
443 int changes;
444 if (derivedScopes.equals(derivedScope)) {
445 changes = 0;
446 } else if (derivedScopes instanceof Collection) {
447 changes = ((Collection<String>) derivedScopes).add(derivedScope) ? CHANGE_SCOPE : 0;
448 } else {
449 Collection<String> scopes = new HashSet<>();
450 scopes.add((String) derivedScopes);
451 scopes.add(derivedScope);
452 derivedScopes = scopes;
453 changes = CHANGE_SCOPE;
454 }
455 int bit = optional ? OPT_TRUE : OPT_FALSE;
456 if ((derivedOptionalities & bit) == 0) {
457 derivedOptionalities |= bit;
458 changes |= CHANGE_OPTIONAL;
459 }
460 return changes;
461 }
462
463 void add(ConflictItem item) {
464 if (children == null) {
465 children = new ArrayList<>(1);
466 }
467 children.add(item);
468 }
469 }
470
471 final class State {
472
473
474
475
476 Object currentId;
477
478
479
480
481 int totalConflictItems;
482
483
484
485
486 final Verbosity verbosity;
487
488
489
490
491
492 final Map<Object, DependencyNode> resolvedIds;
493
494
495
496
497
498
499 final Collection<Object> potentialAncestorIds;
500
501
502
503
504 final Map<?, ?> conflictIds;
505
506
507
508
509 final List<ConflictItem> items;
510
511
512
513
514
515 final Map<List<DependencyNode>, NodeInfo> infos;
516
517
518
519
520
521 final Map<List<DependencyNode>, Object> stack;
522
523
524
525
526 final List<DependencyNode> parentNodes;
527
528
529
530
531 final List<String> parentScopes;
532
533
534
535
536 final List<Boolean> parentOptionals;
537
538
539
540
541
542 final List<NodeInfo> parentInfos;
543
544
545
546
547
548 final ConflictContext conflictCtx;
549
550
551
552
553
554 final ScopeContext scopeCtx;
555
556
557
558
559 final VersionSelector versionSelector;
560
561
562
563
564 final ScopeSelector scopeSelector;
565
566
567
568
569 final ScopeDeriver scopeDeriver;
570
571
572
573
574 final OptionalitySelector optionalitySelector;
575
576 State(
577 DependencyNode root,
578 Map<?, ?> conflictIds,
579 int conflictIdCount,
580 DependencyGraphTransformationContext context)
581 throws RepositoryException {
582 this.conflictIds = conflictIds;
583 this.verbosity = getVerbosity(context.getSession());
584 potentialAncestorIds = new HashSet<>(conflictIdCount * 2);
585 resolvedIds = new HashMap<>(conflictIdCount * 2);
586 items = new ArrayList<>(256);
587 infos = new IdentityHashMap<>(64);
588 stack = new IdentityHashMap<>(64);
589 parentNodes = new ArrayList<>(64);
590 parentScopes = new ArrayList<>(64);
591 parentOptionals = new ArrayList<>(64);
592 parentInfos = new ArrayList<>(64);
593 conflictCtx = new ConflictContext(root, conflictIds, items);
594 scopeCtx = new ScopeContext(null, null);
595 versionSelector = ConflictResolver.this.versionSelector.getInstance(root, context);
596 scopeSelector = ConflictResolver.this.scopeSelector.getInstance(root, context);
597 scopeDeriver = ConflictResolver.this.scopeDeriver.getInstance(root, context);
598 optionalitySelector = ConflictResolver.this.optionalitySelector.getInstance(root, context);
599 }
600
601 void prepare(Object conflictId, Collection<Object> cyclicPredecessors) {
602 currentId = conflictId;
603 conflictCtx.conflictId = conflictId;
604 conflictCtx.winner = null;
605 conflictCtx.scope = null;
606 conflictCtx.optional = null;
607 items.clear();
608 infos.clear();
609 if (cyclicPredecessors != null) {
610 potentialAncestorIds.addAll(cyclicPredecessors);
611 }
612 }
613
614 void finish() {
615 List<DependencyNode> previousParent = null;
616 int previousDepth = 0;
617 totalConflictItems += items.size();
618 for (ListIterator<ConflictItem> iterator = items.listIterator(items.size()); iterator.hasPrevious(); ) {
619 ConflictItem item = iterator.previous();
620 if (item.parent == previousParent) {
621 item.depth = previousDepth;
622 } else if (item.parent != null) {
623 previousParent = item.parent;
624 NodeInfo info = infos.get(previousParent);
625 previousDepth = info.minDepth + 1;
626 item.depth = previousDepth;
627 }
628 }
629 potentialAncestorIds.add(currentId);
630 }
631
632 void winner() {
633 resolvedIds.put(currentId, (conflictCtx.winner != null) ? conflictCtx.winner.node : null);
634 }
635
636 boolean loser(DependencyNode node, Object conflictId) {
637 DependencyNode winner = resolvedIds.get(conflictId);
638 return winner != null && winner != node;
639 }
640
641 boolean push(DependencyNode node, Object conflictId) throws RepositoryException {
642 if (conflictId == null) {
643 if (node.getDependency() != null) {
644 if (node.getData().get(NODE_DATA_WINNER) != null) {
645 return false;
646 }
647 throw new RepositoryException("missing conflict id for node " + node);
648 }
649 } else if (!potentialAncestorIds.contains(conflictId)) {
650 return false;
651 }
652
653 List<DependencyNode> graphNode = node.getChildren();
654 if (stack.put(graphNode, Boolean.TRUE) != null) {
655 return false;
656 }
657
658 int depth = depth();
659 String scope = deriveScope(node, conflictId);
660 boolean optional = deriveOptional(node, conflictId);
661 NodeInfo info = infos.get(graphNode);
662 if (info == null) {
663 info = new NodeInfo(depth, scope, optional);
664 infos.put(graphNode, info);
665 parentInfos.add(info);
666 parentNodes.add(node);
667 parentScopes.add(scope);
668 parentOptionals.add(optional);
669 } else {
670 int changes = info.update(depth, scope, optional);
671 if (changes == 0) {
672 stack.remove(graphNode);
673 return false;
674 }
675 parentInfos.add(null);
676 parentNodes.add(node);
677 parentScopes.add(scope);
678 parentOptionals.add(optional);
679 if (info.children != null) {
680 if ((changes & NodeInfo.CHANGE_SCOPE) != 0) {
681 ListIterator<ConflictItem> itemIterator = info.children.listIterator(info.children.size());
682 while (itemIterator.hasPrevious()) {
683 ConflictItem item = itemIterator.previous();
684 String childScope = deriveScope(item.node, null);
685 item.addScope(childScope);
686 }
687 }
688 if ((changes & NodeInfo.CHANGE_OPTIONAL) != 0) {
689 ListIterator<ConflictItem> itemIterator = info.children.listIterator(info.children.size());
690 while (itemIterator.hasPrevious()) {
691 ConflictItem item = itemIterator.previous();
692 boolean childOptional = deriveOptional(item.node, null);
693 item.addOptional(childOptional);
694 }
695 }
696 }
697 }
698
699 return true;
700 }
701
702 void pop() {
703 int last = parentInfos.size() - 1;
704 parentInfos.remove(last);
705 parentScopes.remove(last);
706 parentOptionals.remove(last);
707 DependencyNode node = parentNodes.remove(last);
708 stack.remove(node.getChildren());
709 }
710
711 void add(DependencyNode node) throws RepositoryException {
712 DependencyNode parent = parent();
713 if (parent == null) {
714 ConflictItem item = newConflictItem(parent, node);
715 items.add(item);
716 } else {
717 NodeInfo info = parentInfos.get(parentInfos.size() - 1);
718 if (info != null) {
719 ConflictItem item = newConflictItem(parent, node);
720 info.add(item);
721 items.add(item);
722 }
723 }
724 }
725
726 private ConflictItem newConflictItem(DependencyNode parent, DependencyNode node) throws RepositoryException {
727 return new ConflictItem(parent, node, deriveScope(node, null), deriveOptional(node, null));
728 }
729
730 private int depth() {
731 return parentNodes.size();
732 }
733
734 private DependencyNode parent() {
735 int size = parentNodes.size();
736 return (size <= 0) ? null : parentNodes.get(size - 1);
737 }
738
739 private String deriveScope(DependencyNode node, Object conflictId) throws RepositoryException {
740 if ((node.getManagedBits() & DependencyNode.MANAGED_SCOPE) != 0
741 || (conflictId != null && resolvedIds.containsKey(conflictId))) {
742 return scope(node.getDependency());
743 }
744
745 int depth = parentNodes.size();
746 scopes(depth, node.getDependency());
747 if (depth > 0) {
748 scopeDeriver.deriveScope(scopeCtx);
749 }
750 return scopeCtx.derivedScope;
751 }
752
753 private void scopes(int parent, Dependency child) {
754 scopeCtx.parentScope = (parent > 0) ? parentScopes.get(parent - 1) : null;
755 scopeCtx.derivedScope = scope(child);
756 scopeCtx.childScope = scope(child);
757 }
758
759 private String scope(Dependency dependency) {
760 return (dependency != null) ? dependency.getScope() : null;
761 }
762
763 private boolean deriveOptional(DependencyNode node, Object conflictId) {
764 Dependency dep = node.getDependency();
765 boolean optional = (dep != null) && dep.isOptional();
766 if (optional
767 || (node.getManagedBits() & DependencyNode.MANAGED_OPTIONAL) != 0
768 || (conflictId != null && resolvedIds.containsKey(conflictId))) {
769 return optional;
770 }
771 int depth = parentNodes.size();
772 return (depth > 0) ? parentOptionals.get(depth - 1) : false;
773 }
774 }
775
776
777
778
779
780
781
782
783 public static final class ScopeContext {
784
785 String parentScope;
786
787 String childScope;
788
789 String derivedScope;
790
791
792
793
794
795
796
797
798
799 public ScopeContext(String parentScope, String childScope) {
800 this.parentScope = (parentScope != null) ? parentScope : "";
801 derivedScope = (childScope != null) ? childScope : "";
802 this.childScope = (childScope != null) ? childScope : "";
803 }
804
805
806
807
808
809
810
811 public String getParentScope() {
812 return parentScope;
813 }
814
815
816
817
818
819
820
821 public String getChildScope() {
822 return childScope;
823 }
824
825
826
827
828
829
830
831 public String getDerivedScope() {
832 return derivedScope;
833 }
834
835
836
837
838
839
840 public void setDerivedScope(String derivedScope) {
841 this.derivedScope = (derivedScope != null) ? derivedScope : "";
842 }
843 }
844
845
846
847
848
849
850
851 public static final class ConflictItem {
852
853
854 final List<DependencyNode> parent;
855
856
857 final Artifact artifact;
858
859
860 DependencyNode node;
861
862 int depth;
863
864
865 Object scopes;
866
867
868 int optionalities;
869
870
871
872
873 public static final int OPTIONAL_FALSE = 0x01;
874
875
876
877
878 public static final int OPTIONAL_TRUE = 0x02;
879
880 ConflictItem(DependencyNode parent, DependencyNode node, String scope, boolean optional) {
881 if (parent != null) {
882 this.parent = parent.getChildren();
883 this.artifact = parent.getArtifact();
884 } else {
885 this.parent = null;
886 this.artifact = null;
887 }
888 this.node = node;
889 this.scopes = scope;
890 this.optionalities = optional ? OPTIONAL_TRUE : OPTIONAL_FALSE;
891 }
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906 public ConflictItem(
907 DependencyNode parent, DependencyNode node, int depth, int optionalities, String... scopes) {
908 this.parent = (parent != null) ? parent.getChildren() : null;
909 this.artifact = (parent != null) ? parent.getArtifact() : null;
910 this.node = node;
911 this.depth = depth;
912 this.optionalities = optionalities;
913 this.scopes = Arrays.asList(scopes);
914 }
915
916
917
918
919
920
921
922 public boolean isSibling(ConflictItem item) {
923 return parent == item.parent;
924 }
925
926
927
928
929
930
931 public DependencyNode getNode() {
932 return node;
933 }
934
935
936
937
938
939
940 public Dependency getDependency() {
941 return node.getDependency();
942 }
943
944
945
946
947
948
949
950
951 public int getDepth() {
952 return depth;
953 }
954
955
956
957
958
959
960
961
962 @SuppressWarnings("unchecked")
963 public Collection<String> getScopes() {
964 if (scopes instanceof String) {
965 return Collections.singleton((String) scopes);
966 }
967 return (Collection<String>) scopes;
968 }
969
970 @SuppressWarnings("unchecked")
971 void addScope(String scope) {
972 if (scopes instanceof Collection) {
973 ((Collection<String>) scopes).add(scope);
974 } else if (!scopes.equals(scope)) {
975 Collection<Object> set = new HashSet<>();
976 set.add(scopes);
977 set.add(scope);
978 scopes = set;
979 }
980 }
981
982
983
984
985
986
987
988
989
990 public int getOptionalities() {
991 return optionalities;
992 }
993
994 void addOptional(boolean optional) {
995 optionalities |= optional ? OPTIONAL_TRUE : OPTIONAL_FALSE;
996 }
997
998 @Override
999 public String toString() {
1000 return node + " @ " + depth + " < " + artifact;
1001 }
1002 }
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012 public static final class ConflictContext {
1013
1014 final DependencyNode root;
1015
1016 final Map<?, ?> conflictIds;
1017
1018 final Collection<ConflictItem> items;
1019
1020 Object conflictId;
1021
1022 ConflictItem winner;
1023
1024 String scope;
1025
1026 Boolean optional;
1027
1028 ConflictContext(DependencyNode root, Map<?, ?> conflictIds, Collection<ConflictItem> items) {
1029 this.root = root;
1030 this.conflictIds = conflictIds;
1031 this.items = Collections.unmodifiableCollection(items);
1032 }
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045 public ConflictContext(
1046 DependencyNode root,
1047 Object conflictId,
1048 Map<DependencyNode, Object> conflictIds,
1049 Collection<ConflictItem> items) {
1050 this(root, conflictIds, items);
1051 this.conflictId = conflictId;
1052 }
1053
1054
1055
1056
1057
1058
1059 public DependencyNode getRoot() {
1060 return root;
1061 }
1062
1063
1064
1065
1066
1067
1068
1069 public boolean isIncluded(DependencyNode node) {
1070 return conflictId.equals(conflictIds.get(node));
1071 }
1072
1073
1074
1075
1076
1077
1078 public Collection<ConflictItem> getItems() {
1079 return items;
1080 }
1081
1082
1083
1084
1085
1086
1087 public ConflictItem getWinner() {
1088 return winner;
1089 }
1090
1091
1092
1093
1094
1095
1096 public void setWinner(ConflictItem winner) {
1097 this.winner = winner;
1098 }
1099
1100
1101
1102
1103
1104
1105 public String getScope() {
1106 return scope;
1107 }
1108
1109
1110
1111
1112
1113
1114 public void setScope(String scope) {
1115 this.scope = scope;
1116 }
1117
1118
1119
1120
1121
1122
1123 public Boolean getOptional() {
1124 return optional;
1125 }
1126
1127
1128
1129
1130
1131
1132 public void setOptional(Boolean optional) {
1133 this.optional = optional;
1134 }
1135
1136 @Override
1137 public String toString() {
1138 return winner + " @ " + scope + " < " + items;
1139 }
1140 }
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150 public abstract static class VersionSelector {
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166 public VersionSelector getInstance(DependencyNode root, DependencyGraphTransformationContext context)
1167 throws RepositoryException {
1168 return this;
1169 }
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180 public abstract void selectVersion(ConflictContext context) throws RepositoryException;
1181 }
1182
1183
1184
1185
1186
1187
1188
1189
1190 public abstract static class ScopeSelector {
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206 public ScopeSelector getInstance(DependencyNode root, DependencyGraphTransformationContext context)
1207 throws RepositoryException {
1208 return this;
1209 }
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220 public abstract void selectScope(ConflictContext context) throws RepositoryException;
1221 }
1222
1223
1224
1225
1226
1227
1228
1229 public abstract static class ScopeDeriver {
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245 public ScopeDeriver getInstance(DependencyNode root, DependencyGraphTransformationContext context)
1246 throws RepositoryException {
1247 return this;
1248 }
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258 public abstract void deriveScope(ScopeContext context) throws RepositoryException;
1259 }
1260
1261
1262
1263
1264
1265
1266
1267
1268 public abstract static class OptionalitySelector {
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284 public OptionalitySelector getInstance(DependencyNode root, DependencyGraphTransformationContext context)
1285 throws RepositoryException {
1286 return this;
1287 }
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298 public abstract void selectOptionality(ConflictContext context) throws RepositoryException;
1299 }
1300 }