View Javadoc

1   package org.apache.maven.project.inheritance;
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.Dependency;
24  import org.apache.maven.model.DependencyManagement;
25  import org.apache.maven.model.DeploymentRepository;
26  import org.apache.maven.model.DistributionManagement;
27  import org.apache.maven.model.Model;
28  import org.apache.maven.model.PluginManagement;
29  import org.apache.maven.model.Reporting;
30  import org.apache.maven.model.Scm;
31  import org.apache.maven.model.Site;
32  import org.apache.maven.project.ModelUtils;
33  import org.codehaus.plexus.util.StringUtils;
34  
35  import java.util.ArrayList;
36  import java.util.Iterator;
37  import java.util.LinkedList;
38  import java.util.List;
39  import java.util.Map;
40  import java.util.Properties;
41  import java.util.StringTokenizer;
42  import java.util.TreeMap;
43  
44  /**
45   * @author <a href="mailto:jason@maven.org">Jason van Zyl </a>
46   * @version $Id: DefaultModelInheritanceAssembler.java,v 1.4 2004/08/23 20:24:54
47   *          jdcasey Exp $
48   * @todo generate this with modello to keep it in sync with changes in the model.
49   */
50  public class DefaultModelInheritanceAssembler
51      implements ModelInheritanceAssembler
52  {
53      public void copyModel( Model dest, Model source )
54      {
55          assembleModelInheritance( dest, source, null, false );
56      }
57  
58      public void assembleModelInheritance( Model child, Model parent, String childPathAdjustment )
59      {
60          assembleModelInheritance( child, parent, childPathAdjustment, true );
61      }
62  
63      public void assembleModelInheritance( Model child, Model parent )
64      {
65          assembleModelInheritance( child, parent, null, true );
66      }
67  
68      private void assembleModelInheritance( Model child, Model parent, String childPathAdjustment, boolean appendPaths )
69      {
70          // cannot inherit from null parent.
71          if ( parent == null )
72          {
73              return;
74          }
75  
76          // Group id
77          if ( child.getGroupId() == null )
78          {
79              child.setGroupId( parent.getGroupId() );
80          }
81  
82          // version
83          if ( child.getVersion() == null )
84          {
85              // The parent version may have resolved to something different, so we take what we asked for...
86              // instead of - child.setVersion( parent.getVersion() );
87  
88              if ( child.getParent() != null )
89              {
90                  child.setVersion( child.getParent().getVersion() );
91              }
92          }
93  
94          // inceptionYear
95          if ( child.getInceptionYear() == null )
96          {
97              child.setInceptionYear( parent.getInceptionYear() );
98          }
99  
100         // url
101         if ( child.getUrl() == null )
102         {
103             if ( parent.getUrl() != null )
104             {
105                 child.setUrl( appendPath( parent.getUrl(), child.getArtifactId(), childPathAdjustment, appendPaths ) );
106             }
107             else
108             {
109                 child.setUrl( parent.getUrl() );
110             }
111         }
112 
113         assembleDistributionInheritence( child, parent, childPathAdjustment, appendPaths );
114 
115         // issueManagement
116         if ( child.getIssueManagement() == null )
117         {
118             child.setIssueManagement( parent.getIssueManagement() );
119         }
120 
121         // description
122         if ( child.getDescription() == null )
123         {
124             child.setDescription( parent.getDescription() );
125         }
126 
127         // Organization
128         if ( child.getOrganization() == null )
129         {
130             child.setOrganization( parent.getOrganization() );
131         }
132 
133         // Scm
134         assembleScmInheritance( child, parent, childPathAdjustment, appendPaths );
135 
136         // ciManagement
137         if ( child.getCiManagement() == null )
138         {
139             child.setCiManagement( parent.getCiManagement() );
140         }
141 
142         // developers
143         if ( child.getDevelopers().size() == 0 )
144         {
145             child.setDevelopers( parent.getDevelopers() );
146         }
147 
148         // licenses
149         if ( child.getLicenses().size() == 0 )
150         {
151             child.setLicenses( parent.getLicenses() );
152         }
153 
154         // developers
155         if ( child.getContributors().size() == 0 )
156         {
157             child.setContributors( parent.getContributors() );
158         }
159 
160         // mailingLists
161         if ( child.getMailingLists().size() == 0 )
162         {
163             child.setMailingLists( parent.getMailingLists() );
164         }
165 
166         // Build
167         assembleBuildInheritance( child, parent );
168 
169         assembleDependencyInheritance( child, parent );
170 
171         child.setRepositories( ModelUtils.mergeRepositoryLists( child.getRepositories(), parent.getRepositories() ) );
172         child.setPluginRepositories(
173             ModelUtils.mergeRepositoryLists( child.getPluginRepositories(), parent.getPluginRepositories() ) );
174 
175         assembleReportingInheritance( child, parent );
176 
177         assembleDependencyManagementInheritance( child, parent );
178 
179         Properties props = new Properties();
180         props.putAll( parent.getProperties() );
181         props.putAll( child.getProperties() );
182 
183         child.setProperties( props );
184     }
185 
186     private void assembleDependencyManagementInheritance( Model child, Model parent )
187     {
188         DependencyManagement parentDepMgmt = parent.getDependencyManagement();
189 
190         DependencyManagement childDepMgmt = child.getDependencyManagement();
191 
192         if ( parentDepMgmt != null )
193         {
194             if ( childDepMgmt == null )
195             {
196                 child.setDependencyManagement( parentDepMgmt );
197             }
198             else
199             {
200                 List childDeps = childDepMgmt.getDependencies();
201 
202                 Map mappedChildDeps = new TreeMap();
203                 for ( Iterator it = childDeps.iterator(); it.hasNext(); )
204                 {
205                     Dependency dep = (Dependency) it.next();
206                     mappedChildDeps.put( dep.getManagementKey(), dep );
207                 }
208 
209                 for ( Iterator it = parentDepMgmt.getDependencies().iterator(); it.hasNext(); )
210                 {
211                     Dependency dep = (Dependency) it.next();
212                     if ( !mappedChildDeps.containsKey( dep.getManagementKey() ) )
213                     {
214                         childDepMgmt.addDependency( dep );
215                     }
216                 }
217             }
218         }
219     }
220 
221     private void assembleReportingInheritance( Model child, Model parent )
222     {
223         // Reports :: aggregate
224         Reporting childReporting = child.getReporting();
225         Reporting parentReporting = parent.getReporting();
226 
227         if ( parentReporting != null )
228         {
229             if ( childReporting == null )
230             {
231                 childReporting = new Reporting();
232                 child.setReporting( childReporting );
233             }
234 
235             if ( childReporting.isExcludeDefaultsValue() == null )
236             {
237                 childReporting.setExcludeDefaultsValue( parentReporting.isExcludeDefaultsValue() );
238             }
239 
240             if ( StringUtils.isEmpty( childReporting.getOutputDirectory() ) )
241             {
242                 childReporting.setOutputDirectory( parentReporting.getOutputDirectory() );
243             }
244 
245             ModelUtils.mergeReportPluginLists( childReporting, parentReporting, true );
246         }
247     }
248 
249     private void assembleDependencyInheritance( Model child, Model parent )
250     {
251         child.setDependencies( ModelUtils.mergeDependencyList( child.getDependencies(), parent.getDependencies() ) );
252     }
253 
254     private void assembleBuildInheritance( Model child, Model parent )
255     {
256         Build childBuild = child.getBuild();
257         Build parentBuild = parent.getBuild();
258 
259         if ( parentBuild != null )
260         {
261             if ( childBuild == null )
262             {
263                 childBuild = new Build();
264                 child.setBuild( childBuild );
265             }
266 
267             // The build has been set but we want to step in here and fill in
268             // values that have not been set by the child.
269 
270             if ( childBuild.getSourceDirectory() == null )
271             {
272                 childBuild.setSourceDirectory( parentBuild.getSourceDirectory() );
273             }
274 
275             if ( childBuild.getScriptSourceDirectory() == null )
276             {
277                 childBuild.setScriptSourceDirectory( parentBuild.getScriptSourceDirectory() );
278             }
279 
280             if ( childBuild.getTestSourceDirectory() == null )
281             {
282                 childBuild.setTestSourceDirectory( parentBuild.getTestSourceDirectory() );
283             }
284 
285             if ( childBuild.getOutputDirectory() == null )
286             {
287                 childBuild.setOutputDirectory( parentBuild.getOutputDirectory() );
288             }
289 
290             if ( childBuild.getTestOutputDirectory() == null )
291             {
292                 childBuild.setTestOutputDirectory( parentBuild.getTestOutputDirectory() );
293             }
294 
295             // Extensions are accumlated
296             ModelUtils.mergeExtensionLists( childBuild, parentBuild );
297 
298             if ( childBuild.getDirectory() == null )
299             {
300                 childBuild.setDirectory( parentBuild.getDirectory() );
301             }
302 
303             if ( childBuild.getDefaultGoal() == null )
304             {
305                 childBuild.setDefaultGoal( parentBuild.getDefaultGoal() );
306             }
307 
308             if ( childBuild.getFinalName() == null )
309             {
310                 childBuild.setFinalName( parentBuild.getFinalName() );
311             }
312 
313             ModelUtils.mergeFilterLists( childBuild.getFilters(), parentBuild.getFilters() );
314 
315             List resources = childBuild.getResources();
316             if ( ( resources == null ) || resources.isEmpty() )
317             {
318                 childBuild.setResources( parentBuild.getResources() );
319             }
320 
321             resources = childBuild.getTestResources();
322             if ( ( resources == null ) || resources.isEmpty() )
323             {
324                 childBuild.setTestResources( parentBuild.getTestResources() );
325             }
326 
327             // Plugins are aggregated if Plugin.inherit != false
328             ModelUtils.mergePluginLists( childBuild, parentBuild, true );
329 
330             // Plugin management :: aggregate
331             PluginManagement dominantPM = childBuild.getPluginManagement();
332             PluginManagement recessivePM = parentBuild.getPluginManagement();
333 
334             if ( ( dominantPM == null ) && ( recessivePM != null ) )
335             {
336                 // FIXME: Filter out the inherited == false stuff!
337                 childBuild.setPluginManagement( recessivePM );
338             }
339             else
340             {
341                 ModelUtils.mergePluginLists( childBuild.getPluginManagement(), parentBuild.getPluginManagement(),
342                                              false );
343             }
344         }
345     }
346 
347     private void assembleScmInheritance( Model child, Model parent, String childPathAdjustment, boolean appendPaths )
348     {
349         if ( parent.getScm() != null )
350         {
351             Scm parentScm = parent.getScm();
352 
353             Scm childScm = child.getScm();
354 
355             if ( childScm == null )
356             {
357                 childScm = new Scm();
358 
359                 child.setScm( childScm );
360             }
361 
362             if ( StringUtils.isEmpty( childScm.getConnection() ) && !StringUtils.isEmpty( parentScm.getConnection() ) )
363             {
364                 childScm.setConnection(
365                     appendPath( parentScm.getConnection(), child.getArtifactId(), childPathAdjustment, appendPaths ) );
366             }
367 
368             if ( StringUtils.isEmpty( childScm.getDeveloperConnection() ) &&
369                 !StringUtils.isEmpty( parentScm.getDeveloperConnection() ) )
370             {
371                 childScm
372                     .setDeveloperConnection( appendPath( parentScm.getDeveloperConnection(), child.getArtifactId(),
373                                                          childPathAdjustment, appendPaths ) );
374             }
375 
376             if ( StringUtils.isEmpty( childScm.getUrl() ) && !StringUtils.isEmpty( parentScm.getUrl() ) )
377             {
378                 childScm.setUrl(
379                     appendPath( parentScm.getUrl(), child.getArtifactId(), childPathAdjustment, appendPaths ) );
380             }
381         }
382     }
383 
384     private void assembleDistributionInheritence( Model child, Model parent, String childPathAdjustment, boolean appendPaths )
385     {
386         if ( parent.getDistributionManagement() != null )
387         {
388             DistributionManagement parentDistMgmt = parent.getDistributionManagement();
389 
390             DistributionManagement childDistMgmt = child.getDistributionManagement();
391 
392             if ( childDistMgmt == null )
393             {
394                 childDistMgmt = new DistributionManagement();
395 
396                 child.setDistributionManagement( childDistMgmt );
397             }
398 
399             if ( childDistMgmt.getSite() == null )
400             {
401                 if ( parentDistMgmt.getSite() != null )
402                 {
403                     Site site = new Site();
404 
405                     childDistMgmt.setSite( site );
406 
407                     site.setId( parentDistMgmt.getSite().getId() );
408 
409                     site.setName( parentDistMgmt.getSite().getName() );
410 
411                     site.setUrl( parentDistMgmt.getSite().getUrl() );
412 
413                     if ( site.getUrl() != null )
414                     {
415                         site.setUrl(
416                             appendPath( site.getUrl(), child.getArtifactId(), childPathAdjustment, appendPaths ) );
417                     }
418                 }
419             }
420 
421             if ( childDistMgmt.getRepository() == null )
422             {
423                 if ( parentDistMgmt.getRepository() != null )
424                 {
425                     DeploymentRepository repository = copyDistributionRepository( parentDistMgmt.getRepository() );
426                     childDistMgmt.setRepository( repository );
427                 }
428             }
429 
430             if ( childDistMgmt.getSnapshotRepository() == null )
431             {
432                 if ( parentDistMgmt.getSnapshotRepository() != null )
433                 {
434                     DeploymentRepository repository =
435                         copyDistributionRepository( parentDistMgmt.getSnapshotRepository() );
436                     childDistMgmt.setSnapshotRepository( repository );
437                 }
438             }
439 
440             if ( StringUtils.isEmpty( childDistMgmt.getDownloadUrl() ) )
441             {
442                 childDistMgmt.setDownloadUrl( parentDistMgmt.getDownloadUrl() );
443             }
444 
445             // NOTE: We SHOULD NOT be inheriting status, since this is an assessment of the POM quality.
446             // NOTE: We SHOULD NOT be inheriting relocation, since this relates to a single POM
447         }
448     }
449 
450     private static DeploymentRepository copyDistributionRepository( DeploymentRepository parentRepository )
451     {
452         DeploymentRepository repository = new DeploymentRepository();
453 
454         repository.setId( parentRepository.getId() );
455 
456         repository.setName( parentRepository.getName() );
457 
458         repository.setUrl( parentRepository.getUrl() );
459 
460         repository.setLayout( parentRepository.getLayout() );
461 
462         repository.setUniqueVersion( parentRepository.isUniqueVersion() );
463 
464         return repository;
465     }
466 
467     // TODO: This should eventually be migrated to DefaultPathTranslator.
468     protected String appendPath( String parentPath, String childPath, String pathAdjustment, boolean appendPaths )
469     {
470         String uncleanPath = parentPath;
471 
472         if ( appendPaths )
473         {
474             if ( pathAdjustment != null )
475             {
476                 uncleanPath += "/" + pathAdjustment;
477             }
478 
479             if ( childPath != null )
480             {
481                 uncleanPath += "/" + childPath;
482             }
483         }
484 
485         String cleanedPath = "";
486 
487         int protocolIdx = uncleanPath.indexOf( "://" );
488 
489         if ( protocolIdx > -1 )
490         {
491             cleanedPath = uncleanPath.substring( 0, protocolIdx + 3 );
492             uncleanPath = uncleanPath.substring( protocolIdx + 3 );
493         }
494 
495         if ( uncleanPath.startsWith( "//" ) )
496         {
497             // preserve leading double slash for UNC paths like "file:////host/pom.xml"
498             cleanedPath += "//";
499         }
500         else if ( uncleanPath.startsWith( "/" ) )
501         {
502             cleanedPath += "/";
503         }
504 
505         return cleanedPath + resolvePath( uncleanPath );
506     }
507 
508     // TODO: Move this to plexus-utils' PathTool.
509     private static String resolvePath( String uncleanPath )
510     {
511         LinkedList pathElements = new LinkedList();
512 
513         StringTokenizer tokenizer = new StringTokenizer( uncleanPath, "/" );
514 
515         while ( tokenizer.hasMoreTokens() )
516         {
517             String token = tokenizer.nextToken();
518 
519             if ( token.equals( "" ) )
520             {
521                 // Empty path entry ("...//.."), remove.
522             }
523             else if ( token.equals( ".." ) )
524             {
525                 if ( pathElements.isEmpty() )
526                 {
527                     // FIXME: somehow report to the user
528                     // that there are too many '..' elements.
529                     // For now, ignore the extra '..'.
530                 }
531                 else
532                 {
533                     pathElements.removeLast();
534                 }
535             }
536             else
537             {
538                 pathElements.addLast( token );
539             }
540         }
541 
542 
543         StringBuffer cleanedPath = new StringBuffer();
544 
545         while ( !pathElements.isEmpty() )
546         {
547             cleanedPath.append( pathElements.removeFirst() );
548             if ( !pathElements.isEmpty() )
549             {
550                 cleanedPath.append( '/' );
551             }
552         }
553 
554         return cleanedPath.toString();
555     }
556 
557 }