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