View Javadoc
1   // =================== DO NOT EDIT THIS FILE ====================
2   //  Generated by Modello Velocity from merger.vm
3   //  template, any modifications will be overwritten.
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       * Merges the specified source object into the given target object.
44       *
45       * @param target The target object whose existing contents should be merged with the source, must not be
46       *            <code>null</code>.
47       * @param source The (read-only) source object that should be merged into the target object, may be
48       *            <code>null</code>.
49       * @param sourceDominant A flag indicating whether either the target object or the source object provides the
50       *            dominant data.
51       * @param hints A set of key-value pairs that customized merger implementations can use to carry domain-specific
52       *            information along, may be <code>null</code>.
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      * Use to compute keys for data structures
163      * @param <T> the data structure type
164      */
165     @FunctionalInterface
166     public interface KeyComputer<T> extends Function<T, Object> {
167     }
168 
169     /**
170      * Merge two lists
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      * Merging list
195      * @param <V>
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 }