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.Collection;
24 import java.util.Iterator;
25 import java.util.LinkedHashMap;
26 import java.util.LinkedList;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Properties;
30 import java.util.StringTokenizer;
31 import java.util.TreeMap;
32
33 import org.apache.maven.model.Build;
34 import org.apache.maven.model.Dependency;
35 import org.apache.maven.model.DependencyManagement;
36 import org.apache.maven.model.DeploymentRepository;
37 import org.apache.maven.model.DistributionManagement;
38 import org.apache.maven.model.Extension;
39 import org.apache.maven.model.Model;
40 import org.apache.maven.model.PluginManagement;
41 import org.apache.maven.model.ReportPlugin;
42 import org.apache.maven.model.ReportSet;
43 import org.apache.maven.model.Reporting;
44 import org.apache.maven.model.Resource;
45 import org.apache.maven.model.Scm;
46 import org.apache.maven.model.Site;
47 import org.apache.maven.project.ModelUtils;
48 import org.codehaus.plexus.component.annotations.Component;
49 import org.codehaus.plexus.util.StringUtils;
50 import org.codehaus.plexus.util.xml.Xpp3Dom;
51
52 @Component( role = ModelInheritanceAssembler.class )
53 public class DefaultModelInheritanceAssembler
54 implements ModelInheritanceAssembler
55 {
56
57 @SuppressWarnings( "unchecked" )
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 assembleDistributionInheritence( 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 @SuppressWarnings( "unchecked" )
310 private void assembleDependencyManagementInheritance( Model child, Model parent )
311 {
312 DependencyManagement parentDepMgmt = parent.getDependencyManagement();
313
314 DependencyManagement childDepMgmt = child.getDependencyManagement();
315
316 if ( parentDepMgmt != null )
317 {
318 if ( childDepMgmt == null )
319 {
320 child.setDependencyManagement( parentDepMgmt );
321 }
322 else
323 {
324 List<Dependency> childDeps = childDepMgmt.getDependencies();
325
326 Map<String, Dependency> mappedChildDeps = new TreeMap<String, Dependency>();
327 for ( Dependency dep : childDeps )
328 {
329 mappedChildDeps.put( dep.getManagementKey(), dep );
330 }
331
332 for ( Dependency dep : parentDepMgmt.getDependencies() )
333 {
334 if ( !mappedChildDeps.containsKey( dep.getManagementKey() ) )
335 {
336 childDepMgmt.addDependency( dep );
337 }
338 }
339 }
340 }
341 }
342
343 private void assembleReportingInheritance( Model child, Model parent )
344 {
345
346 Reporting childReporting = child.getReporting();
347 Reporting parentReporting = parent.getReporting();
348
349 if ( parentReporting != null )
350 {
351 if ( childReporting == null )
352 {
353 childReporting = new Reporting();
354 child.setReporting( childReporting );
355 }
356
357 childReporting.setExcludeDefaults( parentReporting.isExcludeDefaults() );
358
359 if ( StringUtils.isEmpty( childReporting.getOutputDirectory() ) )
360 {
361 childReporting.setOutputDirectory( parentReporting.getOutputDirectory() );
362 }
363
364 mergeReportPluginLists( childReporting, parentReporting, true );
365 }
366 }
367
368 private static void mergeReportPluginLists( Reporting child, Reporting parent, boolean handleAsInheritance )
369 {
370 if ( ( child == null ) || ( parent == null ) )
371 {
372
373 return;
374 }
375
376 List<ReportPlugin> parentPlugins = parent.getPlugins();
377
378 if ( ( parentPlugins != null ) && !parentPlugins.isEmpty() )
379 {
380 Map<String, ReportPlugin> assembledPlugins = new TreeMap<String, ReportPlugin>();
381
382 Map<String, ReportPlugin> childPlugins = child.getReportPluginsAsMap();
383
384 for ( ReportPlugin parentPlugin : parentPlugins )
385 {
386 String parentInherited = parentPlugin.getInherited();
387
388 if ( !handleAsInheritance || ( parentInherited == null ) || Boolean.valueOf( parentInherited ) )
389 {
390
391 ReportPlugin assembledPlugin = parentPlugin;
392
393 ReportPlugin childPlugin = childPlugins.get( parentPlugin.getKey() );
394
395 if ( childPlugin != null )
396 {
397 assembledPlugin = childPlugin;
398
399 mergeReportPluginDefinitions( childPlugin, parentPlugin, handleAsInheritance );
400 }
401
402 if ( handleAsInheritance && ( parentInherited == null ) )
403 {
404 assembledPlugin.unsetInheritanceApplied();
405 }
406
407 assembledPlugins.put( assembledPlugin.getKey(), assembledPlugin );
408 }
409 }
410
411 for ( ReportPlugin childPlugin : childPlugins.values() )
412 {
413 if ( !assembledPlugins.containsKey( childPlugin.getKey() ) )
414 {
415 assembledPlugins.put( childPlugin.getKey(), childPlugin );
416 }
417 }
418
419 child.setPlugins( new ArrayList<ReportPlugin>( assembledPlugins.values() ) );
420
421 child.flushReportPluginMap();
422 }
423 }
424
425 private static void mergeReportSetDefinitions( ReportSet child, ReportSet parent )
426 {
427 List<String> parentReports = parent.getReports();
428 List<String> childReports = child.getReports();
429
430 List<String> reports = new ArrayList<String>();
431
432 if ( ( childReports != null ) && !childReports.isEmpty() )
433 {
434 reports.addAll( childReports );
435 }
436
437 if ( parentReports != null )
438 {
439 for ( String report : parentReports )
440 {
441 if ( !reports.contains( report ) )
442 {
443 reports.add( report );
444 }
445 }
446 }
447
448 child.setReports( reports );
449
450 Xpp3Dom childConfiguration = (Xpp3Dom) child.getConfiguration();
451 Xpp3Dom parentConfiguration = (Xpp3Dom) parent.getConfiguration();
452
453 childConfiguration = Xpp3Dom.mergeXpp3Dom( childConfiguration, parentConfiguration );
454
455 child.setConfiguration( childConfiguration );
456 }
457
458
459 public static void mergeReportPluginDefinitions( ReportPlugin child, ReportPlugin parent,
460 boolean handleAsInheritance )
461 {
462 if ( ( child == null ) || ( parent == null ) )
463 {
464
465 return;
466 }
467
468 if ( ( child.getVersion() == null ) && ( parent.getVersion() != null ) )
469 {
470 child.setVersion( parent.getVersion() );
471 }
472
473
474 String parentInherited = parent.getInherited();
475
476 boolean parentIsInherited = ( parentInherited == null ) || Boolean.valueOf( parentInherited );
477
478 List<ReportSet> parentReportSets = parent.getReportSets();
479
480 if ( ( parentReportSets != null ) && !parentReportSets.isEmpty() )
481 {
482 Map<String, ReportSet> assembledReportSets = new TreeMap<String, ReportSet>();
483
484 Map<String, ReportSet> childReportSets = child.getReportSetsAsMap();
485
486 for ( Object parentReportSet1 : parentReportSets )
487 {
488 ReportSet parentReportSet = (ReportSet) parentReportSet1;
489
490 if ( !handleAsInheritance || parentIsInherited )
491 {
492 ReportSet assembledReportSet = parentReportSet;
493
494 ReportSet childReportSet = childReportSets.get( parentReportSet.getId() );
495
496 if ( childReportSet != null )
497 {
498 mergeReportSetDefinitions( childReportSet, parentReportSet );
499
500 assembledReportSet = childReportSet;
501 }
502 else if ( handleAsInheritance && ( parentInherited == null ) )
503 {
504 parentReportSet.unsetInheritanceApplied();
505 }
506
507 assembledReportSets.put( assembledReportSet.getId(), assembledReportSet );
508 }
509 }
510
511 for ( Map.Entry<String, ReportSet> entry : childReportSets.entrySet() )
512 {
513 String id = entry.getKey();
514
515 if ( !assembledReportSets.containsKey( id ) )
516 {
517 assembledReportSets.put( id, entry.getValue() );
518 }
519 }
520
521 child.setReportSets( new ArrayList<ReportSet>( assembledReportSets.values() ) );
522
523 child.flushReportSetMap();
524 }
525
526 }
527
528
529 @SuppressWarnings( "unchecked" )
530 private void assembleDependencyInheritance( Model child, Model parent )
531 {
532 Map<String, Dependency> depsMap = new LinkedHashMap<String, Dependency>();
533
534 List<Dependency> deps = parent.getDependencies();
535
536 if ( deps != null )
537 {
538 for ( Dependency dependency : deps )
539 {
540 depsMap.put( dependency.getManagementKey(), dependency );
541 }
542 }
543
544 deps = child.getDependencies();
545
546 if ( deps != null )
547 {
548 for ( Dependency dependency : deps )
549 {
550 depsMap.put( dependency.getManagementKey(), dependency );
551 }
552 }
553
554 child.setDependencies( new ArrayList<Dependency>( depsMap.values() ) );
555 }
556
557 private void assembleBuildInheritance( Model child, Model parent )
558 {
559 Build childBuild = child.getBuild();
560 Build parentBuild = parent.getBuild();
561
562 if ( parentBuild != null )
563 {
564 if ( childBuild == null )
565 {
566 childBuild = new Build();
567 child.setBuild( childBuild );
568 }
569
570 assembleBuildInheritance( childBuild, parentBuild, true );
571 }
572 }
573
574 private void assembleDistributionInheritence( Model child, Model parent, String childPathAdjustment,
575 boolean appendPaths )
576 {
577 if ( parent.getDistributionManagement() != null )
578 {
579 DistributionManagement parentDistMgmt = parent.getDistributionManagement();
580
581 DistributionManagement childDistMgmt = child.getDistributionManagement();
582
583 if ( childDistMgmt == null )
584 {
585 childDistMgmt = new DistributionManagement();
586
587 child.setDistributionManagement( childDistMgmt );
588 }
589
590 if ( childDistMgmt.getSite() == null )
591 {
592 if ( parentDistMgmt.getSite() != null )
593 {
594 Site site = new Site();
595
596 childDistMgmt.setSite( site );
597
598 site.setId( parentDistMgmt.getSite().getId() );
599
600 site.setName( parentDistMgmt.getSite().getName() );
601
602 site.setUrl( parentDistMgmt.getSite().getUrl() );
603
604 if ( site.getUrl() != null )
605 {
606 site.setUrl(
607 appendPath( site.getUrl(), child.getArtifactId(), childPathAdjustment, appendPaths ) );
608 }
609 }
610 }
611
612 if ( childDistMgmt.getRepository() == null )
613 {
614 if ( parentDistMgmt.getRepository() != null )
615 {
616 DeploymentRepository repository = copyDistributionRepository( parentDistMgmt.getRepository() );
617 childDistMgmt.setRepository( repository );
618 }
619 }
620
621 if ( childDistMgmt.getSnapshotRepository() == null )
622 {
623 if ( parentDistMgmt.getSnapshotRepository() != null )
624 {
625 DeploymentRepository repository =
626 copyDistributionRepository( parentDistMgmt.getSnapshotRepository() );
627 childDistMgmt.setSnapshotRepository( repository );
628 }
629 }
630
631 if ( StringUtils.isEmpty( childDistMgmt.getDownloadUrl() ) )
632 {
633 childDistMgmt.setDownloadUrl( parentDistMgmt.getDownloadUrl() );
634 }
635
636
637
638 }
639 }
640
641 private static DeploymentRepository copyDistributionRepository( DeploymentRepository parentRepository )
642 {
643 DeploymentRepository repository = new DeploymentRepository();
644
645 repository.setId( parentRepository.getId() );
646
647 repository.setName( parentRepository.getName() );
648
649 repository.setUrl( parentRepository.getUrl() );
650
651 repository.setLayout( parentRepository.getLayout() );
652
653 repository.setUniqueVersion( parentRepository.isUniqueVersion() );
654
655 return repository;
656 }
657
658
659 protected String appendPath( String parentPath, String childPath, String pathAdjustment, boolean appendPaths )
660 {
661 String uncleanPath = parentPath;
662
663 if ( appendPaths )
664 {
665 if ( pathAdjustment != null )
666 {
667 uncleanPath += "/" + pathAdjustment;
668 }
669
670 if ( childPath != null )
671 {
672 uncleanPath += "/" + childPath;
673 }
674 }
675
676 String cleanedPath = "";
677
678 int protocolIdx = uncleanPath.indexOf( "://" );
679
680 if ( protocolIdx > -1 )
681 {
682 cleanedPath = uncleanPath.substring( 0, protocolIdx + 3 );
683 uncleanPath = uncleanPath.substring( protocolIdx + 3 );
684 }
685
686 if ( uncleanPath.startsWith( "/" ) )
687 {
688 cleanedPath += "/";
689 }
690
691 return cleanedPath + resolvePath( uncleanPath );
692 }
693
694
695 private static String resolvePath( String uncleanPath )
696 {
697 LinkedList<String> pathElements = new LinkedList<String>();
698
699 StringTokenizer tokenizer = new StringTokenizer( uncleanPath, "/" );
700
701 while ( tokenizer.hasMoreTokens() )
702 {
703 String token = tokenizer.nextToken();
704
705 if ( token.equals( "" ) )
706 {
707
708 }
709 else if ( token.equals( ".." ) )
710 {
711 if ( pathElements.isEmpty() )
712 {
713
714
715
716 }
717 else
718 {
719 pathElements.removeLast();
720 }
721 }
722 else
723 {
724 pathElements.addLast( token );
725 }
726 }
727
728 StringBuilder cleanedPath = new StringBuilder();
729
730 while ( !pathElements.isEmpty() )
731 {
732 cleanedPath.append( pathElements.removeFirst() );
733 if ( !pathElements.isEmpty() )
734 {
735 cleanedPath.append( '/' );
736 }
737 }
738
739 return cleanedPath.toString();
740 }
741
742 private static void mergeExtensionLists( Build childBuild, Build parentBuild )
743 {
744 for ( Extension e : parentBuild.getExtensions() )
745 {
746 if ( !childBuild.getExtensions().contains( e ) )
747 {
748 childBuild.addExtension( e );
749 }
750 }
751 }
752 }