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 764520 2009-04-13 16:34:12Z pgier $
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(), 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             }
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     private boolean validateStringNotEmpty( String fieldName, ModelValidationResult result, String string )
267     {
268         return validateStringNotEmpty( fieldName, result, string, null );
269     }
270 
271     /**
272      * Asserts:
273      * <p/>
274      * <ul>
275      * <li><code>string.length != null</code>
276      * <li><code>string.length > 0</code>
277      * </ul>
278      */
279     private boolean validateStringNotEmpty( String fieldName, ModelValidationResult result, String string, String sourceHint )
280     {
281         if ( !validateNotNull( fieldName, result, string, sourceHint ) )
282         {
283             return false;
284         }
285 
286         if ( string.length() > 0 )
287         {
288             return true;
289         }
290 
291         if ( sourceHint != null )
292         {
293             result.addMessage( "'" + fieldName + "' is missing for " + sourceHint );
294         }
295         else
296         {
297             result.addMessage( "'" + fieldName + "' is missing." );
298         }
299 
300 
301         return false;
302     }
303 
304     /**
305      * Asserts:
306      * <p/>
307      * <ul>
308      * <li><code>string.length != null</code>
309      * <li><code>string.length > 0</code>
310      * </ul>
311      */
312     private boolean validateSubElementStringNotEmpty( Object subElementInstance, String fieldName,
313                                                       ModelValidationResult result, String string )
314     {
315         if ( !validateSubElementNotNull( subElementInstance, fieldName, result, string ) )
316         {
317             return false;
318         }
319 
320         if ( string.length() > 0 )
321         {
322             return true;
323         }
324 
325         result.addMessage( "In " + subElementInstance + ":\n\n       -> '" + fieldName + "' is missing." );
326 
327         return false;
328     }
329 
330     /**
331      * Asserts:
332      * <p/>
333      * <ul>
334      * <li><code>string != null</code>
335      * </ul>
336      */
337     private boolean validateNotNull( String fieldName, ModelValidationResult result, Object object, String sourceHint )
338     {
339         if ( object != null )
340         {
341             return true;
342         }
343 
344         if ( sourceHint != null )
345         {
346             result.addMessage( "'" + fieldName + "' is missing for " + sourceHint );
347         }
348         else
349         {
350             result.addMessage( "'" + fieldName + "' is missing." );
351         }
352 
353         return false;
354     }
355 
356     /**
357      * Asserts:
358      * <p/>
359      * <ul>
360      * <li><code>string != null</code>
361      * </ul>
362      */
363     private boolean validateSubElementNotNull( Object subElementInstance, String fieldName,
364                                                ModelValidationResult result, Object object )
365     {
366         if ( object != null )
367         {
368             return true;
369         }
370 
371         result.addMessage( "In " + subElementInstance + ":\n\n       -> '" + fieldName + "' is missing." );
372 
373         return false;
374     }
375 }