That was a really helpful example, thank you Toshiya.
This thread looked very similar to my use case, except that I'm wondering how to implement the same approach using the RuleUnit java DSL api.
When defineRules() is invoked on my RuleUnit class, I load json from a database, and create the rules based upon the json structure. If the rule in the database is updated, I would like to rebuild the rules defined in the rule unit.
Just making a new RuleUnit instance doesn't work. The defineRules() method will not be called again. (Because of an internal HashMap in org.drools.ruleunits.impl.RuleUniProviderImpl that I refer to later on )
Would a reasonable equivalent to the approach earlier in this thread be to implement NamedRuleUnitData, then alter the name to allow new "versions" of the rule to be generated at rumtime?
Here's an example in this test the RuleUnit uses NamedRuleUnitData.
I'm thinking that each time a new version of a given rule unit is created, then I would have to create a new instance of my rule unit class and increment the name ("MyRule-v2", "MyRule-v3", ....).
@Test
public void test() {
LOG.info("Creating RuleUnit");
// Let's imagine this knows how to get a rule name. Maybe something like {rule_name}-{tenant_id}-{rule_version}
// The rule_version portion is incremented if the rule is changed at runtime.
String name = getRuleName();
MeasurementUnit measurementUnit = new MeasurementUnit(name);
RuleUnitInstance<MeasurementUnit> instance = RuleUnitProvider.get().createRuleUnitInstance(measurementUnit);
try {
LOG.info("Insert data");
measurementUnit.getMeasurements().add(new Measurement("color", "red"));
measurementUnit.getMeasurements().add(new Measurement("color", "green"));
measurementUnit.getMeasurements().add(new Measurement("color", "blue"));
LOG.info("Run query. Rules are also fired");
List<Measurement> queryResult = instance.executeQuery("FindColor").toList("$m");
assertEquals(3, queryResult.size());
assertTrue("contains red", measurementUnit.getControlSet().contains("red"));
assertTrue("contains green", measurementUnit.getControlSet().contains("green"));
assertTrue("contains blue", measurementUnit.getControlSet().contains("blue"));
} finally {
instance.close();
}
// Sometime later
String name = getRuleName();
// name has now changed
MeasurementUnit measurementUnit = new MeasurementUnit(name);
try (RuleUnitInstance<MeasurementUnit> instance = RuleUnitProvider.get().createRuleUnitInstance(measurementUnit)) {
// fire rules
}
}
One concern though:
I am concerned though that this would create a memory leak? It appears that there isn't a WeakReference to the RuleUnit used in that ruleUnitMap. There is a ServiceLoader used to load the rule unit class, so perhaps that is destroyed and allows the no-longer-used RuleUnitData to be freed. I didn't follow the code enough to determine if that is true though.
Thanks for you help!
-- Adam