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( 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
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
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
287
288
289
290
291
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
320
321
322
323
324
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
346
347
348
349
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
372
373
374
375
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 }