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