From 206509af76604e2777e9125163785de4494187c2 Mon Sep 17 00:00:00 2001 From: Luis Pabon Date: Fri, 22 Mar 2024 17:05:56 -0400 Subject: [PATCH] Load rules via stream --- .../etor/ruleengine/RuleEngine.java | 22 ++++++++++--------- .../etor/ruleengine/RuleLoader.java | 12 ++++------ .../etor/ruleengine/RuleEngineTest.groovy | 10 ++++----- .../etor/ruleengine/RuleLoaderTest.groovy | 16 +++++--------- 4 files changed, 25 insertions(+), 35 deletions(-) diff --git a/etor/src/main/java/gov/hhs/cdc/trustedintermediary/etor/ruleengine/RuleEngine.java b/etor/src/main/java/gov/hhs/cdc/trustedintermediary/etor/ruleengine/RuleEngine.java index 95fb0a51f..81f3125d2 100644 --- a/etor/src/main/java/gov/hhs/cdc/trustedintermediary/etor/ruleengine/RuleEngine.java +++ b/etor/src/main/java/gov/hhs/cdc/trustedintermediary/etor/ruleengine/RuleEngine.java @@ -1,7 +1,9 @@ package gov.hhs.cdc.trustedintermediary.etor.ruleengine; import gov.hhs.cdc.trustedintermediary.wrappers.Logger; -import java.nio.file.Path; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; import javax.inject.Inject; @@ -10,9 +12,6 @@ /** Manages the application of rules loaded from a definitions file using the RuleLoader. */ public class RuleEngine { - private final Path RULES_DEFINITIONS_PATH = - Path.of("../etor/src/main/resources/rule_definitions.json"); - private static final RuleEngine INSTANCE = new RuleEngine(); final List rules = new ArrayList<>(); @@ -37,12 +36,15 @@ public void ensureRulesLoaded() { } private synchronized void loadRules() { - logger.logInfo("Loading rules definitions from " + RULES_DEFINITIONS_PATH); - try { - var loadedRules = ruleLoader.loadRules(RULES_DEFINITIONS_PATH); - rules.addAll(loadedRules); - } catch (RuleLoaderException e) { - logger.logError("Failed to load rules definitions from: " + RULES_DEFINITIONS_PATH, e); + String fileName = "rule_definitions.json"; + try (InputStream ruleDefinitionStream = + getClass().getClassLoader().getResourceAsStream(fileName)) { + assert ruleDefinitionStream != null; + var ruleStream = + new String(ruleDefinitionStream.readAllBytes(), StandardCharsets.UTF_8); + rules.addAll(ruleLoader.loadRules(ruleStream)); + } catch (IOException | RuleLoaderException e) { + logger.logError("Failed to load rules definitions from: " + fileName, e); } } diff --git a/etor/src/main/java/gov/hhs/cdc/trustedintermediary/etor/ruleengine/RuleLoader.java b/etor/src/main/java/gov/hhs/cdc/trustedintermediary/etor/ruleengine/RuleLoader.java index 4bf8c8b5d..e583db68b 100644 --- a/etor/src/main/java/gov/hhs/cdc/trustedintermediary/etor/ruleengine/RuleLoader.java +++ b/etor/src/main/java/gov/hhs/cdc/trustedintermediary/etor/ruleengine/RuleLoader.java @@ -4,9 +4,6 @@ import gov.hhs.cdc.trustedintermediary.wrappers.formatter.Formatter; import gov.hhs.cdc.trustedintermediary.wrappers.formatter.FormatterProcessingException; import gov.hhs.cdc.trustedintermediary.wrappers.formatter.TypeReference; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; import java.util.Collections; import java.util.List; import java.util.Map; @@ -24,15 +21,14 @@ public static RuleLoader getInstance() { return INSTANCE; } - List loadRules(Path configPath) throws RuleLoaderException { + public List loadRules(String ruleStream) throws RuleLoaderException { try { - String fileContent = Files.readString(configPath); Map> jsonObj = - formatter.convertJsonToObject(fileContent, new TypeReference<>() {}); + formatter.convertJsonToObject(ruleStream, new TypeReference<>() {}); return jsonObj.getOrDefault("rules", Collections.emptyList()); - } catch (IOException | FormatterProcessingException e) { + } catch (FormatterProcessingException e) { throw new RuleLoaderException( - "Failed to load rules definitions from: " + configPath, e); + "Failed to load rules definitions for provided stream", e); } } } diff --git a/etor/src/test/groovy/gov/hhs/cdc/trustedintermediary/etor/ruleengine/RuleEngineTest.groovy b/etor/src/test/groovy/gov/hhs/cdc/trustedintermediary/etor/ruleengine/RuleEngineTest.groovy index 157777d35..6219f7610 100644 --- a/etor/src/test/groovy/gov/hhs/cdc/trustedintermediary/etor/ruleengine/RuleEngineTest.groovy +++ b/etor/src/test/groovy/gov/hhs/cdc/trustedintermediary/etor/ruleengine/RuleEngineTest.groovy @@ -5,8 +5,6 @@ import gov.hhs.cdc.trustedintermediary.wrappers.Logger import org.hl7.fhir.r4.model.Bundle import spock.lang.Specification -import java.nio.file.Path - class RuleEngineTest extends Specification { def ruleEngine = RuleEngine.getInstance() def mockRuleLoader = Mock(RuleLoader) @@ -29,7 +27,7 @@ class RuleEngineTest extends Specification { ruleEngine.ensureRulesLoaded() then: - 1 * mockRuleLoader.loadRules(_ as Path) >> [Mock(Rule)] + 1 * mockRuleLoader.loadRules(_ as String) >> [Mock(Rule)] ruleEngine.rules.size() == 1 } @@ -39,13 +37,13 @@ class RuleEngineTest extends Specification { ruleEngine.ensureRulesLoaded() // Call twice to test if rules are loaded only once then: - 1 * mockRuleLoader.loadRules(_ as Path) >> [Mock(Rule)] + 1 * mockRuleLoader.loadRules(_ as String) >> [Mock(Rule)] } def "ensureRulesLoaded logs an error if there is an exception loading the rules"() { given: def exception = new RuleLoaderException("Error loading rules", new Exception()) - mockRuleLoader.loadRules(_ as Path) >> { throw exception } + mockRuleLoader.loadRules(_ as String) >> { throw exception } when: ruleEngine.validate(Mock(Bundle)) @@ -61,7 +59,7 @@ class RuleEngineTest extends Specification { def fhirBundle = Mock(Bundle) def invalidRule = Mock(Rule) invalidRule.getViolationMessage() >> ruleViolationMessage - mockRuleLoader.loadRules(_ as Path) >> [invalidRule] + mockRuleLoader.loadRules(_ as String) >> [invalidRule] when: invalidRule.appliesTo(fhirBundle) >> true diff --git a/etor/src/test/groovy/gov/hhs/cdc/trustedintermediary/etor/ruleengine/RuleLoaderTest.groovy b/etor/src/test/groovy/gov/hhs/cdc/trustedintermediary/etor/ruleengine/RuleLoaderTest.groovy index ff41eef9a..6f3245876 100644 --- a/etor/src/test/groovy/gov/hhs/cdc/trustedintermediary/etor/ruleengine/RuleLoaderTest.groovy +++ b/etor/src/test/groovy/gov/hhs/cdc/trustedintermediary/etor/ruleengine/RuleLoaderTest.groovy @@ -12,7 +12,7 @@ import java.nio.file.Paths class RuleLoaderTest extends Specification { - Path tempRulesFilePath + String fileContents def setup() { TestApplicationContext.reset() @@ -20,8 +20,7 @@ class RuleLoaderTest extends Specification { TestApplicationContext.register(RuleLoader, RuleLoader.getInstance()) TestApplicationContext.injectRegisteredImplementations() - tempRulesFilePath = Files.createTempFile("rules", ".json") - String jsonContent = """ + fileContents = """ { "rules": [ { @@ -32,11 +31,6 @@ class RuleLoaderTest extends Specification { ] } """ - Files.writeString(tempRulesFilePath, jsonContent) - } - - def cleanup() { - Files.deleteIfExists(tempRulesFilePath) } def "load rules from file"() { @@ -46,7 +40,7 @@ class RuleLoaderTest extends Specification { TestApplicationContext.injectRegisteredImplementations() when: - List rules = RuleLoader.getInstance().loadRules(tempRulesFilePath) + List rules = RuleLoader.getInstance().loadRules(fileContents) then: rules.size() == 1 @@ -58,9 +52,9 @@ class RuleLoaderTest extends Specification { ] } - def "handle IOException when loading rules from file"() { + def "handle FormatterProcessingException when loading rules from file"() { when: - RuleLoader.getInstance().loadRules(Paths.get("DogCow")) + RuleLoader.getInstance().loadRules("!K@WJ#8uhy") then: thrown(RuleLoaderException)