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
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
43
44
45
46
47
48
49
50
51
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
183
184
185 @FunctionalInterface
186 public interface KeyComputer<T> extends Function<T, Object>
187 {
188 }
189
190
191
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
222
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 }