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