1 package org.apache.maven.project.validation;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
41
42
43 public class DefaultModelValidator
44 implements ModelValidator
45 {
46 private static final String ID_REGEX = "[A-Za-z0-9_\\-.]+";
47
48
49
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
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
264
265
266 private boolean validateStringNotEmpty( String fieldName, ModelValidationResult result, String string )
267 {
268 return validateStringNotEmpty( fieldName, result, string, null );
269 }
270
271
272
273
274
275
276
277
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
306
307
308
309
310
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
332
333
334
335
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
358
359
360
361
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 }