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