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