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