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