1
2
3
4
5 package org.apache.maven.toolchain.v4;
6
7 import java.io.ObjectStreamException;
8 import java.util.AbstractList;
9 import java.util.ArrayList;
10 import java.util.Collection;
11 import java.util.HashMap;
12 import java.util.Iterator;
13 import java.util.LinkedHashMap;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.Objects;
17 import java.util.function.BinaryOperator;
18 import java.util.function.Function;
19 import java.util.stream.Collectors;
20
21 import org.apache.maven.api.annotations.Generated;
22 import org.apache.maven.api.xml.XmlNode;
23 import org.apache.maven.api.toolchain.TrackableBase;
24 import org.apache.maven.api.toolchain.PersistedToolchains;
25 import org.apache.maven.api.toolchain.ToolchainModel;
26
27 @Generated
28 public class MavenToolchainsMerger {
29
30 private final boolean deepMerge;
31
32 public MavenToolchainsMerger() {
33 this(true);
34 }
35
36 public MavenToolchainsMerger(boolean deepMerge) {
37 this.deepMerge = deepMerge;
38 }
39
40
41
42
43
44
45
46
47
48
49
50
51
52 public PersistedToolchains merge(PersistedToolchains target, PersistedToolchains source, boolean sourceDominant, Map<?, ?> hints) {
53 Objects.requireNonNull(target, "target cannot be null");
54 if (source == null) {
55 return target;
56 }
57 Map<Object, Object> context = new HashMap<>();
58 if (hints != null) {
59 context.putAll(hints);
60 }
61 return mergePersistedToolchains(target, source, sourceDominant, context);
62 }
63
64 protected TrackableBase mergeTrackableBase(TrackableBase target, TrackableBase source, boolean sourceDominant, Map<Object, Object> context) {
65 TrackableBase.Builder builder = TrackableBase.newBuilder(target);
66 mergeTrackableBase(builder, target, source, sourceDominant, context);
67 return builder.build();
68 }
69
70 protected void mergeTrackableBase(TrackableBase.Builder builder, TrackableBase target, TrackableBase source, boolean sourceDominant, Map<Object, Object> context) {
71 }
72
73
74 protected PersistedToolchains mergePersistedToolchains(PersistedToolchains target, PersistedToolchains source, boolean sourceDominant, Map<Object, Object> context) {
75 PersistedToolchains.Builder builder = PersistedToolchains.newBuilder(target);
76 mergePersistedToolchains(builder, target, source, sourceDominant, context);
77 return builder.build();
78 }
79
80 protected void mergePersistedToolchains(PersistedToolchains.Builder builder, PersistedToolchains target, PersistedToolchains source, boolean sourceDominant, Map<Object, Object> context) {
81 mergeTrackableBase(builder, target, source, sourceDominant, context);
82 mergePersistedToolchains_Toolchains(builder, target, source, sourceDominant, context);
83 }
84
85 protected void mergePersistedToolchains_Toolchains(PersistedToolchains.Builder builder, PersistedToolchains target, PersistedToolchains source, boolean sourceDominant, Map<Object, Object> context) {
86 if (deepMerge) {
87 builder.toolchains(merge(target.getToolchains(), source.getToolchains(), getToolchainModelKey(),
88 (t, s) -> mergeToolchainModel(t, s, sourceDominant, context)));
89 } else {
90 builder.toolchains(merge(target.getToolchains(), source.getToolchains(), sourceDominant, getToolchainModelKey()));
91 }
92 }
93
94 protected ToolchainModel mergeToolchainModel(ToolchainModel target, ToolchainModel source, boolean sourceDominant, Map<Object, Object> context) {
95 ToolchainModel.Builder builder = ToolchainModel.newBuilder(target);
96 mergeToolchainModel(builder, target, source, sourceDominant, context);
97 return builder.build();
98 }
99
100 protected void mergeToolchainModel(ToolchainModel.Builder builder, ToolchainModel target, ToolchainModel source, boolean sourceDominant, Map<Object, Object> context) {
101 mergeTrackableBase(builder, target, source, sourceDominant, context);
102 mergeToolchainModel_Type(builder, target, source, sourceDominant, context);
103 mergeToolchainModel_Provides(builder, target, source, sourceDominant, context);
104 mergeToolchainModel_Configuration(builder, target, source, sourceDominant, context);
105 }
106
107 protected void mergeToolchainModel_Type(ToolchainModel.Builder builder, ToolchainModel target, ToolchainModel source, boolean sourceDominant, Map<Object, Object> context) {
108 String src = source.getType();
109 String tgt = target.getType();
110 if (src != null && (sourceDominant || tgt == null)) {
111 builder.type(src);
112 }
113 }
114 protected void mergeToolchainModel_Provides(ToolchainModel.Builder builder, ToolchainModel target, ToolchainModel source, boolean sourceDominant, Map<Object, Object> context) {
115 Map<String, String> src = source.getProvides();
116 if (!src.isEmpty()) {
117 Map<String, String> tgt = target.getProvides();
118 if (tgt.isEmpty()) {
119 builder.provides(src);
120 } else {
121 Map<String, String> merged = new HashMap<>();
122 merged.putAll(sourceDominant ? target.getProvides() : source.getProvides());
123 merged.putAll(sourceDominant ? source.getProvides() : target.getProvides());
124 builder.provides(merged);
125 }
126 }
127 }
128 protected void mergeToolchainModel_Configuration(ToolchainModel.Builder builder, ToolchainModel target, ToolchainModel source, boolean sourceDominant, Map<Object, Object> context) {
129 XmlNode src = source.getConfiguration();
130 if (src != null) {
131 XmlNode tgt = target.getConfiguration();
132 if (tgt == null) {
133 builder.configuration(src);
134 } else if (sourceDominant) {
135 builder.configuration(src.merge(tgt));
136 } else {
137 builder.configuration(tgt.merge(src));
138 }
139 }
140 }
141
142
143 protected KeyComputer<TrackableBase> getTrackableBaseKey() {
144 return v -> v;
145 }
146 protected KeyComputer<PersistedToolchains> getPersistedToolchainsKey() {
147 return v -> v;
148 }
149 protected KeyComputer<ToolchainModel> getToolchainModelKey() {
150 return v -> v;
151 }
152
153
154
155
156
157 @FunctionalInterface
158 public interface KeyComputer<T> extends Function<T, Object> {
159 }
160
161
162
163
164 public static <T> List<T> merge(List<T> tgt, List<T> src, boolean sourceDominant, KeyComputer<T> computer) {
165 return merge(tgt, src, computer, (t, s) -> sourceDominant ? s : t);
166 }
167
168 public static <T> List<T> merge(List<T> tgt, List<T> src, KeyComputer<T> computer, BinaryOperator<T> remapping) {
169 if (src.isEmpty()) {
170 return tgt;
171 }
172
173 MergingList<T> list;
174 if (tgt instanceof MergingList) {
175 list = (MergingList<T>) tgt;
176 } else {
177 list = new MergingList<>(computer, src.size() + tgt.size());
178 list.mergeAll(tgt, (t, s) -> s);
179 }
180
181 list.mergeAll(src, remapping);
182 return list;
183 }
184
185
186
187
188
189 private static class MergingList<V> extends AbstractList<V> implements java.io.Serializable {
190
191 private final KeyComputer<V> keyComputer;
192 private Map<Object, V> map;
193 private List<V> list;
194
195 MergingList(KeyComputer<V> keyComputer, int initialCapacity) {
196 this.map = new LinkedHashMap<>(initialCapacity);
197 this.keyComputer = keyComputer;
198 }
199
200 Object writeReplace() throws ObjectStreamException {
201 return new ArrayList<>(this);
202 }
203
204 @Override
205 public Iterator<V> iterator() {
206 if (map != null) {
207 return map.values().iterator();
208 } else {
209 return list.iterator();
210 }
211 }
212
213 void mergeAll(Collection<V> vs, BinaryOperator<V> remapping) {
214 if (map == null) {
215 map = list.stream().collect(Collectors.toMap(keyComputer,
216 Function.identity(),
217 null,
218 LinkedHashMap::new));
219 list = null;
220 }
221
222 if (vs instanceof MergingList && ((MergingList<V>) vs).map != null) {
223 for (Map.Entry<Object, V> e : ((MergingList<V>) vs).map.entrySet()) {
224 Object key = e.getKey();
225 V v = e.getValue();
226 map.merge(key, v, remapping);
227 }
228 } else {
229 for (V v : vs) {
230 Object key = keyComputer.apply(v);
231 map.merge(key, v, remapping);
232 }
233 }
234 }
235
236 @Override
237 public boolean contains(Object o) {
238 if (map != null) {
239 return map.containsValue(o);
240 } else {
241 return list.contains(o);
242 }
243 }
244
245 private List<V> asList() {
246 if (list == null) {
247 list = new ArrayList<>(map.values());
248 map = null;
249 }
250 return list;
251 }
252
253 @Override
254 public void add(int index, V element) {
255 asList().add(index, element);
256 }
257
258 @Override
259 public V remove(int index) {
260 return asList().remove(index);
261 }
262
263 @Override
264 public V get(int index) {
265 return asList().get(index);
266 }
267
268 @Override
269 public int size() {
270 if (map != null) {
271 return map.size();
272 } else {
273 return list.size();
274 }
275 }
276 }
277 }