com.deliveredtechnologies.rulebook.model.runner.RuleAdapter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of rulebook-core Show documentation
Show all versions of rulebook-core Show documentation
A simple and intuitive rules abstraction for Java
package com.deliveredtechnologies.rulebook.model.runner;
import com.deliveredtechnologies.rulebook.NameValueReferable;
import com.deliveredtechnologies.rulebook.NameValueReferableMap;
import com.deliveredtechnologies.rulebook.Result;
import com.deliveredtechnologies.rulebook.RuleState;
import com.deliveredtechnologies.rulebook.annotation.Given;
import com.deliveredtechnologies.rulebook.annotation.Then;
import com.deliveredtechnologies.rulebook.annotation.When;
import com.deliveredtechnologies.rulebook.model.GoldenRule;
import com.deliveredtechnologies.rulebook.model.Rule;
import com.deliveredtechnologies.rulebook.model.RuleChainActionType;
import com.deliveredtechnologies.rulebook.model.RuleException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.InvalidClassException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.util.List;
import java.util.Arrays;
import java.util.Optional;
import java.util.Collection;
import java.util.Set;
import java.util.Map;
import java.util.ArrayList;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static com.deliveredtechnologies.rulebook.util.AnnotationUtils.getAnnotatedField;
import static com.deliveredtechnologies.rulebook.util.AnnotationUtils.getAnnotatedMethods;
import static com.deliveredtechnologies.rulebook.util.AnnotationUtils.getAnnotatedFields;
import static com.deliveredtechnologies.rulebook.util.AnnotationUtils.getAnnotation;
/**
* Adapts a {@link com.deliveredtechnologies.rulebook.annotation.Rule} annotated POJO to a
* {@link Rule}.
*/
public class RuleAdapter implements Rule {
private static Logger LOGGER = LoggerFactory.getLogger(RuleAdapter.class);
private Rule _rule;
private Object _pojoRule;
private RuleChainActionType _actionType;
/**
* Adapts a POJO to a Rule given a POJO and a Rule.
* @param pojoRule the @Rule annotated POJO
* @param rule a Rule object
* @throws InvalidClassException if the @Rule annotation is missing from the POJO
*/
public RuleAdapter(Object pojoRule, Rule rule) throws InvalidClassException {
com.deliveredtechnologies.rulebook.annotation.Rule ruleAnnotation =
getAnnotation(com.deliveredtechnologies.rulebook.annotation.Rule.class, pojoRule.getClass());
if (ruleAnnotation == null) {
throw new InvalidClassException(pojoRule.getClass() + " is not a Rule; missing @Rule annotation");
}
_actionType = ruleAnnotation.ruleChainAction();
_rule = rule == null ? new GoldenRule(Object.class, _actionType) : rule;
_pojoRule = pojoRule;
}
/**
* Adapts a POJO to a the default Rule type (i.e. {@link GoldenRule}).
* @param pojoRule the @Rule annotated POJO
* @throws InvalidClassException if the @Rule annotation is missing from the POJO
*/
@SuppressWarnings("unchecked")
public RuleAdapter(Object pojoRule) throws InvalidClassException {
this(pojoRule, null);
}
@Override
public void addFacts(NameValueReferable... facts) {
_rule.addFacts(facts);
mapFactsToProperties(_rule.getFacts());
}
@Override
public void addFacts(NameValueReferableMap facts) {
_rule.addFacts(facts);
mapFactsToProperties(_rule.getFacts());
}
@Override
public void setFacts(NameValueReferableMap facts) {
_rule.setFacts(facts);
mapFactsToProperties(_rule.getFacts());
}
@Override
@SuppressWarnings("unchecked")
public void setCondition(Predicate condition) throws IllegalStateException {
_rule.setCondition(condition);
}
@Override
public void setRuleState(RuleState ruleState) {
_rule.setRuleState(ruleState);
}
@Override
@SuppressWarnings("unchecked")
public void addAction(Consumer action) {
_rule.addAction(action);
}
@Override
@SuppressWarnings("unchecked")
public void addAction(BiConsumer action) {
_rule.addAction(action);
}
@Override
public void addFactNameFilter(String... factNames) {
throw new UnsupportedOperationException();
}
@Override
public NameValueReferableMap getFacts() {
return _rule.getFacts();
}
@Override
@SuppressWarnings("unchecked")
public Predicate getCondition() {
//Use what was set by then() first, if it's there
if (_rule.getCondition() != null) {
return _rule.getCondition();
}
//If nothing was explicitly set, then convert the method in the class
_rule.setCondition(Arrays.stream(_pojoRule.getClass().getMethods())
.filter(method -> method.getReturnType() == boolean.class || method.getReturnType() == Boolean.class)
.filter(method -> Arrays.stream(method.getDeclaredAnnotations()).anyMatch(When.class::isInstance))
.findFirst()
.map(method -> object -> {
try {
return (Boolean) method.invoke(_pojoRule);
} catch (InvocationTargetException | IllegalAccessException ex) {
if (_actionType == RuleChainActionType.ERROR_ON_FAILURE) {
throw new RuleException(ex.getCause() == null ? ex : ex.getCause());
}
LOGGER.error(
"Unable to validate condition due to an exception. It will be evaluated as false", ex);
return false;
}
})
//If the condition still can't be determined, then just hand back one that returns true
.orElse(o -> true));
return _rule.getCondition();
}
@Override
public RuleState getRuleState() {
return _rule.getRuleState();
}
@Override
@SuppressWarnings("unchecked")
public List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy