View Javadoc

1   package org.apache.maven.project.injection;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.apache.maven.model.Build;
23  import org.apache.maven.model.BuildBase;
24  import org.apache.maven.model.ConfigurationContainer;
25  import org.apache.maven.model.Dependency;
26  import org.apache.maven.model.DependencyManagement;
27  import org.apache.maven.model.DistributionManagement;
28  import org.apache.maven.model.Model;
29  import org.apache.maven.model.Plugin;
30  import org.apache.maven.model.PluginContainer;
31  import org.apache.maven.model.PluginExecution;
32  import org.apache.maven.model.PluginManagement;
33  import org.apache.maven.model.Profile;
34  import org.apache.maven.model.ReportPlugin;
35  import org.apache.maven.model.ReportSet;
36  import org.apache.maven.model.Reporting;
37  import org.apache.maven.project.ModelUtils;
38  import org.codehaus.plexus.util.StringUtils;
39  import org.codehaus.plexus.util.xml.Xpp3Dom;
40  
41  import java.util.ArrayList;
42  import java.util.Iterator;
43  import java.util.LinkedHashMap;
44  import java.util.List;
45  import java.util.Map;
46  import java.util.Properties;
47  
48  /**
49   * Inject profile data into a Model, using the profile as the dominant data source, and
50   * persisting results of the injection in the Model.
51   *
52   * This will look similar to the ModelUtils/DefaultModelInheritanceAssembler code, but
53   * they are distinct. In model inheritance, the child provides data dominance AND persists
54   * the results of the merge...sort of a 'merge-out' system.
55   *
56   * In this system, the profile is dominant, but the model receives the merge result...sort
57   * of a 'merge-in' system. The two pieces of code look like they could be combined with a
58   * set of flags to determine which direction to merge 'to', but there are enough differences
59   * in the code to justify the extra code involved with separating them, in order to simplify
60   * the logic.
61   */
62  public class DefaultProfileInjector
63      implements ProfileInjector
64  {
65  
66      public void inject( Profile profile, Model model )
67      {
68  
69          model.setDependencies( injectDependencies( profile.getDependencies(), model.getDependencies() ) );
70  
71          injectModules( profile, model );
72  
73          model.setRepositories( ModelUtils.mergeRepositoryLists( profile.getRepositories(), model.getRepositories() ) );
74          model.setPluginRepositories( ModelUtils.mergeRepositoryLists( profile.getPluginRepositories(), model
75              .getPluginRepositories() ) );
76  
77          injectReporting( profile, model );
78  
79          injectDependencyManagement( profile, model );
80  
81          injectDistributionManagement( profile, model );
82  
83          injectBuild( profile, model );
84  
85          Properties props = new Properties();
86          props.putAll( model.getProperties() );
87          props.putAll( profile.getProperties() );
88  
89          model.setProperties( props );
90      }
91  
92      private void injectBuild( Profile profile, Model model )
93      {
94          BuildBase profileBuild = profile.getBuild();
95          Build modelBuild = model.getBuild();
96  
97          // if the parent build is null, obviously we cannot inherit from it...
98          if ( profileBuild != null )
99          {
100             if ( modelBuild == null )
101             {
102                 modelBuild = new Build();
103                 model.setBuild( modelBuild );
104             }
105 
106             if ( profileBuild.getDirectory() != null )
107             {
108                 modelBuild.setDirectory( profileBuild.getDirectory() );
109             }
110 
111             if ( profileBuild.getDefaultGoal() != null )
112             {
113                 modelBuild.setDefaultGoal( profileBuild.getDefaultGoal() );
114             }
115 
116             if ( profileBuild.getFinalName() != null )
117             {
118                 modelBuild.setFinalName( profileBuild.getFinalName() );
119             }
120 
121             ModelUtils.mergeFilterLists( modelBuild.getFilters(), profileBuild.getFilters() );
122             ModelUtils.mergeResourceLists( modelBuild.getResources(), profileBuild.getResources() );
123             ModelUtils.mergeResourceLists( modelBuild.getTestResources(), profileBuild.getTestResources() );
124 
125             injectPlugins( profileBuild, modelBuild );
126 
127             // Plugin management :: aggregate
128             PluginManagement profilePM = profileBuild.getPluginManagement();
129             PluginManagement modelPM = modelBuild.getPluginManagement();
130 
131             if ( modelPM == null )
132             {
133                 modelBuild.setPluginManagement( profilePM );
134             }
135             else
136             {
137                 injectPlugins( profilePM, modelPM );
138             }
139         }
140     }
141 
142     /**
143      * This should be the resulting ordering of plugins after injection:
144      *
145      * Given:
146      *
147      *   model: X -> A -> B -> D -> E
148      *   profile: Y -> A -> C -> D -> F
149      *
150      * Result:
151      *
152      *   X -> Y -> A -> B -> C -> D -> E -> F
153      */
154     protected void injectPlugins( PluginContainer profileContainer, PluginContainer modelContainer )
155     {
156         if ( ( profileContainer == null ) || ( modelContainer == null ) )
157         {
158             // nothing to do...
159             return;
160         }
161 
162         List modelPlugins = modelContainer.getPlugins();
163 
164         if ( modelPlugins == null )
165         {
166             modelContainer.setPlugins( profileContainer.getPlugins() );
167         }
168         else if ( profileContainer.getPlugins() != null )
169         {
170             List mergedPlugins = new ArrayList();
171 
172             Map profilePlugins = profileContainer.getPluginsAsMap();
173 
174             for ( Iterator it = modelPlugins.iterator(); it.hasNext(); )
175             {
176                 Plugin modelPlugin = (Plugin) it.next();
177 
178                 Plugin profilePlugin = (Plugin) profilePlugins.get( modelPlugin.getKey() );
179 
180                 if ( ( profilePlugin != null ) && !mergedPlugins.contains( profilePlugin ) )
181                 {
182                     Plugin mergedPlugin = modelPlugin;
183 
184                     injectPluginDefinition( profilePlugin, modelPlugin );
185 
186                     mergedPlugins.add( mergedPlugin );
187                 }
188             }
189 
190             List results = ModelUtils.orderAfterMerge( mergedPlugins, modelPlugins, profileContainer.getPlugins() );
191 
192             modelContainer.setPlugins( results );
193 
194             modelContainer.flushPluginMap();
195         }
196     }
197 
198     private void injectPluginDefinition( Plugin profilePlugin, Plugin modelPlugin )
199     {
200         if ( ( profilePlugin == null ) || ( modelPlugin == null ) )
201         {
202             // nothing to do.
203             return;
204         }
205 
206         if ( profilePlugin.isExtensions() )
207         {
208             modelPlugin.setExtensions( true );
209         }
210 
211         if ( profilePlugin.getVersion() != null )
212         {
213             modelPlugin.setVersion( profilePlugin.getVersion() );
214         }
215 
216         modelPlugin.setDependencies( injectDependencies( profilePlugin.getDependencies(), modelPlugin.getDependencies() ) );
217 
218         // merge the lists of goals that are not attached to an <execution/>
219         injectConfigurationContainer( profilePlugin, modelPlugin );
220 
221         // from here to the end of the method is dealing with merging of the <executions/> section.
222         List modelExecutions = modelPlugin.getExecutions();
223 
224         if ( ( modelExecutions == null ) || modelExecutions.isEmpty() )
225         {
226             modelPlugin.setExecutions( profilePlugin.getExecutions() );
227         }
228         else
229         {
230             Map executions = new LinkedHashMap();
231 
232             Map profileExecutions = profilePlugin.getExecutionsAsMap();
233 
234             for ( Iterator it = modelExecutions.iterator(); it.hasNext(); )
235             {
236                 PluginExecution modelExecution = (PluginExecution) it.next();
237 
238                 PluginExecution profileExecution = (PluginExecution) profileExecutions.get( modelExecution.getId() );
239 
240                 if ( profileExecution != null )
241                 {
242                     injectConfigurationContainer( profileExecution, modelExecution );
243 
244                     if ( profileExecution.getPhase() != null )
245                     {
246                         modelExecution.setPhase( profileExecution.getPhase() );
247                     }
248 
249                     List profileGoals = profileExecution.getGoals();
250                     List modelGoals = modelExecution.getGoals();
251 
252                     List goals = new ArrayList();
253 
254                     if ( ( modelGoals != null ) && !modelGoals.isEmpty() )
255                     {
256                         goals.addAll( modelGoals );
257                     }
258 
259                     if ( profileGoals != null )
260                     {
261                         for ( Iterator goalIterator = profileGoals.iterator(); goalIterator.hasNext(); )
262                         {
263                             String goal = (String) goalIterator.next();
264 
265                             if ( !goals.contains( goal ) )
266                             {
267                                 goals.add( goal );
268                             }
269                         }
270                     }
271 
272                     modelExecution.setGoals( goals );
273                 }
274 
275                 executions.put( modelExecution.getId(), modelExecution );
276             }
277 
278             for ( Iterator it = profileExecutions.entrySet().iterator(); it.hasNext(); )
279             {
280                 Map.Entry entry = (Map.Entry) it.next();
281 
282                 String id = (String) entry.getKey();
283 
284                 if ( !executions.containsKey( id ) )
285                 {
286                     executions.put( id, entry.getValue() );
287                 }
288             }
289 
290             modelPlugin.setExecutions( new ArrayList( executions.values() ) );
291 
292             modelPlugin.flushExecutionMap();
293         }
294 
295     }
296 
297     /**
298      * Merge two DOMs. Copy the dominant DOM so the original one is left unchanged.
299      * <p>
300      * Use this method instead of a direct call to {@link Xpp3Dom#mergeXpp3Dom(Xpp3Dom, Xpp3Dom)}.
301      * Profiles are dominant, thus they are merge targets, but they may be merged in several times
302      * (e.g. if they are inherited). So with the second merge, you don't get the profile's original
303      * DOM, but an already merged one.
304      * 
305      * @param dominant Dominant DOM
306      * @param recessive Recessive DOM
307      * @return Merged DOM
308      */
309     private Xpp3Dom merge( Xpp3Dom dominant, Xpp3Dom recessive )
310     {
311         Xpp3Dom dominantCopy = ( dominant == null ) ? null : new Xpp3Dom( dominant );
312         return Xpp3Dom.mergeXpp3Dom( dominantCopy, recessive );
313     }
314 
315     private void injectConfigurationContainer( ConfigurationContainer profileContainer,
316                                                ConfigurationContainer modelContainer )
317     {
318         Xpp3Dom configuration = (Xpp3Dom) profileContainer.getConfiguration();
319         Xpp3Dom parentConfiguration = (Xpp3Dom) modelContainer.getConfiguration();
320 
321         configuration = merge( configuration, parentConfiguration );
322 
323         modelContainer.setConfiguration( configuration );
324     }
325 
326     /**
327      * Append modules specified in the profile to the end of the list supplied by the model, if
328      * they don't already exist.
329      */
330     private void injectModules( Profile profile, Model model )
331     {
332         List modules = new ArrayList();
333 
334         List modelModules = model.getModules();
335 
336         if ( ( modelModules != null ) && !modelModules.isEmpty() )
337         {
338             modules.addAll( modelModules );
339         }
340 
341         List profileModules = profile.getModules();
342 
343         if ( profileModules != null )
344         {
345             for ( Iterator it = profileModules.iterator(); it.hasNext(); )
346             {
347                 String module = (String) it.next();
348 
349                 if ( !modules.contains( module ) )
350                 {
351                     modules.add( module );
352                 }
353             }
354         }
355 
356         model.setModules( modules );
357     }
358 
359     private void injectDistributionManagement( Profile profile, Model model )
360     {
361         DistributionManagement pDistMgmt = profile.getDistributionManagement();
362         DistributionManagement mDistMgmt = model.getDistributionManagement();
363 
364         if ( mDistMgmt == null )
365         {
366             model.setDistributionManagement( pDistMgmt );
367         }
368         else if ( pDistMgmt != null )
369         {
370             if ( pDistMgmt.getRepository() != null )
371             {
372                 mDistMgmt.setRepository( pDistMgmt.getRepository() );
373             }
374 
375             if ( pDistMgmt.getSnapshotRepository() != null )
376             {
377                 mDistMgmt.setSnapshotRepository( pDistMgmt.getSnapshotRepository() );
378             }
379 
380             if ( StringUtils.isNotEmpty( pDistMgmt.getDownloadUrl() ) )
381             {
382                 mDistMgmt.setDownloadUrl( pDistMgmt.getDownloadUrl() );
383             }
384 
385             if ( pDistMgmt.getRelocation() != null )
386             {
387                 mDistMgmt.setRelocation( pDistMgmt.getRelocation() );
388             }
389 
390             if ( pDistMgmt.getSite() != null )
391             {
392                 mDistMgmt.setSite( pDistMgmt.getSite() );
393             }
394 
395             // NOTE: We SHOULD NOT be inheriting status, since this is an assessment of the POM quality.
396         }
397     }
398 
399     private void injectDependencyManagement( Profile profile, Model model )
400     {
401         DependencyManagement modelDepMgmt = model.getDependencyManagement();
402 
403         DependencyManagement profileDepMgmt = profile.getDependencyManagement();
404 
405         if ( profileDepMgmt != null )
406         {
407             if ( modelDepMgmt == null )
408             {
409                 model.setDependencyManagement( profileDepMgmt );
410             }
411             else
412             {
413                 Map depsMap = new LinkedHashMap();
414 
415                 List deps = modelDepMgmt.getDependencies();
416 
417                 if ( deps != null )
418                 {
419                     for ( Iterator it = deps.iterator(); it.hasNext(); )
420                     {
421                         Dependency dependency = (Dependency) it.next();
422                         depsMap.put( dependency.getManagementKey(), dependency );
423                     }
424                 }
425 
426                 deps = profileDepMgmt.getDependencies();
427 
428                 if ( deps != null )
429                 {
430                     for ( Iterator it = deps.iterator(); it.hasNext(); )
431                     {
432                         Dependency dependency = (Dependency) it.next();
433                         depsMap.put( dependency.getManagementKey(), dependency );
434                     }
435                 }
436 
437                 modelDepMgmt.setDependencies( new ArrayList( depsMap.values() ) );
438             }
439         }
440     }
441 
442     private void injectReporting( Profile profile, Model model )
443     {
444         // Reports :: aggregate
445         Reporting profileReporting = profile.getReporting();
446         Reporting modelReporting = model.getReporting();
447 
448         if ( profileReporting != null )
449         {
450             if ( modelReporting == null )
451             {
452                 model.setReporting( profileReporting );
453             }
454             else
455             {
456                 if ( StringUtils.isEmpty( modelReporting.getOutputDirectory() ) )
457                 {
458                     modelReporting.setOutputDirectory( profileReporting.getOutputDirectory() );
459                 }
460 
461                 Map mergedReportPlugins = new LinkedHashMap();
462 
463                 Map profileReportersByKey = profileReporting.getReportPluginsAsMap();
464 
465                 List modelReportPlugins = modelReporting.getPlugins();
466 
467                 if ( modelReportPlugins != null )
468                 {
469                     for ( Iterator it = modelReportPlugins.iterator(); it.hasNext(); )
470                     {
471                         ReportPlugin modelReportPlugin = (ReportPlugin) it.next();
472 
473                         String inherited = modelReportPlugin.getInherited();
474 
475                         if ( StringUtils.isEmpty( inherited ) || Boolean.valueOf( inherited ).booleanValue() )
476                         {
477                             ReportPlugin profileReportPlugin = (ReportPlugin) profileReportersByKey
478                                 .get( modelReportPlugin.getKey() );
479 
480                             ReportPlugin mergedReportPlugin = modelReportPlugin;
481 
482                             if ( profileReportPlugin != null )
483                             {
484                                 mergedReportPlugin = profileReportPlugin;
485 
486                                 mergeReportPlugins( profileReportPlugin, modelReportPlugin );
487                             }
488                             else if ( StringUtils.isEmpty( inherited ) )
489                             {
490                                 mergedReportPlugin.unsetInheritanceApplied();
491                             }
492 
493                             mergedReportPlugins.put( mergedReportPlugin.getKey(), mergedReportPlugin );
494                         }
495                     }
496                 }
497 
498                 for ( Iterator it = profileReportersByKey.entrySet().iterator(); it.hasNext(); )
499                 {
500                     Map.Entry entry = (Map.Entry) it.next();
501 
502                     String key = (String) entry.getKey();
503 
504                     if ( !mergedReportPlugins.containsKey( key ) )
505                     {
506                         mergedReportPlugins.put( key, entry.getValue() );
507                     }
508                 }
509 
510                 modelReporting.setPlugins( new ArrayList( mergedReportPlugins.values() ) );
511 
512                 modelReporting.flushReportPluginMap();
513             }
514         }
515     }
516 
517     private void mergeReportPlugins( ReportPlugin dominant, ReportPlugin recessive )
518     {
519         if ( StringUtils.isEmpty( recessive.getVersion() ) )
520         {
521             recessive.setVersion( dominant.getVersion() );
522         }
523 
524         Xpp3Dom dominantConfig = (Xpp3Dom) dominant.getConfiguration();
525         Xpp3Dom recessiveConfig = (Xpp3Dom) recessive.getConfiguration();
526 
527         recessive.setConfiguration( merge( dominantConfig, recessiveConfig ) );
528 
529         Map mergedReportSets = new LinkedHashMap();
530 
531         Map dominantReportSetsById = dominant.getReportSetsAsMap();
532 
533         for ( Iterator it = recessive.getReportSets().iterator(); it.hasNext(); )
534         {
535             ReportSet recessiveReportSet = (ReportSet) it.next();
536 
537             ReportSet dominantReportSet = (ReportSet) dominantReportSetsById.get( recessiveReportSet.getId() );
538 
539             ReportSet merged = recessiveReportSet;
540 
541             if ( dominantReportSet != null )
542             {
543                 merged = recessiveReportSet;
544 
545                 Xpp3Dom dominantRSConfig = (Xpp3Dom) dominantReportSet.getConfiguration();
546                 Xpp3Dom mergedRSConfig = (Xpp3Dom) merged.getConfiguration();
547 
548                 merged.setConfiguration( merge( dominantRSConfig, mergedRSConfig ) );
549 
550                 List mergedReports = merged.getReports();
551 
552                 if ( mergedReports == null )
553                 {
554                     mergedReports = new ArrayList();
555 
556                     merged.setReports( mergedReports );
557                 }
558 
559                 List dominantRSReports = dominantReportSet.getReports();
560 
561                 if ( dominantRSReports != null )
562                 {
563                     for ( Iterator reportIterator = dominantRSReports.iterator(); reportIterator.hasNext(); )
564                     {
565                         String report = (String) reportIterator.next();
566 
567                         if ( !mergedReports.contains( report ) )
568                         {
569                             mergedReports.add( report );
570                         }
571                     }
572                 }
573 
574                 mergedReportSets.put( merged.getId(), merged );
575             }
576         }
577 
578         for ( Iterator rsIterator = dominantReportSetsById.entrySet().iterator(); rsIterator.hasNext(); )
579         {
580             Map.Entry entry = (Map.Entry) rsIterator.next();
581 
582             String key = (String) entry.getKey();
583 
584             if ( !mergedReportSets.containsKey( key ) )
585             {
586                 mergedReportSets.put( key, entry.getValue() );
587             }
588         }
589 
590         recessive.setReportSets( new ArrayList( mergedReportSets.values() ) );
591 
592         recessive.flushReportSetMap();
593     }
594 
595     private List injectDependencies( List profileDeps, List modelDeps )
596     {
597         Map depsMap = new LinkedHashMap();
598 
599         if ( modelDeps != null )
600         {
601             for ( Iterator it = modelDeps.iterator(); it.hasNext(); )
602             {
603                 Dependency dependency = (Dependency) it.next();
604                 depsMap.put( dependency.getManagementKey(), dependency );
605             }
606         }
607 
608         if ( profileDeps != null )
609         {
610             for ( Iterator it = profileDeps.iterator(); it.hasNext(); )
611             {
612                 Dependency dependency = (Dependency) it.next();
613                 depsMap.put( dependency.getManagementKey(), dependency );
614             }
615         }
616 
617         return new ArrayList( depsMap.values() );
618     }
619 
620 }