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 800540 2009-08-03 20:31:37Z jdcasey $
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( final 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(), d.getManagementKey() );
90  
91              validateStringNotEmpty( "dependencies.dependency.version", result, d.getVersion(), d.getManagementKey() );
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                 else if ( Artifact.SCOPE_IMPORT.equals( d.getScope() ) )
153                 {
154                     if ( !"pom".equals( d.getType() ) )
155                     {
156                         result.addMessage( "For managed dependency " + d
157                             + ": dependencies with import scope must have type 'pom'." );
158                     }
159                     else if ( d.getClassifier() != null )
160                     {
161                         result.addMessage( "For managed dependency " + d
162                             + ": dependencies with import scope must NOT have a classifier." );
163                     }
164 
165                 }
166             }
167         }
168 
169         Build build = model.getBuild();
170         if ( build != null )
171         {
172             for ( Iterator it = build.getPlugins().iterator(); it.hasNext(); )
173             {
174                 Plugin p = (Plugin) it.next();
175 
176                 validateStringNotEmpty( "build.plugins.plugin.artifactId", result, p.getArtifactId() );
177 
178                 validateStringNotEmpty( "build.plugins.plugin.groupId", result, p.getGroupId() );
179             }
180 
181             for ( Iterator it = build.getResources().iterator(); it.hasNext(); )
182             {
183                 Resource r = (Resource) it.next();
184 
185                 validateStringNotEmpty( "build.resources.resource.directory", result, r.getDirectory() );
186             }
187 
188             for ( Iterator it = build.getTestResources().iterator(); it.hasNext(); )
189             {
190                 Resource r = (Resource) it.next();
191 
192                 validateStringNotEmpty( "build.testResources.testResource.directory", result, r.getDirectory() );
193             }
194         }
195 
196         Reporting reporting = model.getReporting();
197         if ( reporting != null )
198         {
199             for ( Iterator it = reporting.getPlugins().iterator(); it.hasNext(); )
200             {
201                 ReportPlugin p = (ReportPlugin) it.next();
202 
203                 validateStringNotEmpty( "reporting.plugins.plugin.artifactId", result, p.getArtifactId() );
204 
205                 validateStringNotEmpty( "reporting.plugins.plugin.groupId", result, p.getGroupId() );
206             }
207         }
208 
209         validateRepositories( result, model.getRepositories(), "repositories.repository" );
210 
211         validateRepositories( result, model.getPluginRepositories(), "pluginRepositories.pluginRepository" );
212 
213         forcePluginExecutionIdCollision( model, result );
214 
215         return result;
216     }
217 
218     private boolean validateId( final String fieldName, final ModelValidationResult result, final String id )
219     {
220         if ( !validateStringNotEmpty( fieldName, result, id ) )
221         {
222             return false;
223         }
224         else
225         {
226             boolean match = id.matches( ID_REGEX );
227             if ( !match )
228             {
229                 result.addMessage( "'" + fieldName + "' with value '" + id + "' does not match a valid id pattern." );
230             }
231             return match;
232         }
233     }
234 
235     private void validateRepositories( final ModelValidationResult result, final List repositories, final String prefix )
236     {
237         for ( Iterator it = repositories.iterator(); it.hasNext(); )
238         {
239             Repository repository = (Repository) it.next();
240 
241             validateStringNotEmpty( prefix + ".id", result, repository.getId() );
242 
243             validateStringNotEmpty( prefix + ".url", result, repository.getUrl() );
244         }
245     }
246 
247     private void forcePluginExecutionIdCollision( final Model model, final ModelValidationResult result )
248     {
249         Build build = model.getBuild();
250 
251         if ( build != null )
252         {
253             List plugins = build.getPlugins();
254 
255             if ( plugins != null )
256             {
257                 for ( Iterator it = plugins.iterator(); it.hasNext(); )
258                 {
259                     Plugin plugin = (Plugin) it.next();
260 
261                     // this will force an IllegalStateException, even if we don't have to do inheritance assembly.
262                     try
263                     {
264                         plugin.getExecutionsAsMap();
265                     }
266                     catch ( IllegalStateException collisionException )
267                     {
268                         result.addMessage( collisionException.getMessage() );
269                     }
270                 }
271             }
272         }
273     }
274 
275 
276     // ----------------------------------------------------------------------
277     // Field validation
278     // ----------------------------------------------------------------------
279 
280     private boolean validateStringNotEmpty( final String fieldName, final ModelValidationResult result, final String string )
281     {
282         return validateStringNotEmpty( fieldName, result, string, null );
283     }
284 
285     /**
286      * Asserts:
287      * <p/>
288      * <ul>
289      * <li><code>string.length != null</code>
290      * <li><code>string.length > 0</code>
291      * </ul>
292      */
293     private boolean validateStringNotEmpty( final String fieldName, final ModelValidationResult result, final String string, final String sourceHint )
294     {
295         if ( !validateNotNull( fieldName, result, string, sourceHint ) )
296         {
297             return false;
298         }
299 
300         if ( string.length() > 0 )
301         {
302             return true;
303         }
304 
305         if ( sourceHint != null )
306         {
307             result.addMessage( "'" + fieldName + "' is missing for " + sourceHint );
308         }
309         else
310         {
311             result.addMessage( "'" + fieldName + "' is missing." );
312         }
313 
314 
315         return false;
316     }
317 
318     /**
319      * Asserts:
320      * <p/>
321      * <ul>
322      * <li><code>string.length != null</code>
323      * <li><code>string.length > 0</code>
324      * </ul>
325      */
326     private boolean validateSubElementStringNotEmpty( final Object subElementInstance, final String fieldName,
327                                                       final ModelValidationResult result, final String string )
328     {
329         if ( !validateSubElementNotNull( subElementInstance, fieldName, result, string ) )
330         {
331             return false;
332         }
333 
334         if ( string.length() > 0 )
335         {
336             return true;
337         }
338 
339         result.addMessage( "In " + subElementInstance + ":\n\n       -> '" + fieldName + "' is missing." );
340 
341         return false;
342     }
343 
344     /**
345      * Asserts:
346      * <p/>
347      * <ul>
348      * <li><code>string != null</code>
349      * </ul>
350      */
351     private boolean validateNotNull( final String fieldName, final ModelValidationResult result, final Object object, final String sourceHint )
352     {
353         if ( object != null )
354         {
355             return true;
356         }
357 
358         if ( sourceHint != null )
359         {
360             result.addMessage( "'" + fieldName + "' is missing for " + sourceHint );
361         }
362         else
363         {
364             result.addMessage( "'" + fieldName + "' is missing." );
365         }
366 
367         return false;
368     }
369 
370     /**
371      * Asserts:
372      * <p/>
373      * <ul>
374      * <li><code>string != null</code>
375      * </ul>
376      */
377     private boolean validateSubElementNotNull( final Object subElementInstance, final String fieldName,
378                                                final ModelValidationResult result, final Object object )
379     {
380         if ( object != null )
381         {
382             return true;
383         }
384 
385         result.addMessage( "In " + subElementInstance + ":\n\n       -> '" + fieldName + "' is missing." );
386 
387         return false;
388     }
389 }