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