1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.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 }
172
173 @Override
174 protected void mergeModel_Prerequisites(
175 Model.Builder builder, Model target, Model source, boolean sourceDominant, Map<Object, Object> context) {
176
177 }
178
179 @Override
180 protected void mergeModel_Licenses(
181 Model.Builder builder, Model target, Model source, boolean sourceDominant, Map<Object, Object> context) {
182 builder.licenses(target.getLicenses().isEmpty() ? source.getLicenses() : target.getLicenses());
183 }
184
185 @Override
186 protected void mergeModel_Developers(
187 Model.Builder builder, Model target, Model source, boolean sourceDominant, Map<Object, Object> context) {
188 builder.developers(target.getDevelopers().isEmpty() ? source.getDevelopers() : target.getDevelopers());
189 }
190
191 @Override
192 protected void mergeModel_Contributors(
193 Model.Builder builder, Model target, Model source, boolean sourceDominant, Map<Object, Object> context) {
194 builder.contributors(target.getContributors().isEmpty() ? source.getContributors() : target.getContributors());
195 }
196
197 @Override
198 protected void mergeModel_MailingLists(
199 Model.Builder builder, Model target, Model source, boolean sourceDominant, Map<Object, Object> context) {
200 if (target.getMailingLists().isEmpty()) {
201 builder.mailingLists(source.getMailingLists());
202 }
203 }
204
205 @Override
206 protected void mergeModelBase_Modules(
207 ModelBase.Builder builder,
208 ModelBase target,
209 ModelBase source,
210 boolean sourceDominant,
211 Map<Object, Object> context) {
212 List<String> src = source.getModules();
213 if (!src.isEmpty() && sourceDominant) {
214 List<Integer> indices = new ArrayList<>();
215 List<String> tgt = target.getModules();
216 Set<String> excludes = new LinkedHashSet<>(tgt);
217 List<String> merged = new ArrayList<>(tgt.size() + src.size());
218 merged.addAll(tgt);
219 for (int i = 0, n = tgt.size(); i < n; i++) {
220 indices.add(i);
221 }
222 for (int i = 0, n = src.size(); i < n; i++) {
223 String s = src.get(i);
224 if (!excludes.contains(s)) {
225 merged.add(s);
226 indices.add(~i);
227 }
228 }
229 builder.modules(merged);
230 builder.location(
231 "modules",
232 InputLocation.merge(target.getLocation("modules"), source.getLocation("modules"), indices));
233 }
234 }
235
236 @Override
237 protected void mergeModelBase_Subprojects(
238 ModelBase.Builder builder,
239 ModelBase target,
240 ModelBase source,
241 boolean sourceDominant,
242 Map<Object, Object> context) {
243 List<String> src = source.getSubprojects();
244 if (!src.isEmpty() && sourceDominant) {
245 List<Integer> indices = new ArrayList<>();
246 List<String> tgt = target.getSubprojects();
247 Set<String> excludes = new LinkedHashSet<>(tgt);
248 List<String> merged = new ArrayList<>(tgt.size() + src.size());
249 merged.addAll(tgt);
250 for (int i = 0, n = tgt.size(); i < n; i++) {
251 indices.add(i);
252 }
253 for (int i = 0, n = src.size(); i < n; i++) {
254 String s = src.get(i);
255 if (!excludes.contains(s)) {
256 merged.add(s);
257 indices.add(~i);
258 }
259 }
260 builder.subprojects(merged);
261 builder.location(
262 "subprojects",
263 InputLocation.merge(target.getLocation("subprojects"), source.getLocation("subprojects"), indices));
264 }
265 }
266
267
268
269
270
271 @Override
272 protected void mergeModelBase_Repositories(
273 ModelBase.Builder builder,
274 ModelBase target,
275 ModelBase source,
276 boolean sourceDominant,
277 Map<Object, Object> context) {
278 List<Repository> src = source.getRepositories();
279 if (!src.isEmpty()) {
280 List<Repository> tgt = target.getRepositories();
281 Map<Object, Repository> merged = new LinkedHashMap<>((src.size() + tgt.size()) * 2);
282
283 List<Repository> dominant, recessive;
284 if (sourceDominant) {
285 dominant = src;
286 recessive = tgt;
287 } else {
288 dominant = tgt;
289 recessive = src;
290 }
291
292 for (Repository element : dominant) {
293 Object key = getRepositoryKey().apply(element);
294 merged.put(key, element);
295 }
296
297 for (Repository element : recessive) {
298 Object key = getRepositoryKey().apply(element);
299 if (!merged.containsKey(key)) {
300 merged.put(key, element);
301 }
302 }
303
304 builder.repositories(merged.values());
305 }
306 }
307
308 @Override
309 protected void mergeModelBase_PluginRepositories(
310 ModelBase.Builder builder,
311 ModelBase target,
312 ModelBase source,
313 boolean sourceDominant,
314 Map<Object, Object> context) {
315 List<Repository> src = source.getPluginRepositories();
316 if (!src.isEmpty()) {
317 List<Repository> tgt = target.getPluginRepositories();
318 Map<Object, Repository> merged = new LinkedHashMap<>((src.size() + tgt.size()) * 2);
319
320 List<Repository> dominant, recessive;
321 if (sourceDominant) {
322 dominant = src;
323 recessive = tgt;
324 } else {
325 dominant = tgt;
326 recessive = src;
327 }
328
329 for (Repository element : dominant) {
330 Object key = getRepositoryKey().apply(element);
331 merged.put(key, element);
332 }
333
334 for (Repository element : recessive) {
335 Object key = getRepositoryKey().apply(element);
336 if (!merged.containsKey(key)) {
337 merged.put(key, element);
338 }
339 }
340
341 builder.pluginRepositories(merged.values());
342 }
343 }
344
345
346
347
348 @Override
349 protected void mergeBuildBase_Filters(
350 BuildBase.Builder builder,
351 BuildBase target,
352 BuildBase source,
353 boolean sourceDominant,
354 Map<Object, Object> context) {
355 List<String> src = source.getFilters();
356 if (!src.isEmpty()) {
357 List<String> tgt = target.getFilters();
358 Set<String> excludes = new LinkedHashSet<>(tgt);
359 List<String> merged = new ArrayList<>(tgt.size() + src.size());
360 merged.addAll(tgt);
361 for (String s : src) {
362 if (!excludes.contains(s)) {
363 merged.add(s);
364 }
365 }
366 builder.filters(merged);
367 }
368 }
369
370 @Override
371 protected void mergeBuildBase_Resources(
372 BuildBase.Builder builder,
373 BuildBase target,
374 BuildBase source,
375 boolean sourceDominant,
376 Map<Object, Object> context) {
377 if (sourceDominant || target.getResources().isEmpty()) {
378 super.mergeBuildBase_Resources(builder, target, source, sourceDominant, context);
379 }
380 }
381
382 @Override
383 protected void mergeBuildBase_TestResources(
384 BuildBase.Builder builder,
385 BuildBase target,
386 BuildBase source,
387 boolean sourceDominant,
388 Map<Object, Object> context) {
389 if (sourceDominant || target.getTestResources().isEmpty()) {
390 super.mergeBuildBase_TestResources(builder, target, source, sourceDominant, context);
391 }
392 }
393
394 @Override
395 protected void mergeDistributionManagement_Relocation(
396 DistributionManagement.Builder builder,
397 DistributionManagement target,
398 DistributionManagement source,
399 boolean sourceDominant,
400 Map<Object, Object> context) {}
401
402 @Override
403 protected void mergeDistributionManagement_Repository(
404 DistributionManagement.Builder builder,
405 DistributionManagement target,
406 DistributionManagement source,
407 boolean sourceDominant,
408 Map<Object, Object> context) {
409 DeploymentRepository src = source.getRepository();
410 if (src != null) {
411 DeploymentRepository tgt = target.getRepository();
412 if (sourceDominant || tgt == null) {
413 tgt = DeploymentRepository.newInstance(false);
414 builder.repository(mergeDeploymentRepository(tgt, src, sourceDominant, context));
415 }
416 }
417 }
418
419 @Override
420 protected void mergeDistributionManagement_SnapshotRepository(
421 DistributionManagement.Builder builder,
422 DistributionManagement target,
423 DistributionManagement source,
424 boolean sourceDominant,
425 Map<Object, Object> context) {
426 DeploymentRepository src = source.getSnapshotRepository();
427 if (src != null) {
428 DeploymentRepository tgt = target.getSnapshotRepository();
429 if (sourceDominant || tgt == null) {
430 tgt = DeploymentRepository.newInstance(false);
431 builder.snapshotRepository(mergeDeploymentRepository(tgt, src, sourceDominant, context));
432 }
433 }
434 }
435
436 @Override
437 protected void mergeDistributionManagement_Site(
438 DistributionManagement.Builder builder,
439 DistributionManagement target,
440 DistributionManagement source,
441 boolean sourceDominant,
442 Map<Object, Object> context) {
443 Site src = source.getSite();
444 if (src != null) {
445 Site tgt = target.getSite();
446 if (tgt == null) {
447 tgt = Site.newBuilder(false).build();
448 }
449 Site.Builder sbuilder = Site.newBuilder(tgt);
450 if (sourceDominant || tgt == null || isSiteEmpty(tgt)) {
451 mergeSite(sbuilder, tgt, src, sourceDominant, context);
452 }
453 super.mergeSite_ChildSiteUrlInheritAppendPath(sbuilder, tgt, src, sourceDominant, context);
454 builder.site(sbuilder.build());
455 }
456 }
457
458 @Override
459 protected void mergeSite_ChildSiteUrlInheritAppendPath(
460 Site.Builder builder, Site target, Site source, boolean sourceDominant, Map<Object, Object> context) {}
461
462 protected boolean isSiteEmpty(Site site) {
463 return (site.getId() == null || site.getId().isEmpty())
464 && (site.getName() == null || site.getName().isEmpty())
465 && (site.getUrl() == null || site.getUrl().isEmpty());
466 }
467
468 @Override
469 protected void mergeSite_Url(
470 Site.Builder builder, Site target, Site source, boolean sourceDominant, Map<Object, Object> context) {
471 String src = source.getUrl();
472 if (src != null) {
473 if (sourceDominant) {
474 builder.url(src);
475 builder.location("url", source.getLocation("url"));
476 } else if (target.getUrl() == null) {
477 builder.url(extrapolateChildUrl(src, source.isChildSiteUrlInheritAppendPath(), context));
478 builder.location("url", source.getLocation("url"));
479 }
480 }
481 }
482
483 @Override
484 protected void mergeScm_Url(
485 Scm.Builder builder, Scm target, Scm source, boolean sourceDominant, Map<Object, Object> context) {
486 String src = source.getUrl();
487 if (src != null) {
488 if (sourceDominant) {
489 builder.url(src);
490 builder.location("url", source.getLocation("url"));
491 } else if (target.getUrl() == null) {
492 builder.url(extrapolateChildUrl(src, source.isChildScmUrlInheritAppendPath(), context));
493 builder.location("url", source.getLocation("url"));
494 }
495 }
496 }
497
498 @Override
499 protected void mergeScm_Connection(
500 Scm.Builder builder, Scm target, Scm source, boolean sourceDominant, Map<Object, Object> context) {
501 String src = source.getConnection();
502 if (src != null) {
503 if (sourceDominant) {
504 builder.connection(src);
505 builder.location("connection", source.getLocation("connection"));
506 } else if (target.getConnection() == null) {
507 builder.connection(extrapolateChildUrl(src, source.isChildScmConnectionInheritAppendPath(), context));
508 builder.location("connection", source.getLocation("connection"));
509 }
510 }
511 }
512
513 @Override
514 protected void mergeScm_DeveloperConnection(
515 Scm.Builder builder, Scm target, Scm source, boolean sourceDominant, Map<Object, Object> context) {
516 String src = source.getDeveloperConnection();
517 if (src != null) {
518 if (sourceDominant) {
519 builder.developerConnection(src);
520 builder.location("developerConnection", source.getLocation("developerConnection"));
521 } else if (target.getDeveloperConnection() == null) {
522 String e = extrapolateChildUrl(src, source.isChildScmDeveloperConnectionInheritAppendPath(), context);
523 builder.developerConnection(e);
524 builder.location("developerConnection", source.getLocation("developerConnection"));
525 }
526 }
527 }
528
529 @Override
530 protected void mergePlugin_Executions(
531 Plugin.Builder builder, Plugin target, Plugin source, boolean sourceDominant, Map<Object, Object> context) {
532 List<PluginExecution> src = source.getExecutions();
533 if (!src.isEmpty()) {
534 List<PluginExecution> tgt = target.getExecutions();
535 Map<Object, PluginExecution> merged = new LinkedHashMap<>((src.size() + tgt.size()) * 2);
536
537 for (PluginExecution element : src) {
538 if (sourceDominant || (element.getInherited() != null ? element.isInherited() : source.isInherited())) {
539 Object key = getPluginExecutionKey().apply(element);
540 merged.put(key, element);
541 }
542 }
543
544 for (PluginExecution element : tgt) {
545 Object key = getPluginExecutionKey().apply(element);
546 PluginExecution existing = merged.get(key);
547 if (existing != null) {
548 element = mergePluginExecution(element, existing, sourceDominant, context);
549 }
550 merged.put(key, element);
551 }
552
553 builder.executions(merged.values());
554 }
555 }
556
557 @Override
558 protected void mergePluginExecution_Goals(
559 PluginExecution.Builder builder,
560 PluginExecution target,
561 PluginExecution source,
562 boolean sourceDominant,
563 Map<Object, Object> context) {
564 List<String> src = source.getGoals();
565 if (!src.isEmpty()) {
566 List<String> tgt = target.getGoals();
567 Set<String> excludes = new LinkedHashSet<>(tgt);
568 List<String> merged = new ArrayList<>(tgt.size() + src.size());
569 merged.addAll(tgt);
570 for (String s : src) {
571 if (!excludes.contains(s)) {
572 merged.add(s);
573 }
574 }
575 builder.goals(merged);
576 }
577 }
578
579 @Override
580 protected void mergeReportPlugin_ReportSets(
581 ReportPlugin.Builder builder,
582 ReportPlugin target,
583 ReportPlugin source,
584 boolean sourceDominant,
585 Map<Object, Object> context) {
586 List<ReportSet> src = source.getReportSets();
587 if (!src.isEmpty()) {
588 List<ReportSet> tgt = target.getReportSets();
589 Map<Object, ReportSet> merged = new LinkedHashMap<>((src.size() + tgt.size()) * 2);
590
591 for (ReportSet rset : src) {
592 if (sourceDominant || (rset.getInherited() != null ? rset.isInherited() : source.isInherited())) {
593 Object key = getReportSetKey().apply(rset);
594 merged.put(key, rset);
595 }
596 }
597
598 for (ReportSet element : tgt) {
599 Object key = getReportSetKey().apply(element);
600 ReportSet existing = merged.get(key);
601 if (existing != null) {
602 mergeReportSet(element, existing, sourceDominant, context);
603 }
604 merged.put(key, element);
605 }
606
607 builder.reportSets(merged.values());
608 }
609 }
610
611 @Override
612 protected KeyComputer<Dependency> getDependencyKey() {
613 return Dependency::getManagementKey;
614 }
615
616 @Override
617 protected KeyComputer<Plugin> getPluginKey() {
618 return Plugin::getKey;
619 }
620
621 @Override
622 protected KeyComputer<PluginExecution> getPluginExecutionKey() {
623 return PluginExecution::getId;
624 }
625
626 @Override
627 protected KeyComputer<ReportPlugin> getReportPluginKey() {
628 return ReportPlugin::getKey;
629 }
630
631 @Override
632 protected KeyComputer<ReportSet> getReportSetKey() {
633 return ReportSet::getId;
634 }
635
636 @Override
637 protected KeyComputer<RepositoryBase> getRepositoryBaseKey() {
638 return RepositoryBase::getId;
639 }
640
641 @Override
642 protected KeyComputer<Extension> getExtensionKey() {
643 return e -> e.getGroupId() + ':' + e.getArtifactId();
644 }
645
646 @Override
647 protected KeyComputer<Exclusion> getExclusionKey() {
648 return e -> e.getGroupId() + ':' + e.getArtifactId();
649 }
650
651 protected String extrapolateChildUrl(String parentUrl, boolean appendPath, Map<Object, Object> context) {
652 return parentUrl;
653 }
654 }