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