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  
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       * Merges the specified source object into the given target object.
42       *
43       * @param target The target object whose existing contents should be merged with the source, must not be
44       *            <code>null</code>.
45       * @param source The (read-only) source object that should be merged into the target object, may be
46       *            <code>null</code>.
47       * @param sourceDominant A flag indicating whether either the target object or the source object provides the
48       *            dominant data.
49       * @param hints A set of key-value pairs that customized merger implementations can use to carry domain-specific
50       *            information along, may be <code>null</code>.
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      * Use to compute keys for data structures
155      * @param <T> the data structure type
156      */
157     @FunctionalInterface
158     public interface KeyComputer<T> extends Function<T, Object> {
159     }
160 
161     /**
162      * Merge two lists
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      * Merging list
187      * @param <V>
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 }