- Introduce Abstract rules engine class

- Move priority into Rule interface
pull/3/head
Mahmoud Ben Hassine
parent 2f2941063f
commit b44b1777ee

@ -55,6 +55,18 @@ public interface Rule {
*/
void setDescription(String description);
/**
* Getter for rule priority.
* @return rule priority
*/
int getPriority();
/**
* Setter for rule priority.
* @param priority the priority to set
*/
void setPriority(int priority);
/**
* Rule conditions abstraction : this method encapsulates the rule's conditions.
* @return true if the rule should be applied, false else

@ -29,6 +29,11 @@ public abstract class AbstractRulesEngine<R> implements RulesEngine<R> {
*/
protected boolean skipOnFirstAppliedRule;
/**
* Parameter to skip next rules if priority exceeds a user defined threshold.
*/
protected int rulePriorityThreshold;
/**
* The JMX server instance in which rule's MBeans will be registered.
*/
@ -57,7 +62,7 @@ public abstract class AbstractRulesEngine<R> implements RulesEngine<R> {
/*
* Register a JMX MBean for a rule.
*/
private void registerJmxMBean(final R rule) {
protected void registerJmxMBean(final R rule) {
ObjectName name;
try {

@ -0,0 +1,322 @@
package io.github.benas.easyrules.core;
import io.github.benas.easyrules.annotation.Action;
import io.github.benas.easyrules.annotation.Condition;
import io.github.benas.easyrules.annotation.Priority;
import io.github.benas.easyrules.annotation.Rule;
import io.github.benas.easyrules.util.EasyRulesConstants;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.logging.Level;
/**
* Annotated rules engine implementation.
*
* @author Mahmoud Ben Hassine (md.benhassine@gmail.com)
*/
public class AnnotatedRulesEngine extends AbstractRulesEngine<Object> {
private List<RuleBean> ruleBeans;
/**
* Construct an annotated rules engine with default values.
*/
public AnnotatedRulesEngine() {
this(false, EasyRulesConstants.DEFAULT_RULE_PRIORITY_THRESHOLD);
}
/**
* Constructs an annotated rules engine.
*
* @param skipOnFirstAppliedRule true if the engine should skip next rule after the first applied rule
*/
public AnnotatedRulesEngine(boolean skipOnFirstAppliedRule) {
this(skipOnFirstAppliedRule, EasyRulesConstants.DEFAULT_RULE_PRIORITY_THRESHOLD);
}
/**
* Constructs an annotated rules engine.
*
* @param rulePriorityThreshold rule priority threshold
*/
public AnnotatedRulesEngine(int rulePriorityThreshold) {
this(false, rulePriorityThreshold);
}
/**
* Constructs an annotated rules engine.
*
* @param skipOnFirstAppliedRule true if the engine should skip next rule after the first applied rule
* @param rulePriorityThreshold rule priority threshold
*/
public AnnotatedRulesEngine(boolean skipOnFirstAppliedRule, int rulePriorityThreshold) {
rules = new TreeSet<Object>();
ruleBeans = new ArrayList<RuleBean>();
this.skipOnFirstAppliedRule = skipOnFirstAppliedRule;
this.rulePriorityThreshold = rulePriorityThreshold;
}
@Override
public void registerJmxRule(Object rule) {
registerRule(rule);
registerJmxMBean(rule);
}
@Override
public void registerRule(Object rule) {
//check if rule class is annotated with @Rule
if (!isRuleClassWellDefined(rule)) {
throw new IllegalArgumentException("Rule " + rule + " is not annotated with " + Rule.class.getClass());
}
//check if condition method is well defined
Method conditionMethod = getConditionMethod(rule);
if (null == conditionMethod) {
throw new IllegalArgumentException("Rule " + rule + " does not have a public method annotated with " + Condition.class.getClass());
}
if (!isConditionMethodWellDefined(conditionMethod)) {
throw new IllegalArgumentException("Condition method " + conditionMethod + " defined in rule " + rule + " must be public, have no parameters and return boolean type.");
}
//check if action methods are well defined
List<ActionMethodBean> actionMethods = getActionMethodBeans(rule);
if (actionMethods.isEmpty()) {
throw new IllegalArgumentException("Rule " + rule + " does not have a public method annotated with " + Action.class.getClass());
}
for (ActionMethodBean actionMethodBean : actionMethods) {
Method actionMethod = actionMethodBean.getMethod();
if (!isActionMethodWellDefined(actionMethod)) {
throw new IllegalArgumentException("Action method " + actionMethod + " defined in rule " + rule + " must be public and have no parameters.");
}
}
//get rule priority for later use
List<Method> priorityMethods = getPriorityMethods(rule);
int priority = EasyRulesConstants.DEFAULT_RULE_PRIORITY;
// more than one method annotated with @Priority
if (priorityMethods.size() > 1) {
throw new IllegalArgumentException("Rule " + rule + " have more than one method annotated with " + Priority.class.getClass());
}
//exactly one method annotated with @Priority
if (!priorityMethods.isEmpty()) {
Method priorityMethod = priorityMethods.get(0);
if (!isPriorityMethodWellDefined(priorityMethod)) {
throw new IllegalArgumentException("Priority method " + priorityMethod + " defined in rule " + rule + " must be public, have no parameters and return integer type.");
}
try {
priority = (Integer) priorityMethod.invoke(rule);
} catch (IllegalAccessException e) {
throw new IllegalArgumentException("Unable to access method " + priorityMethod + " to get priority of rule " + rule, e);
} catch (InvocationTargetException e) {
throw new IllegalArgumentException("Unable to invoke method " + priorityMethod + " to get priority of rule " + rule, e);
}
}
ruleBeans.add(new RuleBean(priority, rule));
}
@Override
public void fireRules() {
if (ruleBeans.isEmpty()) {
LOGGER.warning("No rules registered! Nothing to apply.");
return;
}
//sort rules according to their priorities
Collections.sort(ruleBeans);
for (RuleBean ruleBean : ruleBeans) {
Object rule = ruleBean.getRule();
Rule annotation = rule.getClass().getAnnotation(Rule.class);
String name = annotation.name();
Method conditionMethod = getConditionMethod(rule);
List<ActionMethodBean> actionMethods = getActionMethodBeans(rule);
//sort actions according to their execution order
Collections.sort(actionMethods);
try {
int priority = ruleBean.getPriority();
if (priority > rulePriorityThreshold) {
LOGGER.log(Level.INFO, "Rule priority threshold {0} exceeded at rule {1} (priority={2}), next applicable rules will be skipped.",
new Object[]{rulePriorityThreshold, name, priority});
break;
}
Boolean shouldApplyRule = (Boolean) conditionMethod.invoke(rule);
//apply the rule
if (shouldApplyRule) {
LOGGER.log(Level.INFO, "Rule {0} triggered.", new Object[]{name});
try {
//execute all actions in the defined order
for (ActionMethodBean actionMethodBean : actionMethods) {
actionMethodBean.getMethod().invoke(rule);
}
LOGGER.log(Level.INFO, "Rule {0} performed successfully.", new Object[]{name});
if (skipOnFirstAppliedRule) {
LOGGER.info("Next rules will be skipped according to parameter skipOnFirstAppliedRule.");
break;
}
} catch (Exception exception) {
LOGGER.log(Level.SEVERE, "Rule '" + name + "' performed with error.", exception);
}
}
} catch (IllegalAccessException e) {
LOGGER.log(Level.SEVERE, "Unable to access method on rule " + rule, e);
} catch (InvocationTargetException e) {
LOGGER.log(Level.SEVERE, "Unable to invoke method on rule " + rule, e);
}
}
}
@Override
public void clearRules() {
ruleBeans.clear();
super.clearRules();
}
/*
* Private Utility methods
*/
private Method getConditionMethod(Object rule) {
Method[] methods = rule.getClass().getMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(Condition.class)) {
return method;
}
}
return null;
}
private List<ActionMethodBean> getActionMethodBeans(Object rule) {
Method[] methods = rule.getClass().getMethods();
List<ActionMethodBean> actionMethodBeans = new ArrayList<ActionMethodBean>();
for (Method method : methods) {
if (method.isAnnotationPresent(Action.class)) {
Action actionAnnotation = method.getAnnotation(Action.class);
int order = actionAnnotation.order();
actionMethodBeans.add(new ActionMethodBean(method, order));
}
}
return actionMethodBeans;
}
private List<Method> getPriorityMethods(Object rule) {
Method[] methods = rule.getClass().getMethods();
List<Method> priorityMethods = new ArrayList<Method>();
for (Method method : methods) {
if (method.isAnnotationPresent(Priority.class)) {
priorityMethods.add(method);
}
}
return priorityMethods;
}
private boolean isRuleClassWellDefined(Object rule) {
return rule.getClass().isAnnotationPresent(Rule.class);
}
private boolean isConditionMethodWellDefined(Method method) {
return Modifier.isPublic(method.getModifiers())
&& method.getReturnType().equals(Boolean.TYPE)
&& method.getParameterTypes().length == 0;
}
private boolean isActionMethodWellDefined(Method method) {
return Modifier.isPublic(method.getModifiers()) && method.getParameterTypes().length == 0;
}
private boolean isPriorityMethodWellDefined(Method method) {
return Modifier.isPublic(method.getModifiers())
&& method.getReturnType().equals(Integer.TYPE)
&& method.getParameterTypes().length == 0;
}
/**
* Private utility class that associates an action method and its execution order.
*/
private final class ActionMethodBean implements Comparable<ActionMethodBean> {
private Method method;
private int order;
ActionMethodBean(Method method, int order) {
this.method = method;
this.order = order;
}
public int getOrder() {
return order;
}
public Method getMethod() {
return method;
}
@Override
public int compareTo(ActionMethodBean actionMethodBean) {
if (order < actionMethodBean.getOrder()) {
return -1;
} else if (order == actionMethodBean.getOrder()) {
return 0;
} else {
return 1;
}
}
}
/**
* Private utility class that associates a rule to its priority.
*/
private final class RuleBean implements Comparable<RuleBean> {
private int priority;
private Object rule;
private RuleBean(int priority, Object rule) {
this.priority = priority;
this.rule = rule;
}
private int getPriority() {
return priority;
}
private Object getRule() {
return rule;
}
@Override
public int compareTo(RuleBean ruleBean) {
if (priority < ruleBean.getPriority()) {
return -1;
} else if (priority == ruleBean.getPriority()) {
return 0;
} else {
return 1;
}
}
}
}

@ -1,84 +0,0 @@
/*
* The MIT License
*
* Copyright (c) 2014, Mahmoud Ben Hassine (md.benhassine@gmail.com)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package io.github.benas.easyrules.core;
import io.github.benas.easyrules.api.PriorityRule;
import io.github.benas.easyrules.util.EasyRulesConstants;
/**
* Priority rule implementation that provides common methods.<br/>
*
* This class adds rule priority to fire rules according to their priorities.
*
* @author Mahmoud Ben Hassine (md.benhassine@gmail.com)
*/
public class BasicPriorityRule extends BasicRule implements PriorityRule, Comparable<PriorityRule> {
/**
* Rule priority.
*/
protected int priority;
public BasicPriorityRule() {
super();
this.priority = EasyRulesConstants.DEFAULT_RULE_PRIORITY;
}
public BasicPriorityRule(final String name) {
super(name);
this.priority = EasyRulesConstants.DEFAULT_RULE_PRIORITY;
}
public BasicPriorityRule(final String name, final String description) {
this(name, description, EasyRulesConstants.DEFAULT_RULE_PRIORITY);
}
public BasicPriorityRule(final String name, final String description, final int priority) {
super(name, description);
this.priority = priority;
}
@Override
public int compareTo(final PriorityRule rule) {
if (priority < rule.getPriority()) {
return -1;
} else if (priority == rule.getPriority()) {
return 0;
} else {
return 1;
}
}
@Override
public int getPriority() {
return priority;
}
@Override
public void setPriority(int priority) {
this.priority = priority;
}
}

@ -35,7 +35,7 @@ import io.github.benas.easyrules.util.EasyRulesConstants;
*
* @author Mahmoud Ben Hassine (md.benhassine@gmail.com)
*/
public class BasicRule implements Rule {
public class BasicRule implements Rule, Comparable<Rule> {
/**
* Rule name.
@ -47,18 +47,29 @@ public class BasicRule implements Rule {
*/
protected String description;
/**
* Rule priority.
*/
private int priority;
public BasicRule() {
this(EasyRulesConstants.DEFAULT_RULE_NAME,
EasyRulesConstants.DEFAULT_RULE_DESCRIPTION);
EasyRulesConstants.DEFAULT_RULE_DESCRIPTION,
EasyRulesConstants.DEFAULT_RULE_PRIORITY);
}
public BasicRule(final String name) {
this(name, EasyRulesConstants.DEFAULT_RULE_DESCRIPTION);
this(name, EasyRulesConstants.DEFAULT_RULE_DESCRIPTION, EasyRulesConstants.DEFAULT_RULE_PRIORITY);
}
public BasicRule(final String name, final String description) {
this(name, description, EasyRulesConstants.DEFAULT_RULE_PRIORITY);
}
public BasicRule(final String name, final String description, final int priority) {
this.name = name;
this.description = description;
this.priority = priority;
}
/**
@ -87,6 +98,14 @@ public class BasicRule implements Rule {
this.description = description;
}
public int getPriority() {
return priority;
}
public void setPriority(int priority) {
this.priority = priority;
}
/*
* Rules are unique according to their names within a rules engine registry.
*/
@ -112,4 +131,15 @@ public class BasicRule implements Rule {
return name;
}
@Override
public int compareTo(final Rule rule) {
if (priority < rule.getPriority()) {
return -1;
} else if (priority == rule.getPriority()) {
return 0;
} else {
return 1;
}
}
}

@ -1,109 +0,0 @@
/*
* The MIT License
*
* Copyright (c) 2014, Mahmoud Ben Hassine (md.benhassine@gmail.com)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package io.github.benas.easyrules.core;
import io.github.benas.easyrules.api.PriorityRule;
import io.github.benas.easyrules.util.EasyRulesConstants;
import java.util.Set;
import java.util.TreeSet;
/**
* Class representing a composite rule composed of a set of priority rules.<br/>
*
* A composite rule is triggered if <strong>ALL</strong> conditions of its composing rules are satisfied.
* When a composite rule is applied, actions of <strong>ALL</strong> composing rules are performed in their
* natural order.
*
* @author Mahmoud Ben Hassine (md.benhassine@gmail.com)
*/
public class CompositePriorityRule extends BasicPriorityRule {
/**
* The set of composing priority rules.
*/
protected Set<PriorityRule> rules;
public CompositePriorityRule() {
this(EasyRulesConstants.DEFAULT_RULE_NAME,
EasyRulesConstants.DEFAULT_RULE_DESCRIPTION);
}
public CompositePriorityRule(final String name) {
this(name, EasyRulesConstants.DEFAULT_RULE_DESCRIPTION);
}
public CompositePriorityRule(final String name, final String description) {
super(name, description);
rules = new TreeSet<PriorityRule>();
}
/**
* A composite rule is triggered if <strong>ALL</strong> conditions of all composing rules are evaluated to true.
* @return true if <strong>ALL</strong> conditions of composing rules are evaluated to true
*/
@Override
public boolean evaluateConditions() {
if (!rules.isEmpty()) {
for (PriorityRule rule : rules) {
if (!rule.evaluateConditions()) {
return false;
}
}
return true;
}
return false;
}
/**
* When a composite priority rule is applied, <strong>ALL</strong> actions of composing rules are performed
* in their natural order.
*
* @throws Exception thrown if an exception occurs during actions performing
*/
@Override
public void performActions() throws Exception {
for (PriorityRule rule : rules) {
rule.performActions();
}
}
/**
* Add a priority rule to the composite rule.
* @param rule the priority rule to add
*/
public void addRule(final PriorityRule rule) {
rules.add(rule);
}
/**
* Remove a priority rule from the composite rule.
* @param rule the priority rule to remove
*/
public void removeRule(final PriorityRule rule) {
rules.remove(rule);
}
}

@ -77,7 +77,8 @@ public class CompositeRule extends BasicRule {
}
/**
* When a composite rule is applied, <strong>ALL</strong> actions of composing rules are performed.
* When a composite rule is applied, <strong>ALL</strong> actions of composing rules are performed
* in their natural order.
*
* @throws Exception thrown if an exception occurs during actions performing
*/

@ -26,8 +26,9 @@ package io.github.benas.easyrules.core;
import io.github.benas.easyrules.api.Rule;
import io.github.benas.easyrules.api.RulesEngine;
import io.github.benas.easyrules.util.EasyRulesConstants;
import java.util.HashSet;
import java.util.TreeSet;
import java.util.logging.Level;
/**
@ -35,17 +36,44 @@ import java.util.logging.Level;
*
* This implementation handles a set of rules with unique name.
*
* Rules are fired according to their natural order which is priority by default.
*
* @author Mahmoud Ben Hassine (md.benhassine@gmail.com)
*/
public class DefaultRulesEngine extends AbstractRulesEngine<Rule> {
/**
* Construct a default rules engine with default values.
*/
public DefaultRulesEngine() {
this(false);
this(false, EasyRulesConstants.DEFAULT_RULE_PRIORITY_THRESHOLD);
}
/**
* Constructs a default rules engine.
* @param skipOnFirstAppliedRule true if the engine should skip next rule after the first applied rule
*/
public DefaultRulesEngine(boolean skipOnFirstAppliedRule) {
rules = new HashSet<Rule>();
this(skipOnFirstAppliedRule, EasyRulesConstants.DEFAULT_RULE_PRIORITY_THRESHOLD);
}
/**
* Constructs a default rules engine.
* @param rulePriorityThreshold rule priority threshold
*/
public DefaultRulesEngine(int rulePriorityThreshold) {
this(false, rulePriorityThreshold);
}
/**
* Constructs a default rules engine.
* @param skipOnFirstAppliedRule true if the engine should skip next rule after the first applied rule
* @param rulePriorityThreshold rule priority threshold
*/
public DefaultRulesEngine(boolean skipOnFirstAppliedRule, int rulePriorityThreshold) {
rules = new TreeSet<Rule>();
this.skipOnFirstAppliedRule = skipOnFirstAppliedRule;
this.rulePriorityThreshold = rulePriorityThreshold;
}
@Override
@ -56,8 +84,17 @@ public class DefaultRulesEngine extends AbstractRulesEngine<Rule> {
return;
}
//resort rules in case priorities were modified via JMX
rules = new TreeSet<Rule>(rules);
for (Rule rule : rules) {
if (rule.getPriority() > rulePriorityThreshold) {
LOGGER.log(Level.INFO, "Rule priority threshold {0} exceeded at rule {1} (priority={2}), next applicable rules will be skipped.",
new Object[] {rulePriorityThreshold, rule.getName(), rule.getPriority()});
break;
}
if (rule.evaluateConditions()) {
LOGGER.log(Level.INFO, "Rule {0} triggered.", new Object[]{rule.getName()});
try {

@ -1,118 +0,0 @@
/*
* The MIT License
*
* Copyright (c) 2014, Mahmoud Ben Hassine (md.benhassine@gmail.com)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package io.github.benas.easyrules.core;
import io.github.benas.easyrules.api.PriorityRule;
import io.github.benas.easyrules.util.EasyRulesConstants;
import java.util.TreeSet;
import java.util.logging.Level;
/**
* Implementation of {@link io.github.benas.easyrules.api.RulesEngine} that holds a sorted set of
* priority rules according to their priority. Rules are fired according to their natural order
* (lower values represent higher priorities).
*
* @author Mahmoud Ben Hassine (md.benhassine@gmail.com)
*/
public class PriorityRulesEngine extends AbstractRulesEngine<PriorityRule> {
/**
* Parameter to skip next rules if priority exceeds a user defined threshold.
*/
protected int rulePriorityThreshold;
/**
* Construct a priority rules engine with default values.
*/
public PriorityRulesEngine() {
this(false, EasyRulesConstants.DEFAULT_RULE_PRIORITY_THRESHOLD);
}
/**
* Constructs a priority rules engine.
* @param skipOnFirstAppliedRule true if the engine should skip next rule after the first applied rule
*/
public PriorityRulesEngine(boolean skipOnFirstAppliedRule) {
this(skipOnFirstAppliedRule, EasyRulesConstants.DEFAULT_RULE_PRIORITY_THRESHOLD);
}
/**
* Constructs a priority rules engine.
* @param rulePriorityThreshold rule priority threshold
*/
public PriorityRulesEngine(int rulePriorityThreshold) {
this(false, rulePriorityThreshold);
}
/**
* Constructs a priority rules engine.
* @param skipOnFirstAppliedRule true if the engine should skip next rule after the first applied rule
* @param rulePriorityThreshold rule priority threshold
*/
public PriorityRulesEngine(boolean skipOnFirstAppliedRule, int rulePriorityThreshold) {
rules = new TreeSet<PriorityRule>();
this.skipOnFirstAppliedRule = skipOnFirstAppliedRule;
this.rulePriorityThreshold = rulePriorityThreshold;
}
@Override
public void fireRules() {
if (rules.isEmpty()) {
LOGGER.warning("No rules registered! Nothing to apply.");
return;
}
//resort rules in case priorities were modified via JMX
rules = new TreeSet<PriorityRule>(rules);
for (PriorityRule priorityRule : rules) {
if (priorityRule.getPriority() > rulePriorityThreshold) {
LOGGER.log(Level.INFO, "Rules priority threshold {0} exceeded at rule {1} (priority={2}), next applicable rules will be skipped.",
new Object[] {rulePriorityThreshold, priorityRule.getName(), priorityRule.getPriority()});
break;
}
if (priorityRule.evaluateConditions()) {
LOGGER.log(Level.INFO, "Rule {0} triggered.", new Object[]{priorityRule.getName()});
try {
priorityRule.performActions();
LOGGER.log(Level.INFO, "Rule {0} performed successfully.", new Object[]{priorityRule.getName()});
if (skipOnFirstAppliedRule) {
LOGGER.info("Next rules will be skipped according to parameter skipOnFirstAppliedRule.");
break;
}
} catch (Exception exception) {
LOGGER.log(Level.SEVERE, "Rule '" + priorityRule.getName() + "' performed with error.", exception);
}
}
}
}
}
Loading…
Cancel
Save