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  
31      private final boolean deepMerge;
32  
33      public MavenToolchainsMerger() {
34          this(true);
35      }
36  
37      public MavenToolchainsMerger(boolean deepMerge) {
38          this.deepMerge = deepMerge;
39      }
40  
41      /**
42       * Merges the specified source object into the given target object.
43       *
44       * @param target The target object whose existing contents should be merged with the source, must not be
45       *            <code>null</code>.
46       * @param source The (read-only) source object that should be merged into the target object, may be
47       *            <code>null</code>.
48       * @param sourceDominant A flag indicating whether either the target object or the source object provides the
49       *            dominant data.
50       * @param hints A set of key-value pairs that customized merger implementations can use to carry domain-specific
51       *            information along, may be <code>null</code>.
52       */
53      public PersistedToolchains merge( PersistedToolchains target, PersistedToolchains source, boolean sourceDominant, Map<?, ?> hints )
54      {
55          Objects.requireNonNull( target, "target cannot be null" );
56          if ( source == null )
57          {
58              return target;
59          }
60          Map<Object, Object> context = new HashMap<>();
61          if ( hints != null )
62          {
63              context.putAll( hints );
64          }
65          return mergePersistedToolchains( target, source, sourceDominant, context );
66      }
67  
68      protected TrackableBase mergeTrackableBase( TrackableBase target, TrackableBase source, boolean sourceDominant, Map<Object, Object> context )
69      {
70          TrackableBase.Builder builder = TrackableBase.newBuilder( target );
71          mergeTrackableBase( builder, target, source, sourceDominant, context );
72          return builder.build();
73      }
74  
75      protected void mergeTrackableBase( TrackableBase.Builder builder, TrackableBase target, TrackableBase source, boolean sourceDominant, Map<Object, Object> context )
76      {
77      }
78  
79  
80      protected PersistedToolchains mergePersistedToolchains( PersistedToolchains target, PersistedToolchains source, boolean sourceDominant, Map<Object, Object> context )
81      {
82          PersistedToolchains.Builder builder = PersistedToolchains.newBuilder( target );
83          mergePersistedToolchains( builder, target, source, sourceDominant, context );
84          return builder.build();
85      }
86  
87      protected void mergePersistedToolchains( PersistedToolchains.Builder builder, PersistedToolchains target, PersistedToolchains source, boolean sourceDominant, Map<Object, Object> context )
88      {
89          mergeTrackableBase( builder, target ,source, sourceDominant, context );
90          mergePersistedToolchains_Toolchains( builder, target, source, sourceDominant, context );
91      }
92  
93      protected void mergePersistedToolchains_Toolchains( PersistedToolchains.Builder builder, PersistedToolchains target, PersistedToolchains source, boolean sourceDominant, Map<Object, Object> context )
94      {
95          if (deepMerge) {
96              builder.toolchains( merge( target.getToolchains(), source.getToolchains(), getToolchainModelKey(),
97                      ( t, s ) -> mergeToolchainModel( t, s, sourceDominant, context ) ) );
98          } else {
99              builder.toolchains( merge( target.getToolchains(), source.getToolchains(), sourceDominant, getToolchainModelKey() ) );
100         }
101     }
102 
103     protected ToolchainModel mergeToolchainModel( ToolchainModel target, ToolchainModel source, boolean sourceDominant, Map<Object, Object> context )
104     {
105         ToolchainModel.Builder builder = ToolchainModel.newBuilder( target );
106         mergeToolchainModel( builder, target, source, sourceDominant, context );
107         return builder.build();
108     }
109 
110     protected void mergeToolchainModel( ToolchainModel.Builder builder, ToolchainModel target, ToolchainModel source, boolean sourceDominant, Map<Object, Object> context )
111     {
112         mergeTrackableBase( builder, target ,source, sourceDominant, context );
113         mergeToolchainModel_Type( builder, target, source, sourceDominant, context );
114         mergeToolchainModel_Provides( builder, target, source, sourceDominant, context );
115         mergeToolchainModel_Configuration( builder, target, source, sourceDominant, context );
116     }
117 
118     protected void mergeToolchainModel_Type( ToolchainModel.Builder builder, ToolchainModel target, ToolchainModel source, boolean sourceDominant, Map<Object, Object> context )
119     {
120         String src = source.getType();
121         String tgt = target.getType();
122         if ( src != null && ( sourceDominant || tgt == null ) )
123         {
124             builder.type( src );
125         }
126     }
127     protected void mergeToolchainModel_Provides( ToolchainModel.Builder builder, ToolchainModel target, ToolchainModel source, boolean sourceDominant, Map<Object, Object> context )
128     {
129         Map<String, String> src = source.getProvides();
130         if ( !src.isEmpty() )
131         {
132             Map<String, String> tgt = target.getProvides();
133             if ( tgt.isEmpty() )
134             {
135                 builder.provides( src );
136             }
137             else
138             {
139                 Map<String, String> merged = new HashMap<>();
140                 merged.putAll( sourceDominant ? target.getProvides() : source.getProvides() );
141                 merged.putAll( sourceDominant ? source.getProvides() : target.getProvides() );
142                 builder.provides( merged );
143             }
144         }
145     }
146     protected void mergeToolchainModel_Configuration( ToolchainModel.Builder builder, ToolchainModel target, ToolchainModel source, boolean sourceDominant, Map<Object, Object> context )
147     {
148         XmlNode src = source.getConfiguration();
149         if ( src != null )
150         {
151             XmlNode tgt = target.getConfiguration();
152             if ( tgt == null )
153             {
154                 builder.configuration( src );
155             }
156             else if ( sourceDominant )
157             {
158                 builder.configuration( src.merge( tgt ) );
159             }
160             else
161             {
162                 builder.configuration( tgt.merge( src ) );
163             }
164         }
165     }
166 
167 
168     protected KeyComputer<TrackableBase> getTrackableBaseKey()
169     {
170         return v -> v;
171     }
172     protected KeyComputer<PersistedToolchains> getPersistedToolchainsKey()
173     {
174         return v -> v;
175     }
176     protected KeyComputer<ToolchainModel> getToolchainModelKey()
177     {
178         return v -> v;
179     }
180 
181     /**
182      * Use to compute keys for data structures
183      * @param <T> the data structure type
184      */
185     @FunctionalInterface
186     public interface KeyComputer<T> extends Function<T, Object>
187     {
188     }
189 
190     /**
191      * Merge two lists
192      */
193     public static <T> List<T> merge( List<T> tgt, List<T> src, boolean sourceDominant, KeyComputer<T> computer )
194     {
195         return merge( tgt, src, computer, ( t, s ) -> sourceDominant ? s : t );
196     }
197 
198     public static <T> List<T> merge( List<T> tgt, List<T> src, KeyComputer<T> computer, BinaryOperator<T> remapping )
199     {
200         if ( src.isEmpty() )
201         {
202             return tgt;
203         }
204 
205         MergingList<T> list;
206         if ( tgt instanceof MergingList )
207         {
208             list = (MergingList<T>) tgt;
209         }
210         else
211         {
212             list = new MergingList<>( computer, src.size() + tgt.size() );
213             list.mergeAll( tgt, ( t, s ) -> s );
214         }
215 
216         list.mergeAll( src, remapping );
217         return list;
218     }
219 
220     /**
221      * Merging list
222      * @param <V>
223      */
224     private static class MergingList<V> extends AbstractList<V> implements java.io.Serializable
225     {
226 
227         private final KeyComputer<V> keyComputer;
228         private Map<Object, V> map;
229         private List<V> list;
230 
231         MergingList( KeyComputer<V> keyComputer, int initialCapacity )
232         {
233             this.map = new LinkedHashMap<>( initialCapacity );
234             this.keyComputer = keyComputer;
235         }
236 
237         Object writeReplace() throws ObjectStreamException
238         {
239             return new ArrayList<>( this );
240         }
241 
242         @Override
243         public Iterator<V> iterator()
244         {
245             if ( map != null )
246             {
247                 return map.values().iterator();
248             }
249             else
250             {
251                 return list.iterator();
252             }
253         }
254 
255         void mergeAll( Collection<V> vs, BinaryOperator<V> remapping )
256         {
257             if ( map == null )
258             {
259                 map = list.stream().collect( Collectors.toMap( keyComputer,
260                                                                Function.identity(),
261                                                                null,
262                                                                LinkedHashMap::new ) );
263 
264                 list = null;
265             }
266 
267             if ( vs instanceof MergingList && ( (MergingList<V>) vs ).map != null )
268             {
269                 for ( Map.Entry<Object, V> e : ( (MergingList<V>) vs ).map.entrySet() )
270                 {
271                     Object key = e.getKey();
272                     V v = e.getValue();
273                     map.merge( key, v, remapping );
274                 }
275             }
276             else
277             {
278                 for ( V v : vs )
279                 {
280                     Object key = keyComputer.apply( v );
281 
282                     map.merge( key, v, remapping );
283                 }
284             }
285         }
286 
287         @Override
288         public boolean contains( Object o )
289         {
290             if ( map != null )
291             {
292                 return map.containsValue( o );
293             }
294             else
295             {
296                 return list.contains( o );
297             }
298         }
299 
300         private List<V> asList()
301         {
302             if ( list == null )
303             {
304                 list = new ArrayList<>( map.values() );
305                 map = null;
306             }
307             return list;
308         }
309 
310         @Override
311         public void add( int index, V element )
312         {
313             asList().add( index, element );
314         }
315 
316         @Override
317         public V remove( int index )
318         {
319             return asList().remove( index );
320         }
321 
322         @Override
323         public V get( int index )
324         {
325             return asList().get( index );
326         }
327 
328         @Override
329         public int size()
330         {
331             if ( map != null )
332             {
333                 return map.size();
334             }
335             else
336             {
337                 return list.size();
338             }
339         }
340     }
341 }