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