View Javadoc

1   package org.apache.maven.project.validation;
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.artifact.Artifact;
23  import org.apache.maven.model.Build;
24  import org.apache.maven.model.Dependency;
25  import org.apache.maven.model.DependencyManagement;
26  import org.apache.maven.model.Model;
27  import org.apache.maven.model.Parent;
28  import org.apache.maven.model.Plugin;
29  import org.apache.maven.model.ReportPlugin;
30  import org.apache.maven.model.Reporting;
31  import org.apache.maven.model.Repository;
32  import org.apache.maven.model.Resource;
33  import org.codehaus.plexus.util.StringUtils;
34  
35  import java.io.File;
36  import java.util.Iterator;
37  import java.util.List;
38  
39  /**
40   * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
41   * @version $Id: DefaultModelValidator.java 495147 2007-01-11 07:47:53Z jvanzyl $
42   */
43  public class DefaultModelValidator
44      implements ModelValidator
45  {
46      private static final String ID_REGEX = "[A-Za-z0-9_\\-.]+";
47  
48      ///////////////////////////////////////////////////////////////////////////
49      // ModelValidator Implementation
50  
51      public ModelValidationResult validate( Model model )
52      {
53          ModelValidationResult result = new ModelValidationResult();
54  
55          validateStringNotEmpty( "modelVersion", result, model.getModelVersion() );
56  
57          validateId( "groupId", result, model.getGroupId() );
58  
59          validateId( "artifactId", result, model.getArtifactId() );
60  
61          validateStringNotEmpty( "packaging", result, model.getPackaging() );
62          
63          if ( !model.getModules().isEmpty() && !"pom".equals( model.getPackaging() ) )
64          {
65              result.addMessage( "Packaging '" + model.getPackaging() + "' is invalid. Aggregator projects " +
66                      "require 'pom' as packaging." );
67          }
68          
69          Parent parent = model.getParent();
70          if ( parent != null )
71          {
72              if ( parent.getGroupId().equals( model.getGroupId() ) && 
73                      parent.getArtifactId().equals( model.getArtifactId() ) )
74              {
75                  result.addMessage( "The parent element cannot have the same ID as the project." );
76              }
77          }
78  
79          validateStringNotEmpty( "version", result, model.getVersion() );
80  
81          for ( Iterator it = model.getDependencies().iterator(); it.hasNext(); )
82          {
83              Dependency d = (Dependency) it.next();
84  
85              validateId( "dependencies.dependency.artifactId", result, d.getArtifactId() );
86  
87              validateId( "dependencies.dependency.groupId", result, d.getGroupId() );
88  
89              validateStringNotEmpty( "dependencies.dependency.type", result, d.getType(), dependencySourceHint( d ) );
90  
91              validateStringNotEmpty( "dependencies.dependency.version", result, d.getVersion(), dependencySourceHint( d ) );
92  
93              if ( Artifact.SCOPE_SYSTEM.equals( d.getScope() ) )
94              {
95                  String systemPath = d.getSystemPath();
96                  
97                  if ( StringUtils.isEmpty( systemPath ) )
98                  {
99                      result.addMessage( "For dependency " + d + ": system-scoped dependency must specify systemPath." );
100                 }
101                 else
102                 {
103                     if ( ! new File( systemPath ).isAbsolute() )
104                     {
105                         result.addMessage( "For dependency " + d + ": system-scoped dependency must " +
106                                 "specify an absolute path systemPath." );
107                     }
108                 }
109             }
110             else if ( StringUtils.isNotEmpty( d.getSystemPath() ) )
111             {
112                 result.addMessage(
113                     "For dependency " + d + ": only dependency with system scope can specify systemPath." );
114             }
115         }
116 
117         DependencyManagement mgmt = model.getDependencyManagement();
118         if ( mgmt != null )
119         {
120             for ( Iterator it = mgmt.getDependencies().iterator(); it.hasNext(); )
121             {
122                 Dependency d = (Dependency) it.next();
123 
124                 validateSubElementStringNotEmpty( d, "dependencyManagement.dependencies.dependency.artifactId", result,
125                                                   d.getArtifactId() );
126 
127                 validateSubElementStringNotEmpty( d, "dependencyManagement.dependencies.dependency.groupId", result,
128                                                   d.getGroupId() );
129 
130                 if ( Artifact.SCOPE_SYSTEM.equals( d.getScope() ) )
131                 {
132                     String systemPath = d.getSystemPath();
133                     
134                     if ( StringUtils.isEmpty( systemPath ) )
135                     {
136                         result.addMessage( "For managed dependency " + d + ": system-scoped dependency must specify systemPath." );
137                     }
138                     else
139                     {
140                         if ( ! new File( systemPath ).isAbsolute() )
141                         {
142                             result.addMessage( "For managed dependency " + d + ": system-scoped dependency must " +
143                                     "specify an absolute path systemPath." );
144                         }
145                     }
146                 }
147                 else if ( StringUtils.isNotEmpty( d.getSystemPath() ) )
148                 {
149                     result.addMessage(
150                         "For managed dependency " + d + ": only dependency with system scope can specify systemPath." );
151                 }
152             }
153         }
154 
155         Build build = model.getBuild();
156         if ( build != null )
157         {
158             for ( Iterator it = build.getPlugins().iterator(); it.hasNext(); )
159             {
160                 Plugin p = (Plugin) it.next();
161 
162                 validateStringNotEmpty( "build.plugins.plugin.artifactId", result, p.getArtifactId() );
163 
164                 validateStringNotEmpty( "build.plugins.plugin.groupId", result, p.getGroupId() );
165             }
166 
167             for ( Iterator it = build.getResources().iterator(); it.hasNext(); )
168             {
169                 Resource r = (Resource) it.next();
170 
171                 validateStringNotEmpty( "build.resources.resource.directory", result, r.getDirectory() );
172             }
173 
174             for ( Iterator it = build.getTestResources().iterator(); it.hasNext(); )
175             {
176                 Resource r = (Resource) it.next();
177 
178                 validateStringNotEmpty( "build.testResources.testResource.directory", result, r.getDirectory() );
179             }
180         }
181 
182         Reporting reporting = model.getReporting();
183         if ( reporting != null )
184         {
185             for ( Iterator it = reporting.getPlugins().iterator(); it.hasNext(); )
186             {
187                 ReportPlugin p = (ReportPlugin) it.next();
188 
189                 validateStringNotEmpty( "reporting.plugins.plugin.artifactId", result, p.getArtifactId() );
190 
191                 validateStringNotEmpty( "reporting.plugins.plugin.groupId", result, p.getGroupId() );
192             }
193         }
194 
195         validateRepositories( result, model.getRepositories(), "repositories.repository" );
196 
197         validateRepositories( result, model.getPluginRepositories(), "pluginRepositories.pluginRepository" );
198 
199         forcePluginExecutionIdCollision( model, result );
200 
201         return result;
202     }
203 
204     private boolean validateId( String fieldName, ModelValidationResult result, String id )
205     {
206         if ( !validateStringNotEmpty( fieldName, result, id ) )
207         {
208             return false;
209         }
210         else
211         {
212             boolean match = id.matches( ID_REGEX );
213             if ( !match )
214             {
215                 result.addMessage( "'" + fieldName + "' with value '" + id + "' does not match a valid id pattern." );
216             }
217             return match;
218         }
219     }
220 
221     private void validateRepositories( ModelValidationResult result, List repositories, String prefix )
222     {
223         for ( Iterator it = repositories.iterator(); it.hasNext(); )
224         {
225             Repository repository = (Repository) it.next();
226 
227             validateStringNotEmpty( prefix + ".id", result, repository.getId() );
228 
229             validateStringNotEmpty( prefix + ".url", result, repository.getUrl() );
230         }
231     }
232 
233     private void forcePluginExecutionIdCollision( Model model, ModelValidationResult result )
234     {
235         Build build = model.getBuild();
236 
237         if ( build != null )
238         {
239             List plugins = build.getPlugins();
240 
241             if ( plugins != null )
242             {
243                 for ( Iterator it = plugins.iterator(); it.hasNext(); )
244                 {
245                     Plugin plugin = (Plugin) it.next();
246 
247                     // this will force an IllegalStateException, even if we don't have to do inheritance assembly.
248                     try
249                     {
250                         plugin.getExecutionsAsMap();
251                     }
252                     catch ( IllegalStateException collisionException )
253                     {
254                         result.addMessage( collisionException.getMessage() );
255                     }
256                 }
257             }
258         }
259     }
260 
261 
262     // ----------------------------------------------------------------------
263     // Field validation
264     // ----------------------------------------------------------------------
265 
266     /**
267      * Create a hint string consisting of the groupId and artifactId for user validation
268      * messages. For example when the version or type information is missing from a
269      * dependency.
270      *
271      * @param d The dependency from which to make the hint.
272      * @return String of the form g:a.
273      */
274     private String dependencySourceHint( Dependency d )
275     {
276         return d.getGroupId() + ":" + d.getArtifactId();
277     }
278 
279     private boolean validateStringNotEmpty( String fieldName, ModelValidationResult result, String string )
280     {
281         return validateStringNotEmpty( fieldName, result, string, null );
282     }
283 
284     /**
285      * Asserts:
286      * <p/>
287      * <ul>
288      * <li><code>string.length != null</code>
289      * <li><code>string.length > 0</code>
290      * </ul>
291      */
292     private boolean validateStringNotEmpty( String fieldName, ModelValidationResult result, String string, String sourceHint )
293     {
294         if ( !validateNotNull( fieldName, result, string, sourceHint ) )
295         {
296             return false;
297         }
298 
299         if ( string.length() > 0 )
300         {
301             return true;
302         }
303 
304         if ( sourceHint != null )
305         {
306             result.addMessage( "'" + fieldName + "' is missing for " + sourceHint );
307         }
308         else
309         {
310             result.addMessage( "'" + fieldName + "' is missing." );
311         }
312 
313 
314         return false;
315     }
316 
317     /**
318      * Asserts:
319      * <p/>
320      * <ul>
321      * <li><code>string.length != null</code>
322      * <li><code>string.length > 0</code>
323      * </ul>
324      */
325     private boolean validateSubElementStringNotEmpty( Object subElementInstance, String fieldName,
326                                                       ModelValidationResult result, String string )
327     {
328         if ( !validateSubElementNotNull( subElementInstance, fieldName, result, string ) )
329         {
330             return false;
331         }
332 
333         if ( string.length() > 0 )
334         {
335             return true;
336         }
337 
338         result.addMessage( "In " + subElementInstance + ":\n\n       -> '" + fieldName + "' is missing." );
339 
340         return false;
341     }
342 
343     /**
344      * Asserts:
345      * <p/>
346      * <ul>
347      * <li><code>string != null</code>
348      * </ul>
349      */
350     private boolean validateNotNull( String fieldName, ModelValidationResult result, Object object, String sourceHint )
351     {
352         if ( object != null )
353         {
354             return true;
355         }
356 
357         if ( sourceHint != null )
358         {
359             result.addMessage( "'" + fieldName + "' is missing for " + sourceHint );
360         }
361         else
362         {
363             result.addMessage( "'" + fieldName + "' is missing." );
364         }
365 
366         return false;
367     }
368 
369     /**
370      * Asserts:
371      * <p/>
372      * <ul>
373      * <li><code>string != null</code>
374      * </ul>
375      */
376     private boolean validateSubElementNotNull( Object subElementInstance, String fieldName,
377                                                ModelValidationResult result, Object object )
378     {
379         if ( object != null )
380         {
381             return true;
382         }
383 
384         result.addMessage( "In " + subElementInstance + ":\n\n       -> '" + fieldName + "' is missing." );
385 
386         return false;
387     }
388 }