1 package org.apache.maven.model.merge;
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.LinkedHashSet;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Set;
28
29 import org.apache.maven.api.model.BuildBase;
30 import org.apache.maven.api.model.CiManagement;
31 import org.apache.maven.api.model.Dependency;
32 import org.apache.maven.api.model.DeploymentRepository;
33 import org.apache.maven.api.model.DistributionManagement;
34 import org.apache.maven.api.model.Exclusion;
35 import org.apache.maven.api.model.Extension;
36 import org.apache.maven.api.model.InputLocation;
37 import org.apache.maven.api.model.IssueManagement;
38 import org.apache.maven.api.model.Model;
39 import org.apache.maven.api.model.ModelBase;
40 import org.apache.maven.api.model.Organization;
41 import org.apache.maven.api.model.Plugin;
42 import org.apache.maven.api.model.PluginExecution;
43 import org.apache.maven.api.model.ReportPlugin;
44 import org.apache.maven.api.model.ReportSet;
45 import org.apache.maven.api.model.Repository;
46 import org.apache.maven.api.model.RepositoryBase;
47 import org.apache.maven.api.model.Scm;
48 import org.apache.maven.api.model.Site;
49 import org.apache.maven.model.v4.MavenMerger;
50 import org.codehaus.plexus.util.StringUtils;
51
52
53
54
55
56
57
58 public class MavenModelMerger
59 extends MavenMerger
60 {
61
62
63
64
65 public static final String CHILD_PATH_ADJUSTMENT = "child-path-adjustment";
66
67
68
69
70 public static final String ARTIFACT_ID = "artifact-id";
71
72 @Override
73 protected Model mergeModel( Model target, Model source, boolean sourceDominant, Map<Object, Object> context )
74 {
75 context.put( ARTIFACT_ID, target.getArtifactId() );
76
77 return super.mergeModel( target, source, sourceDominant, context );
78 }
79
80 @Override
81 protected void mergeModel_Name( Model.Builder builder, Model target, Model source,
82 boolean sourceDominant, Map<Object, Object> context )
83 {
84 String src = source.getName();
85 if ( src != null )
86 {
87 if ( sourceDominant )
88 {
89 builder.name( src );
90 builder.location( "name", source.getLocation( "name" ) );
91 }
92 }
93 }
94
95 @Override
96 protected void mergeModel_Url( Model.Builder builder, Model target, Model source,
97 boolean sourceDominant, Map<Object, Object> context )
98 {
99 String src = source.getUrl();
100 if ( src != null )
101 {
102 if ( sourceDominant )
103 {
104 builder.url( src );
105 builder.location( "url", source.getLocation( "url" ) );
106 }
107 else if ( target.getUrl() == null )
108 {
109 builder.url( extrapolateChildUrl( src, source.isChildProjectUrlInheritAppendPath(), context ) );
110 builder.location( "url", source.getLocation( "url" ) );
111 }
112 }
113 }
114
115
116
117
118
119 @Override
120 protected void mergeModel_Organization( Model.Builder builder, Model target, Model source, boolean sourceDominant,
121 Map<Object, Object> context )
122 {
123 Organization src = source.getOrganization();
124 if ( src != null )
125 {
126 Organization tgt = target.getOrganization();
127 if ( tgt == null )
128 {
129 builder.organization( src );
130 builder.location( "organisation", source.getLocation( "organisation" ) );
131 }
132 }
133 }
134
135 @Override
136 protected void mergeModel_IssueManagement( Model.Builder builder, Model target, Model source,
137 boolean sourceDominant, Map<Object, Object> context )
138 {
139 IssueManagement src = source.getIssueManagement();
140 if ( src != null )
141 {
142 IssueManagement tgt = target.getIssueManagement();
143 if ( tgt == null )
144 {
145 builder.issueManagement( src );
146 builder.location( "issueManagement", source.getLocation( "issueManagement" ) );
147 }
148 }
149 }
150
151 @Override
152 protected void mergeModel_CiManagement( Model.Builder builder, Model target, Model source, boolean sourceDominant,
153 Map<Object, Object> context )
154 {
155 CiManagement src = source.getCiManagement();
156 if ( src != null )
157 {
158 CiManagement tgt = target.getCiManagement();
159 if ( tgt == null )
160 {
161 builder.ciManagement( src );
162 builder.location( "ciManagement", source.getLocation( "ciManagement" ) );
163 }
164 }
165 }
166
167 @Override
168 protected void mergeModel_ModelVersion( Model.Builder builder, Model target, Model source, boolean sourceDominant,
169 Map<Object, Object> context )
170 {
171
172 }
173
174 @Override
175 protected void mergeModel_ArtifactId( Model.Builder builder, Model target, Model source, boolean sourceDominant,
176 Map<Object, Object> context )
177 {
178
179 }
180
181 @Override
182 protected void mergeModel_Profiles( Model.Builder builder, Model target, Model source, boolean sourceDominant,
183 Map<Object, Object> context )
184 {
185
186 }
187
188 @Override
189 protected void mergeModel_Prerequisites( Model.Builder builder, Model target, Model source, boolean sourceDominant,
190 Map<Object, Object> context )
191 {
192
193 }
194
195 @Override
196 protected void mergeModel_Licenses( Model.Builder builder, Model target, Model source, boolean sourceDominant,
197 Map<Object, Object> context )
198 {
199 builder.licenses( target.getLicenses().isEmpty() ? source.getLicenses() : target.getLicenses() );
200 }
201
202 @Override
203 protected void mergeModel_Developers( Model.Builder builder, Model target, Model source, boolean sourceDominant,
204 Map<Object, Object> context )
205 {
206 builder.developers( target.getDevelopers().isEmpty() ? source.getDevelopers() : target.getDevelopers() );
207 }
208
209 @Override
210 protected void mergeModel_Contributors( Model.Builder builder, Model target, Model source, boolean sourceDominant,
211 Map<Object, Object> context )
212 {
213 builder.contributors( target.getContributors().isEmpty()
214 ? source.getContributors() : target.getContributors() );
215 }
216
217 @Override
218 protected void mergeModel_MailingLists( Model.Builder builder, Model target, Model source, boolean sourceDominant,
219 Map<Object, Object> context )
220 {
221 if ( target.getMailingLists().isEmpty() )
222 {
223 builder.mailingLists( source.getMailingLists() );
224 }
225 }
226
227 @Override
228 protected void mergeModelBase_Modules( ModelBase.Builder builder, ModelBase target, ModelBase source,
229 boolean sourceDominant, Map<Object, Object> context )
230 {
231 List<String> src = source.getModules();
232 if ( !src.isEmpty() && sourceDominant )
233 {
234 List<Integer> indices = new ArrayList<>();
235 List<String> tgt = target.getModules();
236 Set<String> excludes = new LinkedHashSet<>( tgt );
237 List<String> merged = new ArrayList<>( tgt.size() + src.size() );
238 merged.addAll( tgt );
239 for ( int i = 0, n = tgt.size(); i < n; i++ )
240 {
241 indices.add( i );
242 }
243 for ( int i = 0, n = src.size(); i < n; i++ )
244 {
245 String s = src.get( i );
246 if ( !excludes.contains( s ) )
247 {
248 merged.add( s );
249 indices.add( ~i );
250 }
251 }
252 builder.modules( merged );
253 builder.location( "modules", InputLocation.merge( target.getLocation( "modules" ),
254 source.getLocation( "modules" ), indices ) );
255 }
256 }
257
258
259
260
261
262 @Override
263 protected void mergeModelBase_Repositories( ModelBase.Builder builder, ModelBase target, ModelBase source,
264 boolean sourceDominant, Map<Object, Object> context )
265 {
266 List<Repository> src = source.getRepositories();
267 if ( !src.isEmpty() )
268 {
269 List<Repository> tgt = target.getRepositories();
270 Map<Object, Repository> merged = new LinkedHashMap<>( ( src.size() + tgt.size() ) * 2 );
271
272 List<Repository> dominant, recessive;
273 if ( sourceDominant )
274 {
275 dominant = src;
276 recessive = tgt;
277 }
278 else
279 {
280 dominant = tgt;
281 recessive = src;
282 }
283
284 for ( Repository element : dominant )
285 {
286 Object key = getRepositoryKey().apply( element );
287 merged.put( key, element );
288 }
289
290 for ( Repository element : recessive )
291 {
292 Object key = getRepositoryKey().apply( element );
293 if ( !merged.containsKey( key ) )
294 {
295 merged.put( key, element );
296 }
297 }
298
299 builder.repositories( merged.values() );
300 }
301 }
302
303 @Override
304 protected void mergeModelBase_PluginRepositories( ModelBase.Builder builder, ModelBase target, ModelBase source,
305 boolean sourceDominant, Map<Object, Object> context )
306 {
307 List<Repository> src = source.getPluginRepositories();
308 if ( !src.isEmpty() )
309 {
310 List<Repository> tgt = target.getPluginRepositories();
311 Map<Object, Repository> merged = new LinkedHashMap<>( ( src.size() + tgt.size() ) * 2 );
312
313 List<Repository> dominant, recessive;
314 if ( sourceDominant )
315 {
316 dominant = src;
317 recessive = tgt;
318 }
319 else
320 {
321 dominant = tgt;
322 recessive = src;
323 }
324
325 for ( Repository element : dominant )
326 {
327 Object key = getRepositoryKey().apply( element );
328 merged.put( key, element );
329 }
330
331 for ( Repository element : recessive )
332 {
333 Object key = getRepositoryKey().apply( element );
334 if ( !merged.containsKey( key ) )
335 {
336 merged.put( key, element );
337 }
338 }
339
340 builder.pluginRepositories( merged.values() );
341 }
342 }
343
344
345
346
347 @Override
348 protected void mergeBuildBase_Filters( BuildBase.Builder builder, BuildBase target, BuildBase source,
349 boolean sourceDominant, Map<Object, Object> context )
350 {
351 List<String> src = source.getFilters();
352 if ( !src.isEmpty() )
353 {
354 List<String> tgt = target.getFilters();
355 Set<String> excludes = new LinkedHashSet<>( tgt );
356 List<String> merged = new ArrayList<>( tgt.size() + src.size() );
357 merged.addAll( tgt );
358 for ( String s : src )
359 {
360 if ( !excludes.contains( s ) )
361 {
362 merged.add( s );
363 }
364 }
365 builder.filters( merged );
366 }
367 }
368
369 @Override
370 protected void mergeBuildBase_Resources( BuildBase.Builder builder, BuildBase target, BuildBase source,
371 boolean sourceDominant, Map<Object, Object> context )
372 {
373 if ( sourceDominant || target.getResources().isEmpty() )
374 {
375 super.mergeBuildBase_Resources( builder, target, source, sourceDominant, context );
376 }
377 }
378
379 @Override
380 protected void mergeBuildBase_TestResources( BuildBase.Builder builder,
381 BuildBase target,
382 BuildBase source,
383 boolean sourceDominant,
384 Map<Object, Object> context )
385 {
386 if ( sourceDominant || target.getTestResources().isEmpty() )
387 {
388 super.mergeBuildBase_TestResources( builder, target, source, sourceDominant, context );
389 }
390 }
391
392 @Override
393 protected void mergeDistributionManagement_Relocation( DistributionManagement.Builder builder,
394 DistributionManagement target,
395 DistributionManagement source,
396 boolean sourceDominant,
397 Map<Object, Object> context )
398 {
399 }
400
401
402 @Override
403 protected void mergeDistributionManagement_Repository( DistributionManagement.Builder builder,
404 DistributionManagement target,
405 DistributionManagement source,
406 boolean sourceDominant,
407 Map<Object, Object> context )
408 {
409 DeploymentRepository src = source.getRepository();
410 if ( src != null )
411 {
412 DeploymentRepository tgt = target.getRepository();
413 if ( sourceDominant || tgt == null )
414 {
415 tgt = DeploymentRepository.newInstance( false );
416 builder.repository( mergeDeploymentRepository( tgt, src, sourceDominant, context ) );
417 }
418 }
419 }
420
421 @Override
422 protected void mergeDistributionManagement_SnapshotRepository( DistributionManagement.Builder builder,
423 DistributionManagement target,
424 DistributionManagement source,
425 boolean sourceDominant,
426 Map<Object, Object> context )
427 {
428 DeploymentRepository src = source.getSnapshotRepository();
429 if ( src != null )
430 {
431 DeploymentRepository tgt = target.getSnapshotRepository();
432 if ( sourceDominant || tgt == null )
433 {
434 tgt = DeploymentRepository.newInstance( false );
435 builder.snapshotRepository( mergeDeploymentRepository( tgt, src, sourceDominant, context ) );
436 }
437 }
438 }
439
440 @Override
441 protected void mergeDistributionManagement_Site( DistributionManagement.Builder builder,
442 DistributionManagement target,
443 DistributionManagement source,
444 boolean sourceDominant,
445 Map<Object, Object> context )
446 {
447 Site src = source.getSite();
448 if ( src != null )
449 {
450 Site tgt = target.getSite();
451 if ( tgt == null )
452 {
453 tgt = Site.newBuilder( false ).build();
454 }
455 Site.Builder sbuilder = Site.newBuilder( tgt );
456 if ( sourceDominant || tgt == null || isSiteEmpty( tgt ) )
457 {
458 mergeSite( sbuilder, tgt, src, sourceDominant, context );
459 }
460 super.mergeSite_ChildSiteUrlInheritAppendPath( sbuilder, tgt, src, sourceDominant, context );
461 builder.site( sbuilder.build() );
462 }
463 }
464
465 @Override
466 protected void mergeSite_ChildSiteUrlInheritAppendPath( Site.Builder builder, Site target, Site source,
467 boolean sourceDominant, Map<Object, Object> context )
468 {
469 }
470
471 protected boolean isSiteEmpty( Site site )
472 {
473 return StringUtils.isEmpty( site.getId() ) && StringUtils.isEmpty( site.getName() )
474 && StringUtils.isEmpty( site.getUrl() );
475 }
476
477 @Override
478 protected void mergeSite_Url( Site.Builder builder, Site target, Site source,
479 boolean sourceDominant, Map<Object, Object> context )
480 {
481 String src = source.getUrl();
482 if ( src != null )
483 {
484 if ( sourceDominant )
485 {
486 builder.url( src );
487 builder.location( "url", source.getLocation( "url" ) );
488 }
489 else if ( target.getUrl() == null )
490 {
491 builder.url( extrapolateChildUrl( src, source.isChildSiteUrlInheritAppendPath(), context ) );
492 builder.location( "url", source.getLocation( "url" ) );
493 }
494 }
495 }
496
497 @Override
498 protected void mergeScm_Url( Scm.Builder builder, Scm target, Scm source,
499 boolean sourceDominant, Map<Object, Object> context )
500 {
501 String src = source.getUrl();
502 if ( src != null )
503 {
504 if ( sourceDominant )
505 {
506 builder.url( src );
507 builder.location( "url", source.getLocation( "url" ) );
508 }
509 else if ( target.getUrl() == null )
510 {
511 builder.url( extrapolateChildUrl( src, source.isChildScmUrlInheritAppendPath(), context ) );
512 builder.location( "url", source.getLocation( "url" ) );
513 }
514 }
515 }
516
517 @Override
518 protected void mergeScm_Connection( Scm.Builder builder, Scm target, Scm source,
519 boolean sourceDominant, Map<Object, Object> context )
520 {
521 String src = source.getConnection();
522 if ( src != null )
523 {
524 if ( sourceDominant )
525 {
526 builder.connection( src );
527 builder.location( "connection", source.getLocation( "connection" ) );
528 }
529 else if ( target.getConnection() == null )
530 {
531 builder.connection( extrapolateChildUrl( src, source.isChildScmConnectionInheritAppendPath(),
532 context ) );
533 builder.location( "connection", source.getLocation( "connection" ) );
534 }
535 }
536 }
537
538 @Override
539 protected void mergeScm_DeveloperConnection( Scm.Builder builder, Scm target, Scm source,
540 boolean sourceDominant, Map<Object, Object> context )
541 {
542 String src = source.getDeveloperConnection();
543 if ( src != null )
544 {
545 if ( sourceDominant )
546 {
547 builder.developerConnection( src );
548 builder.location( "developerConnection", source.getLocation( "developerConnection" ) );
549 }
550 else if ( target.getDeveloperConnection() == null )
551 {
552 String e = extrapolateChildUrl( src, source.isChildScmDeveloperConnectionInheritAppendPath(), context );
553 builder.developerConnection( e );
554 builder.location( "developerConnection", source.getLocation( "developerConnection" ) );
555 }
556 }
557 }
558
559 @Override
560 protected void mergePlugin_Executions( Plugin.Builder builder, Plugin target, Plugin source,
561 boolean sourceDominant, Map<Object, Object> context )
562 {
563 List<PluginExecution> src = source.getExecutions();
564 if ( !src.isEmpty() )
565 {
566 List<PluginExecution> tgt = target.getExecutions();
567 Map<Object, PluginExecution> merged =
568 new LinkedHashMap<>( ( src.size() + tgt.size() ) * 2 );
569
570 for ( PluginExecution element : src )
571 {
572 if ( sourceDominant
573 || ( element.getInherited() != null ? element.isInherited() : source.isInherited() ) )
574 {
575 Object key = getPluginExecutionKey().apply( element );
576 merged.put( key, element );
577 }
578 }
579
580 for ( PluginExecution element : tgt )
581 {
582 Object key = getPluginExecutionKey().apply( element );
583 PluginExecution existing = merged.get( key );
584 if ( existing != null )
585 {
586 element = mergePluginExecution( element, existing, sourceDominant, context );
587 }
588 merged.put( key, element );
589 }
590
591 builder.executions( merged.values() );
592 }
593 }
594
595 @Override
596 protected void mergePluginExecution_Goals( PluginExecution.Builder builder, PluginExecution target,
597 PluginExecution source, boolean sourceDominant,
598 Map<Object, Object> context )
599 {
600 List<String> src = source.getGoals();
601 if ( !src.isEmpty() )
602 {
603 List<String> tgt = target.getGoals();
604 Set<String> excludes = new LinkedHashSet<>( tgt );
605 List<String> merged = new ArrayList<>( tgt.size() + src.size() );
606 merged.addAll( tgt );
607 for ( String s : src )
608 {
609 if ( !excludes.contains( s ) )
610 {
611 merged.add( s );
612 }
613 }
614 builder.goals( merged );
615 }
616 }
617
618 @Override
619 protected void mergeReportPlugin_ReportSets( ReportPlugin.Builder builder, ReportPlugin target,
620 ReportPlugin source, boolean sourceDominant,
621 Map<Object, Object> context )
622 {
623 List<ReportSet> src = source.getReportSets();
624 if ( !src.isEmpty() )
625 {
626 List<ReportSet> tgt = target.getReportSets();
627 Map<Object, ReportSet> merged = new LinkedHashMap<>( ( src.size() + tgt.size() ) * 2 );
628
629 for ( ReportSet rset : src )
630 {
631 if ( sourceDominant || ( rset.getInherited() != null ? rset.isInherited() : source.isInherited() ) )
632 {
633 Object key = getReportSetKey().apply( rset );
634 merged.put( key, rset );
635 }
636 }
637
638 for ( ReportSet element : tgt )
639 {
640 Object key = getReportSetKey().apply( element );
641 ReportSet existing = merged.get( key );
642 if ( existing != null )
643 {
644 mergeReportSet( element, existing, sourceDominant, context );
645 }
646 merged.put( key, element );
647 }
648
649 builder.reportSets( merged.values() );
650 }
651 }
652
653 @Override
654 protected KeyComputer<Dependency> getDependencyKey()
655 {
656 return Dependency::getManagementKey;
657 }
658
659 @Override
660 protected KeyComputer<Plugin> getPluginKey()
661 {
662 return Plugin::getKey;
663 }
664
665 @Override
666 protected KeyComputer<PluginExecution> getPluginExecutionKey()
667 {
668 return PluginExecution::getId;
669 }
670
671 @Override
672 protected KeyComputer<ReportPlugin> getReportPluginKey()
673 {
674 return ReportPlugin::getKey;
675 }
676
677 @Override
678 protected KeyComputer<ReportSet> getReportSetKey()
679 {
680 return ReportSet::getId;
681 }
682
683 @Override
684 protected KeyComputer<RepositoryBase> getRepositoryBaseKey()
685 {
686 return RepositoryBase::getId;
687 }
688
689 @Override
690 protected KeyComputer<Extension> getExtensionKey()
691 {
692 return e -> e.getGroupId() + ':' + e.getArtifactId();
693 }
694
695 @Override
696 protected KeyComputer<Exclusion> getExclusionKey()
697 {
698 return e -> e.getGroupId() + ':' + e.getArtifactId();
699 }
700
701 protected String extrapolateChildUrl( String parentUrl, boolean appendPath, Map<Object, Object> context )
702 {
703 return parentUrl;
704 }
705
706 }