1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.project.inheritance;
20
21 import java.util.ArrayList;
22 import java.util.LinkedHashMap;
23 import java.util.LinkedList;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.Properties;
27 import java.util.StringTokenizer;
28 import java.util.TreeMap;
29
30 import org.apache.maven.model.Build;
31 import org.apache.maven.model.Dependency;
32 import org.apache.maven.model.DependencyManagement;
33 import org.apache.maven.model.DeploymentRepository;
34 import org.apache.maven.model.DistributionManagement;
35 import org.apache.maven.model.Extension;
36 import org.apache.maven.model.Model;
37 import org.apache.maven.model.PluginManagement;
38 import org.apache.maven.model.ReportPlugin;
39 import org.apache.maven.model.ReportSet;
40 import org.apache.maven.model.Reporting;
41 import org.apache.maven.model.Resource;
42 import org.apache.maven.model.Scm;
43 import org.apache.maven.model.Site;
44 import org.apache.maven.project.ModelUtils;
45 import org.codehaus.plexus.component.annotations.Component;
46 import org.codehaus.plexus.util.StringUtils;
47 import org.codehaus.plexus.util.xml.Xpp3Dom;
48
49
50
51
52 @Component(role = ModelInheritanceAssembler.class)
53 public class DefaultModelInheritanceAssembler implements ModelInheritanceAssembler {
54
55 public void assembleBuildInheritance(Build childBuild, Build parentBuild, boolean handleAsInheritance) {
56
57
58
59 if (childBuild.getSourceDirectory() == null) {
60 childBuild.setSourceDirectory(parentBuild.getSourceDirectory());
61 }
62
63 if (childBuild.getScriptSourceDirectory() == null) {
64 childBuild.setScriptSourceDirectory(parentBuild.getScriptSourceDirectory());
65 }
66
67 if (childBuild.getTestSourceDirectory() == null) {
68 childBuild.setTestSourceDirectory(parentBuild.getTestSourceDirectory());
69 }
70
71 if (childBuild.getOutputDirectory() == null) {
72 childBuild.setOutputDirectory(parentBuild.getOutputDirectory());
73 }
74
75 if (childBuild.getTestOutputDirectory() == null) {
76 childBuild.setTestOutputDirectory(parentBuild.getTestOutputDirectory());
77 }
78
79
80 mergeExtensionLists(childBuild, parentBuild);
81
82 if (childBuild.getDirectory() == null) {
83 childBuild.setDirectory(parentBuild.getDirectory());
84 }
85
86 if (childBuild.getDefaultGoal() == null) {
87 childBuild.setDefaultGoal(parentBuild.getDefaultGoal());
88 }
89
90 if (childBuild.getFinalName() == null) {
91 childBuild.setFinalName(parentBuild.getFinalName());
92 }
93
94 ModelUtils.mergeFilterLists(childBuild.getFilters(), parentBuild.getFilters());
95
96 List<Resource> resources = childBuild.getResources();
97 if ((resources == null) || resources.isEmpty()) {
98 childBuild.setResources(parentBuild.getResources());
99 }
100
101 resources = childBuild.getTestResources();
102 if ((resources == null) || resources.isEmpty()) {
103 childBuild.setTestResources(parentBuild.getTestResources());
104 }
105
106
107 ModelUtils.mergePluginLists(childBuild, parentBuild, handleAsInheritance);
108
109
110 PluginManagement dominantPM = childBuild.getPluginManagement();
111 PluginManagement recessivePM = parentBuild.getPluginManagement();
112
113 if ((dominantPM == null) && (recessivePM != null)) {
114
115 childBuild.setPluginManagement(recessivePM);
116 } else {
117 ModelUtils.mergePluginLists(childBuild.getPluginManagement(), parentBuild.getPluginManagement(), false);
118 }
119 }
120
121 private void assembleScmInheritance(Model child, Model parent, String childPathAdjustment, boolean appendPaths) {
122 if (parent.getScm() != null) {
123 Scm parentScm = parent.getScm();
124
125 Scm childScm = child.getScm();
126
127 if (childScm == null) {
128 childScm = new Scm();
129
130 child.setScm(childScm);
131 }
132
133 if (StringUtils.isEmpty(childScm.getConnection()) && !StringUtils.isEmpty(parentScm.getConnection())) {
134 childScm.setConnection(
135 appendPath(parentScm.getConnection(), child.getArtifactId(), childPathAdjustment, appendPaths));
136 }
137
138 if (StringUtils.isEmpty(childScm.getDeveloperConnection())
139 && !StringUtils.isEmpty(parentScm.getDeveloperConnection())) {
140 childScm.setDeveloperConnection(appendPath(
141 parentScm.getDeveloperConnection(), child.getArtifactId(), childPathAdjustment, appendPaths));
142 }
143
144 if (StringUtils.isEmpty(childScm.getUrl()) && !StringUtils.isEmpty(parentScm.getUrl())) {
145 childScm.setUrl(
146 appendPath(parentScm.getUrl(), child.getArtifactId(), childPathAdjustment, appendPaths));
147 }
148 }
149 }
150
151 public void copyModel(Model dest, Model source) {
152 assembleModelInheritance(dest, source, null, false);
153 }
154
155 public void assembleModelInheritance(Model child, Model parent, String childPathAdjustment) {
156 assembleModelInheritance(child, parent, childPathAdjustment, true);
157 }
158
159 public void assembleModelInheritance(Model child, Model parent) {
160 assembleModelInheritance(child, parent, null, true);
161 }
162
163 private void assembleModelInheritance(Model child, Model parent, String childPathAdjustment, boolean appendPaths) {
164
165 if (parent == null) {
166 return;
167 }
168
169
170 if (child.getGroupId() == null) {
171 child.setGroupId(parent.getGroupId());
172 }
173
174
175 if (child.getVersion() == null) {
176
177
178
179 if (child.getParent() != null) {
180 child.setVersion(child.getParent().getVersion());
181 }
182 }
183
184
185 if (child.getInceptionYear() == null) {
186 child.setInceptionYear(parent.getInceptionYear());
187 }
188
189
190 if (child.getUrl() == null) {
191 if (parent.getUrl() != null) {
192 child.setUrl(appendPath(parent.getUrl(), child.getArtifactId(), childPathAdjustment, appendPaths));
193 } else {
194 child.setUrl(parent.getUrl());
195 }
196 }
197
198 assembleDistributionInheritance(child, parent, childPathAdjustment, appendPaths);
199
200
201 if (child.getIssueManagement() == null) {
202 child.setIssueManagement(parent.getIssueManagement());
203 }
204
205
206 if (child.getDescription() == null) {
207 child.setDescription(parent.getDescription());
208 }
209
210
211 if (child.getOrganization() == null) {
212 child.setOrganization(parent.getOrganization());
213 }
214
215
216 assembleScmInheritance(child, parent, childPathAdjustment, appendPaths);
217
218
219 if (child.getCiManagement() == null) {
220 child.setCiManagement(parent.getCiManagement());
221 }
222
223
224 if (child.getDevelopers().size() == 0) {
225 child.setDevelopers(parent.getDevelopers());
226 }
227
228
229 if (child.getLicenses().size() == 0) {
230 child.setLicenses(parent.getLicenses());
231 }
232
233
234 if (child.getContributors().size() == 0) {
235 child.setContributors(parent.getContributors());
236 }
237
238
239 if (child.getMailingLists().size() == 0) {
240 child.setMailingLists(parent.getMailingLists());
241 }
242
243
244 assembleBuildInheritance(child, parent);
245
246 assembleDependencyInheritance(child, parent);
247
248 child.setRepositories(ModelUtils.mergeRepositoryLists(child.getRepositories(), parent.getRepositories()));
249
250
251
252
253 assembleReportingInheritance(child, parent);
254
255 assembleDependencyManagementInheritance(child, parent);
256
257 Properties props = new Properties();
258 props.putAll(parent.getProperties());
259 props.putAll(child.getProperties());
260
261 child.setProperties(props);
262 }
263
264
265 private void assembleDependencyManagementInheritance(Model child, Model parent) {
266 DependencyManagement parentDepMgmt = parent.getDependencyManagement();
267
268 DependencyManagement childDepMgmt = child.getDependencyManagement();
269
270 if (parentDepMgmt != null) {
271 if (childDepMgmt == null) {
272 child.setDependencyManagement(parentDepMgmt);
273 } else {
274 List<Dependency> childDeps = childDepMgmt.getDependencies();
275
276 Map<String, Dependency> mappedChildDeps = new TreeMap<>();
277 for (Dependency dep : childDeps) {
278 mappedChildDeps.put(dep.getManagementKey(), dep);
279 }
280
281 for (Dependency dep : parentDepMgmt.getDependencies()) {
282 if (!mappedChildDeps.containsKey(dep.getManagementKey())) {
283 childDepMgmt.addDependency(dep);
284 }
285 }
286 }
287 }
288 }
289
290 private void assembleReportingInheritance(Model child, Model parent) {
291
292 Reporting childReporting = child.getReporting();
293 Reporting parentReporting = parent.getReporting();
294
295 if (parentReporting != null) {
296 if (childReporting == null) {
297 childReporting = new Reporting();
298 child.setReporting(childReporting);
299 }
300
301 childReporting.setExcludeDefaults(parentReporting.isExcludeDefaults());
302
303 if (StringUtils.isEmpty(childReporting.getOutputDirectory())) {
304 childReporting.setOutputDirectory(parentReporting.getOutputDirectory());
305 }
306
307 mergeReportPluginLists(childReporting, parentReporting, true);
308 }
309 }
310
311 private static void mergeReportPluginLists(Reporting child, Reporting parent, boolean handleAsInheritance) {
312 if ((child == null) || (parent == null)) {
313
314 return;
315 }
316
317 List<ReportPlugin> parentPlugins = parent.getPlugins();
318
319 if ((parentPlugins != null) && !parentPlugins.isEmpty()) {
320 Map<String, ReportPlugin> assembledPlugins = new TreeMap<>();
321
322 Map<String, ReportPlugin> childPlugins = child.getReportPluginsAsMap();
323
324 for (ReportPlugin parentPlugin : parentPlugins) {
325 String parentInherited = parentPlugin.getInherited();
326
327 if (!handleAsInheritance || (parentInherited == null) || Boolean.parseBoolean(parentInherited)) {
328
329 ReportPlugin assembledPlugin = parentPlugin;
330
331 ReportPlugin childPlugin = childPlugins.get(parentPlugin.getKey());
332
333 if (childPlugin != null) {
334 assembledPlugin = childPlugin;
335
336 mergeReportPluginDefinitions(childPlugin, parentPlugin, handleAsInheritance);
337 }
338
339 if (handleAsInheritance && (parentInherited == null)) {
340 assembledPlugin.unsetInheritanceApplied();
341 }
342
343 assembledPlugins.put(assembledPlugin.getKey(), assembledPlugin);
344 }
345 }
346
347 for (ReportPlugin childPlugin : childPlugins.values()) {
348 if (!assembledPlugins.containsKey(childPlugin.getKey())) {
349 assembledPlugins.put(childPlugin.getKey(), childPlugin);
350 }
351 }
352
353 child.setPlugins(new ArrayList<>(assembledPlugins.values()));
354
355 child.flushReportPluginMap();
356 }
357 }
358
359 private static void mergeReportSetDefinitions(ReportSet child, ReportSet parent) {
360 List<String> parentReports = parent.getReports();
361 List<String> childReports = child.getReports();
362
363 List<String> reports = new ArrayList<>();
364
365 if ((childReports != null) && !childReports.isEmpty()) {
366 reports.addAll(childReports);
367 }
368
369 if (parentReports != null) {
370 for (String report : parentReports) {
371 if (!reports.contains(report)) {
372 reports.add(report);
373 }
374 }
375 }
376
377 child.setReports(reports);
378
379 Xpp3Dom childConfiguration = (Xpp3Dom) child.getConfiguration();
380 Xpp3Dom parentConfiguration = (Xpp3Dom) parent.getConfiguration();
381
382 childConfiguration = Xpp3Dom.mergeXpp3Dom(childConfiguration, parentConfiguration);
383
384 child.setConfiguration(childConfiguration);
385 }
386
387 public static void mergeReportPluginDefinitions(
388 ReportPlugin child, ReportPlugin parent, boolean handleAsInheritance) {
389 if ((child == null) || (parent == null)) {
390
391 return;
392 }
393
394 if ((child.getVersion() == null) && (parent.getVersion() != null)) {
395 child.setVersion(parent.getVersion());
396 }
397
398
399 String parentInherited = parent.getInherited();
400
401 boolean parentIsInherited = (parentInherited == null) || Boolean.parseBoolean(parentInherited);
402
403 List<ReportSet> parentReportSets = parent.getReportSets();
404
405 if ((parentReportSets != null) && !parentReportSets.isEmpty()) {
406 Map<String, ReportSet> assembledReportSets = new TreeMap<>();
407
408 Map<String, ReportSet> childReportSets = child.getReportSetsAsMap();
409
410 for (Object parentReportSet1 : parentReportSets) {
411 ReportSet parentReportSet = (ReportSet) parentReportSet1;
412
413 if (!handleAsInheritance || parentIsInherited) {
414 ReportSet assembledReportSet = parentReportSet;
415
416 ReportSet childReportSet = childReportSets.get(parentReportSet.getId());
417
418 if (childReportSet != null) {
419 mergeReportSetDefinitions(childReportSet, parentReportSet);
420
421 assembledReportSet = childReportSet;
422 } else if (handleAsInheritance && (parentInherited == null)) {
423 parentReportSet.unsetInheritanceApplied();
424 }
425
426 assembledReportSets.put(assembledReportSet.getId(), assembledReportSet);
427 }
428 }
429
430 for (Map.Entry<String, ReportSet> entry : childReportSets.entrySet()) {
431 String id = entry.getKey();
432
433 if (!assembledReportSets.containsKey(id)) {
434 assembledReportSets.put(id, entry.getValue());
435 }
436 }
437
438 child.setReportSets(new ArrayList<>(assembledReportSets.values()));
439
440 child.flushReportSetMap();
441 }
442 }
443
444
445 private void assembleDependencyInheritance(Model child, Model parent) {
446 Map<String, Dependency> depsMap = new LinkedHashMap<>();
447
448 List<Dependency> deps = parent.getDependencies();
449
450 if (deps != null) {
451 for (Dependency dependency : deps) {
452 depsMap.put(dependency.getManagementKey(), dependency);
453 }
454 }
455
456 deps = child.getDependencies();
457
458 if (deps != null) {
459 for (Dependency dependency : deps) {
460 depsMap.put(dependency.getManagementKey(), dependency);
461 }
462 }
463
464 child.setDependencies(new ArrayList<>(depsMap.values()));
465 }
466
467 private void assembleBuildInheritance(Model child, Model parent) {
468 Build childBuild = child.getBuild();
469 Build parentBuild = parent.getBuild();
470
471 if (parentBuild != null) {
472 if (childBuild == null) {
473 childBuild = new Build();
474 child.setBuild(childBuild);
475 }
476
477 assembleBuildInheritance(childBuild, parentBuild, true);
478 }
479 }
480
481 private void assembleDistributionInheritance(
482 Model child, Model parent, String childPathAdjustment, boolean appendPaths) {
483 if (parent.getDistributionManagement() != null) {
484 DistributionManagement parentDistMgmt = parent.getDistributionManagement();
485
486 DistributionManagement childDistMgmt = child.getDistributionManagement();
487
488 if (childDistMgmt == null) {
489 childDistMgmt = new DistributionManagement();
490
491 child.setDistributionManagement(childDistMgmt);
492 }
493
494 if (childDistMgmt.getSite() == null) {
495 if (parentDistMgmt.getSite() != null) {
496 Site site = new Site();
497
498 childDistMgmt.setSite(site);
499
500 site.setId(parentDistMgmt.getSite().getId());
501
502 site.setName(parentDistMgmt.getSite().getName());
503
504 site.setUrl(parentDistMgmt.getSite().getUrl());
505
506 if (site.getUrl() != null) {
507 site.setUrl(appendPath(site.getUrl(), child.getArtifactId(), childPathAdjustment, appendPaths));
508 }
509 }
510 }
511
512 if (childDistMgmt.getRepository() == null) {
513 if (parentDistMgmt.getRepository() != null) {
514 DeploymentRepository repository = copyDistributionRepository(parentDistMgmt.getRepository());
515 childDistMgmt.setRepository(repository);
516 }
517 }
518
519 if (childDistMgmt.getSnapshotRepository() == null) {
520 if (parentDistMgmt.getSnapshotRepository() != null) {
521 DeploymentRepository repository =
522 copyDistributionRepository(parentDistMgmt.getSnapshotRepository());
523 childDistMgmt.setSnapshotRepository(repository);
524 }
525 }
526
527 if (StringUtils.isEmpty(childDistMgmt.getDownloadUrl())) {
528 childDistMgmt.setDownloadUrl(parentDistMgmt.getDownloadUrl());
529 }
530
531
532
533 }
534 }
535
536 private static DeploymentRepository copyDistributionRepository(DeploymentRepository parentRepository) {
537 DeploymentRepository repository = new DeploymentRepository();
538
539 repository.setId(parentRepository.getId());
540
541 repository.setName(parentRepository.getName());
542
543 repository.setUrl(parentRepository.getUrl());
544
545 repository.setLayout(parentRepository.getLayout());
546
547 repository.setUniqueVersion(parentRepository.isUniqueVersion());
548
549 return repository;
550 }
551
552
553 protected String appendPath(String parentPath, String childPath, String pathAdjustment, boolean appendPaths) {
554 String uncleanPath = parentPath;
555
556 if (appendPaths) {
557 if (pathAdjustment != null) {
558 uncleanPath += "/" + pathAdjustment;
559 }
560
561 if (childPath != null) {
562 uncleanPath += "/" + childPath;
563 }
564 }
565
566 String cleanedPath = "";
567
568 int protocolIdx = uncleanPath.indexOf("://");
569
570 if (protocolIdx > -1) {
571 cleanedPath = uncleanPath.substring(0, protocolIdx + 3);
572 uncleanPath = uncleanPath.substring(protocolIdx + 3);
573 }
574
575 if (uncleanPath.startsWith("/")) {
576 cleanedPath += "/";
577 }
578
579 return cleanedPath + resolvePath(uncleanPath);
580 }
581
582
583 private static String resolvePath(String uncleanPath) {
584 LinkedList<String> pathElements = new LinkedList<>();
585
586 StringTokenizer tokenizer = new StringTokenizer(uncleanPath, "/");
587
588 while (tokenizer.hasMoreTokens()) {
589 String token = tokenizer.nextToken();
590
591 switch (token) {
592 case "":
593
594 break;
595 case "..":
596 if (pathElements.isEmpty()) {
597
598
599
600 } else {
601 pathElements.removeLast();
602 }
603 break;
604 default:
605 pathElements.addLast(token);
606 break;
607 }
608 }
609
610 StringBuilder cleanedPath = new StringBuilder();
611
612 while (!pathElements.isEmpty()) {
613 cleanedPath.append(pathElements.removeFirst());
614 if (!pathElements.isEmpty()) {
615 cleanedPath.append('/');
616 }
617 }
618
619 return cleanedPath.toString();
620 }
621
622 private static void mergeExtensionLists(Build childBuild, Build parentBuild) {
623 for (Extension e : parentBuild.getExtensions()) {
624 if (!childBuild.getExtensions().contains(e)) {
625 childBuild.addExtension(e);
626 }
627 }
628 }
629 }