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 @Component( role = ModelInheritanceAssembler.class )
51 public class DefaultModelInheritanceAssembler
52 implements ModelInheritanceAssembler
53 {
54
55 @SuppressWarnings( "unchecked" )
56 public void assembleBuildInheritance( Build childBuild, Build parentBuild, boolean handleAsInheritance )
57 {
58
59
60
61 if ( childBuild.getSourceDirectory() == null )
62 {
63 childBuild.setSourceDirectory( parentBuild.getSourceDirectory() );
64 }
65
66 if ( childBuild.getScriptSourceDirectory() == null )
67 {
68 childBuild.setScriptSourceDirectory( parentBuild.getScriptSourceDirectory() );
69 }
70
71 if ( childBuild.getTestSourceDirectory() == null )
72 {
73 childBuild.setTestSourceDirectory( parentBuild.getTestSourceDirectory() );
74 }
75
76 if ( childBuild.getOutputDirectory() == null )
77 {
78 childBuild.setOutputDirectory( parentBuild.getOutputDirectory() );
79 }
80
81 if ( childBuild.getTestOutputDirectory() == null )
82 {
83 childBuild.setTestOutputDirectory( parentBuild.getTestOutputDirectory() );
84 }
85
86
87 mergeExtensionLists( childBuild, parentBuild );
88
89 if ( childBuild.getDirectory() == null )
90 {
91 childBuild.setDirectory( parentBuild.getDirectory() );
92 }
93
94 if ( childBuild.getDefaultGoal() == null )
95 {
96 childBuild.setDefaultGoal( parentBuild.getDefaultGoal() );
97 }
98
99 if ( childBuild.getFinalName() == null )
100 {
101 childBuild.setFinalName( parentBuild.getFinalName() );
102 }
103
104 ModelUtils.mergeFilterLists( childBuild.getFilters(), parentBuild.getFilters() );
105
106 List<Resource> resources = childBuild.getResources();
107 if ( ( resources == null ) || resources.isEmpty() )
108 {
109 childBuild.setResources( parentBuild.getResources() );
110 }
111
112 resources = childBuild.getTestResources();
113 if ( ( resources == null ) || resources.isEmpty() )
114 {
115 childBuild.setTestResources( parentBuild.getTestResources() );
116 }
117
118
119 ModelUtils.mergePluginLists( childBuild, parentBuild, handleAsInheritance );
120
121
122 PluginManagement dominantPM = childBuild.getPluginManagement();
123 PluginManagement recessivePM = parentBuild.getPluginManagement();
124
125 if ( ( dominantPM == null ) && ( recessivePM != null ) )
126 {
127
128 childBuild.setPluginManagement( recessivePM );
129 }
130 else
131 {
132 ModelUtils.mergePluginLists( childBuild.getPluginManagement(), parentBuild.getPluginManagement(), false );
133 }
134 }
135
136 private void assembleScmInheritance( Model child, Model parent, String childPathAdjustment, boolean appendPaths )
137 {
138 if ( parent.getScm() != null )
139 {
140 Scm parentScm = parent.getScm();
141
142 Scm childScm = child.getScm();
143
144 if ( childScm == null )
145 {
146 childScm = new Scm();
147
148 child.setScm( childScm );
149 }
150
151 if ( StringUtils.isEmpty( childScm.getConnection() ) && !StringUtils.isEmpty( parentScm.getConnection() ) )
152 {
153 childScm.setConnection(
154 appendPath( parentScm.getConnection(), child.getArtifactId(), childPathAdjustment, appendPaths ) );
155 }
156
157 if ( StringUtils.isEmpty( childScm.getDeveloperConnection() )
158 && !StringUtils.isEmpty( parentScm.getDeveloperConnection() ) )
159 {
160 childScm
161 .setDeveloperConnection( appendPath( parentScm.getDeveloperConnection(), child.getArtifactId(),
162 childPathAdjustment, appendPaths ) );
163 }
164
165 if ( StringUtils.isEmpty( childScm.getUrl() ) && !StringUtils.isEmpty( parentScm.getUrl() ) )
166 {
167 childScm.setUrl(
168 appendPath( parentScm.getUrl(), child.getArtifactId(), childPathAdjustment, appendPaths ) );
169 }
170 }
171 }
172
173 public void copyModel( Model dest, Model source )
174 {
175 assembleModelInheritance( dest, source, null, false );
176 }
177
178 public void assembleModelInheritance( Model child, Model parent, String childPathAdjustment )
179 {
180 assembleModelInheritance( child, parent, childPathAdjustment, true );
181 }
182
183 public void assembleModelInheritance( Model child, Model parent )
184 {
185 assembleModelInheritance( child, parent, null, true );
186 }
187
188 private void assembleModelInheritance( Model child, Model parent, String childPathAdjustment, boolean appendPaths )
189 {
190
191 if ( parent == null )
192 {
193 return;
194 }
195
196
197 if ( child.getGroupId() == null )
198 {
199 child.setGroupId( parent.getGroupId() );
200 }
201
202
203 if ( child.getVersion() == null )
204 {
205
206
207
208 if ( child.getParent() != null )
209 {
210 child.setVersion( child.getParent().getVersion() );
211 }
212 }
213
214
215 if ( child.getInceptionYear() == null )
216 {
217 child.setInceptionYear( parent.getInceptionYear() );
218 }
219
220
221 if ( child.getUrl() == null )
222 {
223 if ( parent.getUrl() != null )
224 {
225 child.setUrl( appendPath( parent.getUrl(), child.getArtifactId(), childPathAdjustment, appendPaths ) );
226 }
227 else
228 {
229 child.setUrl( parent.getUrl() );
230 }
231 }
232
233 assembleDistributionInheritance( child, parent, childPathAdjustment, appendPaths );
234
235
236 if ( child.getIssueManagement() == null )
237 {
238 child.setIssueManagement( parent.getIssueManagement() );
239 }
240
241
242 if ( child.getDescription() == null )
243 {
244 child.setDescription( parent.getDescription() );
245 }
246
247
248 if ( child.getOrganization() == null )
249 {
250 child.setOrganization( parent.getOrganization() );
251 }
252
253
254 assembleScmInheritance( child, parent, childPathAdjustment, appendPaths );
255
256
257 if ( child.getCiManagement() == null )
258 {
259 child.setCiManagement( parent.getCiManagement() );
260 }
261
262
263 if ( child.getDevelopers().size() == 0 )
264 {
265 child.setDevelopers( parent.getDevelopers() );
266 }
267
268
269 if ( child.getLicenses().size() == 0 )
270 {
271 child.setLicenses( parent.getLicenses() );
272 }
273
274
275 if ( child.getContributors().size() == 0 )
276 {
277 child.setContributors( parent.getContributors() );
278 }
279
280
281 if ( child.getMailingLists().size() == 0 )
282 {
283 child.setMailingLists( parent.getMailingLists() );
284 }
285
286
287 assembleBuildInheritance( child, parent );
288
289 assembleDependencyInheritance( child, parent );
290
291 child.setRepositories( ModelUtils.mergeRepositoryLists( child.getRepositories(), parent.getRepositories() ) );
292
293
294
295 assembleReportingInheritance( child, parent );
296
297 assembleDependencyManagementInheritance( child, parent );
298
299 Properties props = new Properties();
300 props.putAll( parent.getProperties() );
301 props.putAll( child.getProperties() );
302
303 child.setProperties( props );
304 }
305
306
307 @SuppressWarnings( "unchecked" )
308 private void assembleDependencyManagementInheritance( Model child, Model parent )
309 {
310 DependencyManagement parentDepMgmt = parent.getDependencyManagement();
311
312 DependencyManagement childDepMgmt = child.getDependencyManagement();
313
314 if ( parentDepMgmt != null )
315 {
316 if ( childDepMgmt == null )
317 {
318 child.setDependencyManagement( parentDepMgmt );
319 }
320 else
321 {
322 List<Dependency> childDeps = childDepMgmt.getDependencies();
323
324 Map<String, Dependency> mappedChildDeps = new TreeMap<>();
325 for ( Dependency dep : childDeps )
326 {
327 mappedChildDeps.put( dep.getManagementKey(), dep );
328 }
329
330 for ( Dependency dep : parentDepMgmt.getDependencies() )
331 {
332 if ( !mappedChildDeps.containsKey( dep.getManagementKey() ) )
333 {
334 childDepMgmt.addDependency( dep );
335 }
336 }
337 }
338 }
339 }
340
341 private void assembleReportingInheritance( Model child, Model parent )
342 {
343
344 Reporting childReporting = child.getReporting();
345 Reporting parentReporting = parent.getReporting();
346
347 if ( parentReporting != null )
348 {
349 if ( childReporting == null )
350 {
351 childReporting = new Reporting();
352 child.setReporting( childReporting );
353 }
354
355 childReporting.setExcludeDefaults( parentReporting.isExcludeDefaults() );
356
357 if ( StringUtils.isEmpty( childReporting.getOutputDirectory() ) )
358 {
359 childReporting.setOutputDirectory( parentReporting.getOutputDirectory() );
360 }
361
362 mergeReportPluginLists( childReporting, parentReporting, true );
363 }
364 }
365
366 private static void mergeReportPluginLists( Reporting child, Reporting parent, boolean handleAsInheritance )
367 {
368 if ( ( child == null ) || ( parent == null ) )
369 {
370
371 return;
372 }
373
374 List<ReportPlugin> parentPlugins = parent.getPlugins();
375
376 if ( ( parentPlugins != null ) && !parentPlugins.isEmpty() )
377 {
378 Map<String, ReportPlugin> assembledPlugins = new TreeMap<>();
379
380 Map<String, ReportPlugin> childPlugins = child.getReportPluginsAsMap();
381
382 for ( ReportPlugin parentPlugin : parentPlugins )
383 {
384 String parentInherited = parentPlugin.getInherited();
385
386 if ( !handleAsInheritance || ( parentInherited == null ) || Boolean.valueOf( parentInherited ) )
387 {
388
389 ReportPlugin assembledPlugin = parentPlugin;
390
391 ReportPlugin childPlugin = childPlugins.get( parentPlugin.getKey() );
392
393 if ( childPlugin != null )
394 {
395 assembledPlugin = childPlugin;
396
397 mergeReportPluginDefinitions( childPlugin, parentPlugin, handleAsInheritance );
398 }
399
400 if ( handleAsInheritance && ( parentInherited == null ) )
401 {
402 assembledPlugin.unsetInheritanceApplied();
403 }
404
405 assembledPlugins.put( assembledPlugin.getKey(), assembledPlugin );
406 }
407 }
408
409 for ( ReportPlugin childPlugin : childPlugins.values() )
410 {
411 if ( !assembledPlugins.containsKey( childPlugin.getKey() ) )
412 {
413 assembledPlugins.put( childPlugin.getKey(), childPlugin );
414 }
415 }
416
417 child.setPlugins( new ArrayList<>( assembledPlugins.values() ) );
418
419 child.flushReportPluginMap();
420 }
421 }
422
423 private static void mergeReportSetDefinitions( ReportSet child, ReportSet parent )
424 {
425 List<String> parentReports = parent.getReports();
426 List<String> childReports = child.getReports();
427
428 List<String> reports = new ArrayList<>();
429
430 if ( ( childReports != null ) && !childReports.isEmpty() )
431 {
432 reports.addAll( childReports );
433 }
434
435 if ( parentReports != null )
436 {
437 for ( String report : parentReports )
438 {
439 if ( !reports.contains( report ) )
440 {
441 reports.add( report );
442 }
443 }
444 }
445
446 child.setReports( reports );
447
448 Xpp3Dom childConfiguration = (Xpp3Dom) child.getConfiguration();
449 Xpp3Dom parentConfiguration = (Xpp3Dom) parent.getConfiguration();
450
451 childConfiguration = Xpp3Dom.mergeXpp3Dom( childConfiguration, parentConfiguration );
452
453 child.setConfiguration( childConfiguration );
454 }
455
456
457 public static void mergeReportPluginDefinitions( ReportPlugin child, ReportPlugin parent,
458 boolean handleAsInheritance )
459 {
460 if ( ( child == null ) || ( parent == null ) )
461 {
462
463 return;
464 }
465
466 if ( ( child.getVersion() == null ) && ( parent.getVersion() != null ) )
467 {
468 child.setVersion( parent.getVersion() );
469 }
470
471
472 String parentInherited = parent.getInherited();
473
474 boolean parentIsInherited = ( parentInherited == null ) || Boolean.valueOf( parentInherited );
475
476 List<ReportSet> parentReportSets = parent.getReportSets();
477
478 if ( ( parentReportSets != null ) && !parentReportSets.isEmpty() )
479 {
480 Map<String, ReportSet> assembledReportSets = new TreeMap<>();
481
482 Map<String, ReportSet> childReportSets = child.getReportSetsAsMap();
483
484 for ( Object parentReportSet1 : parentReportSets )
485 {
486 ReportSet parentReportSet = (ReportSet) parentReportSet1;
487
488 if ( !handleAsInheritance || parentIsInherited )
489 {
490 ReportSet assembledReportSet = parentReportSet;
491
492 ReportSet childReportSet = childReportSets.get( parentReportSet.getId() );
493
494 if ( childReportSet != null )
495 {
496 mergeReportSetDefinitions( childReportSet, parentReportSet );
497
498 assembledReportSet = childReportSet;
499 }
500 else if ( handleAsInheritance && ( parentInherited == null ) )
501 {
502 parentReportSet.unsetInheritanceApplied();
503 }
504
505 assembledReportSets.put( assembledReportSet.getId(), assembledReportSet );
506 }
507 }
508
509 for ( Map.Entry<String, ReportSet> entry : childReportSets.entrySet() )
510 {
511 String id = entry.getKey();
512
513 if ( !assembledReportSets.containsKey( id ) )
514 {
515 assembledReportSets.put( id, entry.getValue() );
516 }
517 }
518
519 child.setReportSets( new ArrayList<>( assembledReportSets.values() ) );
520
521 child.flushReportSetMap();
522 }
523
524 }
525
526
527 @SuppressWarnings( "unchecked" )
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 }