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
235
236
237
238 @Override
239 protected void mergeModelBase_Repositories(
240 ModelBase.Builder builder,
241 ModelBase target,
242 ModelBase source,
243 boolean sourceDominant,
244 Map<Object, Object> context) {
245 List<Repository> src = source.getRepositories();
246 if (!src.isEmpty()) {
247 List<Repository> tgt = target.getRepositories();
248 Map<Object, Repository> merged = new LinkedHashMap<>((src.size() + tgt.size()) * 2);
249
250 List<Repository> dominant, recessive;
251 if (sourceDominant) {
252 dominant = src;
253 recessive = tgt;
254 } else {
255 dominant = tgt;
256 recessive = src;
257 }
258
259 for (Repository element : dominant) {
260 Object key = getRepositoryKey().apply(element);
261 merged.put(key, element);
262 }
263
264 for (Repository element : recessive) {
265 Object key = getRepositoryKey().apply(element);
266 if (!merged.containsKey(key)) {
267 merged.put(key, element);
268 }
269 }
270
271 builder.repositories(merged.values());
272 }
273 }
274
275 @Override
276 protected void mergeModelBase_PluginRepositories(
277 ModelBase.Builder builder,
278 ModelBase target,
279 ModelBase source,
280 boolean sourceDominant,
281 Map<Object, Object> context) {
282 List<Repository> src = source.getPluginRepositories();
283 if (!src.isEmpty()) {
284 List<Repository> tgt = target.getPluginRepositories();
285 Map<Object, Repository> merged = new LinkedHashMap<>((src.size() + tgt.size()) * 2);
286
287 List<Repository> dominant, recessive;
288 if (sourceDominant) {
289 dominant = src;
290 recessive = tgt;
291 } else {
292 dominant = tgt;
293 recessive = src;
294 }
295
296 for (Repository element : dominant) {
297 Object key = getRepositoryKey().apply(element);
298 merged.put(key, element);
299 }
300
301 for (Repository element : recessive) {
302 Object key = getRepositoryKey().apply(element);
303 if (!merged.containsKey(key)) {
304 merged.put(key, element);
305 }
306 }
307
308 builder.pluginRepositories(merged.values());
309 }
310 }
311
312
313
314
315 @Override
316 protected void mergeBuildBase_Filters(
317 BuildBase.Builder builder,
318 BuildBase target,
319 BuildBase source,
320 boolean sourceDominant,
321 Map<Object, Object> context) {
322 List<String> src = source.getFilters();
323 if (!src.isEmpty()) {
324 List<String> tgt = target.getFilters();
325 Set<String> excludes = new LinkedHashSet<>(tgt);
326 List<String> merged = new ArrayList<>(tgt.size() + src.size());
327 merged.addAll(tgt);
328 for (String s : src) {
329 if (!excludes.contains(s)) {
330 merged.add(s);
331 }
332 }
333 builder.filters(merged);
334 }
335 }
336
337 @Override
338 protected void mergeBuildBase_Resources(
339 BuildBase.Builder builder,
340 BuildBase target,
341 BuildBase source,
342 boolean sourceDominant,
343 Map<Object, Object> context) {
344 if (sourceDominant || target.getResources().isEmpty()) {
345 super.mergeBuildBase_Resources(builder, target, source, sourceDominant, context);
346 }
347 }
348
349 @Override
350 protected void mergeBuildBase_TestResources(
351 BuildBase.Builder builder,
352 BuildBase target,
353 BuildBase source,
354 boolean sourceDominant,
355 Map<Object, Object> context) {
356 if (sourceDominant || target.getTestResources().isEmpty()) {
357 super.mergeBuildBase_TestResources(builder, target, source, sourceDominant, context);
358 }
359 }
360
361 @Override
362 protected void mergeDistributionManagement_Relocation(
363 DistributionManagement.Builder builder,
364 DistributionManagement target,
365 DistributionManagement source,
366 boolean sourceDominant,
367 Map<Object, Object> context) {}
368
369 @Override
370 protected void mergeDistributionManagement_Repository(
371 DistributionManagement.Builder builder,
372 DistributionManagement target,
373 DistributionManagement source,
374 boolean sourceDominant,
375 Map<Object, Object> context) {
376 DeploymentRepository src = source.getRepository();
377 if (src != null) {
378 DeploymentRepository tgt = target.getRepository();
379 if (sourceDominant || tgt == null) {
380 tgt = DeploymentRepository.newInstance(false);
381 builder.repository(mergeDeploymentRepository(tgt, src, sourceDominant, context));
382 }
383 }
384 }
385
386 @Override
387 protected void mergeDistributionManagement_SnapshotRepository(
388 DistributionManagement.Builder builder,
389 DistributionManagement target,
390 DistributionManagement source,
391 boolean sourceDominant,
392 Map<Object, Object> context) {
393 DeploymentRepository src = source.getSnapshotRepository();
394 if (src != null) {
395 DeploymentRepository tgt = target.getSnapshotRepository();
396 if (sourceDominant || tgt == null) {
397 tgt = DeploymentRepository.newInstance(false);
398 builder.snapshotRepository(mergeDeploymentRepository(tgt, src, sourceDominant, context));
399 }
400 }
401 }
402
403 @Override
404 protected void mergeDistributionManagement_Site(
405 DistributionManagement.Builder builder,
406 DistributionManagement target,
407 DistributionManagement source,
408 boolean sourceDominant,
409 Map<Object, Object> context) {
410 Site src = source.getSite();
411 if (src != null) {
412 Site tgt = target.getSite();
413 if (tgt == null) {
414 tgt = Site.newBuilder(false).build();
415 }
416 Site.Builder sbuilder = Site.newBuilder(tgt);
417 if (sourceDominant || tgt == null || isSiteEmpty(tgt)) {
418 mergeSite(sbuilder, tgt, src, sourceDominant, context);
419 }
420 super.mergeSite_ChildSiteUrlInheritAppendPath(sbuilder, tgt, src, sourceDominant, context);
421 builder.site(sbuilder.build());
422 }
423 }
424
425 @Override
426 protected void mergeSite_ChildSiteUrlInheritAppendPath(
427 Site.Builder builder, Site target, Site source, boolean sourceDominant, Map<Object, Object> context) {}
428
429 protected boolean isSiteEmpty(Site site) {
430 return (site.getId() == null || site.getId().isEmpty())
431 && (site.getName() == null || site.getName().isEmpty())
432 && (site.getUrl() == null || site.getUrl().isEmpty());
433 }
434
435 @Override
436 protected void mergeSite_Url(
437 Site.Builder builder, Site target, Site source, boolean sourceDominant, Map<Object, Object> context) {
438 String src = source.getUrl();
439 if (src != null) {
440 if (sourceDominant) {
441 builder.url(src);
442 builder.location("url", source.getLocation("url"));
443 } else if (target.getUrl() == null) {
444 builder.url(extrapolateChildUrl(src, source.isChildSiteUrlInheritAppendPath(), context));
445 builder.location("url", source.getLocation("url"));
446 }
447 }
448 }
449
450 @Override
451 protected void mergeScm_Url(
452 Scm.Builder builder, Scm target, Scm source, boolean sourceDominant, Map<Object, Object> context) {
453 String src = source.getUrl();
454 if (src != null) {
455 if (sourceDominant) {
456 builder.url(src);
457 builder.location("url", source.getLocation("url"));
458 } else if (target.getUrl() == null) {
459 builder.url(extrapolateChildUrl(src, source.isChildScmUrlInheritAppendPath(), context));
460 builder.location("url", source.getLocation("url"));
461 }
462 }
463 }
464
465 @Override
466 protected void mergeScm_Connection(
467 Scm.Builder builder, Scm target, Scm source, boolean sourceDominant, Map<Object, Object> context) {
468 String src = source.getConnection();
469 if (src != null) {
470 if (sourceDominant) {
471 builder.connection(src);
472 builder.location("connection", source.getLocation("connection"));
473 } else if (target.getConnection() == null) {
474 builder.connection(extrapolateChildUrl(src, source.isChildScmConnectionInheritAppendPath(), context));
475 builder.location("connection", source.getLocation("connection"));
476 }
477 }
478 }
479
480 @Override
481 protected void mergeScm_DeveloperConnection(
482 Scm.Builder builder, Scm target, Scm source, boolean sourceDominant, Map<Object, Object> context) {
483 String src = source.getDeveloperConnection();
484 if (src != null) {
485 if (sourceDominant) {
486 builder.developerConnection(src);
487 builder.location("developerConnection", source.getLocation("developerConnection"));
488 } else if (target.getDeveloperConnection() == null) {
489 String e = extrapolateChildUrl(src, source.isChildScmDeveloperConnectionInheritAppendPath(), context);
490 builder.developerConnection(e);
491 builder.location("developerConnection", source.getLocation("developerConnection"));
492 }
493 }
494 }
495
496 @Override
497 protected void mergePlugin_Executions(
498 Plugin.Builder builder, Plugin target, Plugin source, boolean sourceDominant, Map<Object, Object> context) {
499 List<PluginExecution> src = source.getExecutions();
500 if (!src.isEmpty()) {
501 List<PluginExecution> tgt = target.getExecutions();
502 Map<Object, PluginExecution> merged = new LinkedHashMap<>((src.size() + tgt.size()) * 2);
503
504 for (PluginExecution element : src) {
505 if (sourceDominant || (element.getInherited() != null ? element.isInherited() : source.isInherited())) {
506 Object key = getPluginExecutionKey().apply(element);
507 merged.put(key, element);
508 }
509 }
510
511 for (PluginExecution element : tgt) {
512 Object key = getPluginExecutionKey().apply(element);
513 PluginExecution existing = merged.get(key);
514 if (existing != null) {
515 element = mergePluginExecution(element, existing, sourceDominant, context);
516 }
517 merged.put(key, element);
518 }
519
520 builder.executions(merged.values());
521 }
522 }
523
524 @Override
525 protected void mergePluginExecution_Goals(
526 PluginExecution.Builder builder,
527 PluginExecution target,
528 PluginExecution source,
529 boolean sourceDominant,
530 Map<Object, Object> context) {
531 List<String> src = source.getGoals();
532 if (!src.isEmpty()) {
533 List<String> tgt = target.getGoals();
534 Set<String> excludes = new LinkedHashSet<>(tgt);
535 List<String> merged = new ArrayList<>(tgt.size() + src.size());
536 merged.addAll(tgt);
537 for (String s : src) {
538 if (!excludes.contains(s)) {
539 merged.add(s);
540 }
541 }
542 builder.goals(merged);
543 }
544 }
545
546 @Override
547 protected void mergeReportPlugin_ReportSets(
548 ReportPlugin.Builder builder,
549 ReportPlugin target,
550 ReportPlugin source,
551 boolean sourceDominant,
552 Map<Object, Object> context) {
553 List<ReportSet> src = source.getReportSets();
554 if (!src.isEmpty()) {
555 List<ReportSet> tgt = target.getReportSets();
556 Map<Object, ReportSet> merged = new LinkedHashMap<>((src.size() + tgt.size()) * 2);
557
558 for (ReportSet rset : src) {
559 if (sourceDominant || (rset.getInherited() != null ? rset.isInherited() : source.isInherited())) {
560 Object key = getReportSetKey().apply(rset);
561 merged.put(key, rset);
562 }
563 }
564
565 for (ReportSet element : tgt) {
566 Object key = getReportSetKey().apply(element);
567 ReportSet existing = merged.get(key);
568 if (existing != null) {
569 mergeReportSet(element, existing, sourceDominant, context);
570 }
571 merged.put(key, element);
572 }
573
574 builder.reportSets(merged.values());
575 }
576 }
577
578 @Override
579 protected KeyComputer<Dependency> getDependencyKey() {
580 return Dependency::getManagementKey;
581 }
582
583 @Override
584 protected KeyComputer<Plugin> getPluginKey() {
585 return Plugin::getKey;
586 }
587
588 @Override
589 protected KeyComputer<PluginExecution> getPluginExecutionKey() {
590 return PluginExecution::getId;
591 }
592
593 @Override
594 protected KeyComputer<ReportPlugin> getReportPluginKey() {
595 return ReportPlugin::getKey;
596 }
597
598 @Override
599 protected KeyComputer<ReportSet> getReportSetKey() {
600 return ReportSet::getId;
601 }
602
603 @Override
604 protected KeyComputer<RepositoryBase> getRepositoryBaseKey() {
605 return RepositoryBase::getId;
606 }
607
608 @Override
609 protected KeyComputer<Extension> getExtensionKey() {
610 return e -> e.getGroupId() + ':' + e.getArtifactId();
611 }
612
613 @Override
614 protected KeyComputer<Exclusion> getExclusionKey() {
615 return e -> e.getGroupId() + ':' + e.getArtifactId();
616 }
617
618 protected String extrapolateChildUrl(String parentUrl, boolean appendPath, Map<Object, Object> context) {
619 return parentUrl;
620 }
621 }