Skip to content

Commit

Permalink
[DROOLS-7416] Rebuild RuleUnit option
Browse files Browse the repository at this point in the history
  • Loading branch information
tkobayas committed Jul 14, 2023
1 parent eeaf429 commit c018b16
Show file tree
Hide file tree
Showing 4 changed files with 185 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,16 @@ public interface RuleUnitProvider extends KieService {
* Provides the {@link RuleUnit} generated for the given {@link RuleUnitData}.
* @return The generated {@link RuleUnit} or null if there's no {@link RuleUnit} generated for the given {@link RuleUnitData}.
*/
<T extends RuleUnitData> RuleUnit<T> getRuleUnit(T ruleUnitData);
default <T extends RuleUnitData> RuleUnit<T> getRuleUnit(T ruleUnitData) {
return getRuleUnit(ruleUnitData, false);
}

/**
* Provides the {@link RuleUnit} generated for the given {@link RuleUnitData}.
* @param rebuild if true, the {@link RuleUnit} is regenerated instead of using the cached one.
* @return The generated {@link RuleUnit} or null if there's no {@link RuleUnit} generated for the given {@link RuleUnitData}.
*/
<T extends RuleUnitData> RuleUnit<T> getRuleUnit(T ruleUnitData, boolean rebuild);

/**
* Creates a new {@link RuleUnitInstance} from the {@link RuleUnit} generated for the given {@link RuleUnitData}.
Expand All @@ -38,7 +47,21 @@ public interface RuleUnitProvider extends KieService {
* throwing a runtime exception if there isn't any {@link RuleUnit} generated for the given {@link RuleUnitData}.
*/
default <T extends RuleUnitData> RuleUnitInstance<T> createRuleUnitInstance(T ruleUnitData) {
RuleUnit<T> ruleUnit = getRuleUnit(ruleUnitData);
return createRuleUnitInstance(ruleUnitData, false);
}

/**
* Creates a new {@link RuleUnitInstance} from the {@link RuleUnit} generated for the given {@link RuleUnitData}.
* This is equivalent to
* <pre>
* RuleUnitProvider.get().getRuleUnit(ruleUnitData, rebuild).createInstance(ruleUnitData);
* </pre>
* throwing a runtime exception if there isn't any {@link RuleUnit} generated for the given {@link RuleUnitData}.
*
* @param rebuild if true, the {@link RuleUnit} is regenerated before creating the {@link RuleUnitInstance}.
*/
default <T extends RuleUnitData> RuleUnitInstance<T> createRuleUnitInstance(T ruleUnitData, boolean rebuild) {
RuleUnit<T> ruleUnit = getRuleUnit(ruleUnitData, rebuild);
if (ruleUnit == null) {
throw new RuntimeException("Cannot find any rule unit for RuleUnitData of class:" + ruleUnitData.getClass().getCanonicalName());
}
Expand All @@ -54,7 +77,21 @@ default <T extends RuleUnitData> RuleUnitInstance<T> createRuleUnitInstance(T ru
* throwing a runtime exception if there isn't any {@link RuleUnit} generated for the given {@link RuleUnitData}.
*/
default <T extends RuleUnitData> RuleUnitInstance<T> createRuleUnitInstance(T ruleUnitData, RuleConfig ruleConfig) {
RuleUnit<T> ruleUnit = getRuleUnit(ruleUnitData);
return createRuleUnitInstance(ruleUnitData, ruleConfig, false);
}

/**
* Creates a new {@link RuleUnitInstance} from the {@link RuleUnit} generated for the given {@link RuleUnitData} with {@link RuleConfig}.
* This is equivalent to
* <pre>
* RuleUnitProvider.get().getRuleUnit(ruleUnitData).createInstance(ruleUnitData, ruleConfig);
* </pre>
* throwing a runtime exception if there isn't any {@link RuleUnit} generated for the given {@link RuleUnitData}.
*
* @param rebuild if true, the {@link RuleUnit} is regenerated before creating the {@link RuleUnitInstance}.
*/
default <T extends RuleUnitData> RuleUnitInstance<T> createRuleUnitInstance(T ruleUnitData, RuleConfig ruleConfig, boolean rebuild) {
RuleUnit<T> ruleUnit = getRuleUnit(ruleUnitData, rebuild);
if (ruleUnit == null) {
throw new RuntimeException("Cannot find any rule unit for RuleUnitData of class:" + ruleUnitData.getClass().getCanonicalName());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright 2023 Red Hat, Inc. and/or its affiliates.
*
* 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
*
* 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.
*/
package org.drools.ruleunits.dsl;

import java.util.ArrayList;
import java.util.List;

import org.drools.ruleunits.api.DataSource;
import org.drools.ruleunits.api.DataStore;

import static org.drools.model.Index.ConstraintType.EQUAL;

public class DynamicHelloWorldUnit implements RuleUnitDefinition {

private final DataStore<String> strings;

private final List<String> results = new ArrayList<>();

private final String expectedMessage; // this is the dynamic part

public DynamicHelloWorldUnit(String expectedMessage) {
this.strings = DataSource.createStore();
this.expectedMessage = expectedMessage;
}

public DataStore<String> getStrings() {
return strings;
}


public List<String> getResults() {
return results;
}

@Override
public void defineRules(RulesFactory rulesFactory) {
// /strings[ this == expectedMessage ]
rulesFactory.rule()
.on(strings)
.filter(EQUAL, expectedMessage) // when no extractor is provided "this" is implicit
.execute(results, r -> r.add("it worked!")); // the consequence can ignore the matched facts
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* Copyright 2023 Red Hat, Inc. and/or its affiliates.
*
* 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
*
* 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.
*/
package org.drools.ruleunits.dsl;

import org.drools.ruleunits.api.RuleUnitInstance;
import org.drools.ruleunits.api.RuleUnitProvider;
import org.drools.ruleunits.api.conf.RuleConfig;
import org.drools.ruleunits.impl.listener.TestRuleRuntimeEventListener;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;

class RuleUnitRebuildTest {

@Test
void dynamicHelloWorld() {
DynamicHelloWorldUnit unit = new DynamicHelloWorldUnit("Hello World");
unit.getStrings().add("Hello World");

try (RuleUnitInstance<DynamicHelloWorldUnit> unitInstance = RuleUnitProvider.get().createRuleUnitInstance(unit, true)) { // rebuild. Do not be affected by other tests
assertThat(unitInstance.fire()).isEqualTo(1);
assertThat(unit.getResults()).containsExactly("it worked!");
}

DynamicHelloWorldUnit newUnit = new DynamicHelloWorldUnit("Goodbye World");
newUnit.getStrings().add("Hello World");

try (RuleUnitInstance<DynamicHelloWorldUnit> newUnitInstance = RuleUnitProvider.get().createRuleUnitInstance(newUnit, true)) { // rebuild
assertThat(newUnitInstance.fire()).isZero();
assertThat(newUnit.getResults()).isEmpty();

newUnit.getStrings().add("Goodbye World");
assertThat(newUnitInstance.fire()).isEqualTo(1);
assertThat(newUnit.getResults()).containsExactly("it worked!");
}
}

@Test
void dynamicHelloWorldWithRuleConfig() {
TestRuleRuntimeEventListener testRuleRuntimeEventListener = new TestRuleRuntimeEventListener();

RuleConfig ruleConfig = RuleUnitProvider.get().newRuleConfig();
ruleConfig.getRuleRuntimeListeners().add(testRuleRuntimeEventListener);

DynamicHelloWorldUnit unit = new DynamicHelloWorldUnit("Hello World");
unit.getStrings().add("Hello World");

try (RuleUnitInstance<DynamicHelloWorldUnit> unitInstance = RuleUnitProvider.get().createRuleUnitInstance(unit, ruleConfig, true)) { // rebuild. Do not be affected by other tests
assertThat(unitInstance.fire()).isEqualTo(1);
assertThat(unit.getResults()).containsExactly("it worked!");
assertThat(testRuleRuntimeEventListener.getResults()).containsExactly("objectInserted : Hello World");
}
testRuleRuntimeEventListener.getResults().clear();

DynamicHelloWorldUnit newUnit = new DynamicHelloWorldUnit("Goodbye World"); // rule has changed
newUnit.getStrings().add("Hello World");

try (RuleUnitInstance<DynamicHelloWorldUnit> newUnitInstance = RuleUnitProvider.get().createRuleUnitInstance(newUnit, ruleConfig, true)) { // rebuild
assertThat(newUnitInstance.fire()).isZero();
assertThat(newUnit.getResults()).isEmpty();

newUnit.getStrings().add("Goodbye World");
assertThat(newUnitInstance.fire()).isEqualTo(1);
assertThat(newUnit.getResults()).containsExactly("it worked!");
assertThat(testRuleRuntimeEventListener.getResults()).containsExactly("objectInserted : Hello World", "objectInserted : Goodbye World");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,16 @@ public RuleUnitProviderImpl() {
}

@Override
public <T extends RuleUnitData> RuleUnit<T> getRuleUnit(T ruleUnitData) {
public <T extends RuleUnitData> RuleUnit<T> getRuleUnit(T ruleUnitData, boolean rebuild) {
String ruleUnitName = getRuleUnitName(ruleUnitData);
RuleUnit<T> ruleUnit = ruleUnitMap.get(ruleUnitName);
if (ruleUnit != null) {
return ruleUnit;

if (!rebuild) {
RuleUnit<T> ruleUnit = ruleUnitMap.get(ruleUnitName);
if (ruleUnit != null) {
return ruleUnit;
}
}

ruleUnitMap.putAll(generateRuleUnit(ruleUnitData));
return ruleUnitMap.get(ruleUnitName);
}
Expand Down

0 comments on commit c018b16

Please sign in to comment.