| package org.apache.maven.model.validation; |
| |
| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| import org.apache.maven.model.Activation; |
| import org.apache.maven.model.ActivationFile; |
| import org.apache.maven.model.Build; |
| import org.apache.maven.model.BuildBase; |
| import org.apache.maven.model.Dependency; |
| import org.apache.maven.model.DependencyManagement; |
| import org.apache.maven.model.DistributionManagement; |
| import org.apache.maven.model.Exclusion; |
| import org.apache.maven.model.InputLocation; |
| import org.apache.maven.model.InputLocationTracker; |
| import org.apache.maven.model.Model; |
| import org.apache.maven.model.Parent; |
| import org.apache.maven.model.Plugin; |
| import org.apache.maven.model.PluginExecution; |
| import org.apache.maven.model.PluginManagement; |
| import org.apache.maven.model.Profile; |
| import org.apache.maven.model.ReportPlugin; |
| import org.apache.maven.model.Reporting; |
| import org.apache.maven.model.Repository; |
| import org.apache.maven.model.Resource; |
| import org.apache.maven.model.building.ModelBuildingRequest; |
| import org.apache.maven.model.building.ModelProblem.Severity; |
| import org.apache.maven.model.building.ModelProblem.Version; |
| import org.apache.maven.model.building.ModelProblemCollector; |
| import org.apache.maven.model.building.ModelProblemCollectorRequest; |
| import org.apache.maven.model.interpolation.AbstractStringBasedModelInterpolator; |
| import org.codehaus.plexus.util.StringUtils; |
| |
| import java.io.File; |
| import java.util.Arrays; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Objects; |
| import java.util.Set; |
| import java.util.regex.Matcher; |
| import java.util.regex.Pattern; |
| |
| import javax.inject.Named; |
| import javax.inject.Singleton; |
| |
| /** |
| * @author <a href="mailto:trygvis@inamo.no">Trygve Laugstøl</a> |
| */ |
| @Named |
| @Singleton |
| public class DefaultModelValidator |
| implements ModelValidator |
| { |
| |
| private static final Pattern CI_FRIENDLY_EXPRESSION = Pattern.compile( "\\$\\{(.+?)\\}" ); |
| |
| private static final List<String> CI_FRIENDLY_POSSIBLE_PROPERTY_NAMES = |
| Arrays.asList( AbstractStringBasedModelInterpolator.REVISION_PROPERTY, |
| AbstractStringBasedModelInterpolator.CHANGELIST_PROPERTY, |
| AbstractStringBasedModelInterpolator.SHA1_PROPERTY ); |
| |
| private static final String ILLEGAL_FS_CHARS = "\\/:\"<>|?*"; |
| |
| private static final String ILLEGAL_VERSION_CHARS = ILLEGAL_FS_CHARS; |
| |
| private static final String ILLEGAL_REPO_ID_CHARS = ILLEGAL_FS_CHARS; |
| |
| private static final String EMPTY = ""; |
| |
| private final Set<String> validIds = new HashSet<>(); |
| |
| @Override |
| public void validateFileModel( Model m, ModelBuildingRequest request, ModelProblemCollector problems ) |
| { |
| Parent parent = m.getParent(); |
| if ( parent != null ) |
| { |
| validateStringNotEmpty( "parent.groupId", problems, Severity.FATAL, Version.BASE, parent.getGroupId(), |
| parent ); |
| |
| validateStringNotEmpty( "parent.artifactId", problems, Severity.FATAL, Version.BASE, parent.getArtifactId(), |
| parent ); |
| |
| if ( equals( parent.getGroupId(), m.getGroupId() ) && equals( parent.getArtifactId(), m.getArtifactId() ) ) |
| { |
| addViolation( problems, Severity.FATAL, Version.BASE, "parent.artifactId", null, |
| "must be changed" |
| + ", the parent element cannot have the same groupId:artifactId as the project.", |
| parent ); |
| } |
| |
| if ( equals( "LATEST", parent.getVersion() ) || equals( "RELEASE", parent.getVersion() ) ) |
| { |
| addViolation( problems, Severity.WARNING, Version.BASE, "parent.version", null, |
| "is either LATEST or RELEASE (both of them are being deprecated)", parent ); |
| } |
| |
| } |
| |
| if ( request.getValidationLevel() >= ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0 ) |
| { |
| Set<String> modules = new HashSet<>(); |
| for ( int i = 0, n = m.getModules().size(); i < n; i++ ) |
| { |
| String module = m.getModules().get( i ); |
| if ( !modules.add( module ) ) |
| { |
| addViolation( problems, Severity.ERROR, Version.V20, "modules.module[" + i + "]", null, |
| "specifies duplicate child module " + module, m.getLocation( "modules" ) ); |
| } |
| } |
| |
| Severity errOn30 = getSeverity( request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_0 ); |
| |
| // [MNG-6074] Maven should produce an error if no model version has been set in a POM file used to build an |
| // effective model. |
| // |
| // As of 3.4, the model version is mandatory even in raw models. The XML element still is optional in the |
| // XML schema and this will not change anytime soon. We do not want to build effective models based on |
| // models without a version starting with 3.4. |
| validateStringNotEmpty( "modelVersion", problems, Severity.ERROR, Version.V20, m.getModelVersion(), m ); |
| |
| validateModelVersion( problems, m.getModelVersion(), m, "4.0.0" ); |
| |
| validateStringNoExpression( "groupId", problems, Severity.WARNING, Version.V20, m.getGroupId(), m ); |
| if ( parent == null ) |
| { |
| validateStringNotEmpty( "groupId", problems, Severity.FATAL, Version.V20, m.getGroupId(), m ); |
| } |
| |
| validateStringNoExpression( "artifactId", problems, Severity.WARNING, Version.V20, m.getArtifactId(), m ); |
| validateStringNotEmpty( "artifactId", problems, Severity.FATAL, Version.V20, m.getArtifactId(), m ); |
| |
| validateVersionNoExpression( "version", problems, Severity.WARNING, Version.V20, m.getVersion(), m ); |
| if ( parent == null ) |
| { |
| validateStringNotEmpty( "version", problems, Severity.FATAL, Version.V20, m.getVersion(), m ); |
| } |
| |
| validate20RawDependencies( problems, m.getDependencies(), "dependencies.dependency.", EMPTY, request ); |
| |
| validate20RawDependenciesSelfReferencing( problems, m, m.getDependencies(), "dependencies.dependency", |
| request ); |
| |
| if ( m.getDependencyManagement() != null ) |
| { |
| validate20RawDependencies( problems, m.getDependencyManagement().getDependencies(), |
| "dependencyManagement.dependencies.dependency.", EMPTY, request ); |
| } |
| |
| validateRawRepositories( problems, m.getRepositories(), "repositories.repository.", EMPTY, request ); |
| |
| validateRawRepositories( problems, m.getPluginRepositories(), "pluginRepositories.pluginRepository.", |
| EMPTY, request ); |
| |
| Build build = m.getBuild(); |
| if ( build != null ) |
| { |
| validate20RawPlugins( problems, build.getPlugins(), "build.plugins.plugin.", EMPTY, request ); |
| |
| PluginManagement mgmt = build.getPluginManagement(); |
| if ( mgmt != null ) |
| { |
| validate20RawPlugins( problems, mgmt.getPlugins(), "build.pluginManagement.plugins.plugin.", |
| EMPTY, request ); |
| } |
| } |
| |
| Set<String> profileIds = new HashSet<>(); |
| |
| for ( Profile profile : m.getProfiles() ) |
| { |
| String prefix = "profiles.profile[" + profile.getId() + "]."; |
| |
| validateId( prefix, "id", problems, Severity.ERROR, Version.V40, profile.getId(), null, m ); |
| |
| if ( !profileIds.add( profile.getId() ) ) |
| { |
| addViolation( problems, errOn30, Version.V20, "profiles.profile.id", null, |
| "must be unique but found duplicate profile with id " + profile.getId(), profile ); |
| } |
| |
| validate30RawProfileActivation( problems, profile.getActivation(), profile.getId(), |
| prefix, "activation", request ); |
| |
| validate20RawDependencies( problems, profile.getDependencies(), prefix, "dependencies.dependency.", |
| request ); |
| |
| if ( profile.getDependencyManagement() != null ) |
| { |
| validate20RawDependencies( problems, profile.getDependencyManagement().getDependencies(), |
| prefix, "dependencyManagement.dependencies.dependency.", request ); |
| } |
| |
| validateRawRepositories( problems, profile.getRepositories(), prefix, "repositories.repository.", |
| request ); |
| |
| validateRawRepositories( problems, profile.getPluginRepositories(), |
| prefix, "pluginRepositories.pluginRepository.", request ); |
| |
| BuildBase buildBase = profile.getBuild(); |
| if ( buildBase != null ) |
| { |
| validate20RawPlugins( problems, buildBase.getPlugins(), prefix, "plugins.plugin.", request ); |
| |
| PluginManagement mgmt = buildBase.getPluginManagement(); |
| if ( mgmt != null ) |
| { |
| validate20RawPlugins( problems, mgmt.getPlugins(), prefix, "pluginManagement.plugins.plugin.", |
| request ); |
| } |
| } |
| } |
| } |
| } |
| |
| @Override |
| public void validateRawModel( Model m, ModelBuildingRequest request, ModelProblemCollector problems ) |
| { |
| Parent parent = m.getParent(); |
| |
| if ( parent != null ) |
| { |
| validateStringNotEmpty( "parent.version", problems, Severity.FATAL, Version.BASE, parent.getVersion(), |
| parent ); |
| } |
| } |
| |
| private void validate30RawProfileActivation( ModelProblemCollector problems, Activation activation, |
| String sourceHint, String prefix, String fieldName, |
| ModelBuildingRequest request ) |
| { |
| if ( activation == null ) |
| { |
| return; |
| } |
| |
| ActivationFile file = activation.getFile(); |
| |
| if ( file != null ) |
| { |
| String path; |
| boolean missing; |
| |
| if ( StringUtils.isNotEmpty( file.getExists() ) ) |
| { |
| path = file.getExists(); |
| missing = false; |
| } |
| else if ( StringUtils.isNotEmpty( file.getMissing() ) ) |
| { |
| path = file.getMissing(); |
| missing = true; |
| } |
| else |
| { |
| return; |
| } |
| |
| if ( path.contains( "${project.basedir}" ) ) |
| { |
| addViolation( problems, Severity.WARNING, Version.V30, |
| prefix + fieldName + ( missing ? ".file.missing" : ".file.exists" ), null, |
| "Failed to interpolate file location " + path + " for profile " + sourceHint |
| + ": ${project.basedir} expression not supported during profile activation, " |
| + "use ${basedir} instead", |
| file.getLocation( missing ? "missing" : "exists" ) ); |
| } |
| else if ( hasProjectExpression( path ) ) |
| { |
| addViolation( problems, Severity.WARNING, Version.V30, |
| prefix + fieldName + ( missing ? ".file.missing" : ".file.exists" ), null, |
| "Failed to interpolate file location " + path + " for profile " + sourceHint |
| + ": ${project.*} expressions are not supported during profile activation", |
| file.getLocation( missing ? "missing" : "exists" ) ); |
| } |
| } |
| } |
| |
| private void validate20RawPlugins( ModelProblemCollector problems, List<Plugin> plugins, String prefix, |
| String prefix2, ModelBuildingRequest request ) |
| { |
| Severity errOn31 = getSeverity( request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_1 ); |
| |
| Map<String, Plugin> index = new HashMap<>(); |
| |
| for ( Plugin plugin : plugins ) |
| { |
| if ( plugin.getGroupId() == null |
| || ( plugin.getGroupId() != null && plugin.getGroupId().trim().isEmpty() ) ) |
| { |
| addViolation( problems, Severity.FATAL, Version.V20, prefix + prefix2 + "(groupId:artifactId)", null, |
| "groupId of a plugin must be defined. ", plugin ); |
| } |
| |
| if ( plugin.getArtifactId() == null |
| || ( plugin.getArtifactId() != null && plugin.getArtifactId().trim().isEmpty() ) ) |
| { |
| addViolation( problems, Severity.FATAL, Version.V20, prefix + prefix2 + "(groupId:artifactId)", null, |
| "artifactId of a plugin must be defined. ", plugin ); |
| } |
| |
| // This will catch cases like <version></version> or <version/> |
| if ( plugin.getVersion() != null && plugin.getVersion().trim().isEmpty() ) |
| { |
| addViolation( problems, Severity.FATAL, Version.V20, prefix + prefix2 + "(groupId:artifactId)", null, |
| "version of a plugin must be defined. ", plugin ); |
| } |
| |
| String key = plugin.getKey(); |
| |
| Plugin existing = index.get( key ); |
| |
| if ( existing != null ) |
| { |
| addViolation( problems, errOn31, Version.V20, prefix + prefix2 + "(groupId:artifactId)", null, |
| "must be unique but found duplicate declaration of plugin " + key, plugin ); |
| } |
| else |
| { |
| index.put( key, plugin ); |
| } |
| |
| Set<String> executionIds = new HashSet<>(); |
| |
| for ( PluginExecution exec : plugin.getExecutions() ) |
| { |
| if ( !executionIds.add( exec.getId() ) ) |
| { |
| addViolation( problems, Severity.ERROR, Version.V20, |
| prefix + prefix2 + "[" + plugin.getKey() + "].executions.execution.id", null, |
| "must be unique but found duplicate execution with id " + exec.getId(), exec ); |
| } |
| } |
| } |
| } |
| |
| @Override |
| public void validateEffectiveModel( Model m, ModelBuildingRequest request, ModelProblemCollector problems ) |
| { |
| validateStringNotEmpty( "modelVersion", problems, Severity.ERROR, Version.BASE, m.getModelVersion(), m ); |
| |
| validateId( "groupId", problems, m.getGroupId(), m ); |
| |
| validateId( "artifactId", problems, m.getArtifactId(), m ); |
| |
| validateStringNotEmpty( "packaging", problems, Severity.ERROR, Version.BASE, m.getPackaging(), m ); |
| |
| if ( !m.getModules().isEmpty() ) |
| { |
| if ( !"pom".equals( m.getPackaging() ) ) |
| { |
| addViolation( problems, Severity.ERROR, Version.BASE, "packaging", null, "with value '" |
| + m.getPackaging() + "' is invalid. Aggregator projects " + "require 'pom' as packaging.", m ); |
| } |
| |
| for ( int i = 0, n = m.getModules().size(); i < n; i++ ) |
| { |
| String module = m.getModules().get( i ); |
| if ( StringUtils.isBlank( module ) ) |
| { |
| addViolation( problems, Severity.ERROR, Version.BASE, "modules.module[" + i + "]", null, |
| "has been specified without a path to the project directory.", |
| m.getLocation( "modules" ) ); |
| } |
| } |
| } |
| |
| validateStringNotEmpty( "version", problems, Severity.ERROR, Version.BASE, m.getVersion(), m ); |
| |
| Severity errOn30 = getSeverity( request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_0 ); |
| |
| validateEffectiveDependencies( problems, m, m.getDependencies(), false, request ); |
| |
| DependencyManagement mgmt = m.getDependencyManagement(); |
| if ( mgmt != null ) |
| { |
| validateEffectiveDependencies( problems, m, mgmt.getDependencies(), true, request ); |
| } |
| |
| if ( request.getValidationLevel() >= ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0 ) |
| { |
| Severity errOn31 = getSeverity( request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_1 ); |
| |
| validateBannedCharacters( EMPTY, "version", problems, errOn31, Version.V20, m.getVersion(), null, m, |
| ILLEGAL_VERSION_CHARS ); |
| validate20ProperSnapshotVersion( "version", problems, errOn31, Version.V20, m.getVersion(), null, m ); |
| |
| Build build = m.getBuild(); |
| if ( build != null ) |
| { |
| for ( Plugin p : build.getPlugins() ) |
| { |
| validateStringNotEmpty( "build.plugins.plugin.artifactId", problems, Severity.ERROR, Version.V20, |
| p.getArtifactId(), p ); |
| |
| validateStringNotEmpty( "build.plugins.plugin.groupId", problems, Severity.ERROR, Version.V20, |
| p.getGroupId(), p ); |
| |
| validate20PluginVersion( "build.plugins.plugin.version", problems, p.getVersion(), p.getKey(), p, |
| request ); |
| |
| validateBoolean( "build.plugins.plugin.inherited", EMPTY, problems, errOn30, Version.V20, |
| p.getInherited(), p.getKey(), p ); |
| |
| validateBoolean( "build.plugins.plugin.extensions", EMPTY, problems, errOn30, Version.V20, |
| p.getExtensions(), p.getKey(), p ); |
| |
| validate20EffectivePluginDependencies( problems, p, request ); |
| } |
| |
| validate20RawResources( problems, build.getResources(), "build.resources.resource.", request ); |
| |
| validate20RawResources( problems, build.getTestResources(), "build.testResources.testResource.", |
| request ); |
| } |
| |
| Reporting reporting = m.getReporting(); |
| if ( reporting != null ) |
| { |
| for ( ReportPlugin p : reporting.getPlugins() ) |
| { |
| validateStringNotEmpty( "reporting.plugins.plugin.artifactId", problems, Severity.ERROR, |
| Version.V20, p.getArtifactId(), p ); |
| |
| validateStringNotEmpty( "reporting.plugins.plugin.groupId", problems, Severity.ERROR, Version.V20, |
| p.getGroupId(), p ); |
| } |
| } |
| |
| for ( Repository repository : m.getRepositories() ) |
| { |
| validate20EffectiveRepository( problems, repository, "repositories.repository.", request ); |
| } |
| |
| for ( Repository repository : m.getPluginRepositories() ) |
| { |
| validate20EffectiveRepository( problems, repository, "pluginRepositories.pluginRepository.", request ); |
| } |
| |
| DistributionManagement distMgmt = m.getDistributionManagement(); |
| if ( distMgmt != null ) |
| { |
| if ( distMgmt.getStatus() != null ) |
| { |
| addViolation( problems, Severity.ERROR, Version.V20, "distributionManagement.status", null, |
| "must not be specified.", distMgmt ); |
| } |
| |
| validate20EffectiveRepository( problems, distMgmt.getRepository(), "distributionManagement.repository.", |
| request ); |
| validate20EffectiveRepository( problems, distMgmt.getSnapshotRepository(), |
| "distributionManagement.snapshotRepository.", request ); |
| } |
| } |
| } |
| |
| private void validate20RawDependencies( ModelProblemCollector problems, List<Dependency> dependencies, |
| String prefix, String prefix2, ModelBuildingRequest request ) |
| { |
| Severity errOn30 = getSeverity( request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_0 ); |
| Severity errOn31 = getSeverity( request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_1 ); |
| |
| Map<String, Dependency> index = new HashMap<>(); |
| |
| for ( Dependency dependency : dependencies ) |
| { |
| String key = dependency.getManagementKey(); |
| |
| if ( "import".equals( dependency.getScope() ) ) |
| { |
| if ( !"pom".equals( dependency.getType() ) ) |
| { |
| addViolation( problems, Severity.WARNING, Version.V20, prefix + prefix2 + "type", key, |
| "must be 'pom' to import the managed dependencies.", dependency ); |
| } |
| else if ( StringUtils.isNotEmpty( dependency.getClassifier() ) ) |
| { |
| addViolation( problems, errOn30, Version.V20, prefix + prefix2 + "classifier", key, |
| "must be empty, imported POM cannot have a classifier.", dependency ); |
| } |
| } |
| else if ( "system".equals( dependency.getScope() ) ) |
| { |
| |
| if ( request.getValidationLevel() >= ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_1 ) |
| { |
| addViolation( problems, Severity.WARNING, Version.V31, prefix + prefix2 + "scope", key, |
| "declares usage of deprecated 'system' scope ", dependency ); |
| } |
| |
| String sysPath = dependency.getSystemPath(); |
| if ( StringUtils.isNotEmpty( sysPath ) ) |
| { |
| if ( !hasExpression( sysPath ) ) |
| { |
| addViolation( problems, Severity.WARNING, Version.V20, prefix + prefix2 + "systemPath", key, |
| "should use a variable instead of a hard-coded path " + sysPath, dependency ); |
| } |
| else if ( sysPath.contains( "${basedir}" ) || sysPath.contains( "${project.basedir}" ) ) |
| { |
| addViolation( problems, Severity.WARNING, Version.V20, prefix + prefix2 + "systemPath", key, |
| "should not point at files within the project directory, " + sysPath |
| + " will be unresolvable by dependent projects", |
| dependency ); |
| } |
| } |
| } |
| |
| if ( equals( "LATEST", dependency.getVersion() ) || equals( "RELEASE", dependency.getVersion() ) ) |
| { |
| addViolation( problems, Severity.WARNING, Version.BASE, prefix + prefix2 + "version", key, |
| "is either LATEST or RELEASE (both of them are being deprecated)", dependency ); |
| } |
| |
| Dependency existing = index.get( key ); |
| |
| if ( existing != null ) |
| { |
| String msg; |
| if ( equals( existing.getVersion(), dependency.getVersion() ) ) |
| { |
| msg = "duplicate declaration of version " |
| + Objects.toString( dependency.getVersion(), "(?)" ); |
| } |
| else |
| { |
| msg = "version " + Objects.toString( existing.getVersion(), "(?)" ) + " vs " |
| + Objects.toString( dependency.getVersion(), "(?)" ); |
| } |
| |
| addViolation( problems, errOn31, Version.V20, prefix + prefix2 + "(groupId:artifactId:type:classifier)", |
| null, "must be unique: " + key + " -> " + msg, dependency ); |
| } |
| else |
| { |
| index.put( key, dependency ); |
| } |
| } |
| } |
| |
| private void validate20RawDependenciesSelfReferencing( ModelProblemCollector problems, Model m, |
| List<Dependency> dependencies, String prefix, |
| ModelBuildingRequest request ) |
| { |
| // We only check for groupId/artifactId/version/classifier cause if there is another |
| // module with the same groupId/artifactId/version/classifier this will fail the build |
| // earlier like "Project '...' is duplicated in the reactor. |
| // So it is sufficient to check only groupId/artifactId/version/classifier and not the |
| // packaging type. |
| for ( Dependency dependency : dependencies ) |
| { |
| String key = dependency.getGroupId() + ":" + dependency.getArtifactId() + ":" + dependency.getVersion() |
| + ( dependency.getClassifier() != null ? ":" + dependency.getClassifier() : EMPTY ); |
| String mKey = m.getGroupId() + ":" + m.getArtifactId() + ":" + m.getVersion(); |
| if ( key.equals( mKey ) ) |
| { |
| // This means a module which is build has a dependency which has the same |
| // groupId, artifactId, version and classifier coordinates. This is in consequence |
| // a self reference or in other words a circular reference which can not being resolved. |
| addViolation( problems, Severity.FATAL, Version.V31, prefix + "[" + key + "]", key, |
| "is referencing itself.", dependency ); |
| |
| } |
| } |
| } |
| |
| private void validateEffectiveDependencies( ModelProblemCollector problems, Model m, List<Dependency> dependencies, |
| boolean management, ModelBuildingRequest request ) |
| { |
| Severity errOn30 = getSeverity( request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_0 ); |
| |
| String prefix = management ? "dependencyManagement.dependencies.dependency." : "dependencies.dependency."; |
| |
| for ( Dependency d : dependencies ) |
| { |
| validateEffectiveDependency( problems, d, management, prefix, request ); |
| |
| if ( request.getValidationLevel() >= ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0 ) |
| { |
| validateBoolean( prefix, "optional", problems, errOn30, Version.V20, d.getOptional(), |
| d.getManagementKey(), d ); |
| |
| if ( !management ) |
| { |
| validateVersion( prefix, "version", problems, errOn30, Version.V20, d.getVersion(), |
| d.getManagementKey(), d ); |
| |
| /* |
| * TODO Extensions like Flex Mojos use custom scopes like "merged", "internal", "external", etc. In |
| * order to don't break backward-compat with those, only warn but don't error out. |
| */ |
| validateEnum( prefix, "scope", problems, Severity.WARNING, Version.V20, d.getScope(), |
| d.getManagementKey(), d, "provided", "compile", "runtime", "test", "system" ); |
| |
| validateEffectiveModelAgainstDependency( prefix, problems, m, d, request ); |
| } |
| else |
| { |
| validateEnum( prefix, "scope", problems, Severity.WARNING, Version.V20, d.getScope(), |
| d.getManagementKey(), d, "provided", "compile", "runtime", "test", "system", |
| "import" ); |
| } |
| } |
| } |
| } |
| |
| private void validateEffectiveModelAgainstDependency( String prefix, ModelProblemCollector problems, Model m, |
| Dependency d, ModelBuildingRequest request ) |
| { |
| String key = d.getGroupId() + ":" + d.getArtifactId() + ":" + d.getVersion() |
| + ( d.getClassifier() != null ? ":" + d.getClassifier() : EMPTY ); |
| String mKey = m.getGroupId() + ":" + m.getArtifactId() + ":" + m.getVersion(); |
| if ( key.equals( mKey ) ) |
| { |
| // This means a module which is build has a dependency which has the same |
| // groupId, artifactId, version and classifier coordinates. This is in consequence |
| // a self reference or in other words a circular reference which can not being resolved. |
| addViolation( problems, Severity.FATAL, Version.V31, prefix + "[" + key + "]", key, |
| "is referencing itself.", d ); |
| |
| } |
| |
| } |
| |
| private void validate20EffectivePluginDependencies( ModelProblemCollector problems, Plugin plugin, |
| ModelBuildingRequest request ) |
| { |
| List<Dependency> dependencies = plugin.getDependencies(); |
| |
| if ( !dependencies.isEmpty() ) |
| { |
| String prefix = "build.plugins.plugin[" + plugin.getKey() + "].dependencies.dependency."; |
| |
| Severity errOn30 = getSeverity( request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_0 ); |
| |
| for ( Dependency d : dependencies ) |
| { |
| validateEffectiveDependency( problems, d, false, prefix, request ); |
| |
| validateVersion( prefix, "version", problems, errOn30, Version.BASE, d.getVersion(), |
| d.getManagementKey(), d ); |
| |
| validateEnum( prefix, "scope", problems, errOn30, Version.BASE, d.getScope(), d.getManagementKey(), d, |
| "compile", "runtime", "system" ); |
| } |
| } |
| } |
| |
| private void validateEffectiveDependency( ModelProblemCollector problems, Dependency d, boolean management, |
| String prefix, ModelBuildingRequest request ) |
| { |
| validateId( prefix, "artifactId", problems, Severity.ERROR, Version.BASE, d.getArtifactId(), |
| d.getManagementKey(), d ); |
| |
| validateId( prefix, "groupId", problems, Severity.ERROR, Version.BASE, d.getGroupId(), |
| d.getManagementKey(), d ); |
| |
| if ( !management ) |
| { |
| validateStringNotEmpty( prefix, "type", problems, Severity.ERROR, Version.BASE, d.getType(), |
| d.getManagementKey(), d ); |
| |
| validateDependencyVersion( problems, d, prefix ); |
| } |
| |
| if ( "system".equals( d.getScope() ) ) |
| { |
| String systemPath = d.getSystemPath(); |
| |
| if ( StringUtils.isEmpty( systemPath ) ) |
| { |
| addViolation( problems, Severity.ERROR, Version.BASE, prefix + "systemPath", d.getManagementKey(), |
| "is missing.", d ); |
| } |
| else |
| { |
| File sysFile = new File( systemPath ); |
| if ( !sysFile.isAbsolute() ) |
| { |
| addViolation( problems, Severity.ERROR, Version.BASE, prefix + "systemPath", d.getManagementKey(), |
| "must specify an absolute path but is " + systemPath, d ); |
| } |
| else if ( !sysFile.isFile() ) |
| { |
| String msg = "refers to a non-existing file " + sysFile.getAbsolutePath(); |
| systemPath = systemPath.replace( '/', File.separatorChar ).replace( '\\', File.separatorChar ); |
| String jdkHome = |
| request.getSystemProperties().getProperty( "java.home", EMPTY ) + File.separator + ".."; |
| if ( systemPath.startsWith( jdkHome ) ) |
| { |
| msg += ". Please verify that you run Maven using a JDK and not just a JRE."; |
| } |
| addViolation( problems, Severity.WARNING, Version.BASE, prefix + "systemPath", d.getManagementKey(), |
| msg, d ); |
| } |
| } |
| } |
| else if ( StringUtils.isNotEmpty( d.getSystemPath() ) ) |
| { |
| addViolation( problems, Severity.ERROR, Version.BASE, prefix + "systemPath", d.getManagementKey(), |
| "must be omitted." + " This field may only be specified for a dependency with system scope.", |
| d ); |
| } |
| |
| if ( request.getValidationLevel() >= ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0 ) |
| { |
| for ( Exclusion exclusion : d.getExclusions() ) |
| { |
| if ( request.getValidationLevel() < ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_0 ) |
| { |
| validateId( prefix, "exclusions.exclusion.groupId", problems, Severity.WARNING, Version.V20, |
| exclusion.getGroupId(), d.getManagementKey(), exclusion ); |
| |
| validateId( prefix, "exclusions.exclusion.artifactId", problems, Severity.WARNING, Version.V20, |
| exclusion.getArtifactId(), d.getManagementKey(), exclusion ); |
| } |
| else |
| { |
| validateIdWithWildcards( prefix, "exclusions.exclusion.groupId", problems, Severity.WARNING, |
| Version.V30, exclusion.getGroupId(), d.getManagementKey(), exclusion ); |
| |
| validateIdWithWildcards( prefix, "exclusions.exclusion.artifactId", problems, Severity.WARNING, |
| Version.V30, exclusion.getArtifactId(), d.getManagementKey(), exclusion ); |
| } |
| } |
| } |
| } |
| |
| /** |
| * @since 3.2.4 |
| */ |
| protected void validateDependencyVersion( ModelProblemCollector problems, Dependency d, String prefix ) |
| { |
| validateStringNotEmpty( prefix, "version", problems, Severity.ERROR, Version.BASE, d.getVersion(), |
| d.getManagementKey(), d ); |
| } |
| |
| private void validateRawRepositories( ModelProblemCollector problems, List<Repository> repositories, String prefix, |
| String prefix2, ModelBuildingRequest request ) |
| { |
| Map<String, Repository> index = new HashMap<>(); |
| |
| for ( Repository repository : repositories ) |
| { |
| validateStringNotEmpty( prefix, prefix2, "id", problems, Severity.ERROR, Version.V20, repository.getId(), |
| null, repository ); |
| |
| validateStringNotEmpty( prefix, prefix2, "[" + repository.getId() + "].url", problems, Severity.ERROR, |
| Version.V20, repository.getUrl(), null, repository ); |
| |
| String key = repository.getId(); |
| |
| Repository existing = index.get( key ); |
| |
| if ( existing != null ) |
| { |
| Severity errOn30 = getSeverity( request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_0 ); |
| |
| addViolation( problems, errOn30, Version.V20, prefix + prefix2 + "id", null, "must be unique: " |
| + repository.getId() + " -> " + existing.getUrl() + " vs " + repository.getUrl(), repository ); |
| } |
| else |
| { |
| index.put( key, repository ); |
| } |
| } |
| } |
| |
| private void validate20EffectiveRepository( ModelProblemCollector problems, Repository repository, String prefix, |
| ModelBuildingRequest request ) |
| { |
| if ( repository != null ) |
| { |
| Severity errOn31 = getSeverity( request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_1 ); |
| |
| validateBannedCharacters( prefix, "id", problems, errOn31, Version.V20, repository.getId(), null, |
| repository, ILLEGAL_REPO_ID_CHARS ); |
| |
| if ( "local".equals( repository.getId() ) ) |
| { |
| addViolation( problems, errOn31, Version.V20, prefix + "id", null, |
| "must not be 'local'" + ", this identifier is reserved for the local repository" |
| + ", using it for other repositories will corrupt your repository metadata.", |
| repository ); |
| } |
| |
| if ( "legacy".equals( repository.getLayout() ) ) |
| { |
| addViolation( problems, Severity.WARNING, Version.V20, prefix + "layout", repository.getId(), |
| "uses the unsupported value 'legacy', artifact resolution might fail.", repository ); |
| } |
| } |
| } |
| |
| private void validate20RawResources( ModelProblemCollector problems, List<Resource> resources, String prefix, |
| ModelBuildingRequest request ) |
| { |
| Severity errOn30 = getSeverity( request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_0 ); |
| |
| for ( Resource resource : resources ) |
| { |
| validateStringNotEmpty( prefix, "directory", problems, Severity.ERROR, Version.V20, |
| resource.getDirectory(), null, resource ); |
| |
| validateBoolean( prefix, "filtering", problems, errOn30, Version.V20, resource.getFiltering(), |
| resource.getDirectory(), resource ); |
| } |
| } |
| |
| // ---------------------------------------------------------------------- |
| // Field validation |
| // ---------------------------------------------------------------------- |
| |
| private boolean validateId( String fieldName, ModelProblemCollector problems, String id, |
| InputLocationTracker tracker ) |
| { |
| return validateId( EMPTY, fieldName, problems, Severity.ERROR, Version.BASE, id, null, tracker ); |
| } |
| |
| @SuppressWarnings( "checkstyle:parameternumber" ) |
| private boolean validateId( String prefix, String fieldName, ModelProblemCollector problems, Severity severity, |
| Version version, String id, String sourceHint, InputLocationTracker tracker ) |
| { |
| if ( validIds.contains( id ) ) |
| { |
| return true; |
| } |
| if ( !validateStringNotEmpty( prefix, fieldName, problems, severity, version, id, sourceHint, tracker ) ) |
| { |
| return false; |
| } |
| else |
| { |
| if ( !isValidId( id ) ) |
| { |
| addViolation( problems, severity, version, prefix + fieldName, sourceHint, |
| "with value '" + id + "' does not match a valid id pattern.", tracker ); |
| return false; |
| } |
| validIds.add( id ); |
| return true; |
| } |
| } |
| |
| private boolean isValidId( String id ) |
| { |
| for ( int i = 0; i < id.length(); i++ ) |
| { |
| char c = id.charAt( i ); |
| if ( !isValidIdCharacter( c ) ) |
| { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| |
| private boolean isValidIdCharacter( char c ) |
| { |
| return c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9' || c == '-' || c == '_' || c == '.'; |
| } |
| |
| @SuppressWarnings( "checkstyle:parameternumber" ) |
| private boolean validateIdWithWildcards( String prefix, String fieldName, ModelProblemCollector problems, |
| Severity severity, Version version, String id, String sourceHint, |
| InputLocationTracker tracker ) |
| { |
| if ( !validateStringNotEmpty( prefix, fieldName, problems, severity, version, id, sourceHint, tracker ) ) |
| { |
| return false; |
| } |
| else |
| { |
| if ( !isValidIdWithWildCards( id ) ) |
| { |
| addViolation( problems, severity, version, prefix + fieldName, sourceHint, |
| "with value '" + id + "' does not match a valid id pattern.", tracker ); |
| return false; |
| } |
| return true; |
| } |
| } |
| |
| private boolean isValidIdWithWildCards( String id ) |
| { |
| for ( int i = 0; i < id.length(); i++ ) |
| { |
| char c = id.charAt( i ); |
| if ( !isValidIdWithWildCardCharacter( c ) ) |
| { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| private boolean isValidIdWithWildCardCharacter( char c ) |
| { |
| return isValidIdCharacter( c ) || c == '?' || c == '*'; |
| } |
| |
| private boolean validateStringNoExpression( String fieldName, ModelProblemCollector problems, Severity severity, |
| Version version, String string, InputLocationTracker tracker ) |
| { |
| if ( !hasExpression( string ) ) |
| { |
| return true; |
| } |
| |
| addViolation( problems, severity, version, fieldName, null, "contains an expression but should be a constant.", |
| tracker ); |
| |
| return false; |
| } |
| |
| private boolean validateVersionNoExpression( String fieldName, ModelProblemCollector problems, Severity severity, |
| Version version, String string, InputLocationTracker tracker ) |
| { |
| if ( !hasExpression( string ) ) |
| { |
| return true; |
| } |
| |
| // |
| // Acceptable versions for continuous delivery |
| // |
| // changelist |
| // revision |
| // sha1 |
| // |
| Matcher m = CI_FRIENDLY_EXPRESSION.matcher( string.trim() ); |
| while ( m.find() ) |
| { |
| if ( !CI_FRIENDLY_POSSIBLE_PROPERTY_NAMES.contains( m.group( 1 ) ) ) |
| { |
| addViolation( problems, severity, version, fieldName, null, |
| "contains an expression but should be a constant.", tracker ); |
| |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| private boolean hasExpression( String value ) |
| { |
| return value != null && value.contains( "${" ); |
| } |
| |
| private boolean hasProjectExpression( String value ) |
| { |
| return value != null && value.contains( "${project." ); |
| } |
| |
| private boolean validateStringNotEmpty( String fieldName, ModelProblemCollector problems, Severity severity, |
| Version version, String string, InputLocationTracker tracker ) |
| { |
| return validateStringNotEmpty( EMPTY, fieldName, problems, severity, version, string, null, tracker ); |
| } |
| |
| /** |
| * Asserts: |
| * <p/> |
| * <ul> |
| * <li><code>string != null</code> |
| * <li><code>string.length > 0</code> |
| * </ul> |
| */ |
| @SuppressWarnings( "checkstyle:parameternumber" ) |
| private boolean validateStringNotEmpty( String prefix, String prefix2, String fieldName, |
| ModelProblemCollector problems, Severity severity, Version version, |
| String string, String sourceHint, InputLocationTracker tracker ) |
| { |
| if ( !validateNotNull( prefix, prefix2, fieldName, problems, severity, version, string, sourceHint, tracker ) ) |
| { |
| return false; |
| } |
| |
| if ( !string.isEmpty() ) |
| { |
| return true; |
| } |
| |
| addViolation( problems, severity, version, prefix + prefix2 + fieldName, sourceHint, "is missing.", tracker ); |
| |
| return false; |
| } |
| |
| /** |
| * Asserts: |
| * <p/> |
| * <ul> |
| * <li><code>string != null</code> |
| * <li><code>string.length > 0</code> |
| * </ul> |
| */ |
| @SuppressWarnings( "checkstyle:parameternumber" ) |
| private boolean validateStringNotEmpty( String prefix, String fieldName, ModelProblemCollector problems, |
| Severity severity, Version version, String string, String sourceHint, |
| InputLocationTracker tracker ) |
| { |
| if ( !validateNotNull( prefix, fieldName, problems, severity, version, string, sourceHint, tracker ) ) |
| { |
| return false; |
| } |
| |
| if ( string.length() > 0 ) |
| { |
| return true; |
| } |
| |
| addViolation( problems, severity, version, prefix + fieldName, sourceHint, "is missing.", tracker ); |
| |
| return false; |
| } |
| |
| /** |
| * Asserts: |
| * <p/> |
| * <ul> |
| * <li><code>string != null</code> |
| * </ul> |
| */ |
| @SuppressWarnings( "checkstyle:parameternumber" ) |
| private boolean validateNotNull( String prefix, String fieldName, ModelProblemCollector problems, Severity severity, |
| Version version, Object object, String sourceHint, InputLocationTracker tracker ) |
| { |
| if ( object != null ) |
| { |
| return true; |
| } |
| |
| addViolation( problems, severity, version, prefix + fieldName, sourceHint, "is missing.", tracker ); |
| |
| return false; |
| } |
| |
| /** |
| * Asserts: |
| * <p/> |
| * <ul> |
| * <li><code>string != null</code> |
| * </ul> |
| */ |
| @SuppressWarnings( "checkstyle:parameternumber" ) |
| private boolean validateNotNull( String prefix, String prefix2, String fieldName, |
| ModelProblemCollector problems, Severity severity, Version version, |
| Object object, String sourceHint, InputLocationTracker tracker ) |
| { |
| if ( object != null ) |
| { |
| return true; |
| } |
| |
| addViolation( problems, severity, version, prefix + prefix2 + fieldName, sourceHint, "is missing.", tracker ); |
| |
| return false; |
| } |
| |
| @SuppressWarnings( "checkstyle:parameternumber" ) |
| private boolean validateBoolean( String prefix, String fieldName, ModelProblemCollector problems, Severity severity, |
| Version version, String string, String sourceHint, InputLocationTracker tracker ) |
| { |
| if ( string == null || string.length() <= 0 ) |
| { |
| return true; |
| } |
| |
| if ( "true".equalsIgnoreCase( string ) || "false".equalsIgnoreCase( string ) ) |
| { |
| return true; |
| } |
| |
| addViolation( problems, severity, version, prefix + fieldName, sourceHint, |
| "must be 'true' or 'false' but is '" + string + "'.", tracker ); |
| |
| return false; |
| } |
| |
| @SuppressWarnings( "checkstyle:parameternumber" ) |
| private boolean validateEnum( String prefix, String fieldName, ModelProblemCollector problems, Severity severity, |
| Version version, String string, String sourceHint, InputLocationTracker tracker, |
| String... validValues ) |
| { |
| if ( string == null || string.length() <= 0 ) |
| { |
| return true; |
| } |
| |
| List<String> values = Arrays.asList( validValues ); |
| |
| if ( values.contains( string ) ) |
| { |
| return true; |
| } |
| |
| addViolation( problems, severity, version, prefix + fieldName, sourceHint, |
| "must be one of " + values + " but is '" + string + "'.", tracker ); |
| |
| return false; |
| } |
| |
| @SuppressWarnings( "checkstyle:parameternumber" ) |
| private boolean validateModelVersion( ModelProblemCollector problems, String string, InputLocationTracker tracker, |
| String... validVersions ) |
| { |
| if ( string == null || string.length() <= 0 ) |
| { |
| return true; |
| } |
| |
| List<String> values = Arrays.asList( validVersions ); |
| |
| if ( values.contains( string ) ) |
| { |
| return true; |
| } |
| |
| boolean newerThanAll = true; |
| boolean olderThanAll = true; |
| for ( String validValue : validVersions ) |
| { |
| final int comparison = compareModelVersions( validValue, string ); |
| newerThanAll = newerThanAll && comparison < 0; |
| olderThanAll = olderThanAll && comparison > 0; |
| } |
| |
| if ( newerThanAll ) |
| { |
| addViolation( problems, Severity.FATAL, Version.V20, "modelVersion", null, |
| "of '" + string + "' is newer than the versions supported by this version of Maven: " + values |
| + ". Building this project requires a newer version of Maven.", tracker ); |
| |
| } |
| else if ( olderThanAll ) |
| { |
| // note this will not be hit for Maven 1.x project.xml as it is an incompatible schema |
| addViolation( problems, Severity.FATAL, Version.V20, "modelVersion", null, |
| "of '" + string + "' is older than the versions supported by this version of Maven: " + values |
| + ". Building this project requires an older version of Maven.", tracker ); |
| |
| } |
| else |
| { |
| addViolation( problems, Severity.ERROR, Version.V20, "modelVersion", null, |
| "must be one of " + values + " but is '" + string + "'.", tracker ); |
| } |
| |
| return false; |
| } |
| |
| /** |
| * Compares two model versions. |
| * |
| * @param first the first version. |
| * @param second the second version. |
| * @return negative if the first version is newer than the second version, zero if they are the same or positive if |
| * the second version is the newer. |
| */ |
| private static int compareModelVersions( String first, String second ) |
| { |
| // we use a dedicated comparator because we control our model version scheme. |
| String[] firstSegments = StringUtils.split( first, "." ); |
| String[] secondSegments = StringUtils.split( second, "." ); |
| for ( int i = 0; i < Math.min( firstSegments.length, secondSegments.length ); i++ ) |
| { |
| int result = Long.valueOf( firstSegments[i] ).compareTo( Long.valueOf( secondSegments[i] ) ); |
| if ( result != 0 ) |
| { |
| return result; |
| } |
| } |
| if ( firstSegments.length == secondSegments.length ) |
| { |
| return 0; |
| } |
| return firstSegments.length > secondSegments.length ? -1 : 1; |
| } |
| |
| @SuppressWarnings( "checkstyle:parameternumber" ) |
| private boolean validateBannedCharacters( String prefix, String fieldName, ModelProblemCollector problems, |
| Severity severity, Version version, String string, String sourceHint, |
| InputLocationTracker tracker, String banned ) |
| { |
| if ( string != null ) |
| { |
| for ( int i = string.length() - 1; i >= 0; i-- ) |
| { |
| if ( banned.indexOf( string.charAt( i ) ) >= 0 ) |
| { |
| addViolation( problems, severity, version, prefix + fieldName, sourceHint, |
| "must not contain any of these characters " + banned + " but found " |
| + string.charAt( i ), |
| tracker ); |
| return false; |
| } |
| } |
| } |
| |
| return true; |
| } |
| |
| @SuppressWarnings( "checkstyle:parameternumber" ) |
| private boolean validateVersion( String prefix, String fieldName, ModelProblemCollector problems, Severity severity, |
| Version version, String string, String sourceHint, InputLocationTracker tracker ) |
| { |
| if ( string == null || string.length() <= 0 ) |
| { |
| return true; |
| } |
| |
| if ( hasExpression( string ) ) |
| { |
| addViolation( problems, severity, version, prefix + fieldName, sourceHint, |
| "must be a valid version but is '" + string + "'.", tracker ); |
| return false; |
| } |
| |
| return validateBannedCharacters( prefix, fieldName, problems, severity, version, string, sourceHint, tracker, |
| ILLEGAL_VERSION_CHARS ); |
| |
| } |
| |
| private boolean validate20ProperSnapshotVersion( String fieldName, ModelProblemCollector problems, |
| Severity severity, Version version, String string, |
| String sourceHint, InputLocationTracker tracker ) |
| { |
| if ( string == null || string.length() <= 0 ) |
| { |
| return true; |
| } |
| |
| if ( string.endsWith( "SNAPSHOT" ) && !string.endsWith( "-SNAPSHOT" ) ) |
| { |
| addViolation( problems, severity, version, fieldName, sourceHint, |
| "uses an unsupported snapshot version format, should be '*-SNAPSHOT' instead.", tracker ); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| private boolean validate20PluginVersion( String fieldName, ModelProblemCollector problems, String string, |
| String sourceHint, InputLocationTracker tracker, |
| ModelBuildingRequest request ) |
| { |
| if ( string == null ) |
| { |
| // NOTE: The check for missing plugin versions is handled directly by the model builder |
| return true; |
| } |
| |
| Severity errOn30 = getSeverity( request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_0 ); |
| |
| if ( !validateVersion( EMPTY, fieldName, problems, errOn30, Version.V20, string, sourceHint, tracker ) ) |
| { |
| return false; |
| } |
| |
| if ( string.length() <= 0 || "RELEASE".equals( string ) || "LATEST".equals( string ) ) |
| { |
| addViolation( problems, errOn30, Version.V20, fieldName, sourceHint, |
| "must be a valid version but is '" + string + "'.", tracker ); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| private static void addViolation( ModelProblemCollector problems, Severity severity, Version version, |
| String fieldName, String sourceHint, String message, |
| InputLocationTracker tracker ) |
| { |
| StringBuilder buffer = new StringBuilder( 256 ); |
| buffer.append( '\'' ).append( fieldName ).append( '\'' ); |
| |
| if ( sourceHint != null ) |
| { |
| buffer.append( " for " ).append( sourceHint ); |
| } |
| |
| buffer.append( ' ' ).append( message ); |
| |
| // CHECKSTYLE_OFF: LineLength |
| problems.add( new ModelProblemCollectorRequest( severity, version ).setMessage( |
| buffer.toString() ).setLocation( getLocation( fieldName, tracker ) ) ); |
| // CHECKSTYLE_ON: LineLength |
| } |
| |
| private static InputLocation getLocation( String fieldName, InputLocationTracker tracker ) |
| { |
| InputLocation location = null; |
| |
| if ( tracker != null ) |
| { |
| if ( fieldName != null ) |
| { |
| Object key = fieldName; |
| |
| int idx = fieldName.lastIndexOf( '.' ); |
| if ( idx >= 0 ) |
| { |
| fieldName = fieldName.substring( idx + 1 ); |
| key = fieldName; |
| } |
| |
| if ( fieldName.endsWith( "]" ) ) |
| { |
| key = fieldName.substring( fieldName.lastIndexOf( '[' ) + 1, fieldName.length() - 1 ); |
| try |
| { |
| key = Integer.valueOf( key.toString() ); |
| } |
| catch ( NumberFormatException e ) |
| { |
| // use key as is |
| } |
| } |
| |
| location = tracker.getLocation( key ); |
| } |
| |
| if ( location == null ) |
| { |
| location = tracker.getLocation( EMPTY ); |
| } |
| } |
| |
| return location; |
| } |
| |
| private static boolean equals( String s1, String s2 ) |
| { |
| return StringUtils.clean( s1 ).equals( StringUtils.clean( s2 ) ); |
| } |
| |
| private static Severity getSeverity( ModelBuildingRequest request, int errorThreshold ) |
| { |
| return getSeverity( request.getValidationLevel(), errorThreshold ); |
| } |
| |
| private static Severity getSeverity( int validationLevel, int errorThreshold ) |
| { |
| if ( validationLevel < errorThreshold ) |
| { |
| return Severity.WARNING; |
| } |
| else |
| { |
| return Severity.ERROR; |
| } |
| } |
| |
| } |