View Javadoc

1   package org.apache.maven.plugins.enforcer;
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 java.io.FileNotFoundException;
23  import java.io.FileReader;
24  import java.io.IOException;
25  import java.util.HashMap;
26  import java.util.HashSet;
27  import java.util.List;
28  import java.util.Map;
29  import java.util.Set;
30  
31  import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
32  import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
33  import org.apache.maven.model.Dependency;
34  import org.apache.maven.model.Model;
35  import org.apache.maven.model.Profile;
36  import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
37  import org.apache.maven.project.MavenProject;
38  import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
39  import org.codehaus.plexus.util.IOUtil;
40  import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
41  
42  /**
43   * Since Maven 3 'dependencies.dependency.(groupId:artifactId:type:classifier)' must be unique.
44   * Early versions of Maven 3 already warn, this rule can force to break a build for this reason. 
45   * 
46   * @author Robert Scholte
47   * @since 1.3
48   *
49   */
50  public class BanDuplicatePomDependencyVersions
51      extends AbstractNonCacheableEnforcerRule
52  {
53  
54      public void execute( EnforcerRuleHelper helper )
55          throws EnforcerRuleException
56      {
57          // get the project
58          MavenProject project;
59          try
60          {
61              project = (MavenProject) helper.evaluate( "${project}" );
62          }
63          catch ( ExpressionEvaluationException eee )
64          {
65              throw new EnforcerRuleException( "Unable to retrieve the MavenProject: ", eee );
66          }
67          
68          
69          // re-read model, because M3 uses optimized model
70          MavenXpp3Reader modelReader = new MavenXpp3Reader();
71          FileReader pomReader = null;
72          Model model;
73          try
74          {
75              pomReader = new FileReader( project.getFile() );
76  
77              model = modelReader.read( pomReader );
78          }
79          catch ( FileNotFoundException e )
80          {
81              throw new EnforcerRuleException( "Unable to retrieve the MavenProject: ", e );
82          }
83          catch ( IOException e )
84          {
85              throw new EnforcerRuleException( "Unable to retrieve the MavenProject: ", e );
86          }
87          catch ( XmlPullParserException e )
88          {
89              throw new EnforcerRuleException( "Unable to retrieve the MavenProject: ", e );
90          }
91          finally
92          {
93              IOUtil.close( pomReader );
94          }
95  
96          // @todo reuse ModelValidator when possible
97          
98  //        Object modelValidator = null;
99  //        try
100 //        {
101 //            modelValidator = helper.getComponent( "org.apache.maven.model.validation.ModelValidator" );
102 //        }
103 //        catch ( ComponentLookupException e1 )
104 //        {
105 //            // noop
106 //        }
107 
108 
109 //        if( modelValidator == null )
110 //        {
111             maven2Validation( helper, model );            
112 //        }
113 //        else
114 //        {
115 //        }
116     }
117 
118     private void maven2Validation( EnforcerRuleHelper helper, Model model )
119         throws EnforcerRuleException
120     {
121         @SuppressWarnings( "unchecked" )
122         List<Dependency> dependencies = model.getDependencies();
123         Map<String, Integer> duplicateDependencies = validateDependencies( dependencies );
124 
125         int duplicates = duplicateDependencies.size();
126         
127         StringBuilder summary = new StringBuilder();
128         messageBuilder( duplicateDependencies, "dependencies.dependency", summary );
129 
130         if ( model.getDependencyManagement() != null )
131         {
132             @SuppressWarnings( "unchecked" )
133             List<Dependency> managementDependencies = model.getDependencies();
134             Map<String, Integer> duplicateManagementDependencies = validateDependencies( managementDependencies );
135             duplicates += duplicateManagementDependencies.size();
136 
137             messageBuilder( duplicateManagementDependencies, "dependencyManagement.dependencies.dependency", summary );
138         }
139         
140         
141         @SuppressWarnings( "unchecked" )
142         List<Profile> profiles = model.getProfiles();
143         for ( Profile profile : profiles )
144         {
145             @SuppressWarnings( "unchecked" )
146             List<Dependency> profileDependencies = profile.getDependencies();
147 
148             Map<String, Integer> duplicateProfileDependencies = validateDependencies( profileDependencies );
149 
150             duplicates += duplicateProfileDependencies.size();
151             
152             messageBuilder( duplicateProfileDependencies, "profiles.profile[" + profile.getId()
153                 + "].dependencies.dependency", summary );
154 
155             if ( model.getDependencyManagement() != null )
156             {
157                 @SuppressWarnings( "unchecked" )
158                 List<Dependency> profileManagementDependencies = profile.getDependencies();
159                 
160                 Map<String, Integer> duplicateProfileManagementDependencies =
161                     validateDependencies( profileManagementDependencies );
162 
163                 duplicates += duplicateProfileManagementDependencies.size();
164                 
165                 messageBuilder( duplicateProfileManagementDependencies, "profiles.profile[" + profile.getId()
166                     + "].dependencyManagement.dependencies.dependency", summary );
167             }
168         }
169             
170         if ( summary.length() > 0 )
171         {
172             StringBuilder message = new StringBuilder();
173             message.append( "Found " ).append( duplicates ).append( " duplicate dependency " );
174             message.append( duplicateDependencies.size() == 1 ? "declaration" : "declarations" ).append( " in this project:\n" );
175             message.append( summary );
176             throw new EnforcerRuleException( message.toString() );
177         }
178     }
179 
180     private void messageBuilder( Map<String, Integer> duplicateDependencies, String prefix, StringBuilder message )
181     {
182         if ( !duplicateDependencies.isEmpty() )
183         {
184             for ( Map.Entry<String, Integer> entry : duplicateDependencies.entrySet() )
185             {
186                 message.append( " - " ).append( prefix ).append( '[' ).append( entry.getKey() ).append( "] ( " ).append( entry.getValue() ).append( " times )\n" );
187             }
188         }
189     }
190     
191 
192     private Map<String, Integer> validateDependencies( List<Dependency> dependencies )
193         throws EnforcerRuleException
194     {
195         Map<String, Integer> duplicateDeps = new HashMap<String, Integer>();
196         Set<String> deps = new HashSet<String>();
197         for ( Dependency dependency : dependencies )
198         {
199             String key = dependency.getManagementKey();
200 
201             if ( deps.contains( key ) )
202             {
203                 int times = 1;
204                 if ( duplicateDeps.containsKey( key ) )
205                 {
206                     times = duplicateDeps.get( key );
207                 }
208                 duplicateDeps.put( key, times + 1 );
209             }
210             else
211             {
212                 deps.add( key );
213             }
214         }
215         return duplicateDeps;
216     }
217 
218 }