All Downloads are FREE. Search and download functionalities are using the official Maven repository.

info.lostred.ruler.engine.AbstractRulesEngine Maven / Gradle / Ivy

There is a newer version: 3.4.0
Show newest version
package info.lostred.ruler.engine;

import info.lostred.ruler.domain.Report;
import info.lostred.ruler.domain.Result;
import info.lostred.ruler.domain.RuleDefinition;
import info.lostred.ruler.factory.RuleFactory;
import info.lostred.ruler.rule.AbstractRule;
import org.springframework.expression.BeanResolver;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;

import static info.lostred.ruler.constant.SpELConstants.INDEX_KEY;
import static info.lostred.ruler.constant.SpELConstants.INDEX_LABEL;

/**
 * 抽象规则引擎
 *
 * @author lostred
 */
public abstract class AbstractRulesEngine implements RulesEngine {
    private final RuleFactory ruleFactory;
    /**
     * 业务类型
     */
    private final String businessType;
    /**
     * bean解析器
     */
    protected final BeanResolver beanResolver;
    /**
     * 表达式解析器
     */
    protected final ExpressionParser parser;
    /**
     * 全局函数
     */
    protected final List globalFunctions;
    /**
     * 规则引擎中的规则集合
     */
    protected final List rules = new CopyOnWriteArrayList<>();

    public AbstractRulesEngine(RuleFactory ruleFactory, String businessType,
                               BeanResolver beanResolver, ExpressionParser parser, List globalFunctions) {
        this.ruleFactory = ruleFactory;
        this.businessType = businessType;
        this.beanResolver = beanResolver;
        this.parser = parser;
        this.globalFunctions = globalFunctions;
        this.reloadRules();
    }

    /**
     * 针对数组参数执行
     *
     * @param context 评估上下文
     * @param array   数组参数
     * @param rule    规则
     * @return 结果,数组中的所有元素有一个不通过时返回true,否则返回false
     */
    protected boolean executeForArray(StandardEvaluationContext context, Object[] array,
                                      AbstractRule rule) {
        if (array != null) {
            boolean flag = false;
            for (int i = 0; i < array.length; i++) {
                context.setVariable(INDEX_KEY, i);
                flag = flag || this.executeForObject(context, array[i], rule);
            }
            return flag;
        }
        return false;
    }

    /**
     * 针对数组参数执行
     *
     * @param context 评估上下文
     * @param array   数组参数
     * @param rule    规则
     * @param result  引擎执行的结果
     */
    protected void executeForArray(StandardEvaluationContext context, Object[] array,
                                   AbstractRule rule, Result result) {
        if (array != null) {
            for (int i = 0; i < array.length; i++) {
                context.setVariable(INDEX_KEY, i);
                this.executeForObject(context, array[i], rule, result);
            }
        }
    }

    /**
     * 针对对象参数执行
     *
     * @param context 评估上下文
     * @param object  对象参数
     * @param rule    规则
     * @return 结果
     */
    protected boolean executeForObject(StandardEvaluationContext context, Object object,
                                       AbstractRule rule) {
        if (rule.supports(context, parser, object)) {
            return rule.judge(context, parser, object);
        }
        return false;
    }

    /**
     * 针对对象参数执行,并收集违规字段与值,放入结果中
     *
     * @param context 评估上下文
     * @param object  对象参数
     * @param rule    规则
     * @param result  引擎执行的结果
     */
    protected void executeForObject(StandardEvaluationContext context, Object object,
                                    AbstractRule rule, Result result) {
        if (rule.supports(context, parser, object)) {
            if (rule.judge(context, parser, object)) {
                Map map = rule.collectMappings(context, parser, object);
                Report report = Report.of(rule.getRuleDefinition()).putError(map);
                result.addReport(report);
            }
        }
    }

    /**
     * 针对无详细结果的处理
     *
     * @param context 评估上下文
     * @param object  待校验的对象
     * @param rule    当前规则
     * @return 结果,true表示不通过,false表示通过
     */
    protected boolean handle(StandardEvaluationContext context, Object object, AbstractRule rule) {
        String parameterExp = rule.getRuleDefinition().getParameterExp();
        if (parameterExp.contains(INDEX_LABEL)) {
            String arrayExp = parameterExp.substring(0, parameterExp.indexOf(INDEX_LABEL));
            Object[] array = parser.parseExpression(arrayExp).getValue(context, Object[].class);
            return this.executeForArray(context, array, rule);
        } else {
            return this.executeForObject(context, object, rule);
        }
    }

    @Override
    public String getBusinessType() {
        return businessType;
    }

    @Override
    public boolean evaluate(Object object) {
        StandardEvaluationContext context = new StandardEvaluationContext(object);
        this.setBeanResolver(context);
        this.registerFunctions(context, globalFunctions);
        for (AbstractRule rule : rules) {
            if (this.handle(context, object, rule)) {
                return true;
            }
        }
        return false;
    }

    @Override
    public List getRuleDefinitions() {
        return this.rules.stream()
                .map(AbstractRule::getRuleDefinition)
                .collect(Collectors.toList());
    }

    @Override
    public AbstractRule getRule(String ruleCode) {
        return this.rules.stream()
                .filter(rule -> rule.getRuleDefinition().getRuleCode().equals(ruleCode))
                .findAny()
                .orElse(null);
    }

    @Override
    public void addRule(String ruleCode) {
        AbstractRule rule = this.ruleFactory.getRule(ruleCode);
        for (int i = 0; i < this.rules.size(); i++) {
            if (this.rules.get(i).getRuleDefinition().getOrder()
                    > rule.getRuleDefinition().getOrder()) {
                this.rules.add(i, rule);
                return;
            }
        }
        this.rules.add(rule);
    }

    @Override
    public void addRule(Collection ruleCodes) {
        ruleCodes.forEach(this::addRule);
    }

    @Override
    public AbstractRule removeRule(String ruleCode) {
        if (ruleCode == null) {
            return null;
        }
        for (int i = 0; i < this.rules.size(); i++) {
            AbstractRule rule = this.rules.get(i);
            if (rule.getRuleDefinition().getRuleCode().equals(ruleCode)) {
                if (rule.getRuleDefinition().isRequired()) {
                    throw new RuntimeException("The rule [" + ruleCode + "] is required.");
                }
                return this.rules.remove(i);
            }
        }
        return null;
    }

    @Override
    public void forceRemoveRule(String ruleCode) {
        this.rules.removeIf(rule -> rule.getRuleDefinition().getRuleCode().equals(ruleCode));
    }

    @Override
    public void reloadRules() {
        List rules = ruleFactory.findRules(businessType).stream()
                .filter(rule -> rule.getRuleDefinition().isEnabled())
                .sorted(Comparator.comparingInt(rule -> rule.getRuleDefinition().getOrder()))
                .collect(Collectors.toList());
        this.rules.clear();
        this.rules.addAll(rules);
    }

    @Override
    public void setBeanResolver(StandardEvaluationContext context) {
        context.setBeanResolver(beanResolver);
    }

    @Override
    public void setVariable(StandardEvaluationContext context, String name, Object object) {
        context.setVariable(name, object);
    }

    @Override
    public void registerFunctions(StandardEvaluationContext context, List methods) {
        if (methods != null) {
            for (Method method : methods) {
                context.registerFunction(method.getName(), method);
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy