2016-09-29 90 views
1

注册Drools的6运营商定制我有这样的下列对象的几个连锁店,我想使用Drools的6.4.0处理:如何以编程方式KieServices与Java

@Value 
public final class Node { 
    private final String code; 
    private final Node prev; 
} 

一个例子规则来使用,例如,如下:

rule "Initial repetition" 
when 
    $n1: Node(prev == null, $c: code) 
    $n2: Node(prev == $n1, code == $c) 
then 
    System.out.println($c + ": " + $n1 + ":" + $n2); 
end 

的Drools被初始化,并与下面的代码运行:

private KieBase base; 

public void process(List<Node> nodes) { 
    initialise(); 
    KieSession session = base.newKieSession(); 
    nodes.forEach(session::insert); 
    session.fireAllRules(); 
    session.dispose(); 
} 

private void initialise() { 
    if (base == null) { 
     // Get the KIE services 
     KieServices services = KieServices.Factory.get(); 
     // Get a virtual file system 
     KieFileSystem fileSystem = services.newKieFileSystem(); 
     // Add a DRL file to the virtual file system 
     String location = "/drools/Repetitions.drl"; 
     InputStream stream = getClass().getResourceAsStream(location); 
     Resource resource = ResourceFactory.newInputStreamResource(stream); 
     fileSystem.write("src/main/resources" + location, resource); 
     // Build the virtual file system into a repository's container 
     KieBuilder builder = services.newKieBuilder(fileSystem).buildAll(); 
     Results results = builder.getResults(); 
     if (results.hasMessages(ERROR)) { 
      throw new RuntimeException(join("\n", results.getMessages())); 
     } 
     KieRepository repository = services.getRepository(); 
     KieContainer container = services.newKieContainer(repository.getDefaultReleaseId()); 
     // Get the knowledge base 
     base = container.newKieBase(); 
    } 
} 

由于我必须识别每个链中的第一Node的任何重复,我虽然来定义自定义操作符“之前”,以简化的规则起草并能够例如写:

rule "Any repetition of first nodes" 
when 
    $n1: Node(prev == null, $c: code) 
    $n2: Node($n1 precedes this, code == $c) 
then 
    System.out.println($n2); 
end 

我已经创建PrecedesEvaluatorPrecedesEvaluatorDefinition如下:

public class PrecedesEvaluator extends BaseEvaluator { 
    private static final long serialVersionUID = ...L; 
    private final boolean isNegated; 

    public PrecedesEvaluator(ValueType type, boolean isNegated) { 
     super(type, isNegated ? 
       PrecedesEvaluatorDefinition.NOT_PRECEDES : 
       PrecedesEvaluatorDefinition.PRECEDES); 
     this.isNegated = isNegated; 
    } 

    @Override 
    public boolean evaluate(InternalWorkingMemory workingMemory, InternalReadAccessor extractor, InternalFactHandle factHandle, FieldValue value) { 
     Object nodeLeft = extractor.getValue(workingMemory, factHandle.getObject()); 
     return isNegated^evaluateUnsafe(nodeLeft, value.getValue()); 
    } 

    @Override 
    public boolean evaluate(InternalWorkingMemory workingMemory, InternalReadAccessor leftExtractor, InternalFactHandle left, InternalReadAccessor rightExtractor, InternalFactHandle right) { 
     Object nodeLeft = leftExtractor.getValue(workingMemory, left.getObject()); 
     Object nodeRight = rightExtractor.getBigDecimalValue(workingMemory, right.getObject()); 
     return isNegated^evaluateUnsafe(nodeLeft, nodeRight); 
    } 

    @Override 
    public boolean evaluateCachedLeft(InternalWorkingMemory workingMemory, VariableContextEntry context, InternalFactHandle right) { 
     Object nodeLeft = context.getFieldExtractor().getValue(workingMemory, right.getObject()); 
     Object nodeRight = right.getObject(); 
     return isNegated^evaluateUnsafe(nodeLeft, nodeRight); 
    } 

    @Override 
    public boolean evaluateCachedRight(InternalWorkingMemory workingMemory, VariableContextEntry context, InternalFactHandle left) { 
     Object nodeLeft = ((ObjectVariableContextEntry) context).right; 
     Object nodeRight = context.getFieldExtractor().getValue(workingMemory, left.getObject()); 
     return isNegated^evaluateUnsafe(nodeLeft, nodeRight); 
    } 

    private boolean evaluateUnsafe(Object nodeLeft, Object nodeRight) { 
     if (!(nodeLeft instanceof Node)) { 
      throw new IllegalArgumentException("'nodeLeft' can't be casted to Node: " + nodeLeft.getClass()); 
     } 
     if (!(nodeRight instanceof Node)) { 
      throw new IllegalArgumentException("'nodeRight' can't be casted to Node: " + nodeRight.getClass()); 
     } 
     return evaluate((Node) nodeLeft, (Node) nodeRight); 
    } 

    private boolean evaluate(node nodeLeft, node nodeRight) { 
     Node current = nodeRight; 
     while (current != null) { 
      if (current == null) { 
       return false; 
      } 
      if (current == nodeLeft) { 
       return true; 
      } 
      current = current.getPrev(); 
     } 
     return false; 
    } 
} 

public class PrecedesEvaluatorDefinition implements EvaluatorDefinition { 
    private static final long serialVersionUID = ...L; 

    protected static final String precedesOp = "precedes"; 

    public static Operator PRECEDES; 
    public static Operator NOT_PRECEDES; 
    private static String[] SUPPORTED_IDS; 

    private PrecedesEvaluator evaluator; 
    private PrecedesEvaluator negatedEvaluator; 

    @Override 
    public String[] getEvaluatorIds() { 
     return new String[] {precedesOp}; 
    } 

    @Override 
    public boolean isNegatable() { 
     return true; 
    } 

    @Override 
    public Evaluator getEvaluator(ValueType type, String operatorId, boolean isNegated, String parameterText, Target leftTarget, Target rightTarget) { 
     return isNegated ? 
       (negatedEvaluator == null ? new PrecedesEvaluator(type, true) : negatedEvaluator) : 
       (evaluator == null ? new PrecedesEvaluator(type, false) : evaluator); 
    } 

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

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

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

    @Override 
    public boolean supportsType(ValueType type) { 
     return true; 
    } 

    @Override 
    public Target getTarget() { 
     return Target.BOTH; 
    } 

    @Override 
    public void writeExternal(ObjectOutput out) throws IOException { 
     throw new UnsupportedOperationException("writeExternal not usable"); 
    } 

    @Override 
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { 
     throw new UnsupportedOperationException("readExternal not usable"); 
    } 

    static { 
     if (SUPPORTED_IDS == null) { 
      PRECEDES = Operator.addOperatorToRegistry(precedesOp, false); 
      NOT_PRECEDES = Operator.addOperatorToRegistry(precedesOp, true); 
      SUPPORTED_IDS = new String[] {precedesOp}; 
     } 
    } 
} 

我看了一些导游网上,我试图注册程序的新操作如下:

private void initialise() { 
    if (base == null) { 
     ... 
     KieBaseConfiguration configuration = services.newKieBaseConfiguration(); 
     KieBaseOption option = EvaluatorOption.get(precedesOp, new PrecedesEvaluatorDefinition()); 
     configuration.setOption(option); // Wrong type 
     ... 
     base = container.newKieBase(configuration); 
    } 
} 

private void initialise() { 
    if (base == null) { 
     KnowledgeBuilderConfiguration configuration = KnowledgeBuilderFactory.newKnowledgeBuilderConfiguration(); 
     EvaluatorOption option = EvaluatorOption.get(precedesOp, new PrecedesEvaluatorDefinition()); 
     configuration.setOption(option); 
     ... 
     base = container.newKieBase(configuration); // Wrong type! 
    } 
} 

在这两种情况下,但是,一个类型不匹配发生,并且编译失败。

所以我的问题是:我该如何注册我的操作符才能在规则中使用(请注意,如果可能,我不希望使用XML文件)?

回答

1

我结束了使用KieHelper以下初始化,初始化全是干净多了。

KieServices ks = KieServices.Factory.get(); 
KieModuleModel kieModel = ks 
    .newKieModuleModel() 
    .setConfigurationProperty("drools.evaluator.precedes", PrecedesEvaluatorDefinition.class.getName()); 

KieBase kieBase = new KieHelper() 
    .setKieModuleModel(kieModel) 
    .addFromClassPath("/drools/Repetitions.drl") 
    .build(); 

受到drools本身的this test的启发。

+0

酷!我不知道这可能通过'KieServices'! :+1: –

0

下面的代码工作,但使用KnowledgeBase它被废弃了(所以这并不算作一个答案):

private KnowledgeBase base; 

public void process(List<Node> nodes) { 
    initialise(); 
    KieSession session = base.newKieSession(); 
    nodes.forEach(session::insert); 
    session.fireAllRules(); 
    session.dispose(); 
} 

private void initialise() { 
    if (base == null) { 
     // Get a configuration 
     KnowledgeBuilderConfiguration configuration = KnowledgeBuilderFactory.newKnowledgeBuilderConfiguration(); 
     // Instantiate the new custom operator and add it to configuration 
     EvaluatorOption option = EvaluatorOption.get(precedesOp, new PrecedesEvaluatorDefinition()); 
     configuration.setOption(option); 

     // Get a builder from the configuration 
     KnowledgeBuilder builder = KnowledgeBuilderFactory.newKnowledgeBuilder(configuration); 
     // Load a DRL and add it to the builder 
     String location = "/drools/Repetitions.drl"; 
     InputStream stream = getClass().getResourceAsStream(location); 
     Resource resource = ResourceFactory.newInputStreamResource(stream); 
     builder.add(resource, ResourceType.DRL); 
     // Test the builder for errors 
     if (builder.hasErrors()) { 
      throw new RuntimeException(join("\n", builder.getErrors())); 
     } 

     // Get a knowledge base and fill it with the builder's content 
     base = KnowledgeBaseFactory.newKnowledgeBase(); 
     base.addKnowledgePackages(builder.getKnowledgePackages()); 
    } 
}