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