1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.model.merge;
20
21 import java.util.ArrayList;
22 import java.util.LinkedHashMap;
23 import java.util.LinkedHashSet;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.Set;
27 import org.apache.maven.api.model.BuildBase;
28 import org.apache.maven.api.model.CiManagement;
29 import org.apache.maven.api.model.Dependency;
30 import org.apache.maven.api.model.DeploymentRepository;
31 import org.apache.maven.api.model.DistributionManagement;
32 import org.apache.maven.api.model.Exclusion;
33 import org.apache.maven.api.model.Extension;
34 import org.apache.maven.api.model.InputLocation;
35 import org.apache.maven.api.model.IssueManagement;
36 import org.apache.maven.api.model.Model;
37 import org.apache.maven.api.model.ModelBase;
38 import org.apache.maven.api.model.Organization;
39 import org.apache.maven.api.model.Plugin;
40 import org.apache.maven.api.model.PluginExecution;
41 import org.apache.maven.api.model.ReportPlugin;
42 import org.apache.maven.api.model.ReportSet;
43 import org.apache.maven.api.model.Repository;
44 import org.apache.maven.api.model.RepositoryBase;
45 import org.apache.maven.api.model.Scm;
46 import org.apache.maven.api.model.Site;
47 import org.apache.maven.model.v4.MavenMerger;
48 import org.codehaus.plexus.util.StringUtils;
49
50
51
52
53
54
55
56 public class MavenModelMerger extends MavenMerger {
57
58
59
60
61 public static final String CHILD_PATH_ADJUSTMENT = "child-path-adjustment";
62
63
64
65
66 public static final String ARTIFACT_ID = "artifact-id";
67
68 @Override
69 protected Model mergeModel(Model target, Model source, boolean sourceDominant, Map<Object, Object> context) {
70 context.put(ARTIFACT_ID, target.getArtifactId());
71
72 return super.mergeModel(target, source, sourceDominant, context);
73 }
74
75 @Override
76 protected void mergeModel_Name(
77 Model.Builder builder, Model target, Model source, boolean sourceDominant, Map<Object, Object> context) {
78 String src = source.getName();
79 if (src != null) {
80 if (sourceDominant) {
81 builder.name(src);
82 builder.location("name", source.getLocation("name"));
83 }
84 }
85 }
86
87 @Override
88 protected void mergeModel_Url(
89 Model.Builder builder, Model target, Model source, boolean sourceDominant, Map<Object, Object> context) {
90 String src = source.getUrl();
91 if (src != null) {
92 if (sourceDominant) {
93 builder.url(src);
94 builder.location("url", source.getLocation("url"));
95 } else if (target.getUrl() == null) {
96 builder.url(extrapolateChildUrl(src, source.isChildProjectUrlInheritAppendPath(), context));
97 builder.location("url", source.getLocation("url"));
98 }
99 }
100 }
101
102
103
104
105
106 @Override
107 protected void mergeModel_Organization(
108 Model.Builder builder, Model target, Model source, boolean sourceDominant, Map<Object, Object> context) {
109 Organization src = source.getOrganization();
110 if (src != null) {
111 Organization tgt = target.getOrganization();
112 if (tgt == null) {
113 builder.organization(src);
114 builder.location("organisation", source.getLocation("organisation"));
115 }
116 }
117 }
118
119 @Override
120 protected void mergeModel_IssueManagement(
121 Model.Builder builder, Model target, Model source, boolean sourceDominant, Map<Object, Object> context) {
122 IssueManagement src = source.getIssueManagement();
123 if (src != null) {
124 IssueManagement tgt = target.getIssueManagement();
125 if (tgt == null) {
126 builder.issueManagement(src);
127 builder.location("issueManagement", source.getLocation("issueManagement"));
128 }
129 }
130 }
131
132 @Override
133 protected void mergeModel_CiManagement(
134 Model.Builder builder, Model target, Model source, boolean sourceDominant, Map<Object, Object> context) {
135 CiManagement src = source.getCiManagement();
136 if (src != null) {
137 CiManagement tgt = target.getCiManagement();
138 if (tgt == null) {
139 builder.ciManagement(src);
140 builder.location("ciManagement", source.getLocation("ciManagement"));
141 }
142 }
143 }
144
145 @Override
146 protected void mergeModel_ModelVersion(
147 Model.Builder builder, Model target, Model source, boolean sourceDominant, Map<Object, Object> context) {
148
149 }
150
151 @Override
152 protected void mergeModel_ArtifactId(
153 Model.Builder builder, Model target, Model source, boolean sourceDominant, Map<Object, Object> context) {
154
155 }
156
157 @Override
158 protected void mergeModel_Profiles(
159 Model.Builder builder, Model target, Model source, boolean sourceDominant, Map<Object, Object> context) {
160
161 }
162
163 @Override
164 protected void mergeModel_Prerequisites(
165 Model.Builder builder, Model target, Model source, boolean sourceDominant, Map<Object, Object> context) {
166
167 }
168
169 @Override
170 protected void mergeModel_Licenses(
171 Model.Builder builder, Model target, Model source, boolean sourceDominant, Map<Object, Object> context) {
172 builder.licenses(target.getLicenses().isEmpty() ? source.getLicenses() : target.getLicenses());
173 }
174
175 @Override
176 protected void mergeModel_Developers(
177 Model.Builder builder, Model target, Model source, boolean sourceDominant, Map<Object, Object> context) {
178 builder.developers(target.getDevelopers().isEmpty() ? source.getDevelopers() : target.getDevelopers());
179 }
180
181 @Override
182 protected void mergeModel_Contributors(
183 Model.Builder builder, Model target, Model source, boolean sourceDominant, Map<Object, Object> context) {
184 builder.contributors(target.getContributors().isEmpty() ? source.getContributors() : target.getContributors());
185 }
186
187 @Override
188 protected void mergeModel_MailingLists(
189 Model.Builder builder, Model target, Model source, boolean sourceDominant, Map<Object, Object> context) {
190 if (target.getMailingLists().isEmpty()) {
191 builder.mailingLists(source.getMailingLists());
192 }
193 }
194
195 @Override
196 protected void mergeModelBase_Modules(
197 ModelBase.Builder builder,
198 ModelBase target,
199 ModelBase source,
200 boolean sourceDominant,
201 Map<Object, Object> context) {
202 List<String> src = source.getModules();
203 if (!src.isEmpty() && sourceDominant) {
204 List<Integer> indices = new ArrayList<>();
205 List<String> tgt = target.getModules();
206 Set<String> excludes = new LinkedHashSet<>(tgt);
207 List<String> merged = new ArrayList<>(tgt.size() + src.size());
208 merged.addAll(tgt);
209 for (int i = 0, n = tgt.size(); i < n; i++) {
210 indices.add(i);
211 }
212 for (int i = 0, n = src.size(); i < n; i++) {
213 String s = src.get(i);
214 if (!excludes.contains(s)) {
215 merged.add(s);
216 indices.add(~i);
217 }
218 }
219 builder.modules(merged);
220 builder.location(
221 "modules",
222 InputLocation.merge(target.getLocation("modules"), source.getLocation("modules"), indices));
223 }
224 }
225
226
227
228
229
230 @Override
231 protected void mergeModelBase_Repositories(
232 ModelBase.Builder builder,
233 ModelBase target,
234 ModelBase source,
235 boolean sourceDominant,
236 Map<Object, Object> context) {
237 List<Repository> src = source.getRepositories();
238 if (!src.isEmpty()) {
239 List<Repository> tgt = target.getRepositories();
240 Map<Object, Repository> merged = new LinkedHashMap<>((src.size() + tgt.size()) * 2);
241
242 List<Repository> dominant, recessive;
243 if (sourceDominant) {
244 dominant = src;
245 recessive = tgt;
246 } else {
247 dominant = tgt;
248 recessive = src;
249 }
250
251 for (Repository element : dominant) {
252 Object key = getRepositoryKey().apply(element);
253 merged.put(key, element);
254 }
255
256 for (Repository element : recessive) {
257 Object key = getRepositoryKey().apply(element);
258 if (!merged.containsKey(key)) {
259 merged.put(key, element);
260 }
261 }
262
263 builder.repositories(merged.values());
264 }
265 }
266
267 @Override
268 protected void mergeModelBase_PluginRepositories(
269 ModelBase.Builder builder,
270 ModelBase target,
271 ModelBase source,
272 boolean sourceDominant,
273 Map<Object, Object> context) {
274 List<Repository> src = source.getPluginRepositories();
275 if (!src.isEmpty()) {
276 List<Repository> tgt = target.getPluginRepositories();
277 Map<Object, Repository> merged = new LinkedHashMap<>((src.size() + tgt.size()) * 2);
278
279 List<Repository> dominant, recessive;
280 if (sourceDominant) {
281 dominant = src;
282 recessive = tgt;
283 } else {
284 dominant = tgt;
285 recessive = src;
286 }
287
288 for (Repository element : dominant) {
289 Object key = getRepositoryKey().apply(element);
290 merged.put(key, element);
291 }
292
293 for (Repository element : recessive) {
294 Object key = getRepositoryKey().apply(element);
295 if (!merged.containsKey(key)) {
296 merged.put(key, element);
297 }
298 }
299
300 builder.pluginRepositories(merged.values());
301 }
302 }
303
304
305
306
307 @Override
308 protected void mergeBuildBase_Filters(
309 BuildBase.Builder builder,
310 BuildBase target,
311 BuildBase source,
312 boolean sourceDominant,
313 Map<Object, Object> context) {
314 List<String> src = source.getFilters();
315 if (!src.isEmpty()) {
316 List<String> tgt = target.getFilters();
317 Set<String> excludes = new LinkedHashSet<>(tgt);
318 List<String> merged = new ArrayList<>(tgt.size() + src.size());
319 merged.addAll(tgt);
320 for (String s : src) {
321 if (!excludes.contains(s)) {
322 merged.add(s);
323 }
324 }
325 builder.filters(merged);
326 }
327 }
328
329 @Override
330 protected void mergeBuildBase_Resources(
331 BuildBase.Builder builder,
332 BuildBase target,
333 BuildBase source,
334 boolean sourceDominant,
335 Map<Object, Object> context) {
336 if (sourceDominant || target.getResources().isEmpty()) {
337 super.mergeBuildBase_Resources(builder, target, source, sourceDominant, context);
338 }
339 }
340
341 @Override
342 protected void mergeBuildBase_TestResources(
343 BuildBase.Builder builder,
344 BuildBase target,
345 BuildBase source,
346 boolean sourceDominant,
347 Map<Object, Object> context) {
348 if (sourceDominant || target.getTestResources().isEmpty()) {
349 super.mergeBuildBase_TestResources(builder, target, source, sourceDominant, context);
350 }
351 }
352
353 @Override
354 protected void mergeDistributionManagement_Relocation(
355 DistributionManagement.Builder builder,
356 DistributionManagement target,
357 DistributionManagement source,
358 boolean sourceDominant,
359 Map<Object, Object> context) {}
360
361 @Override
362 protected void mergeDistributionManagement_Repository(
363 DistributionManagement.Builder builder,
364 DistributionManagement target,
365 DistributionManagement source,
366 boolean sourceDominant,
367 Map<Object, Object> context) {
368 DeploymentRepository src = source.getRepository();
369 if (src != null) {
370 DeploymentRepository tgt = target.getRepository();
371 if (sourceDominant || tgt == null) {
372 tgt = DeploymentRepository.newInstance(false);
373 builder.repository(mergeDeploymentRepository(tgt, src, sourceDominant, context));
374 }
375 }
376 }
377
378 @Override
379 protected void mergeDistributionManagement_SnapshotRepository(
380 DistributionManagement.Builder builder,
381 DistributionManagement target,
382 DistributionManagement source,
383 boolean sourceDominant,
384 Map<Object, Object> context) {
385 DeploymentRepository src = source.getSnapshotRepository();
386 if (src != null) {
387 DeploymentRepository tgt = target.getSnapshotRepository();
388 if (sourceDominant || tgt == null) {
389 tgt = DeploymentRepository.newInstance(false);
390 builder.snapshotRepository(mergeDeploymentRepository(tgt, src, sourceDominant, context));
391 }
392 }
393 }
394
395 @Override
396 protected void mergeDistributionManagement_Site(
397 DistributionManagement.Builder builder,
398 DistributionManagement target,
399 DistributionManagement source,
400 boolean sourceDominant,
401 Map<Object, Object> context) {
402 Site src = source.getSite();
403 if (src != null) {
404 Site tgt = target.getSite();
405 if (tgt == null) {
406 tgt = Site.newBuilder(false).build();
407 }
408 Site.Builder sbuilder = Site.newBuilder(tgt);
409 if (sourceDominant || tgt == null || isSiteEmpty(tgt)) {
410 mergeSite(sbuilder, tgt, src, sourceDominant, context);
411 }
412 super.mergeSite_ChildSiteUrlInheritAppendPath(sbuilder, tgt, src, sourceDominant, context);
413 builder.site(sbuilder.build());
414 }
415 }
416
417 @Override
418 protected void mergeSite_ChildSiteUrlInheritAppendPath(
419 Site.Builder builder, Site target, Site source, boolean sourceDominant, Map<Object, Object> context) {}
420
421 protected boolean isSiteEmpty(Site site) {
422 return StringUtils.isEmpty(site.getId())
423 && StringUtils.isEmpty(site.getName())
424 && StringUtils.isEmpty(site.getUrl());
425 }
426
427 @Override
428 protected void mergeSite_Url(
429 Site.Builder builder, Site target, Site source, boolean sourceDominant, Map<Object, Object> context) {
430 String src = source.getUrl();
431 if (src != null) {
432 if (sourceDominant) {
433 builder.url(src);
434 builder.location("url", source.getLocation("url"));
435 } else if (target.getUrl() == null) {
436 builder.url(extrapolateChildUrl(src, source.isChildSiteUrlInheritAppendPath(), context));
437 builder.location("url", source.getLocation("url"));
438 }
439 }
440 }
441
442 @Override
443 protected void mergeScm_Url(
444 Scm.Builder builder, Scm target, Scm source, boolean sourceDominant, Map<Object, Object> context) {
445 String src = source.getUrl();
446 if (src != null) {
447 if (sourceDominant) {
448 builder.url(src);
449 builder.location("url", source.getLocation("url"));
450 } else if (target.getUrl() == null) {
451 builder.url(extrapolateChildUrl(src, source.isChildScmUrlInheritAppendPath(), context));
452 builder.location("url", source.getLocation("url"));
453 }
454 }
455 }
456
457 @Override
458 protected void mergeScm_Connection(
459 Scm.Builder builder, Scm target, Scm source, boolean sourceDominant, Map<Object, Object> context) {
460 String src = source.getConnection();
461 if (src != null) {
462 if (sourceDominant) {
463 builder.connection(src);
464 builder.location("connection", source.getLocation("connection"));
465 } else if (target.getConnection() == null) {
466 builder.connection(extrapolateChildUrl(src, source.isChildScmConnectionInheritAppendPath(), context));
467 builder.location("connection", source.getLocation("connection"));
468 }
469 }
470 }
471
472 @Override
473 protected void mergeScm_DeveloperConnection(
474 Scm.Builder builder, Scm target, Scm source, boolean sourceDominant, Map<Object, Object> context) {
475 String src = source.getDeveloperConnection();
476 if (src != null) {
477 if (sourceDominant) {
478 builder.developerConnection(src);
479 builder.location("developerConnection", source.getLocation("developerConnection"));
480 } else if (target.getDeveloperConnection() == null) {
481 String e = extrapolateChildUrl(src, source.isChildScmDeveloperConnectionInheritAppendPath(), context);
482 builder.developerConnection(e);
483 builder.location("developerConnection", source.getLocation("developerConnection"));
484 }
485 }
486 }
487
488 @Override
489 protected void mergePlugin_Executions(
490 Plugin.Builder builder, Plugin target, Plugin source, boolean sourceDominant, Map<Object, Object> context) {
491 List<PluginExecution> src = source.getExecutions();
492 if (!src.isEmpty()) {
493 List<PluginExecution> tgt = target.getExecutions();
494 Map<Object, PluginExecution> merged = new LinkedHashMap<>((src.size() + tgt.size()) * 2);
495
496 for (PluginExecution element : src) {
497 if (sourceDominant || (element.getInherited() != null ? element.isInherited() : source.isInherited())) {
498 Object key = getPluginExecutionKey().apply(element);
499 merged.put(key, element);
500 }
501 }
502
503 for (PluginExecution element : tgt) {
504 Object key = getPluginExecutionKey().apply(element);
505 PluginExecution existing = merged.get(key);
506 if (existing != null) {
507 element = mergePluginExecution(element, existing, sourceDominant, context);
508 }
509 merged.put(key, element);
510 }
511
512 builder.executions(merged.values());
513 }
514 }
515
516 @Override
517 protected void mergePluginExecution_Goals(
518 PluginExecution.Builder builder,
519 PluginExecution target,
520 PluginExecution source,
521 boolean sourceDominant,
522 Map<Object, Object> context) {
523 List<String> src = source.getGoals();
524 if (!src.isEmpty()) {
525 List<String> tgt = target.getGoals();
526 Set<String> excludes = new LinkedHashSet<>(tgt);
527 List<String> merged = new ArrayList<>(tgt.size() + src.size());
528 merged.addAll(tgt);
529 for (String s : src) {
530 if (!excludes.contains(s)) {
531 merged.add(s);
532 }
533 }
534 builder.goals(merged);
535 }
536 }
537
538 @Override
539 protected void mergeReportPlugin_ReportSets(
540 ReportPlugin.Builder builder,
541 ReportPlugin target,
542 ReportPlugin source,
543 boolean sourceDominant,
544 Map<Object, Object> context) {
545 List<ReportSet> src = source.getReportSets();
546 if (!src.isEmpty()) {
547 List<ReportSet> tgt = target.getReportSets();
548 Map<Object, ReportSet> merged = new LinkedHashMap<>((src.size() + tgt.size()) * 2);
549
550 for (ReportSet rset : src) {
551 if (sourceDominant || (rset.getInherited() != null ? rset.isInherited() : source.isInherited())) {
552 Object key = getReportSetKey().apply(rset);
553 merged.put(key, rset);
554 }
555 }
556
557 for (ReportSet element : tgt) {
558 Object key = getReportSetKey().apply(element);
559 ReportSet existing = merged.get(key);
560 if (existing != null) {
561 mergeReportSet(element, existing, sourceDominant, context);
562 }
563 merged.put(key, element);
564 }
565
566 builder.reportSets(merged.values());
567 }
568 }
569
570 @Override
571 protected KeyComputer<Dependency> getDependencyKey() {
572 return Dependency::getManagementKey;
573 }
574
575 @Override
576 protected KeyComputer<Plugin> getPluginKey() {
577 return Plugin::getKey;
578 }
579
580 @Override
581 protected KeyComputer<PluginExecution> getPluginExecutionKey() {
582 return PluginExecution::getId;
583 }
584
585 @Override
586 protected KeyComputer<ReportPlugin> getReportPluginKey() {
587 return ReportPlugin::getKey;
588 }
589
590 @Override
591 protected KeyComputer<ReportSet> getReportSetKey() {
592 return ReportSet::getId;
593 }
594
595 @Override
596 protected KeyComputer<RepositoryBase> getRepositoryBaseKey() {
597 return RepositoryBase::getId;
598 }
599
600 @Override
601 protected KeyComputer<Extension> getExtensionKey() {
602 return e -> e.getGroupId() + ':' + e.getArtifactId();
603 }
604
605 @Override
606 protected KeyComputer<Exclusion> getExclusionKey() {
607 return e -> e.getGroupId() + ':' + e.getArtifactId();
608 }
609
610 protected String extrapolateChildUrl(String parentUrl, boolean appendPath, Map<Object, Object> context) {
611 return parentUrl;
612 }
613 }