2016-09-29 48 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()); 
    } 
}