1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.model.validation;
20
21 import javax.inject.Inject;
22 import javax.inject.Named;
23 import javax.inject.Singleton;
24
25 import java.io.File;
26 import java.util.Arrays;
27 import java.util.HashMap;
28 import java.util.HashSet;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Objects;
32 import java.util.Set;
33 import java.util.regex.Matcher;
34 import java.util.regex.Pattern;
35
36 import org.apache.maven.api.model.Activation;
37 import org.apache.maven.api.model.ActivationFile;
38 import org.apache.maven.api.model.Build;
39 import org.apache.maven.api.model.BuildBase;
40 import org.apache.maven.api.model.Dependency;
41 import org.apache.maven.api.model.DependencyManagement;
42 import org.apache.maven.api.model.DistributionManagement;
43 import org.apache.maven.api.model.Exclusion;
44 import org.apache.maven.api.model.InputLocation;
45 import org.apache.maven.api.model.InputLocationTracker;
46 import org.apache.maven.api.model.Parent;
47 import org.apache.maven.api.model.Plugin;
48 import org.apache.maven.api.model.PluginExecution;
49 import org.apache.maven.api.model.PluginManagement;
50 import org.apache.maven.api.model.Profile;
51 import org.apache.maven.api.model.ReportPlugin;
52 import org.apache.maven.api.model.Reporting;
53 import org.apache.maven.api.model.Repository;
54 import org.apache.maven.api.model.Resource;
55 import org.apache.maven.model.Model;
56 import org.apache.maven.model.building.ModelBuildingRequest;
57 import org.apache.maven.model.building.ModelProblem.Severity;
58 import org.apache.maven.model.building.ModelProblem.Version;
59 import org.apache.maven.model.building.ModelProblemCollector;
60 import org.apache.maven.model.building.ModelProblemCollectorRequest;
61 import org.apache.maven.model.interpolation.ModelVersionProcessor;
62 import org.codehaus.plexus.util.StringUtils;
63
64
65
66
67 @Named
68 @Singleton
69 public class DefaultModelValidator implements ModelValidator {
70
71 private static final Pattern EXPRESSION_NAME_PATTERN = Pattern.compile("\\$\\{(.+?)}");
72
73 private static final String ILLEGAL_FS_CHARS = "\\/:\"<>|?*";
74
75 private static final String ILLEGAL_VERSION_CHARS = ILLEGAL_FS_CHARS;
76
77 private static final String ILLEGAL_REPO_ID_CHARS = ILLEGAL_FS_CHARS;
78
79 private static final String EMPTY = "";
80
81 private final Set<String> validCoordinateIds = new HashSet<>();
82
83 private final Set<String> validProfileIds = new HashSet<>();
84
85 private final ModelVersionProcessor versionProcessor;
86
87 @Inject
88 public DefaultModelValidator(ModelVersionProcessor versionProcessor) {
89 this.versionProcessor = versionProcessor;
90 }
91
92 @Override
93 public void validateFileModel(Model ma, ModelBuildingRequest request, ModelProblemCollector problems) {
94
95 org.apache.maven.api.model.Model m = ma.getDelegate();
96
97 Parent parent = m.getParent();
98 if (parent != null) {
99 validateStringNotEmpty(
100 "parent.groupId", problems, Severity.FATAL, Version.BASE, parent.getGroupId(), parent);
101
102 validateStringNotEmpty(
103 "parent.artifactId", problems, Severity.FATAL, Version.BASE, parent.getArtifactId(), parent);
104
105 if (equals(parent.getGroupId(), m.getGroupId()) && equals(parent.getArtifactId(), m.getArtifactId())) {
106 addViolation(
107 problems,
108 Severity.FATAL,
109 Version.BASE,
110 "parent.artifactId",
111 null,
112 "must be changed"
113 + ", the parent element cannot have the same groupId:artifactId as the project.",
114 parent);
115 }
116
117 if (equals("LATEST", parent.getVersion()) || equals("RELEASE", parent.getVersion())) {
118 addViolation(
119 problems,
120 Severity.WARNING,
121 Version.BASE,
122 "parent.version",
123 null,
124 "is either LATEST or RELEASE (both of them are being deprecated)",
125 parent);
126 }
127 }
128
129 if (request.getValidationLevel() >= ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0) {
130 Set<String> modules = new HashSet<>();
131 for (int i = 0, n = m.getModules().size(); i < n; i++) {
132 String module = m.getModules().get(i);
133 if (!modules.add(module)) {
134 addViolation(
135 problems,
136 Severity.ERROR,
137 Version.V20,
138 "modules.module[" + i + "]",
139 null,
140 "specifies duplicate child module " + module,
141 m.getLocation("modules"));
142 }
143 }
144
145 Severity errOn30 = getSeverity(request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_0);
146
147
148
149
150
151
152
153 validateStringNotEmpty("modelVersion", problems, Severity.ERROR, Version.V20, m.getModelVersion(), m);
154
155 validateModelVersion(problems, m.getModelVersion(), m, "4.0.0");
156
157 validateStringNoExpression("groupId", problems, Severity.WARNING, Version.V20, m.getGroupId(), m);
158 if (parent == null) {
159 validateStringNotEmpty("groupId", problems, Severity.FATAL, Version.V20, m.getGroupId(), m);
160 }
161
162 validateStringNoExpression("artifactId", problems, Severity.WARNING, Version.V20, m.getArtifactId(), m);
163 validateStringNotEmpty("artifactId", problems, Severity.FATAL, Version.V20, m.getArtifactId(), m);
164
165 validateVersionNoExpression("version", problems, Severity.WARNING, Version.V20, m.getVersion(), m);
166 if (parent == null) {
167 validateStringNotEmpty("version", problems, Severity.FATAL, Version.V20, m.getVersion(), m);
168 }
169
170 validate20RawDependencies(problems, m.getDependencies(), "dependencies.dependency.", EMPTY, request);
171
172 validate20RawDependenciesSelfReferencing(
173 problems, m, m.getDependencies(), "dependencies.dependency", request);
174
175 if (m.getDependencyManagement() != null) {
176 validate20RawDependencies(
177 problems,
178 m.getDependencyManagement().getDependencies(),
179 "dependencyManagement.dependencies.dependency.",
180 EMPTY,
181 request);
182 }
183
184 validateRawRepositories(problems, m.getRepositories(), "repositories.repository.", EMPTY, request);
185
186 validateRawRepositories(
187 problems, m.getPluginRepositories(), "pluginRepositories.pluginRepository.", EMPTY, request);
188
189 Build build = m.getBuild();
190 if (build != null) {
191 validate20RawPlugins(problems, build.getPlugins(), "build.plugins.plugin.", EMPTY, request);
192
193 PluginManagement mgmt = build.getPluginManagement();
194 if (mgmt != null) {
195 validate20RawPlugins(
196 problems, mgmt.getPlugins(), "build.pluginManagement.plugins.plugin.", EMPTY, request);
197 }
198 }
199
200 Set<String> profileIds = new HashSet<>();
201
202 for (Profile profile : m.getProfiles()) {
203 String prefix = "profiles.profile[" + profile.getId() + "].";
204
205 validateProfileId(prefix, "id", problems, Severity.ERROR, Version.V40, profile.getId(), null, m);
206
207 if (!profileIds.add(profile.getId())) {
208 addViolation(
209 problems,
210 errOn30,
211 Version.V20,
212 "profiles.profile.id",
213 null,
214 "must be unique but found duplicate profile with id " + profile.getId(),
215 profile);
216 }
217
218 validate30RawProfileActivation(
219 problems, profile.getActivation(), profile.getId(), prefix, "activation", request);
220
221 validate20RawDependencies(
222 problems, profile.getDependencies(), prefix, "dependencies.dependency.", request);
223
224 if (profile.getDependencyManagement() != null) {
225 validate20RawDependencies(
226 problems,
227 profile.getDependencyManagement().getDependencies(),
228 prefix,
229 "dependencyManagement.dependencies.dependency.",
230 request);
231 }
232
233 validateRawRepositories(
234 problems, profile.getRepositories(), prefix, "repositories.repository.", request);
235
236 validateRawRepositories(
237 problems,
238 profile.getPluginRepositories(),
239 prefix,
240 "pluginRepositories.pluginRepository.",
241 request);
242
243 BuildBase buildBase = profile.getBuild();
244 if (buildBase != null) {
245 validate20RawPlugins(problems, buildBase.getPlugins(), prefix, "plugins.plugin.", request);
246
247 PluginManagement mgmt = buildBase.getPluginManagement();
248 if (mgmt != null) {
249 validate20RawPlugins(
250 problems, mgmt.getPlugins(), prefix, "pluginManagement.plugins.plugin.", request);
251 }
252 }
253 }
254 }
255 }
256
257 @Override
258 public void validateRawModel(Model ma, ModelBuildingRequest request, ModelProblemCollector problems) {
259 org.apache.maven.api.model.Model m = ma.getDelegate();
260
261 Parent parent = m.getParent();
262
263 if (parent != null) {
264 validateStringNotEmpty(
265 "parent.version", problems, Severity.FATAL, Version.BASE, parent.getVersion(), parent);
266 }
267 }
268
269 private void validate30RawProfileActivation(
270 ModelProblemCollector problems,
271 Activation activation,
272 String sourceHint,
273 String prefix,
274 String fieldName,
275 ModelBuildingRequest request) {
276 if (activation == null) {
277 return;
278 }
279
280 ActivationFile file = activation.getFile();
281
282 if (file != null) {
283 String path;
284 boolean missing;
285
286 if (StringUtils.isNotEmpty(file.getExists())) {
287 path = file.getExists();
288 missing = false;
289 } else if (StringUtils.isNotEmpty(file.getMissing())) {
290 path = file.getMissing();
291 missing = true;
292 } else {
293 return;
294 }
295
296 if (path.contains("${project.basedir}")) {
297 addViolation(
298 problems,
299 Severity.WARNING,
300 Version.V30,
301 prefix + fieldName + (missing ? ".file.missing" : ".file.exists"),
302 null,
303 "Failed to interpolate file location " + path + " for profile " + sourceHint
304 + ": ${project.basedir} expression not supported during profile activation, "
305 + "use ${basedir} instead",
306 file.getLocation(missing ? "missing" : "exists"));
307 } else if (hasProjectExpression(path)) {
308 addViolation(
309 problems,
310 Severity.WARNING,
311 Version.V30,
312 prefix + fieldName + (missing ? ".file.missing" : ".file.exists"),
313 null,
314 "Failed to interpolate file location " + path + " for profile " + sourceHint
315 + ": ${project.*} expressions are not supported during profile activation",
316 file.getLocation(missing ? "missing" : "exists"));
317 }
318 }
319 }
320
321 private void validate20RawPlugins(
322 ModelProblemCollector problems,
323 List<Plugin> plugins,
324 String prefix,
325 String prefix2,
326 ModelBuildingRequest request) {
327 Severity errOn31 = getSeverity(request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_1);
328
329 Map<String, Plugin> index = new HashMap<>();
330
331 for (Plugin plugin : plugins) {
332 if (plugin.getGroupId() == null
333 || (plugin.getGroupId() != null
334 && plugin.getGroupId().trim().isEmpty())) {
335 addViolation(
336 problems,
337 Severity.FATAL,
338 Version.V20,
339 prefix + prefix2 + "(groupId:artifactId)",
340 null,
341 "groupId of a plugin must be defined. ",
342 plugin);
343 }
344
345 if (plugin.getArtifactId() == null
346 || (plugin.getArtifactId() != null
347 && plugin.getArtifactId().trim().isEmpty())) {
348 addViolation(
349 problems,
350 Severity.FATAL,
351 Version.V20,
352 prefix + prefix2 + "(groupId:artifactId)",
353 null,
354 "artifactId of a plugin must be defined. ",
355 plugin);
356 }
357
358
359 if (plugin.getVersion() != null && plugin.getVersion().trim().isEmpty()) {
360 addViolation(
361 problems,
362 Severity.FATAL,
363 Version.V20,
364 prefix + prefix2 + "(groupId:artifactId)",
365 null,
366 "version of a plugin must be defined. ",
367 plugin);
368 }
369
370 String key = plugin.getKey();
371
372 Plugin existing = index.get(key);
373
374 if (existing != null) {
375 addViolation(
376 problems,
377 errOn31,
378 Version.V20,
379 prefix + prefix2 + "(groupId:artifactId)",
380 null,
381 "must be unique but found duplicate declaration of plugin " + key,
382 plugin);
383 } else {
384 index.put(key, plugin);
385 }
386
387 Set<String> executionIds = new HashSet<>();
388
389 for (PluginExecution exec : plugin.getExecutions()) {
390 if (!executionIds.add(exec.getId())) {
391 addViolation(
392 problems,
393 Severity.ERROR,
394 Version.V20,
395 prefix + prefix2 + "[" + plugin.getKey() + "].executions.execution.id",
396 null,
397 "must be unique but found duplicate execution with id " + exec.getId(),
398 exec);
399 }
400 }
401 }
402 }
403
404 @Override
405 public void validateEffectiveModel(Model ma, ModelBuildingRequest request, ModelProblemCollector problems) {
406 org.apache.maven.api.model.Model m = ma.getDelegate();
407
408 validateStringNotEmpty("modelVersion", problems, Severity.ERROR, Version.BASE, m.getModelVersion(), m);
409
410 validateCoordinateId("groupId", problems, m.getGroupId(), m);
411
412 validateCoordinateId("artifactId", problems, m.getArtifactId(), m);
413
414 validateStringNotEmpty("packaging", problems, Severity.ERROR, Version.BASE, m.getPackaging(), m);
415
416 if (!m.getModules().isEmpty()) {
417 if (!"pom".equals(m.getPackaging())) {
418 addViolation(
419 problems,
420 Severity.ERROR,
421 Version.BASE,
422 "packaging",
423 null,
424 "with value '" + m.getPackaging() + "' is invalid. Aggregator projects "
425 + "require 'pom' as packaging.",
426 m);
427 }
428
429 for (int i = 0, n = m.getModules().size(); i < n; i++) {
430 String module = m.getModules().get(i);
431 if (StringUtils.isBlank(module)) {
432 addViolation(
433 problems,
434 Severity.ERROR,
435 Version.BASE,
436 "modules.module[" + i + "]",
437 null,
438 "has been specified without a path to the project directory.",
439 m.getLocation("modules"));
440 }
441 }
442 }
443
444 validateStringNotEmpty("version", problems, Severity.ERROR, Version.BASE, m.getVersion(), m);
445
446 Severity errOn30 = getSeverity(request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_0);
447
448 validateEffectiveDependencies(problems, m, m.getDependencies(), false, request);
449
450 DependencyManagement mgmt = m.getDependencyManagement();
451 if (mgmt != null) {
452 validateEffectiveDependencies(problems, m, mgmt.getDependencies(), true, request);
453 }
454
455 if (request.getValidationLevel() >= ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0) {
456 Severity errOn31 = getSeverity(request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_1);
457
458 validateBannedCharacters(
459 EMPTY, "version", problems, errOn31, Version.V20, m.getVersion(), null, m, ILLEGAL_VERSION_CHARS);
460 validate20ProperSnapshotVersion("version", problems, errOn31, Version.V20, m.getVersion(), null, m);
461
462 Build build = m.getBuild();
463 if (build != null) {
464 for (Plugin p : build.getPlugins()) {
465 validateStringNotEmpty(
466 "build.plugins.plugin.artifactId",
467 problems,
468 Severity.ERROR,
469 Version.V20,
470 p.getArtifactId(),
471 p);
472
473 validateStringNotEmpty(
474 "build.plugins.plugin.groupId", problems, Severity.ERROR, Version.V20, p.getGroupId(), p);
475
476 validate20PluginVersion(
477 "build.plugins.plugin.version", problems, p.getVersion(), p.getKey(), p, request);
478
479 validateBoolean(
480 "build.plugins.plugin.inherited",
481 EMPTY,
482 problems,
483 errOn30,
484 Version.V20,
485 p.getInherited(),
486 p.getKey(),
487 p);
488
489 validateBoolean(
490 "build.plugins.plugin.extensions",
491 EMPTY,
492 problems,
493 errOn30,
494 Version.V20,
495 p.getExtensions(),
496 p.getKey(),
497 p);
498
499 validate20EffectivePluginDependencies(problems, p, request);
500 }
501
502 validate20RawResources(problems, build.getResources(), "build.resources.resource.", request);
503
504 validate20RawResources(
505 problems, build.getTestResources(), "build.testResources.testResource.", request);
506 }
507
508 Reporting reporting = m.getReporting();
509 if (reporting != null) {
510 for (ReportPlugin p : reporting.getPlugins()) {
511 validateStringNotEmpty(
512 "reporting.plugins.plugin.artifactId",
513 problems,
514 Severity.ERROR,
515 Version.V20,
516 p.getArtifactId(),
517 p);
518
519 validateStringNotEmpty(
520 "reporting.plugins.plugin.groupId",
521 problems,
522 Severity.ERROR,
523 Version.V20,
524 p.getGroupId(),
525 p);
526 }
527 }
528
529 for (Repository repository : m.getRepositories()) {
530 validate20EffectiveRepository(problems, repository, "repositories.repository.", request);
531 }
532
533 for (Repository repository : m.getPluginRepositories()) {
534 validate20EffectiveRepository(problems, repository, "pluginRepositories.pluginRepository.", request);
535 }
536
537 DistributionManagement distMgmt = m.getDistributionManagement();
538 if (distMgmt != null) {
539 if (distMgmt.getStatus() != null) {
540 addViolation(
541 problems,
542 Severity.ERROR,
543 Version.V20,
544 "distributionManagement.status",
545 null,
546 "must not be specified.",
547 distMgmt);
548 }
549
550 validate20EffectiveRepository(
551 problems, distMgmt.getRepository(), "distributionManagement.repository.", request);
552 validate20EffectiveRepository(
553 problems,
554 distMgmt.getSnapshotRepository(),
555 "distributionManagement.snapshotRepository.",
556 request);
557 }
558 }
559 }
560
561 private void validate20RawDependencies(
562 ModelProblemCollector problems,
563 List<Dependency> dependencies,
564 String prefix,
565 String prefix2,
566 ModelBuildingRequest request) {
567 Severity errOn30 = getSeverity(request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_0);
568 Severity errOn31 = getSeverity(request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_1);
569
570 Map<String, Dependency> index = new HashMap<>();
571
572 for (Dependency dependency : dependencies) {
573 String key = dependency.getManagementKey();
574
575 if ("import".equals(dependency.getScope())) {
576 if (!"pom".equals(dependency.getType())) {
577 addViolation(
578 problems,
579 Severity.WARNING,
580 Version.V20,
581 prefix + prefix2 + "type",
582 key,
583 "must be 'pom' to import the managed dependencies.",
584 dependency);
585 } else if (StringUtils.isNotEmpty(dependency.getClassifier())) {
586 addViolation(
587 problems,
588 errOn30,
589 Version.V20,
590 prefix + prefix2 + "classifier",
591 key,
592 "must be empty, imported POM cannot have a classifier.",
593 dependency);
594 }
595 } else if ("system".equals(dependency.getScope())) {
596
597 if (request.getValidationLevel() >= ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_1) {
598 addViolation(
599 problems,
600 Severity.WARNING,
601 Version.V31,
602 prefix + prefix2 + "scope",
603 key,
604 "declares usage of deprecated 'system' scope ",
605 dependency);
606 }
607
608 String sysPath = dependency.getSystemPath();
609 if (StringUtils.isNotEmpty(sysPath)) {
610 if (!hasExpression(sysPath)) {
611 addViolation(
612 problems,
613 Severity.WARNING,
614 Version.V20,
615 prefix + prefix2 + "systemPath",
616 key,
617 "should use a variable instead of a hard-coded path " + sysPath,
618 dependency);
619 } else if (sysPath.contains("${basedir}") || sysPath.contains("${project.basedir}")) {
620 addViolation(
621 problems,
622 Severity.WARNING,
623 Version.V20,
624 prefix + prefix2 + "systemPath",
625 key,
626 "should not point at files within the project directory, " + sysPath
627 + " will be unresolvable by dependent projects",
628 dependency);
629 }
630 }
631 }
632
633 if (equals("LATEST", dependency.getVersion()) || equals("RELEASE", dependency.getVersion())) {
634 addViolation(
635 problems,
636 Severity.WARNING,
637 Version.BASE,
638 prefix + prefix2 + "version",
639 key,
640 "is either LATEST or RELEASE (both of them are being deprecated)",
641 dependency);
642 }
643
644 Dependency existing = index.get(key);
645
646 if (existing != null) {
647 String msg;
648 if (equals(existing.getVersion(), dependency.getVersion())) {
649 msg = "duplicate declaration of version " + Objects.toString(dependency.getVersion(), "(?)");
650 } else {
651 msg = "version " + Objects.toString(existing.getVersion(), "(?)") + " vs "
652 + Objects.toString(dependency.getVersion(), "(?)");
653 }
654
655 addViolation(
656 problems,
657 errOn31,
658 Version.V20,
659 prefix + prefix2 + "(groupId:artifactId:type:classifier)",
660 null,
661 "must be unique: " + key + " -> " + msg,
662 dependency);
663 } else {
664 index.put(key, dependency);
665 }
666 }
667 }
668
669 private void validate20RawDependenciesSelfReferencing(
670 ModelProblemCollector problems,
671 org.apache.maven.api.model.Model m,
672 List<Dependency> dependencies,
673 String prefix,
674 ModelBuildingRequest request) {
675
676
677
678
679
680 for (Dependency dependency : dependencies) {
681 String key = dependency.getGroupId() + ":" + dependency.getArtifactId() + ":" + dependency.getVersion()
682 + (dependency.getClassifier() != null ? ":" + dependency.getClassifier() : EMPTY);
683 String mKey = m.getGroupId() + ":" + m.getArtifactId() + ":" + m.getVersion();
684 if (key.equals(mKey)) {
685
686
687
688 addViolation(
689 problems,
690 Severity.FATAL,
691 Version.V31,
692 prefix + "[" + key + "]",
693 key,
694 "is referencing itself.",
695 dependency);
696 }
697 }
698 }
699
700 private void validateEffectiveDependencies(
701 ModelProblemCollector problems,
702 org.apache.maven.api.model.Model m,
703 List<Dependency> dependencies,
704 boolean management,
705 ModelBuildingRequest request) {
706 Severity errOn30 = getSeverity(request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_0);
707
708 String prefix = management ? "dependencyManagement.dependencies.dependency." : "dependencies.dependency.";
709
710 for (Dependency d : dependencies) {
711 validateEffectiveDependency(problems, d, management, prefix, request);
712
713 if (request.getValidationLevel() >= ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0) {
714 validateBoolean(
715 prefix, "optional", problems, errOn30, Version.V20, d.getOptional(), d.getManagementKey(), d);
716
717 if (!management) {
718 validateVersion(
719 prefix, "version", problems, errOn30, Version.V20, d.getVersion(), d.getManagementKey(), d);
720
721
722
723
724
725 validateEnum(
726 prefix,
727 "scope",
728 problems,
729 Severity.WARNING,
730 Version.V20,
731 d.getScope(),
732 d.getManagementKey(),
733 d,
734 "provided",
735 "compile",
736 "runtime",
737 "test",
738 "system");
739
740 validateEffectiveModelAgainstDependency(prefix, problems, m, d, request);
741 } else {
742 validateEnum(
743 prefix,
744 "scope",
745 problems,
746 Severity.WARNING,
747 Version.V20,
748 d.getScope(),
749 d.getManagementKey(),
750 d,
751 "provided",
752 "compile",
753 "runtime",
754 "test",
755 "system",
756 "import");
757 }
758 }
759 }
760 }
761
762 private void validateEffectiveModelAgainstDependency(
763 String prefix,
764 ModelProblemCollector problems,
765 org.apache.maven.api.model.Model m,
766 Dependency d,
767 ModelBuildingRequest request) {
768 String key = d.getGroupId() + ":" + d.getArtifactId() + ":" + d.getVersion()
769 + (d.getClassifier() != null ? ":" + d.getClassifier() : EMPTY);
770 String mKey = m.getGroupId() + ":" + m.getArtifactId() + ":" + m.getVersion();
771 if (key.equals(mKey)) {
772
773
774
775 addViolation(
776 problems, Severity.FATAL, Version.V31, prefix + "[" + key + "]", key, "is referencing itself.", d);
777 }
778 }
779
780 private void validate20EffectivePluginDependencies(
781 ModelProblemCollector problems, Plugin plugin, ModelBuildingRequest request) {
782 List<Dependency> dependencies = plugin.getDependencies();
783
784 if (!dependencies.isEmpty()) {
785 String prefix = "build.plugins.plugin[" + plugin.getKey() + "].dependencies.dependency.";
786
787 Severity errOn30 = getSeverity(request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_0);
788
789 for (Dependency d : dependencies) {
790 validateEffectiveDependency(problems, d, false, prefix, request);
791
792 validateVersion(
793 prefix, "version", problems, errOn30, Version.BASE, d.getVersion(), d.getManagementKey(), d);
794
795 validateEnum(
796 prefix,
797 "scope",
798 problems,
799 errOn30,
800 Version.BASE,
801 d.getScope(),
802 d.getManagementKey(),
803 d,
804 "compile",
805 "runtime",
806 "system");
807 }
808 }
809 }
810
811 private void validateEffectiveDependency(
812 ModelProblemCollector problems,
813 Dependency d,
814 boolean management,
815 String prefix,
816 ModelBuildingRequest request) {
817 validateCoordinateId(
818 prefix,
819 "artifactId",
820 problems,
821 Severity.ERROR,
822 Version.BASE,
823 d.getArtifactId(),
824 d.getManagementKey(),
825 d);
826
827 validateCoordinateId(
828 prefix, "groupId", problems, Severity.ERROR, Version.BASE, d.getGroupId(), d.getManagementKey(), d);
829
830 if (!management) {
831 validateStringNotEmpty(
832 prefix, "type", problems, Severity.ERROR, Version.BASE, d.getType(), d.getManagementKey(), d);
833
834 validateDependencyVersion(problems, d, prefix);
835 }
836
837 if ("system".equals(d.getScope())) {
838 String systemPath = d.getSystemPath();
839
840 if (StringUtils.isEmpty(systemPath)) {
841 addViolation(
842 problems,
843 Severity.ERROR,
844 Version.BASE,
845 prefix + "systemPath",
846 d.getManagementKey(),
847 "is missing.",
848 d);
849 } else {
850 File sysFile = new File(systemPath);
851 if (!sysFile.isAbsolute()) {
852 addViolation(
853 problems,
854 Severity.ERROR,
855 Version.BASE,
856 prefix + "systemPath",
857 d.getManagementKey(),
858 "must specify an absolute path but is " + systemPath,
859 d);
860 } else if (!sysFile.isFile()) {
861 String msg = "refers to a non-existing file " + sysFile.getAbsolutePath();
862 systemPath = systemPath.replace('/', File.separatorChar).replace('\\', File.separatorChar);
863 String jdkHome =
864 request.getSystemProperties().getProperty("java.home", EMPTY) + File.separator + "..";
865 if (systemPath.startsWith(jdkHome)) {
866 msg += ". Please verify that you run Maven using a JDK and not just a JRE.";
867 }
868 addViolation(
869 problems,
870 Severity.WARNING,
871 Version.BASE,
872 prefix + "systemPath",
873 d.getManagementKey(),
874 msg,
875 d);
876 }
877 }
878 } else if (StringUtils.isNotEmpty(d.getSystemPath())) {
879 addViolation(
880 problems,
881 Severity.ERROR,
882 Version.BASE,
883 prefix + "systemPath",
884 d.getManagementKey(),
885 "must be omitted." + " This field may only be specified for a dependency with system scope.",
886 d);
887 }
888
889 if (request.getValidationLevel() >= ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0) {
890 for (Exclusion exclusion : d.getExclusions()) {
891 if (request.getValidationLevel() < ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_0) {
892 validateCoordinateId(
893 prefix,
894 "exclusions.exclusion.groupId",
895 problems,
896 Severity.WARNING,
897 Version.V20,
898 exclusion.getGroupId(),
899 d.getManagementKey(),
900 exclusion);
901
902 validateCoordinateId(
903 prefix,
904 "exclusions.exclusion.artifactId",
905 problems,
906 Severity.WARNING,
907 Version.V20,
908 exclusion.getArtifactId(),
909 d.getManagementKey(),
910 exclusion);
911 } else {
912 validateCoordinateIdWithWildcards(
913 prefix,
914 "exclusions.exclusion.groupId",
915 problems,
916 Severity.WARNING,
917 Version.V30,
918 exclusion.getGroupId(),
919 d.getManagementKey(),
920 exclusion);
921
922 validateCoordinateIdWithWildcards(
923 prefix,
924 "exclusions.exclusion.artifactId",
925 problems,
926 Severity.WARNING,
927 Version.V30,
928 exclusion.getArtifactId(),
929 d.getManagementKey(),
930 exclusion);
931 }
932 }
933 }
934 }
935
936
937
938
939 protected void validateDependencyVersion(ModelProblemCollector problems, Dependency d, String prefix) {
940 validateStringNotEmpty(
941 prefix, "version", problems, Severity.ERROR, Version.BASE, d.getVersion(), d.getManagementKey(), d);
942 }
943
944 private void validateRawRepositories(
945 ModelProblemCollector problems,
946 List<Repository> repositories,
947 String prefix,
948 String prefix2,
949 ModelBuildingRequest request) {
950 Map<String, Repository> index = new HashMap<>();
951
952 for (Repository repository : repositories) {
953 validateStringNotEmpty(
954 prefix, prefix2, "id", problems, Severity.ERROR, Version.V20, repository.getId(), null, repository);
955
956 if (validateStringNotEmpty(
957 prefix,
958 prefix2,
959 "[" + repository.getId() + "].url",
960 problems,
961 Severity.ERROR,
962 Version.V20,
963 repository.getUrl(),
964 null,
965 repository)) {
966
967 Matcher m = EXPRESSION_NAME_PATTERN.matcher(repository.getUrl());
968 while (m.find()) {
969 if (!("basedir".equals(m.group(1)) || "project.basedir".equals(m.group(1)))) {
970 validateStringNoExpression(
971 prefix + prefix2 + "[" + repository.getId() + "].url",
972 problems,
973 Severity.ERROR,
974 Version.V40,
975 repository.getUrl(),
976 repository);
977 break;
978 }
979 }
980 }
981
982 String key = repository.getId();
983
984 Repository existing = index.get(key);
985
986 if (existing != null) {
987 Severity errOn30 = getSeverity(request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_0);
988
989 addViolation(
990 problems,
991 errOn30,
992 Version.V20,
993 prefix + prefix2 + "id",
994 null,
995 "must be unique: " + repository.getId() + " -> " + existing.getUrl() + " vs "
996 + repository.getUrl(),
997 repository);
998 } else {
999 index.put(key, repository);
1000 }
1001 }
1002 }
1003
1004 private void validate20EffectiveRepository(
1005 ModelProblemCollector problems, Repository repository, String prefix, ModelBuildingRequest request) {
1006 if (repository != null) {
1007 Severity errOn31 = getSeverity(request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_1);
1008
1009 validateBannedCharacters(
1010 prefix,
1011 "id",
1012 problems,
1013 errOn31,
1014 Version.V20,
1015 repository.getId(),
1016 null,
1017 repository,
1018 ILLEGAL_REPO_ID_CHARS);
1019
1020 if ("local".equals(repository.getId())) {
1021 addViolation(
1022 problems,
1023 errOn31,
1024 Version.V20,
1025 prefix + "id",
1026 null,
1027 "must not be 'local'" + ", this identifier is reserved for the local repository"
1028 + ", using it for other repositories will corrupt your repository metadata.",
1029 repository);
1030 }
1031
1032 if ("legacy".equals(repository.getLayout())) {
1033 addViolation(
1034 problems,
1035 Severity.WARNING,
1036 Version.V20,
1037 prefix + "layout",
1038 repository.getId(),
1039 "uses the unsupported value 'legacy', artifact resolution might fail.",
1040 repository);
1041 }
1042 }
1043 }
1044
1045 private void validate20RawResources(
1046 ModelProblemCollector problems, List<Resource> resources, String prefix, ModelBuildingRequest request) {
1047 Severity errOn30 = getSeverity(request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_0);
1048
1049 for (Resource resource : resources) {
1050 validateStringNotEmpty(
1051 prefix,
1052 "directory",
1053 problems,
1054 Severity.ERROR,
1055 Version.V20,
1056 resource.getDirectory(),
1057 null,
1058 resource);
1059
1060 validateBoolean(
1061 prefix,
1062 "filtering",
1063 problems,
1064 errOn30,
1065 Version.V20,
1066 resource.getFiltering(),
1067 resource.getDirectory(),
1068 resource);
1069 }
1070 }
1071
1072
1073
1074
1075
1076 private boolean validateCoordinateId(
1077 String fieldName, ModelProblemCollector problems, String id, InputLocationTracker tracker) {
1078 return validateCoordinateId(EMPTY, fieldName, problems, Severity.ERROR, Version.BASE, id, null, tracker);
1079 }
1080
1081 @SuppressWarnings("checkstyle:parameternumber")
1082 private boolean validateCoordinateId(
1083 String prefix,
1084 String fieldName,
1085 ModelProblemCollector problems,
1086 Severity severity,
1087 Version version,
1088 String id,
1089 String sourceHint,
1090 InputLocationTracker tracker) {
1091 if (validCoordinateIds.contains(id)) {
1092 return true;
1093 }
1094 if (!validateStringNotEmpty(prefix, fieldName, problems, severity, version, id, sourceHint, tracker)) {
1095 return false;
1096 } else {
1097 if (!isValidCoordinateId(id)) {
1098 addViolation(
1099 problems,
1100 severity,
1101 version,
1102 prefix + fieldName,
1103 sourceHint,
1104 "with value '" + id + "' does not match a valid coordinate id pattern.",
1105 tracker);
1106 return false;
1107 }
1108 validCoordinateIds.add(id);
1109 return true;
1110 }
1111 }
1112
1113 private boolean isValidCoordinateId(String id) {
1114 for (int i = 0; i < id.length(); i++) {
1115 char c = id.charAt(i);
1116 if (!isValidCoordinateIdCharacter(c)) {
1117 return false;
1118 }
1119 }
1120 return true;
1121 }
1122
1123 private boolean isValidCoordinateIdCharacter(char c) {
1124 return c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9' || c == '-' || c == '_' || c == '.';
1125 }
1126
1127 @SuppressWarnings("checkstyle:parameternumber")
1128 private boolean validateProfileId(
1129 String prefix,
1130 String fieldName,
1131 ModelProblemCollector problems,
1132 Severity severity,
1133 Version version,
1134 String id,
1135 String sourceHint,
1136 InputLocationTracker tracker) {
1137 if (validProfileIds.contains(id)) {
1138 return true;
1139 }
1140 if (!validateStringNotEmpty(prefix, fieldName, problems, severity, version, id, sourceHint, tracker)) {
1141 return false;
1142 } else {
1143 if (!isValidProfileId(id)) {
1144 addViolation(
1145 problems,
1146 severity,
1147 version,
1148 prefix + fieldName,
1149 sourceHint,
1150 "with value '" + id + "' does not match a valid profile id pattern.",
1151 tracker);
1152 return false;
1153 }
1154 validProfileIds.add(id);
1155 return true;
1156 }
1157 }
1158
1159 private boolean isValidProfileId(String id) {
1160 switch (id.charAt(0)) {
1161 case '+':
1162 case '-':
1163 case '!':
1164 case '?':
1165 return false;
1166 default:
1167 }
1168 return true;
1169 }
1170
1171 @SuppressWarnings("checkstyle:parameternumber")
1172 private boolean validateCoordinateIdWithWildcards(
1173 String prefix,
1174 String fieldName,
1175 ModelProblemCollector problems,
1176 Severity severity,
1177 Version version,
1178 String id,
1179 String sourceHint,
1180 InputLocationTracker tracker) {
1181 if (!validateStringNotEmpty(prefix, fieldName, problems, severity, version, id, sourceHint, tracker)) {
1182 return false;
1183 } else {
1184 if (!isValidCoordinateIdWithWildCards(id)) {
1185 addViolation(
1186 problems,
1187 severity,
1188 version,
1189 prefix + fieldName,
1190 sourceHint,
1191 "with value '" + id + "' does not match a valid coordinate id pattern.",
1192 tracker);
1193 return false;
1194 }
1195 return true;
1196 }
1197 }
1198
1199 private boolean isValidCoordinateIdWithWildCards(String id) {
1200 for (int i = 0; i < id.length(); i++) {
1201 char c = id.charAt(i);
1202 if (!isValidCoordinateIdWithWildCardCharacter(c)) {
1203 return false;
1204 }
1205 }
1206 return true;
1207 }
1208
1209 private boolean isValidCoordinateIdWithWildCardCharacter(char c) {
1210 return isValidCoordinateIdCharacter(c) || c == '?' || c == '*';
1211 }
1212
1213 private boolean validateStringNoExpression(
1214 String fieldName,
1215 ModelProblemCollector problems,
1216 Severity severity,
1217 Version version,
1218 String string,
1219 InputLocationTracker tracker) {
1220 if (!hasExpression(string)) {
1221 return true;
1222 }
1223
1224 addViolation(
1225 problems,
1226 severity,
1227 version,
1228 fieldName,
1229 null,
1230 "contains an expression but should be a constant.",
1231 tracker);
1232
1233 return false;
1234 }
1235
1236 private boolean validateVersionNoExpression(
1237 String fieldName,
1238 ModelProblemCollector problems,
1239 Severity severity,
1240 Version version,
1241 String string,
1242 InputLocationTracker tracker) {
1243 if (!hasExpression(string)) {
1244 return true;
1245 }
1246
1247 Matcher m = EXPRESSION_NAME_PATTERN.matcher(string.trim());
1248 while (m.find()) {
1249 String property = m.group(1);
1250 if (!versionProcessor.isValidProperty(property)) {
1251 addViolation(
1252 problems,
1253 severity,
1254 version,
1255 fieldName,
1256 null,
1257 "contains an expression but should be a constant.",
1258 tracker);
1259
1260 return false;
1261 }
1262 }
1263
1264 return true;
1265 }
1266
1267 private boolean hasExpression(String value) {
1268 return value != null && value.contains("${");
1269 }
1270
1271 private boolean hasProjectExpression(String value) {
1272 return value != null && value.contains("${project.");
1273 }
1274
1275 private boolean validateStringNotEmpty(
1276 String fieldName,
1277 ModelProblemCollector problems,
1278 Severity severity,
1279 Version version,
1280 String string,
1281 InputLocationTracker tracker) {
1282 return validateStringNotEmpty(EMPTY, fieldName, problems, severity, version, string, null, tracker);
1283 }
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293 @SuppressWarnings("checkstyle:parameternumber")
1294 private boolean validateStringNotEmpty(
1295 String prefix,
1296 String prefix2,
1297 String fieldName,
1298 ModelProblemCollector problems,
1299 Severity severity,
1300 Version version,
1301 String string,
1302 String sourceHint,
1303 InputLocationTracker tracker) {
1304 if (!validateNotNull(prefix, prefix2, fieldName, problems, severity, version, string, sourceHint, tracker)) {
1305 return false;
1306 }
1307
1308 if (!string.isEmpty()) {
1309 return true;
1310 }
1311
1312 addViolation(problems, severity, version, prefix + prefix2 + fieldName, sourceHint, "is missing.", tracker);
1313
1314 return false;
1315 }
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325 @SuppressWarnings("checkstyle:parameternumber")
1326 private boolean validateStringNotEmpty(
1327 String prefix,
1328 String fieldName,
1329 ModelProblemCollector problems,
1330 Severity severity,
1331 Version version,
1332 String string,
1333 String sourceHint,
1334 InputLocationTracker tracker) {
1335 if (!validateNotNull(prefix, fieldName, problems, severity, version, string, sourceHint, tracker)) {
1336 return false;
1337 }
1338
1339 if (string.length() > 0) {
1340 return true;
1341 }
1342
1343 addViolation(problems, severity, version, prefix + fieldName, sourceHint, "is missing.", tracker);
1344
1345 return false;
1346 }
1347
1348
1349
1350
1351
1352
1353
1354
1355 @SuppressWarnings("checkstyle:parameternumber")
1356 private boolean validateNotNull(
1357 String prefix,
1358 String fieldName,
1359 ModelProblemCollector problems,
1360 Severity severity,
1361 Version version,
1362 Object object,
1363 String sourceHint,
1364 InputLocationTracker tracker) {
1365 if (object != null) {
1366 return true;
1367 }
1368
1369 addViolation(problems, severity, version, prefix + fieldName, sourceHint, "is missing.", tracker);
1370
1371 return false;
1372 }
1373
1374
1375
1376
1377
1378
1379
1380
1381 @SuppressWarnings("checkstyle:parameternumber")
1382 private boolean validateNotNull(
1383 String prefix,
1384 String prefix2,
1385 String fieldName,
1386 ModelProblemCollector problems,
1387 Severity severity,
1388 Version version,
1389 Object object,
1390 String sourceHint,
1391 InputLocationTracker tracker) {
1392 if (object != null) {
1393 return true;
1394 }
1395
1396 addViolation(problems, severity, version, prefix + prefix2 + fieldName, sourceHint, "is missing.", tracker);
1397
1398 return false;
1399 }
1400
1401 @SuppressWarnings("checkstyle:parameternumber")
1402 private boolean validateBoolean(
1403 String prefix,
1404 String fieldName,
1405 ModelProblemCollector problems,
1406 Severity severity,
1407 Version version,
1408 String string,
1409 String sourceHint,
1410 InputLocationTracker tracker) {
1411 if (string == null || string.length() <= 0) {
1412 return true;
1413 }
1414
1415 if ("true".equalsIgnoreCase(string) || "false".equalsIgnoreCase(string)) {
1416 return true;
1417 }
1418
1419 addViolation(
1420 problems,
1421 severity,
1422 version,
1423 prefix + fieldName,
1424 sourceHint,
1425 "must be 'true' or 'false' but is '" + string + "'.",
1426 tracker);
1427
1428 return false;
1429 }
1430
1431 @SuppressWarnings("checkstyle:parameternumber")
1432 private boolean validateEnum(
1433 String prefix,
1434 String fieldName,
1435 ModelProblemCollector problems,
1436 Severity severity,
1437 Version version,
1438 String string,
1439 String sourceHint,
1440 InputLocationTracker tracker,
1441 String... validValues) {
1442 if (string == null || string.length() <= 0) {
1443 return true;
1444 }
1445
1446 List<String> values = Arrays.asList(validValues);
1447
1448 if (values.contains(string)) {
1449 return true;
1450 }
1451
1452 addViolation(
1453 problems,
1454 severity,
1455 version,
1456 prefix + fieldName,
1457 sourceHint,
1458 "must be one of " + values + " but is '" + string + "'.",
1459 tracker);
1460
1461 return false;
1462 }
1463
1464 @SuppressWarnings("checkstyle:parameternumber")
1465 private boolean validateModelVersion(
1466 ModelProblemCollector problems, String string, InputLocationTracker tracker, String... validVersions) {
1467 if (string == null || string.length() <= 0) {
1468 return true;
1469 }
1470
1471 List<String> values = Arrays.asList(validVersions);
1472
1473 if (values.contains(string)) {
1474 return true;
1475 }
1476
1477 boolean newerThanAll = true;
1478 boolean olderThanAll = true;
1479 for (String validValue : validVersions) {
1480 final int comparison = compareModelVersions(validValue, string);
1481 newerThanAll = newerThanAll && comparison < 0;
1482 olderThanAll = olderThanAll && comparison > 0;
1483 }
1484
1485 if (newerThanAll) {
1486 addViolation(
1487 problems,
1488 Severity.FATAL,
1489 Version.V20,
1490 "modelVersion",
1491 null,
1492 "of '" + string + "' is newer than the versions supported by this version of Maven: " + values
1493 + ". Building this project requires a newer version of Maven.",
1494 tracker);
1495
1496 } else if (olderThanAll) {
1497
1498 addViolation(
1499 problems,
1500 Severity.FATAL,
1501 Version.V20,
1502 "modelVersion",
1503 null,
1504 "of '" + string + "' is older than the versions supported by this version of Maven: " + values
1505 + ". Building this project requires an older version of Maven.",
1506 tracker);
1507
1508 } else {
1509 addViolation(
1510 problems,
1511 Severity.ERROR,
1512 Version.V20,
1513 "modelVersion",
1514 null,
1515 "must be one of " + values + " but is '" + string + "'.",
1516 tracker);
1517 }
1518
1519 return false;
1520 }
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530 private static int compareModelVersions(String first, String second) {
1531
1532 String[] firstSegments = StringUtils.split(first, ".");
1533 String[] secondSegments = StringUtils.split(second, ".");
1534 for (int i = 0; i < Math.min(firstSegments.length, secondSegments.length); i++) {
1535 int result = Long.valueOf(firstSegments[i]).compareTo(Long.valueOf(secondSegments[i]));
1536 if (result != 0) {
1537 return result;
1538 }
1539 }
1540 if (firstSegments.length == secondSegments.length) {
1541 return 0;
1542 }
1543 return firstSegments.length > secondSegments.length ? -1 : 1;
1544 }
1545
1546 @SuppressWarnings("checkstyle:parameternumber")
1547 private boolean validateBannedCharacters(
1548 String prefix,
1549 String fieldName,
1550 ModelProblemCollector problems,
1551 Severity severity,
1552 Version version,
1553 String string,
1554 String sourceHint,
1555 InputLocationTracker tracker,
1556 String banned) {
1557 if (string != null) {
1558 for (int i = string.length() - 1; i >= 0; i--) {
1559 if (banned.indexOf(string.charAt(i)) >= 0) {
1560 addViolation(
1561 problems,
1562 severity,
1563 version,
1564 prefix + fieldName,
1565 sourceHint,
1566 "must not contain any of these characters " + banned + " but found " + string.charAt(i),
1567 tracker);
1568 return false;
1569 }
1570 }
1571 }
1572
1573 return true;
1574 }
1575
1576 @SuppressWarnings("checkstyle:parameternumber")
1577 private boolean validateVersion(
1578 String prefix,
1579 String fieldName,
1580 ModelProblemCollector problems,
1581 Severity severity,
1582 Version version,
1583 String string,
1584 String sourceHint,
1585 InputLocationTracker tracker) {
1586 if (string == null || string.length() <= 0) {
1587 return true;
1588 }
1589
1590 if (hasExpression(string)) {
1591 addViolation(
1592 problems,
1593 severity,
1594 version,
1595 prefix + fieldName,
1596 sourceHint,
1597 "must be a valid version but is '" + string + "'.",
1598 tracker);
1599 return false;
1600 }
1601
1602 return validateBannedCharacters(
1603 prefix, fieldName, problems, severity, version, string, sourceHint, tracker, ILLEGAL_VERSION_CHARS);
1604 }
1605
1606 private boolean validate20ProperSnapshotVersion(
1607 String fieldName,
1608 ModelProblemCollector problems,
1609 Severity severity,
1610 Version version,
1611 String string,
1612 String sourceHint,
1613 InputLocationTracker tracker) {
1614 if (string == null || string.length() <= 0) {
1615 return true;
1616 }
1617
1618 if (string.endsWith("SNAPSHOT") && !string.endsWith("-SNAPSHOT")) {
1619 addViolation(
1620 problems,
1621 severity,
1622 version,
1623 fieldName,
1624 sourceHint,
1625 "uses an unsupported snapshot version format, should be '*-SNAPSHOT' instead.",
1626 tracker);
1627 return false;
1628 }
1629
1630 return true;
1631 }
1632
1633 private boolean validate20PluginVersion(
1634 String fieldName,
1635 ModelProblemCollector problems,
1636 String string,
1637 String sourceHint,
1638 InputLocationTracker tracker,
1639 ModelBuildingRequest request) {
1640 if (string == null) {
1641
1642 return true;
1643 }
1644
1645 Severity errOn30 = getSeverity(request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_0);
1646
1647 if (!validateVersion(EMPTY, fieldName, problems, errOn30, Version.V20, string, sourceHint, tracker)) {
1648 return false;
1649 }
1650
1651 if (string.length() <= 0 || "RELEASE".equals(string) || "LATEST".equals(string)) {
1652 addViolation(
1653 problems,
1654 errOn30,
1655 Version.V20,
1656 fieldName,
1657 sourceHint,
1658 "must be a valid version but is '" + string + "'.",
1659 tracker);
1660 return false;
1661 }
1662
1663 return true;
1664 }
1665
1666 private static void addViolation(
1667 ModelProblemCollector problems,
1668 Severity severity,
1669 Version version,
1670 String fieldName,
1671 String sourceHint,
1672 String message,
1673 InputLocationTracker tracker) {
1674 StringBuilder buffer = new StringBuilder(256);
1675 buffer.append('\'').append(fieldName).append('\'');
1676
1677 if (sourceHint != null) {
1678 buffer.append(" for ").append(sourceHint);
1679 }
1680
1681 buffer.append(' ').append(message);
1682
1683 problems.add(new ModelProblemCollectorRequest(severity, version)
1684 .setMessage(buffer.toString())
1685 .setLocation(getLocation(fieldName, tracker)));
1686 }
1687
1688 private static org.apache.maven.model.InputLocation getLocation(String fieldName, InputLocationTracker tracker) {
1689 InputLocation location = null;
1690
1691 if (tracker != null) {
1692 if (fieldName != null) {
1693 Object key = fieldName;
1694
1695 int idx = fieldName.lastIndexOf('.');
1696 if (idx >= 0) {
1697 fieldName = fieldName.substring(idx + 1);
1698 key = fieldName;
1699 }
1700
1701 if (fieldName.endsWith("]")) {
1702 key = fieldName.substring(fieldName.lastIndexOf('[') + 1, fieldName.length() - 1);
1703 try {
1704 key = Integer.valueOf(key.toString());
1705 } catch (NumberFormatException e) {
1706
1707 }
1708 }
1709
1710 location = tracker.getLocation(key);
1711 }
1712
1713 if (location == null) {
1714 location = tracker.getLocation(EMPTY);
1715 }
1716 }
1717
1718 return location != null ? new org.apache.maven.model.InputLocation(location) : null;
1719 }
1720
1721 private static boolean equals(String s1, String s2) {
1722 return StringUtils.clean(s1).equals(StringUtils.clean(s2));
1723 }
1724
1725 private static Severity getSeverity(ModelBuildingRequest request, int errorThreshold) {
1726 return getSeverity(request.getValidationLevel(), errorThreshold);
1727 }
1728
1729 private static Severity getSeverity(int validationLevel, int errorThreshold) {
1730 if (validationLevel < errorThreshold) {
1731 return Severity.WARNING;
1732 } else {
1733 return Severity.ERROR;
1734 }
1735 }
1736 }