summaryrefslogtreecommitdiffstats
path: root/src/main
diff options
context:
space:
mode:
authormark.j.leonard <mark.j.leonard@gmail.com>2019-02-14 13:51:11 +0000
committermark.j.leonard <mark.j.leonard@gmail.com>2019-02-14 13:51:11 +0000
commit13b3d5d42bae10ce2733c86814177c3e31eb2014 (patch)
tree9ece0ac87d1725891a0bcaed8c186af0b74d563a /src/main
parentc9cdd245b2b575164a11785ab7a4710395f950c7 (diff)
Add support for common rules across types
Refactor the Rule Driven Validator implementation for loading the Groovy rules. Firstly, support multiple top-level folders. Secondly, include each top-level folder in the set of paths to search for *.groovy files. Pull a common rule up to the top-level to remove the duplication. Add tests to exercise the exception handling code. Change-Id: Ib70fe03ab5b1f2f8c1711760236b07850aaaa398 Issue-ID: AAI-2155 Signed-off-by: mark.j.leonard <mark.j.leonard@gmail.com>
Diffstat (limited to 'src/main')
-rw-r--r--src/main/java/org/onap/aai/validation/ruledriven/RuleDrivenValidator.java141
-rw-r--r--src/main/java/org/onap/aai/validation/ruledriven/rule/GroovyRule.java16
-rw-r--r--src/main/java/org/onap/aai/validation/ruledriven/rule/Rule.java15
3 files changed, 118 insertions, 54 deletions
diff --git a/src/main/java/org/onap/aai/validation/ruledriven/RuleDrivenValidator.java b/src/main/java/org/onap/aai/validation/ruledriven/RuleDrivenValidator.java
index 4b22d77..5ca7025 100644
--- a/src/main/java/org/onap/aai/validation/ruledriven/RuleDrivenValidator.java
+++ b/src/main/java/org/onap/aai/validation/ruledriven/RuleDrivenValidator.java
@@ -27,7 +27,6 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.text.MessageFormat;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
@@ -36,6 +35,8 @@ import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.commons.lang.StringUtils;
import org.onap.aai.validation.Validator;
@@ -68,7 +69,12 @@ public class RuleDrivenValidator implements Validator {
private static final String RULES_CONFIG_FILE_SUFFIX = ".groovy";
- private Path configurationPath;
+ /**
+ * The set of directories/folders containing the rules configuration files. Rules that are common to all event types
+ * will be stored in a file directly under a specified Path. Rules which are specific to a named event type will be
+ * stored in a direct child directory.
+ */
+ private Collection<Path> configurationPaths;
private OxmReader oxmReader;
private EventReader eventReader;
private Optional<RuleIndexingConfig> ruleIndexingConfig;
@@ -78,17 +84,17 @@ public class RuleDrivenValidator implements Validator {
/**
* Construct a Validator that is configured using rule files.
*
- * @param configurationPath
- * path to the Groovy rules files
+ * @param configurationPaths
+ * paths to the Groovy rules files and sub-folders
* @param oxmReader
* required for validating entity types
* @param eventReader
* a reader for extracting entities from each event to be validated
* @param ruleIndexingConfig
*/
- public RuleDrivenValidator(final Path configurationPath, final OxmReader oxmReader, final EventReader eventReader,
- final RuleIndexingConfig ruleIndexingConfig) {
- this.configurationPath = configurationPath;
+ public RuleDrivenValidator(final List<Path> configurationPaths, final OxmReader oxmReader,
+ final EventReader eventReader, final RuleIndexingConfig ruleIndexingConfig) {
+ this.configurationPaths = configurationPaths;
this.oxmReader = oxmReader;
this.eventReader = eventReader;
this.ruleIndexingConfig = Optional.ofNullable(ruleIndexingConfig);
@@ -104,38 +110,6 @@ public class RuleDrivenValidator implements Validator {
validateRulesConfiguration();
}
- private RuleManager loadRulesConfiguration(String eventType) throws ValidationServiceException {
- StringBuilder rulesText = new StringBuilder();
- try (Stream<Path> paths = Files.find(configurationPath.resolve(eventType), 1,
- (path, basicFileAttributes) -> path.toFile().getName().matches(".*\\" + RULES_CONFIG_FILE_SUFFIX));) {
- paths.forEach(appendFileContent(rulesText));
- } catch (IOException e) {
- throw new ValidationServiceException(ValidationServiceError.RULES_FILE_ERROR,
- configurationPath.toAbsolutePath(), e);
- }
-
- try {
- return RulesConfigurationLoader.loadConfiguration(rulesText.toString());
- } catch (GroovyConfigurationException e) {
- throw new ValidationServiceException(ValidationServiceError.RULES_FILE_ERROR, e,
- configurationPath.toAbsolutePath() + File.separator + "*" + RULES_CONFIG_FILE_SUFFIX);
- }
- }
-
- private void validateRulesConfiguration() throws ValidationServiceException {
- for (RuleManager ruleManager : ruleManagers.values()) {
- for (EntitySection entity : ruleManager.getEntities()) {
- if (ruleIndexingConfig.isPresent() && ruleIndexingConfig.get().skipOxmValidation(entity.getName())) {
- continue;
- }
- if (oxmReader != null && oxmReader.getPrimaryKeys(entity.getName()).isEmpty()) {
- throw new ValidationServiceException(ValidationServiceError.OXM_MISSING_KEY,
- entity.getName() + " defined in " + configurationPath.toAbsolutePath() + File.separator
- + "*" + RULES_CONFIG_FILE_SUFFIX);
- }
- }
- }
- }
/**
* Helper method to expose the configured rules. This simplifies testing of the validator.
@@ -203,6 +177,81 @@ public class RuleDrivenValidator implements Validator {
return validationResults;
}
+ /**
+ * Find and concatenate the text content of all common rules files, and all the eventType-specific rules files.
+ * Invoke the Configuration Loader to parse the text content and create the Groovy Rules.
+ *
+ * @param eventType
+ * @return
+ * @throws ValidationServiceException
+ */
+ private RuleManager loadRulesConfiguration(String eventType) throws ValidationServiceException {
+ StringBuilder rulesText = new StringBuilder();
+
+ Stream.concat(getGroovyRulePaths(Optional.of(eventType)), getGroovyRulePaths(Optional.empty()))
+ .forEach(appendFileContent(rulesText));
+
+ try {
+ return RulesConfigurationLoader.loadConfiguration(rulesText.toString());
+ } catch (GroovyConfigurationException e) {
+ throw new ValidationServiceException(ValidationServiceError.RULES_FILE_ERROR, e,
+ getConfigurationPathWildcards());
+ }
+ }
+
+ /**
+ * For logging and error reporting purposes, create a set of Strings each formatted to document the top-level
+ * folders for rules configuration files, and also the file suffix used to find the files.
+ *
+ * @return all the wildcard patterns used for matching rules files
+ */
+ private List<String> getConfigurationPathWildcards() {
+ return configurationPaths.stream()
+ .map(path -> path.toAbsolutePath() + File.separator + "*" + RULES_CONFIG_FILE_SUFFIX)
+ .collect(Collectors.toList());
+ }
+
+ /**
+ * Find all files matching the rules configuration file suffix that are immediate children of a rules configuration
+ * Path. If a subPath is specified then only find files in the resolved subPath.
+ *
+ * @param subPath
+ * an optional subPath (e.g. for an event type)
+ * @return all rules configuration files as Paths
+ * @throws ValidationServiceException
+ * if an I/O error occurs when accessing the file system
+ */
+ private Stream<Path> getGroovyRulePaths(Optional<String> subPath) throws ValidationServiceException {
+ List<Path> groovyRules = new ArrayList<>();
+ for (Path configPath : configurationPaths) {
+ Path rulesPath = subPath.map(configPath::resolve).orElse(configPath);
+ if (rulesPath.toFile().exists()) {
+ try (Stream<Path> stream = Files.find(rulesPath, 1, (path, basicFileAttributes) -> path.toFile()
+ .getName().matches(".*\\" + RULES_CONFIG_FILE_SUFFIX));) {
+ groovyRules.addAll(stream.collect(Collectors.toList()));
+ } catch (IOException e) {
+ throw new ValidationServiceException(ValidationServiceError.RULES_FILE_ERROR,
+ configPath.toAbsolutePath(), e);
+ }
+ }
+ }
+ return groovyRules.stream();
+ }
+
+ private void validateRulesConfiguration() throws ValidationServiceException {
+ for (RuleManager ruleManager : ruleManagers.values()) {
+ for (EntitySection entity : ruleManager.getEntities()) {
+ if (ruleIndexingConfig.isPresent() && ruleIndexingConfig.get().skipOxmValidation(entity.getName())) {
+ continue;
+ }
+ if (oxmReader != null && oxmReader.getPrimaryKeys(entity.getName()).isEmpty()) {
+ throw new ValidationServiceException(ValidationServiceError.OXM_MISSING_KEY,
+ entity.getName() + " defined in " + getConfigurationPathWildcards());
+ }
+ }
+ }
+ }
+
private Optional<List<Rule>> getRulesToApply(Entity entity, Optional<String> eventType)
throws ValidationServiceException {
Optional<List<Rule>> rules = Optional.empty();
@@ -292,7 +341,17 @@ public class RuleDrivenValidator implements Validator {
}
private Collection<String> getSupportedEventTypes() {
- String[] list = configurationPath.toFile().list((current, name) -> new File(current, name).isDirectory());
- return list == null ? Collections.emptyList() : Arrays.asList(list);
+ Function<? super Path, ? extends Stream<? extends Path>> getDirectories = path -> {
+ try {
+ return Files.walk(path, 1).filter(Files::isDirectory);
+ } catch (IOException e) {
+ applicationLogger.error(ApplicationMsgs.READ_FILE_ERROR, e, "from the rules configuration path");
+ return Stream.empty();
+ }
+ };
+ return configurationPaths.stream() //
+ .flatMap(getDirectories) //
+ .map(path -> path.getFileName().toString()) //
+ .collect(Collectors.toList());
}
}
diff --git a/src/main/java/org/onap/aai/validation/ruledriven/rule/GroovyRule.java b/src/main/java/org/onap/aai/validation/ruledriven/rule/GroovyRule.java
index df15791..d8cd61e 100644
--- a/src/main/java/org/onap/aai/validation/ruledriven/rule/GroovyRule.java
+++ b/src/main/java/org/onap/aai/validation/ruledriven/rule/GroovyRule.java
@@ -1,19 +1,22 @@
-/*
- * ============LICENSE_START===================================================
- * Copyright (c) 2018 Amdocs
- * ============================================================================
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright (c) 2018-2019 AT&T Intellectual Property. All rights reserved.
+ * Copyright (c) 2018-2019 European Software Marketing Ltd.
+ * ================================================================================
* Licensed 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
+ * 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.
- * ============LICENSE_END=====================================================
+ * ============LICENSE_END=========================================================
*/
package org.onap.aai.validation.ruledriven.rule;
@@ -65,7 +68,6 @@ public class GroovyRule implements Rule {
private boolean ruleIsValid = true;
private String name;
-
/**
* @param ruleConfig
* @throws InstantiationException
diff --git a/src/main/java/org/onap/aai/validation/ruledriven/rule/Rule.java b/src/main/java/org/onap/aai/validation/ruledriven/rule/Rule.java
index 60705ea..e4c2078 100644
--- a/src/main/java/org/onap/aai/validation/ruledriven/rule/Rule.java
+++ b/src/main/java/org/onap/aai/validation/ruledriven/rule/Rule.java
@@ -1,19 +1,22 @@
-/*
- * ============LICENSE_START===================================================
- * Copyright (c) 2018 Amdocs
- * ============================================================================
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright (c) 2018-2019 AT&T Intellectual Property. All rights reserved.
+ * Copyright (c) 2018-2019 European Software Marketing Ltd.
+ * ================================================================================
* Licensed 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
+ * 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.
- * ============LICENSE_END=====================================================
+ * ============LICENSE_END=========================================================
*/
package org.onap.aai.validation.ruledriven.rule;