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 ( 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 parentPlugins = parent.getPlugins();
376
377 if ( ( parentPlugins != null ) && !parentPlugins.isEmpty() )
378 {
379 Map assembledPlugins = new TreeMap();
380
381 Map childPlugins = child.getReportPluginsAsMap();
382
383 for ( Object parentPlugin1 : parentPlugins )
384 {
385 ReportPlugin parentPlugin = (ReportPlugin) parentPlugin1;
386
387 String parentInherited = parentPlugin.getInherited();
388
389 if ( !handleAsInheritance || ( parentInherited == null ) || Boolean.valueOf( parentInherited ) )
390 {
391
392 ReportPlugin assembledPlugin = parentPlugin;
393
394 ReportPlugin childPlugin = (ReportPlugin) childPlugins.get( parentPlugin.getKey() );
395
396 if ( childPlugin != null )
397 {
398 assembledPlugin = childPlugin;
399
400 mergeReportPluginDefinitions( childPlugin, parentPlugin, handleAsInheritance );
401 }
402
403 if ( handleAsInheritance && ( parentInherited == null ) )
404 {
405 assembledPlugin.unsetInheritanceApplied();
406 }
407
408 assembledPlugins.put( assembledPlugin.getKey(), assembledPlugin );
409 }
410 }
411
412 for ( Iterator it = childPlugins.values().iterator(); it.hasNext(); )
413 {
414 ReportPlugin childPlugin = (ReportPlugin) it.next();
415
416 if ( !assembledPlugins.containsKey( childPlugin.getKey() ) )
417 {
418 assembledPlugins.put( childPlugin.getKey(), childPlugin );
419 }
420 }
421
422 child.setPlugins( new ArrayList( assembledPlugins.values() ) );
423
424 child.flushReportPluginMap();
425 }
426 }
427
428 private static void mergeReportSetDefinitions( ReportSet child, ReportSet parent )
429 {
430 List parentReports = parent.getReports();
431 List childReports = child.getReports();
432
433 List reports = new ArrayList();
434
435 if ( ( childReports != null ) && !childReports.isEmpty() )
436 {
437 reports.addAll( childReports );
438 }
439
440 if ( parentReports != null )
441 {
442 for ( Iterator i = parentReports.iterator(); i.hasNext(); )
443 {
444 String report = (String) i.next();
445
446 if ( !reports.contains( report ) )
447 {
448 reports.add( report );
449 }
450 }
451 }
452
453 child.setReports( reports );
454
455 Xpp3Dom childConfiguration = (Xpp3Dom) child.getConfiguration();
456 Xpp3Dom parentConfiguration = (Xpp3Dom) parent.getConfiguration();
457
458 childConfiguration = Xpp3Dom.mergeXpp3Dom( childConfiguration, parentConfiguration );
459
460 child.setConfiguration( childConfiguration );
461 }
462
463
464 public static void mergeReportPluginDefinitions( ReportPlugin child, ReportPlugin parent,
465 boolean handleAsInheritance )
466 {
467 if ( ( child == null ) || ( parent == null ) )
468 {
469
470 return;
471 }
472
473 if ( ( child.getVersion() == null ) && ( parent.getVersion() != null ) )
474 {
475 child.setVersion( parent.getVersion() );
476 }
477
478
479 String parentInherited = parent.getInherited();
480
481 boolean parentIsInherited = ( parentInherited == null ) || Boolean.valueOf( parentInherited );
482
483 List parentReportSets = parent.getReportSets();
484
485 if ( ( parentReportSets != null ) && !parentReportSets.isEmpty() )
486 {
487 Map assembledReportSets = new TreeMap();
488
489 Map childReportSets = child.getReportSetsAsMap();
490
491 for ( Iterator it = parentReportSets.iterator(); it.hasNext(); )
492 {
493 ReportSet parentReportSet = (ReportSet) it.next();
494
495 if ( !handleAsInheritance || parentIsInherited )
496 {
497 ReportSet assembledReportSet = parentReportSet;
498
499 ReportSet childReportSet = (ReportSet) childReportSets.get( parentReportSet.getId() );
500
501 if ( childReportSet != null )
502 {
503 mergeReportSetDefinitions( childReportSet, parentReportSet );
504
505 assembledReportSet = childReportSet;
506 }
507 else if ( handleAsInheritance && ( parentInherited == null ) )
508 {
509 parentReportSet.unsetInheritanceApplied();
510 }
511
512 assembledReportSets.put( assembledReportSet.getId(), assembledReportSet );
513 }
514 }
515
516 for ( Iterator it = childReportSets.entrySet().iterator(); it.hasNext(); )
517 {
518 Map.Entry entry = (Map.Entry) it.next();
519
520 String id = (String) entry.getKey();
521
522 if ( !assembledReportSets.containsKey( id ) )
523 {
524 assembledReportSets.put( id, entry.getValue() );
525 }
526 }
527
528 child.setReportSets( new ArrayList( assembledReportSets.values() ) );
529
530 child.flushReportSetMap();
531 }
532
533 }
534
535
536 @SuppressWarnings( "unchecked" )
537 private void assembleDependencyInheritance( Model child, Model parent )
538 {
539 Map<String, Dependency> depsMap = new LinkedHashMap<String, Dependency>();
540
541 List<Dependency> deps = parent.getDependencies();
542
543 if ( deps != null )
544 {
545 for ( Dependency dependency : deps )
546 {
547 depsMap.put( dependency.getManagementKey(), dependency );
548 }
549 }
550
551 deps = child.getDependencies();
552
553 if ( deps != null )
554 {
555 for ( Dependency dependency : deps )
556 {
557 depsMap.put( dependency.getManagementKey(), dependency );
558 }
559 }
560
561 child.setDependencies( new ArrayList<Dependency>( depsMap.values() ) );
562 }
563
564 private void assembleBuildInheritance( Model child, Model parent )
565 {
566 Build childBuild = child.getBuild();
567 Build parentBuild = parent.getBuild();
568
569 if ( parentBuild != null )
570 {
571 if ( childBuild == null )
572 {
573 childBuild = new Build();
574 child.setBuild( childBuild );
575 }
576
577 assembleBuildInheritance( childBuild, parentBuild, true );
578 }
579 }
580
581 private void assembleDistributionInheritence( Model child, Model parent, String childPathAdjustment,
582 boolean appendPaths )
583 {
584 if ( parent.getDistributionManagement() != null )
585 {
586 DistributionManagement parentDistMgmt = parent.getDistributionManagement();
587
588 DistributionManagement childDistMgmt = child.getDistributionManagement();
589
590 if ( childDistMgmt == null )
591 {
592 childDistMgmt = new DistributionManagement();
593
594 child.setDistributionManagement( childDistMgmt );
595 }
596
597 if ( childDistMgmt.getSite() == null )
598 {
599 if ( parentDistMgmt.getSite() != null )
600 {
601 Site site = new Site();
602
603 childDistMgmt.setSite( site );
604
605 site.setId( parentDistMgmt.getSite().getId() );
606
607 site.setName( parentDistMgmt.getSite().getName() );
608
609 site.setUrl( parentDistMgmt.getSite().getUrl() );
610
611 if ( site.getUrl() != null )
612 {
613 site.setUrl(
614 appendPath( site.getUrl(), child.getArtifactId(), childPathAdjustment, appendPaths ) );
615 }
616 }
617 }
618
619 if ( childDistMgmt.getRepository() == null )
620 {
621 if ( parentDistMgmt.getRepository() != null )
622 {
623 DeploymentRepository repository = copyDistributionRepository( parentDistMgmt.getRepository() );
624 childDistMgmt.setRepository( repository );
625 }
626 }
627
628 if ( childDistMgmt.getSnapshotRepository() == null )
629 {
630 if ( parentDistMgmt.getSnapshotRepository() != null )
631 {
632 DeploymentRepository repository =
633 copyDistributionRepository( parentDistMgmt.getSnapshotRepository() );
634 childDistMgmt.setSnapshotRepository( repository );
635 }
636 }
637
638 if ( StringUtils.isEmpty( childDistMgmt.getDownloadUrl() ) )
639 {
640 childDistMgmt.setDownloadUrl( parentDistMgmt.getDownloadUrl() );
641 }
642
643
644
645 }
646 }
647
648 private static DeploymentRepository copyDistributionRepository( DeploymentRepository parentRepository )
649 {
650 DeploymentRepository repository = new DeploymentRepository();
651
652 repository.setId( parentRepository.getId() );
653
654 repository.setName( parentRepository.getName() );
655
656 repository.setUrl( parentRepository.getUrl() );
657
658 repository.setLayout( parentRepository.getLayout() );
659
660 repository.setUniqueVersion( parentRepository.isUniqueVersion() );
661
662 return repository;
663 }
664
665
666 protected String appendPath( String parentPath, String childPath, String pathAdjustment, boolean appendPaths )
667 {
668 String uncleanPath = parentPath;
669
670 if ( appendPaths )
671 {
672 if ( pathAdjustment != null )
673 {
674 uncleanPath += "/" + pathAdjustment;
675 }
676
677 if ( childPath != null )
678 {
679 uncleanPath += "/" + childPath;
680 }
681 }
682
683 String cleanedPath = "";
684
685 int protocolIdx = uncleanPath.indexOf( "://" );
686
687 if ( protocolIdx > -1 )
688 {
689 cleanedPath = uncleanPath.substring( 0, protocolIdx + 3 );
690 uncleanPath = uncleanPath.substring( protocolIdx + 3 );
691 }
692
693 if ( uncleanPath.startsWith( "/" ) )
694 {
695 cleanedPath += "/";
696 }
697
698 return cleanedPath + resolvePath( uncleanPath );
699 }
700
701
702 private static String resolvePath( String uncleanPath )
703 {
704 LinkedList<String> pathElements = new LinkedList<String>();
705
706 StringTokenizer tokenizer = new StringTokenizer( uncleanPath, "/" );
707
708 while ( tokenizer.hasMoreTokens() )
709 {
710 String token = tokenizer.nextToken();
711
712 if ( token.equals( "" ) )
713 {
714
715 }
716 else if ( token.equals( ".." ) )
717 {
718 if ( pathElements.isEmpty() )
719 {
720
721
722
723 }
724 else
725 {
726 pathElements.removeLast();
727 }
728 }
729 else
730 {
731 pathElements.addLast( token );
732 }
733 }
734
735 StringBuilder cleanedPath = new StringBuilder();
736
737 while ( !pathElements.isEmpty() )
738 {
739 cleanedPath.append( pathElements.removeFirst() );
740 if ( !pathElements.isEmpty() )
741 {
742 cleanedPath.append( '/' );
743 }
744 }
745
746 return cleanedPath.toString();
747 }
748
749 private static void mergeExtensionLists( Build childBuild, Build parentBuild )
750 {
751 for ( Extension e : parentBuild.getExtensions() )
752 {
753 if ( !childBuild.getExtensions().contains( e ) )
754 {
755 childBuild.addExtension( e );
756 }
757 }
758 }
759 }