我们知道drools提供了12种关系操作符
基于drools创建自己的关系操作符_java

但是有些时候这12种操作符依然不能满足我们的业务需求,我们可以扩展自己的操作符,下面是为某一航空公司做项目时扩展了操作符,在这分享下


首先,我们要实现的逻辑是对航班记录 frFfpTravelDetail的票价级别etFareBasis属性做比配(逻辑:票价级别 去除非英文和数字字符后,第二位开始包含“ID**”或“DG**”或“AD**”(**为数字)),这个逻辑太复杂,用以上12种关系操作符都不能满足,为此要进行扩展。
第一步:新增CsairEvaluatorDefinition类
package com.csair.cbd.rules.drools.services.impl;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.drools.base.ValueType;
import org.drools.base.evaluators.EvaluatorDefinition;
import org.drools.base.evaluators.Operator;
import org.drools.spi.Evaluator;


public class CsairEvaluatorDefinition implements EvaluatorDefinition {


public static final Operator STR_COMPARE = Operator.addOperatorToRegistry(
"csair", false);
public static final Operator NOT_STR_COMPARE = Operator
.addOperatorToRegistry("csair", true);
private static final String[] SUPPORTED_IDS = { STR_COMPARE
.getOperatorString() };


public enum Operations {
FbInculde
}


private Evaluator[] evaluator;


public Evaluator getEvaluator(ValueType type, Operator operator) {
return this.getEvaluator(type, operator.getOperatorString(), operator
.isNegated(), null);
}


public Evaluator getEvaluator(ValueType type, Operator operator,
String parameterText) {
return this.getEvaluator(type, operator.getOperatorString(), operator
.isNegated(), parameterText);
}


public Evaluator getEvaluator(ValueType type, String operatorId,
boolean isNegated, String parameterText) {
return getEvaluator(type, operatorId, isNegated, parameterText,
Target.FACT, Target.FACT);
}


public Evaluator getEvaluator(ValueType type, String operatorId,
boolean isNegated, String parameterText, Target leftTarget,
Target rightTarget) {
CsairEvaluator evaluator = new CsairEvaluator(type, isNegated);
evaluator.setParameterText(parameterText);
return evaluator;
}


public String[] getEvaluatorIds() {
return SUPPORTED_IDS;
}


public Target getTarget() {
return Target.FACT;
}


public boolean isNegatable() {
return true;
}


public boolean supportsType(ValueType arg0) {
return true;
}


public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException {
evaluator = (Evaluator[]) in.readObject();


}


public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject(evaluator);
}


}

第二步骤,新增CsairEvaluator类

package com.csair.cbd.rules.drools.services.impl;


import org.drools.base.BaseEvaluator;
import org.drools.base.ValueType;
import org.drools.common.InternalWorkingMemory;
import org.drools.rule.VariableRestriction.VariableContextEntry;
import org.drools.spi.FieldValue;
import org.drools.spi.InternalReadAccessor;


import com.csair.cbd.rules.drools.services.impl.CsairEvaluatorDefinition.Operations;


public class CsairEvaluator extends BaseEvaluator {


private Operations parameter;


public void setParameterText(String parameterText) {
this.parameter = Operations.valueOf(parameterText);
}


public Operations getParameter() {
return parameter;
}

public CsairEvaluator(final ValueType type, final boolean isNegated) {
  super(type, isNegated ?  CsairEvaluatorDefinition.NOT_STR_COMPARE: CsairEvaluatorDefinition.STR_COMPARE);
}


public boolean evaluate(InternalWorkingMemory workingMemory,
InternalReadAccessor extractor, Object object, FieldValue value) {
final Object objectValue = extractor.getValue(workingMemory, object);
switch (parameter) {
case FbInculde:
String sObjectValue = String.valueOf(objectValue);
String sObjectValueTrim = sObjectValue.replaceAll("[^a-zA-Z0-9]","");
String sFieldvalue  = String.valueOf(value.getValue());
boolean ret =sObjectValueTrim.substring(1).matches("^.*["+sFieldvalue+"][0-9]+.*$");
return  ret;
default:
throw new IllegalAccessError("Illegal str comparison parameter");
}
}


public boolean evaluate(InternalWorkingMemory arg0,
InternalReadAccessor arg1, Object arg2, InternalReadAccessor arg3,
Object arg4) {
return false;
}


public boolean evaluateCachedLeft(InternalWorkingMemory arg0,
VariableContextEntry arg1, Object arg2) {
return false;
}


public boolean evaluateCachedRight(InternalWorkingMemory arg0,
VariableContextEntry arg1, Object arg2) {
return false;
}


}

第三步骤,配置使drools规则引擎能够识别你定制的逻辑操作符
    System.setProperty("drools.dateformat", "yyyy-MM-dd");
            System.setProperty("drools.dialect.java.compiler", "JANINO");
//修改默认Java Dialect编译器
Properties props = new Properties();
//set default java compiler
//TODO use a file property to allow configuration
props.setProperty("drools.dialect.java.compiler", "JANINO");

PackageBuilderConfiguration pkgBuilderCfg = new PackageBuilderConfiguration(props);
//扩展csair条件比配操作符,caozhiping
pkgBuilderCfg.setOption(EvaluatorOption.get("csair",new CsairEvaluatorDefinition()));

// 声明新的KnowledgeBuilder对象
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory
.newKnowledgeBuilder(pkgBuilderCfg);


经过以上三步后,你就可以正常使用你自己的关系操作符csair[FBInculde]了,这里贴上项目中的规则

rule "MingZhuKa-KeDuiHuanLiCheng-500000000001751-p20130727013"
salience 1          
no-loop false 
activation-group "1" 
ruleflow-group "1" 
 
    when 
        mileages : ArrayList() 
        mileageRuleMiddleValue : MileageRuleMiddleValue() 
        and frFfpTravelDetail : FrFfpTravelDetail(cumulateCabin == "E") 
        and FrFfpTravelDetail(this == frFfpTravelDetail &&
etFareBasis csair[FbInculde] "(ID)|(DG)|(AD)"
 
    then 
        Date[] dates = ruleGlobalUtil.getMileageRuleCalculate().getValidBeginEndDatesFromTheDate(55,mileageRuleMiddleValue.getBeginValidDate());
        Mileage mileage = new Mileage("000001", "000001", mileageRuleMiddleValue.getBaseMileage()*44*0.01, mileageRuleMiddleValue.getRemark(),"ruleId", dates[0], dates[1], "travel-basic-award-1");
        mileages.add(mileage); 
end