1 package org.apache.maven.model.validation;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.File;
23 import java.util.Arrays;
24 import java.util.HashMap;
25 import java.util.HashSet;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Set;
29
30 import org.apache.maven.model.Build;
31 import org.apache.maven.model.BuildBase;
32 import org.apache.maven.model.Dependency;
33 import org.apache.maven.model.DependencyManagement;
34 import org.apache.maven.model.DistributionManagement;
35 import org.apache.maven.model.Exclusion;
36 import org.apache.maven.model.InputLocation;
37 import org.apache.maven.model.InputLocationTracker;
38 import org.apache.maven.model.Model;
39 import org.apache.maven.model.Parent;
40 import org.apache.maven.model.Plugin;
41 import org.apache.maven.model.PluginExecution;
42 import org.apache.maven.model.PluginManagement;
43 import org.apache.maven.model.Profile;
44 import org.apache.maven.model.ReportPlugin;
45 import org.apache.maven.model.Reporting;
46 import org.apache.maven.model.Repository;
47 import org.apache.maven.model.Resource;
48 import org.apache.maven.model.building.ModelBuildingRequest;
49 import org.apache.maven.model.building.ModelProblem.Severity;
50 import org.apache.maven.model.building.ModelProblemCollector;
51 import org.codehaus.plexus.component.annotations.Component;
52 import org.codehaus.plexus.util.StringUtils;
53
54
55
56
57
58 @Component( role = ModelValidator.class )
59 public class DefaultModelValidator
60 implements ModelValidator
61 {
62
63 private static final String ID_REGEX = "[A-Za-z0-9_\\-.]+";
64
65 private static final String ILLEGAL_FS_CHARS = "\\/:\"<>|?*";
66
67 private static final String ILLEGAL_VERSION_CHARS = ILLEGAL_FS_CHARS;
68
69 private static final String ILLEGAL_REPO_ID_CHARS = ILLEGAL_FS_CHARS;
70
71 public void validateRawModel( Model model, ModelBuildingRequest request, ModelProblemCollector problems )
72 {
73 Parent parent = model.getParent();
74 if ( parent != null )
75 {
76 validateStringNotEmpty( "parent.groupId", problems, Severity.FATAL, parent.getGroupId(), parent );
77
78 validateStringNotEmpty( "parent.artifactId", problems, Severity.FATAL, parent.getArtifactId(), parent );
79
80 validateStringNotEmpty( "parent.version", problems, Severity.FATAL, parent.getVersion(), parent );
81
82 if ( equals( parent.getGroupId(), model.getGroupId() )
83 && equals( parent.getArtifactId(), model.getArtifactId() ) )
84 {
85 addViolation( problems, Severity.FATAL, "parent.artifactId", null, "must be changed"
86 + ", the parent element cannot have the same groupId:artifactId as the project.", parent );
87 }
88 }
89
90 if ( request.getValidationLevel() >= ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0 )
91 {
92 Severity errOn30 = getSeverity( request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_0 );
93
94 validateEnum( "modelVersion", problems, Severity.ERROR, model.getModelVersion(), null, model, "4.0.0" );
95 validateStringNoExpression( "groupId", problems, Severity.WARNING, model.getGroupId(), model );
96 validateStringNoExpression( "artifactId", problems, Severity.WARNING, model.getArtifactId(), model );
97 validateStringNoExpression( "version", problems, Severity.WARNING, model.getVersion(), model );
98
99 validateRawDependencies( problems, model.getDependencies(), "dependencies.dependency", request );
100
101 if ( model.getDependencyManagement() != null )
102 {
103 validateRawDependencies( problems, model.getDependencyManagement().getDependencies(),
104 "dependencyManagement.dependencies.dependency", request );
105 }
106
107 validateRepositories( problems, model.getRepositories(), "repositories.repository", request );
108
109 validateRepositories( problems, model.getPluginRepositories(), "pluginRepositories.pluginRepository",
110 request );
111
112 Build build = model.getBuild();
113 if ( build != null )
114 {
115 validateRawPlugins( problems, build.getPlugins(), "build.plugins.plugin", request );
116
117 PluginManagement mngt = build.getPluginManagement();
118 if ( mngt != null )
119 {
120 validateRawPlugins( problems, mngt.getPlugins(), "build.pluginManagement.plugins.plugin",
121 request );
122 }
123 }
124
125 Set<String> profileIds = new HashSet<String>();
126
127 for ( Profile profile : model.getProfiles() )
128 {
129 String prefix = "profiles.profile[" + profile.getId() + "]";
130
131 if ( !profileIds.add( profile.getId() ) )
132 {
133 addViolation( problems, errOn30, "profiles.profile.id", null,
134 "must be unique but found duplicate profile with id " + profile.getId(), profile );
135 }
136
137 validateRawDependencies( problems, profile.getDependencies(), prefix + ".dependencies.dependency",
138 request );
139
140 if ( profile.getDependencyManagement() != null )
141 {
142 validateRawDependencies( problems, profile.getDependencyManagement().getDependencies(), prefix
143 + ".dependencyManagement.dependencies.dependency", request );
144 }
145
146 validateRepositories( problems, profile.getRepositories(), prefix + ".repositories.repository",
147 request );
148
149 validateRepositories( problems, profile.getPluginRepositories(), prefix
150 + ".pluginRepositories.pluginRepository", request );
151
152 BuildBase buildBase = profile.getBuild();
153 if ( buildBase != null )
154 {
155 validateRawPlugins( problems, buildBase.getPlugins(), prefix + ".plugins.plugin", request );
156
157 PluginManagement mngt = buildBase.getPluginManagement();
158 if ( mngt != null )
159 {
160 validateRawPlugins( problems, mngt.getPlugins(), prefix + ".pluginManagement.plugins.plugin",
161 request );
162 }
163 }
164 }
165 }
166 }
167
168 private void validateRawPlugins( ModelProblemCollector problems, List<Plugin> plugins, String prefix,
169 ModelBuildingRequest request )
170 {
171 Severity errOn31 = getSeverity( request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_1 );
172
173 Map<String, Plugin> index = new HashMap<String, Plugin>();
174
175 for ( Plugin plugin : plugins )
176 {
177 String key = plugin.getKey();
178
179 Plugin existing = index.get( key );
180
181 if ( existing != null )
182 {
183 addViolation( problems, errOn31, prefix + ".(groupId:artifactId)", null,
184 "must be unique but found duplicate declaration of plugin " + key, plugin );
185 }
186 else
187 {
188 index.put( key, plugin );
189 }
190
191 Set<String> executionIds = new HashSet<String>();
192
193 for ( PluginExecution exec : plugin.getExecutions() )
194 {
195 if ( !executionIds.add( exec.getId() ) )
196 {
197 addViolation( problems, Severity.ERROR, prefix + "[" + plugin.getKey()
198 + "].executions.execution.id", null, "must be unique but found duplicate execution with id "
199 + exec.getId(), exec );
200 }
201 }
202 }
203 }
204
205 public void validateEffectiveModel( Model model, ModelBuildingRequest request, ModelProblemCollector problems )
206 {
207 validateStringNotEmpty( "modelVersion", problems, Severity.ERROR, model.getModelVersion(), model );
208
209 validateId( "groupId", problems, model.getGroupId(), model );
210
211 validateId( "artifactId", problems, model.getArtifactId(), model );
212
213 validateStringNotEmpty( "packaging", problems, Severity.ERROR, model.getPackaging(), model );
214
215 if ( !model.getModules().isEmpty() )
216 {
217 if ( !"pom".equals( model.getPackaging() ) )
218 {
219 addViolation( problems, Severity.ERROR, "packaging", null, "with value '" + model.getPackaging()
220 + "' is invalid. Aggregator projects " + "require 'pom' as packaging.", model );
221 }
222
223 for ( int i = 0, n = model.getModules().size(); i < n; i++ )
224 {
225 String module = model.getModules().get( i );
226 if ( StringUtils.isBlank( module ) )
227 {
228 addViolation( problems, Severity.WARNING, "modules.module[" + i + "]", null,
229 "has been specified without a path to the project directory.",
230 model.getLocation( "modules" ) );
231 }
232 }
233 }
234
235 validateStringNotEmpty( "version", problems, Severity.ERROR, model.getVersion(), model );
236
237 Severity errOn30 = getSeverity( request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_0 );
238
239 validateEffectiveDependencies( problems, model.getDependencies(), false, request );
240
241 DependencyManagement mgmt = model.getDependencyManagement();
242 if ( mgmt != null )
243 {
244 validateEffectiveDependencies( problems, mgmt.getDependencies(), true, request );
245 }
246
247 if ( request.getValidationLevel() >= ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0 )
248 {
249 Set<String> modules = new HashSet<String>();
250 for ( int i = 0, n = model.getModules().size(); i < n; i++ )
251 {
252 String module = model.getModules().get( i );
253 if ( !modules.add( module ) )
254 {
255 addViolation( problems, Severity.ERROR, "modules.module[" + i + "]", null,
256 "specifies duplicate child module " + module, model.getLocation( "modules" ) );
257 }
258 }
259
260 Severity errOn31 = getSeverity( request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_1 );
261
262 validateBannedCharacters( "version", problems, errOn31, model.getVersion(), null, model,
263 ILLEGAL_VERSION_CHARS );
264
265 Build build = model.getBuild();
266 if ( build != null )
267 {
268 for ( Plugin p : build.getPlugins() )
269 {
270 validateStringNotEmpty( "build.plugins.plugin.artifactId", problems, Severity.ERROR,
271 p.getArtifactId(), p );
272
273 validateStringNotEmpty( "build.plugins.plugin.groupId", problems, Severity.ERROR, p.getGroupId(),
274 p );
275
276 validatePluginVersion( "build.plugins.plugin.version", problems, p.getVersion(), p.getKey(), p,
277 request );
278
279 validateBoolean( "build.plugins.plugin.inherited", problems, errOn30, p.getInherited(), p.getKey(),
280 p );
281
282 validateBoolean( "build.plugins.plugin.extensions", problems, errOn30, p.getExtensions(),
283 p.getKey(), p );
284
285 validateEffectivePluginDependencies( problems, p, request );
286 }
287
288 validateResources( problems, build.getResources(), "build.resources.resource", request );
289
290 validateResources( problems, build.getTestResources(), "build.testResources.testResource", request );
291 }
292
293 Reporting reporting = model.getReporting();
294 if ( reporting != null )
295 {
296 for ( ReportPlugin p : reporting.getPlugins() )
297 {
298 validateStringNotEmpty( "reporting.plugins.plugin.artifactId", problems, Severity.ERROR,
299 p.getArtifactId(), p );
300
301 validateStringNotEmpty( "reporting.plugins.plugin.groupId", problems, Severity.ERROR,
302 p.getGroupId(), p );
303
304 validateStringNotEmpty( "reporting.plugins.plugin.version", problems, errOn31, p.getVersion(),
305 p.getKey(), p );
306 }
307 }
308
309 for ( Repository repository : model.getRepositories() )
310 {
311 validateRepository( problems, repository, "repositories.repository", request );
312 }
313
314 for ( Repository repository : model.getPluginRepositories() )
315 {
316 validateRepository( problems, repository, "pluginRepositories.pluginRepository", request );
317 }
318
319 DistributionManagement distMgmt = model.getDistributionManagement();
320 if ( distMgmt != null )
321 {
322 if ( distMgmt.getStatus() != null )
323 {
324 addViolation( problems, Severity.ERROR, "distributionManagement.status", null,
325 "must not be specified.", distMgmt );
326 }
327
328 validateRepository( problems, distMgmt.getRepository(), "distributionManagement.repository", request );
329 validateRepository( problems, distMgmt.getSnapshotRepository(),
330 "distributionManagement.snapshotRepository", request );
331 }
332 }
333 }
334
335 private void validateRawDependencies( ModelProblemCollector problems, List<Dependency> dependencies, String prefix,
336 ModelBuildingRequest request )
337 {
338 Severity errOn30 = getSeverity( request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_0 );
339 Severity errOn31 = getSeverity( request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_1 );
340
341 Map<String, Dependency> index = new HashMap<String, Dependency>();
342
343 for ( Dependency dependency : dependencies )
344 {
345 String key = dependency.getManagementKey();
346
347 if ( "pom".equals( dependency.getType() ) && "import".equals( dependency.getScope() )
348 && StringUtils.isNotEmpty( dependency.getClassifier() ) )
349 {
350 addViolation( problems, errOn30, prefix + ".classifier", key,
351 "must be empty, imported POM cannot have a classifier.", dependency );
352 }
353 else if ( "system".equals( dependency.getScope() ) )
354 {
355 String sysPath = dependency.getSystemPath();
356 if ( StringUtils.isNotEmpty( sysPath ) && !hasExpression( sysPath ) )
357 {
358 addViolation( problems, Severity.WARNING, prefix + ".systemPath", key,
359 "should use a variable instead of a hard-coded path " + sysPath, dependency );
360 }
361 }
362
363 Dependency existing = index.get( key );
364
365 if ( existing != null )
366 {
367 String msg;
368 if ( equals( existing.getVersion(), dependency.getVersion() ) )
369 {
370 msg =
371 "duplicate declaration of version "
372 + StringUtils.defaultString( dependency.getVersion(), "(?)" );
373 }
374 else
375 {
376 msg =
377 "version " + StringUtils.defaultString( existing.getVersion(), "(?)" ) + " vs "
378 + StringUtils.defaultString( dependency.getVersion(), "(?)" );
379 }
380
381 addViolation( problems, errOn31, prefix + ".(groupId:artifactId:type:classifier)", null,
382 "must be unique: " + key + " -> " + msg, dependency );
383 }
384 else
385 {
386 index.put( key, dependency );
387 }
388 }
389 }
390
391 private void validateEffectiveDependencies( ModelProblemCollector problems, List<Dependency> dependencies,
392 boolean management, ModelBuildingRequest request )
393 {
394 Severity errOn30 = getSeverity( request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_0 );
395
396 String prefix = management ? "dependencyManagement.dependencies.dependency." : "dependencies.dependency.";
397
398 for ( Dependency d : dependencies )
399 {
400 validateEffectiveDependency( problems, d, management, prefix, request );
401
402 if ( request.getValidationLevel() >= ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0 )
403 {
404 validateBoolean( prefix + "optional", problems, errOn30, d.getOptional(), d.getManagementKey(), d );
405
406 if ( !management )
407 {
408 validateVersion( prefix + "version", problems, errOn30, d.getVersion(), d.getManagementKey(), d );
409
410
411
412
413
414 validateEnum( prefix + "scope", problems, Severity.WARNING, d.getScope(), d.getManagementKey(), d,
415 "provided", "compile", "runtime", "test", "system" );
416 }
417 }
418 }
419 }
420
421 private void validateEffectivePluginDependencies( ModelProblemCollector problems, Plugin plugin,
422 ModelBuildingRequest request )
423 {
424 List<Dependency> dependencies = plugin.getDependencies();
425
426 if ( !dependencies.isEmpty() )
427 {
428 String prefix = "build.plugins.plugin[" + plugin.getKey() + "].dependencies.dependency.";
429
430 Severity errOn30 = getSeverity( request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_0 );
431
432 for ( Dependency d : dependencies )
433 {
434 validateEffectiveDependency( problems, d, false, prefix, request );
435
436 validateVersion( prefix + "version", problems, errOn30, d.getVersion(), d.getManagementKey(), d );
437
438 validateEnum( prefix + "scope", problems, errOn30, d.getScope(), d.getManagementKey(), d, "compile",
439 "runtime", "system" );
440 }
441 }
442 }
443
444 private void validateEffectiveDependency( ModelProblemCollector problems, Dependency d, boolean management,
445 String prefix, ModelBuildingRequest request )
446 {
447 validateId( prefix + "artifactId", problems, Severity.ERROR, d.getArtifactId(), d.getManagementKey(), d );
448
449 validateId( prefix + "groupId", problems, Severity.ERROR, d.getGroupId(), d.getManagementKey(), d );
450
451 if ( !management )
452 {
453 validateStringNotEmpty( prefix + "type", problems, Severity.ERROR, d.getType(), d.getManagementKey(), d );
454
455 validateStringNotEmpty( prefix + "version", problems, Severity.ERROR, d.getVersion(), d.getManagementKey(),
456 d );
457 }
458
459 if ( "system".equals( d.getScope() ) )
460 {
461 String systemPath = d.getSystemPath();
462
463 if ( StringUtils.isEmpty( systemPath ) )
464 {
465 addViolation( problems, Severity.ERROR, prefix + "systemPath", d.getManagementKey(), "is missing.",
466 d );
467 }
468 else
469 {
470 File sysFile = new File( systemPath );
471 if ( !sysFile.isAbsolute() )
472 {
473 addViolation( problems, Severity.ERROR, prefix + "systemPath", d.getManagementKey(),
474 "must specify an absolute path but is " + systemPath, d );
475 }
476 else if ( !sysFile.isFile() )
477 {
478 String msg = "refers to a non-existing file " + sysFile.getAbsolutePath();
479 systemPath = systemPath.replace( '/', File.separatorChar ).replace( '\\', File.separatorChar );
480 String jdkHome =
481 request.getSystemProperties().getProperty( "java.home", "" ) + File.separator + "..";
482 if ( systemPath.startsWith( jdkHome ) )
483 {
484 msg += ". Please verify that you run Maven using a JDK and not just a JRE.";
485 }
486 addViolation( problems, Severity.WARNING, prefix + "systemPath", d.getManagementKey(), msg, d );
487 }
488 }
489 }
490 else if ( StringUtils.isNotEmpty( d.getSystemPath() ) )
491 {
492 addViolation( problems, Severity.ERROR, prefix + "systemPath", d.getManagementKey(), "must be omitted."
493 + " This field may only be specified for a dependency with system scope.", d );
494 }
495
496 if ( request.getValidationLevel() >= ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0 )
497 {
498 for ( Exclusion exclusion : d.getExclusions() )
499 {
500 validateId( prefix + "exclusions.exclusion.groupId", problems, Severity.WARNING,
501 exclusion.getGroupId(), d.getManagementKey(), exclusion );
502
503 validateId( prefix + "exclusions.exclusion.artifactId", problems, Severity.WARNING,
504 exclusion.getArtifactId(), d.getManagementKey(), exclusion );
505 }
506 }
507 }
508
509 private void validateRepositories( ModelProblemCollector problems, List<Repository> repositories, String prefix,
510 ModelBuildingRequest request )
511 {
512 Map<String, Repository> index = new HashMap<String, Repository>();
513
514 for ( Repository repository : repositories )
515 {
516 validateStringNotEmpty( prefix + ".id", problems, Severity.ERROR, repository.getId(), repository );
517
518 validateStringNotEmpty( prefix + "[" + repository.getId() + "].url", problems, Severity.ERROR,
519 repository.getUrl(), repository );
520
521 String key = repository.getId();
522
523 Repository existing = index.get( key );
524
525 if ( existing != null )
526 {
527 Severity errOn30 = getSeverity( request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_0 );
528
529 addViolation( problems, errOn30, prefix + ".id", null, "must be unique: " + repository.getId() + " -> "
530 + existing.getUrl() + " vs " + repository.getUrl(), repository );
531 }
532 else
533 {
534 index.put( key, repository );
535 }
536 }
537 }
538
539 private void validateRepository( ModelProblemCollector problems, Repository repository, String prefix,
540 ModelBuildingRequest request )
541 {
542 if ( repository != null )
543 {
544 Severity errOn31 = getSeverity( request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_1 );
545
546 validateBannedCharacters( prefix + ".id", problems, errOn31, repository.getId(), null, repository,
547 ILLEGAL_REPO_ID_CHARS );
548
549 if ( "local".equals( repository.getId() ) )
550 {
551 addViolation( problems, errOn31, prefix + ".id", null, "must not be 'local'"
552 + ", this identifier is reserved for the local repository"
553 + ", using it for other repositories will corrupt your repository metadata.", repository );
554 }
555
556 if ( "legacy".equals( repository.getLayout() ) )
557 {
558 addViolation( problems, Severity.WARNING, prefix + ".layout", repository.getId(),
559 "uses the unsupported value 'legacy', artifact resolution might fail.", repository );
560 }
561 }
562 }
563
564 private void validateResources( ModelProblemCollector problems, List<Resource> resources, String prefix,
565 ModelBuildingRequest request )
566 {
567 Severity errOn30 = getSeverity( request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_0 );
568
569 for ( Resource resource : resources )
570 {
571 validateStringNotEmpty( prefix + ".directory", problems, Severity.ERROR, resource.getDirectory(),
572 resource );
573
574 validateBoolean( prefix + ".filtering", problems, errOn30, resource.getFiltering(),
575 resource.getDirectory(), resource );
576 }
577 }
578
579
580
581
582
583 private boolean validateId( String fieldName, ModelProblemCollector problems, String id,
584 InputLocationTracker tracker )
585 {
586 return validateId( fieldName, problems, Severity.ERROR, id, null, tracker );
587 }
588
589 private boolean validateId( String fieldName, ModelProblemCollector problems, Severity severity, String id,
590 String sourceHint, InputLocationTracker tracker )
591 {
592 if ( !validateStringNotEmpty( fieldName, problems, severity, id, sourceHint, tracker ) )
593 {
594 return false;
595 }
596 else
597 {
598 boolean match = id.matches( ID_REGEX );
599 if ( !match )
600 {
601 addViolation( problems, severity, fieldName, sourceHint, "with value '" + id
602 + "' does not match a valid id pattern.", tracker );
603 }
604 return match;
605 }
606 }
607
608 private boolean validateStringNoExpression( String fieldName, ModelProblemCollector problems, Severity severity,
609 String string, InputLocationTracker tracker )
610 {
611 if ( !hasExpression( string ) )
612 {
613 return true;
614 }
615
616 addViolation( problems, severity, fieldName, null, "contains an expression but should be a constant.",
617 tracker );
618
619 return false;
620 }
621
622 private boolean hasExpression( String value )
623 {
624 return value != null && value.indexOf( "${" ) >= 0;
625 }
626
627 private boolean validateStringNotEmpty( String fieldName, ModelProblemCollector problems, Severity severity,
628 String string, InputLocationTracker tracker )
629 {
630 return validateStringNotEmpty( fieldName, problems, severity, string, null, tracker );
631 }
632
633
634
635
636
637
638
639
640
641 private boolean validateStringNotEmpty( String fieldName, ModelProblemCollector problems, Severity severity,
642 String string, String sourceHint, InputLocationTracker tracker )
643 {
644 if ( !validateNotNull( fieldName, problems, severity, string, sourceHint, tracker ) )
645 {
646 return false;
647 }
648
649 if ( string.length() > 0 )
650 {
651 return true;
652 }
653
654 addViolation( problems, severity, fieldName, sourceHint, "is missing.", tracker );
655
656 return false;
657 }
658
659
660
661
662
663
664
665
666 private boolean validateNotNull( String fieldName, ModelProblemCollector problems, Severity severity,
667 Object object, String sourceHint, InputLocationTracker tracker )
668 {
669 if ( object != null )
670 {
671 return true;
672 }
673
674 addViolation( problems, severity, fieldName, sourceHint, "is missing.", tracker );
675
676 return false;
677 }
678
679 private boolean validateBoolean( String fieldName, ModelProblemCollector problems, Severity severity,
680 String string, String sourceHint, InputLocationTracker tracker )
681 {
682 if ( string == null || string.length() <= 0 )
683 {
684 return true;
685 }
686
687 if ( "true".equalsIgnoreCase( string ) || "false".equalsIgnoreCase( string ) )
688 {
689 return true;
690 }
691
692 addViolation( problems, severity, fieldName, sourceHint, "must be 'true' or 'false' but is '" + string + "'.",
693 tracker );
694
695 return false;
696 }
697
698 private boolean validateEnum( String fieldName, ModelProblemCollector problems, Severity severity, String string,
699 String sourceHint, InputLocationTracker tracker, String... validValues )
700 {
701 if ( string == null || string.length() <= 0 )
702 {
703 return true;
704 }
705
706 List<String> values = Arrays.asList( validValues );
707
708 if ( values.contains( string ) )
709 {
710 return true;
711 }
712
713 addViolation( problems, severity, fieldName, sourceHint, "must be one of " + values + " but is '" + string
714 + "'.", tracker );
715
716 return false;
717 }
718
719 private boolean validateBannedCharacters( String fieldName, ModelProblemCollector problems, Severity severity,
720 String string, String sourceHint, InputLocationTracker tracker,
721 String banned )
722 {
723 if ( string != null )
724 {
725 for ( int i = string.length() - 1; i >= 0; i-- )
726 {
727 if ( banned.indexOf( string.charAt( i ) ) >= 0 )
728 {
729 addViolation( problems, severity, fieldName, sourceHint,
730 "must not contain any of these characters " + banned + " but found "
731 + string.charAt( i ), tracker );
732 return false;
733 }
734 }
735 }
736
737 return true;
738 }
739
740 private boolean validateVersion( String fieldName, ModelProblemCollector problems, Severity severity,
741 String string, String sourceHint, InputLocationTracker tracker )
742 {
743 if ( string == null || string.length() <= 0 )
744 {
745 return true;
746 }
747
748 if ( !hasExpression( string ) )
749 {
750 return true;
751 }
752
753 addViolation( problems, severity, fieldName, sourceHint, "must be a valid version but is '" + string + "'.",
754 tracker );
755
756 return false;
757 }
758
759 private boolean validatePluginVersion( String fieldName, ModelProblemCollector problems, String string,
760 String sourceHint, InputLocationTracker tracker,
761 ModelBuildingRequest request )
762 {
763 Severity errOn30 = getSeverity( request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_0 );
764
765 if ( string == null )
766 {
767
768 return true;
769 }
770
771 if ( string.length() > 0 && !hasExpression( string ) && !"RELEASE".equals( string )
772 && !"LATEST".equals( string ) )
773 {
774 return true;
775 }
776
777 addViolation( problems, errOn30, fieldName, sourceHint, "must be a valid version but is '" + string + "'.",
778 tracker );
779
780 return false;
781 }
782
783 private static void addViolation( ModelProblemCollector problems, Severity severity, String fieldName,
784 String sourceHint, String message, InputLocationTracker tracker )
785 {
786 StringBuilder buffer = new StringBuilder( 256 );
787 buffer.append( '\'' ).append( fieldName ).append( '\'' );
788
789 if ( sourceHint != null )
790 {
791 buffer.append( " for " ).append( sourceHint );
792 }
793
794 buffer.append( ' ' ).append( message );
795
796 problems.add( severity, buffer.toString(), getLocation( fieldName, tracker ), null );
797 }
798
799 private static InputLocation getLocation( String fieldName, InputLocationTracker tracker )
800 {
801 InputLocation location = null;
802
803 if ( tracker != null )
804 {
805 if ( fieldName != null )
806 {
807 Object key = fieldName;
808
809 int idx = fieldName.lastIndexOf( '.' );
810 if ( idx >= 0 )
811 {
812 key = fieldName = fieldName.substring( idx + 1 );
813 }
814
815 if ( fieldName.endsWith( "]" ) )
816 {
817 key = fieldName.substring( fieldName.lastIndexOf( '[' ) + 1, fieldName.length() - 1 );
818 try
819 {
820 key = Integer.valueOf( key.toString() );
821 }
822 catch ( NumberFormatException e )
823 {
824
825 }
826 }
827
828 location = tracker.getLocation( key );
829 }
830
831 if ( location == null )
832 {
833 location = tracker.getLocation( "" );
834 }
835 }
836
837 return location;
838 }
839
840 private static boolean equals( String s1, String s2 )
841 {
842 return StringUtils.clean( s1 ).equals( StringUtils.clean( s2 ) );
843 }
844
845 private static Severity getSeverity( ModelBuildingRequest request, int errorThreshold )
846 {
847 return getSeverity( request.getValidationLevel(), errorThreshold );
848 }
849
850 private static Severity getSeverity( int validationLevel, int errorThreshold )
851 {
852 if ( validationLevel < errorThreshold )
853 {
854 return Severity.WARNING;
855 }
856 else
857 {
858 return Severity.ERROR;
859 }
860 }
861
862 }