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             assembleBuildInheritance( childBuild, parentBuild, true );
268         }
269     }
270 
271     public void assembleBuildInheritance( Build childBuild,
272                                            Build parentBuild,
273                                            boolean handleAsInheritance )
274     {
275         // The build has been set but we want to step in here and fill in
276         // values that have not been set by the child.
277 
278         if ( childBuild.getSourceDirectory() == null )
279         {
280             childBuild.setSourceDirectory( parentBuild.getSourceDirectory() );
281         }
282 
283         if ( childBuild.getScriptSourceDirectory() == null )
284         {
285             childBuild.setScriptSourceDirectory( parentBuild.getScriptSourceDirectory() );
286         }
287 
288         if ( childBuild.getTestSourceDirectory() == null )
289         {
290             childBuild.setTestSourceDirectory( parentBuild.getTestSourceDirectory() );
291         }
292 
293         if ( childBuild.getOutputDirectory() == null )
294         {
295             childBuild.setOutputDirectory( parentBuild.getOutputDirectory() );
296         }
297 
298         if ( childBuild.getTestOutputDirectory() == null )
299         {
300             childBuild.setTestOutputDirectory( parentBuild.getTestOutputDirectory() );
301         }
302 
303         // Extensions are accumlated
304         ModelUtils.mergeExtensionLists( childBuild, parentBuild );
305 
306         if ( childBuild.getDirectory() == null )
307         {
308             childBuild.setDirectory( parentBuild.getDirectory() );
309         }
310 
311         if ( childBuild.getDefaultGoal() == null )
312         {
313             childBuild.setDefaultGoal( parentBuild.getDefaultGoal() );
314         }
315 
316         if ( childBuild.getFinalName() == null )
317         {
318             childBuild.setFinalName( parentBuild.getFinalName() );
319         }
320 
321         ModelUtils.mergeFilterLists( childBuild.getFilters(), parentBuild.getFilters() );
322 
323         List resources = childBuild.getResources();
324         if ( ( resources == null ) || resources.isEmpty() )
325         {
326             childBuild.setResources( parentBuild.getResources() );
327         }
328 
329         resources = childBuild.getTestResources();
330         if ( ( resources == null ) || resources.isEmpty() )
331         {
332             childBuild.setTestResources( parentBuild.getTestResources() );
333         }
334 
335         // Plugins are aggregated if Plugin.inherit != false
336         ModelUtils.mergePluginLists( childBuild, parentBuild, handleAsInheritance );
337 
338         // Plugin management :: aggregate
339         PluginManagement dominantPM = childBuild.getPluginManagement();
340         PluginManagement recessivePM = parentBuild.getPluginManagement();
341 
342         if ( ( dominantPM == null ) && ( recessivePM != null ) )
343         {
344             // FIXME: Filter out the inherited == false stuff!
345             childBuild.setPluginManagement( recessivePM );
346         }
347         else
348         {
349             ModelUtils.mergePluginLists( childBuild.getPluginManagement(), parentBuild.getPluginManagement(),
350                                          false );
351         }
352     }
353 
354     private void assembleScmInheritance( Model child, Model parent, String childPathAdjustment, boolean appendPaths )
355     {
356         if ( parent.getScm() != null )
357         {
358             Scm parentScm = parent.getScm();
359 
360             Scm childScm = child.getScm();
361 
362             if ( childScm == null )
363             {
364                 childScm = new Scm();
365 
366                 child.setScm( childScm );
367             }
368 
369             if ( StringUtils.isEmpty( childScm.getConnection() ) && !StringUtils.isEmpty( parentScm.getConnection() ) )
370             {
371                 childScm.setConnection(
372                     appendPath( parentScm.getConnection(), child.getArtifactId(), childPathAdjustment, appendPaths ) );
373             }
374 
375             if ( StringUtils.isEmpty( childScm.getDeveloperConnection() ) &&
376                 !StringUtils.isEmpty( parentScm.getDeveloperConnection() ) )
377             {
378                 childScm
379                     .setDeveloperConnection( appendPath( parentScm.getDeveloperConnection(), child.getArtifactId(),
380                                                          childPathAdjustment, appendPaths ) );
381             }
382 
383             if ( StringUtils.isEmpty( childScm.getUrl() ) && !StringUtils.isEmpty( parentScm.getUrl() ) )
384             {
385                 childScm.setUrl(
386                     appendPath( parentScm.getUrl(), child.getArtifactId(), childPathAdjustment, appendPaths ) );
387             }
388         }
389     }
390 
391     private void assembleDistributionInheritence( Model child, Model parent, String childPathAdjustment, boolean appendPaths )
392     {
393         if ( parent.getDistributionManagement() != null )
394         {
395             DistributionManagement parentDistMgmt = parent.getDistributionManagement();
396 
397             DistributionManagement childDistMgmt = child.getDistributionManagement();
398 
399             if ( childDistMgmt == null )
400             {
401                 childDistMgmt = new DistributionManagement();
402 
403                 child.setDistributionManagement( childDistMgmt );
404             }
405 
406             if ( childDistMgmt.getSite() == null )
407             {
408                 if ( parentDistMgmt.getSite() != null )
409                 {
410                     Site site = new Site();
411 
412                     childDistMgmt.setSite( site );
413 
414                     site.setId( parentDistMgmt.getSite().getId() );
415 
416                     site.setName( parentDistMgmt.getSite().getName() );
417 
418                     site.setUrl( parentDistMgmt.getSite().getUrl() );
419 
420                     if ( site.getUrl() != null )
421                     {
422                         site.setUrl(
423                             appendPath( site.getUrl(), child.getArtifactId(), childPathAdjustment, appendPaths ) );
424                     }
425                 }
426             }
427 
428             if ( childDistMgmt.getRepository() == null )
429             {
430                 if ( parentDistMgmt.getRepository() != null )
431                 {
432                     DeploymentRepository repository = copyDistributionRepository( parentDistMgmt.getRepository() );
433                     childDistMgmt.setRepository( repository );
434                 }
435             }
436 
437             if ( childDistMgmt.getSnapshotRepository() == null )
438             {
439                 if ( parentDistMgmt.getSnapshotRepository() != null )
440                 {
441                     DeploymentRepository repository =
442                         copyDistributionRepository( parentDistMgmt.getSnapshotRepository() );
443                     childDistMgmt.setSnapshotRepository( repository );
444                 }
445             }
446 
447             if ( StringUtils.isEmpty( childDistMgmt.getDownloadUrl() ) )
448             {
449                 childDistMgmt.setDownloadUrl( parentDistMgmt.getDownloadUrl() );
450             }
451 
452             // NOTE: We SHOULD NOT be inheriting status, since this is an assessment of the POM quality.
453             // NOTE: We SHOULD NOT be inheriting relocation, since this relates to a single POM
454         }
455     }
456 
457     private static DeploymentRepository copyDistributionRepository( DeploymentRepository parentRepository )
458     {
459         DeploymentRepository repository = new DeploymentRepository();
460 
461         repository.setId( parentRepository.getId() );
462 
463         repository.setName( parentRepository.getName() );
464 
465         repository.setUrl( parentRepository.getUrl() );
466 
467         repository.setLayout( parentRepository.getLayout() );
468 
469         repository.setUniqueVersion( parentRepository.isUniqueVersion() );
470 
471         return repository;
472     }
473 
474     // TODO: This should eventually be migrated to DefaultPathTranslator.
475     protected String appendPath( String parentPath, String childPath, String pathAdjustment, boolean appendPaths )
476     {
477         String uncleanPath = parentPath;
478 
479         if ( appendPaths )
480         {
481             if ( pathAdjustment != null )
482             {
483                 uncleanPath += "/" + pathAdjustment;
484             }
485 
486             if ( childPath != null )
487             {
488                 uncleanPath += "/" + childPath;
489             }
490         }
491 
492         String cleanedPath = "";
493 
494         int protocolIdx = uncleanPath.indexOf( "://" );
495 
496         if ( protocolIdx > -1 )
497         {
498             cleanedPath = uncleanPath.substring( 0, protocolIdx + 3 );
499             uncleanPath = uncleanPath.substring( protocolIdx + 3 );
500         }
501 
502         if ( uncleanPath.startsWith( "//" ) )
503         {
504             // preserve leading double slash for UNC paths like "file:////host/pom.xml"
505             cleanedPath += "//";
506         }
507         else if ( uncleanPath.startsWith( "/" ) )
508         {
509             cleanedPath += "/";
510         }
511 
512         return cleanedPath + resolvePath( uncleanPath );
513     }
514 
515     // TODO: Move this to plexus-utils' PathTool.
516     private static String resolvePath( String uncleanPath )
517     {
518         LinkedList pathElements = new LinkedList();
519 
520         StringTokenizer tokenizer = new StringTokenizer( uncleanPath, "/" );
521 
522         while ( tokenizer.hasMoreTokens() )
523         {
524             String token = tokenizer.nextToken();
525 
526             if ( token.equals( "" ) )
527             {
528                 // Empty path entry ("...//.."), remove.
529             }
530             else if ( token.equals( ".." ) )
531             {
532                 if ( pathElements.isEmpty() )
533                 {
534                     // FIXME: somehow report to the user
535                     // that there are too many '..' elements.
536                     // For now, ignore the extra '..'.
537                 }
538                 else
539                 {
540                     pathElements.removeLast();
541                 }
542             }
543             else
544             {
545                 pathElements.addLast( token );
546             }
547         }
548 
549 
550         StringBuffer cleanedPath = new StringBuffer();
551 
552         while ( !pathElements.isEmpty() )
553         {
554             cleanedPath.append( pathElements.removeFirst() );
555             if ( !pathElements.isEmpty() )
556             {
557                 cleanedPath.append( '/' );
558             }
559         }
560 
561         return cleanedPath.toString();
562     }
563 
564 }