Search code examples
javadroolskie

KIE execution server - guided rule inserted fact - how to get it in Java?


I'm using 6.3.0 Drools Workbench and KIE Execution server with REST communication from JAVA app to KIE Execution server.

I'm novice in using Drools.

Here are the similar questions, but not clearing the problem (especially for REST and 6.3.0 combination):

OK, now that we set the ground, is this really impossible? Or we are all understanding this wrong? Something else? :)

The thing is that this is something that should be encountered very often because when you use the Guided Rule in Drools Workbench, it provides only this kind of action in THEN part of the rule: "Insert Fact ..." and "Logically insert fact ..." (and call method).

When added fact ("Transaction" in my case), it generates rule code like this:

import java.lang.Number;

rule "BigAmount"
    dialect "mvel"
    when
        Transaction( amount > 10000.0 )
    then
        Transaction fact0 = new Transaction();
        fact0.setActivatedRule( "BigAmount" );
        insert( fact0 );
end

And one would like to get this fact back in Java. What comes in Java result is this:

<fact-handle identifier="Transaction" external-form="0:9:338894407:338894407:9:DEFAULT:NON_TRAIT:hr.company.Transaction"/>

And when tried to retrieve it like this, you get NULL:

    ... before is request sent ...
    KieServerCommand call = new CallContainerCommand(containerId, xStreamXml);

    List<KieServerCommand> cmds = Arrays.asList(call);
    CommandScript script = new CommandScript(cmds);

    for (int i=0; i<1; i++) {        
        ServiceResponsesList reply = client.executeScript(script);        

        for (ServiceResponse<? extends Object> r : reply.getResponses()) {
            System.out.println(r.getResult());

            ExecutionResultImpl result = (ExecutionResultImpl) BatchExecutionHelper.newXStreamMarshaller().fromXML( (String) r.getResult() );
            DefaultFactHandle obj = (DefaultFactHandle) result.getFactHandle("Transaction");
            Transaction t = (Transaction) obj.getObject();
            System.out.println("BU!");
        }
    };

Or this is simply wrong approach?

Thanks!


Solution

  • Played with this some time, here is what I found out...

    I'm not sure if suggested solutions in mentioned questions and answers are different because of different Drools/KIE version or the fact that this is REST communication with KIE server, but they are not applicable here.

    Getting inserted objects (facts) in rules

    If you have rule like this:

    rule "BigAmount"
        dialect "mvel"
        when
            Transaction( amount > 10000.0 )
        then
            Transaction fact0 = new Transaction();
            fact0.setActivatedRule( "BigAmount" );
            insert( fact0 );
    end
    

    And you want to retrieve it in JAVA via REST, you need to insert GetObjects command in your BatchExecutionCommand:

        Transaction trans = new Transaction();      
        trans.setAmount(new Double(10001));
    
        // define commands
        InsertObjectCommand insertObjectCommand = new InsertObjectCommand(trans, "InputTransaction");
    
        GetObjectsCommand getObjectsCommand = new GetObjectsCommand();
        getObjectsCommand.setOutIdentifier("objects");
    
        FireAllRulesCommand fireAllRulesCommand = new FireAllRulesCommand("RunAllRules");
    
        // insert commands into Command object (BatchExecutionCommand)
        List<GenericCommand<?>> commands = new ArrayList<GenericCommand<?>>();
        commands.add(insertObjectCommand);
        commands.add(fireAllRulesCommand);
        commands.add(getObjectsCommand);
        BatchExecutionCommand command = new BatchExecutionCommandImpl(commands);
    
        String xStreamXml = BatchExecutionHelper.newXStreamMarshaller().toXML(command); // actual XML request
    

    So, important part here is:

        GetObjectsCommand getObjectsCommand = new GetbjectsCommand();
        getObjectsCommand.setOutIdentifier("objects");
    

    which will tell KIE server to return you separate node in XML - <result identifier="objects">, where you will find all objects in KIE session:

    <execution-results>
      <result identifier="InputTransaction">
        <com.company.fm.Transaction>
          <amount>10001.0</amount>
          <activatedRule>
            <string>BigAmount</string>
          </activatedRule>
        </com.company.fm.Transaction>
      </result>
      <result identifier="RunAllRules">
        <int>1</int>
      </result>
      <result identifier="objects">
        <list>
           ... all objects ...
        </list>
      </result>
      <fact-handle identifier="InputTransaction" external-form="0:1:226077856:226077856:1:DEFAULT:NON_TRAIT:com.company.fm.Transaction"/>
    </execution-results>
    

    After that, you can get ALL objects from session:

        // define kie client
        KieServicesConfiguration config = KieServicesFactory.newRestConfiguration(
                "http://docklin:8180/kie-server/services/rest/server",
                "ks-user",      //user must have role "kie-server" assigned
                "ks-user");
        config.setMarshallingFormat(MarshallingFormat.XSTREAM);     
    
        KieServicesClient client = KieServicesFactory.newKieServicesClient(config);     
    
        // set container for execution and prepare the call
        String containerId = "fm";
        KieServerCommand call = new CallContainerCommand(containerId, xStreamXml);        
        List<KieServerCommand> cmds = Arrays.asList(call);
        CommandScript script = new CommandScript(cmds);
    
        ServiceResponsesList reply = client.executeScript(script);        
    
        for (ServiceResponse<? extends Object> r : reply.getResponses()) {
                System.out.println(r.getResult());
    
                if (r.getResult() != null) {
                    ExecutionResultImpl result = (ExecutionResultImpl) BatchExecutionHelper.newXStreamMarshaller().fromXML((String) r.getResult());
                    // getting the same object that was sent but with filled in values
                    trans = (Transaction) result.getResults().get("InputTransaction");
                    // Objects From insert(fact0) in rule. The problem is that they are staying and multiplying there in Drools, don't know yet how to manage it. ToDo.
                    ArrayList<Object> objects = (ArrayList<Object>) result.getResults().get("objects");                 
                    System.out.println(objects); 
        }
        else
                    System.out.println("Empty result...?");
        }
    

    As noted in comment, this will return all objects in session. If you call the program several times, it will add objects to the session without removing old ones. I didn't have more time to play with it to figure out how this could be resolved to get only those from this single call. Retract or something probably.

    I actually found out that I don't need this at all (and that insert(fact) is probably not good for my use case) but that I want back the same input object I sent with filled values into it's attributes.

    Setting attributes to sent input object and retrieving this object back to Java

    I found out (told you I was a novice in Drools) that I can actually assign a variable to object in Drools workbench->Guided Rule. When you add an object in "WHEN" part of the rule by "Add a condition to the rule..." you just set the variable name (on the bottom of popup) and it will provide additional options in "THEN" part, like "Modify", "Change field values of ", ...

    If you choose "Change field ..." it will create rule like this:

    rule "BigAmount"
        dialect "mvel"
        when
            f : Transaction( amount >= 10000 )
        then
            f.addActivatedRule( "BigAmount" );
    end
    

    and then you'll actually get this value in the input object you sent ("InputTransaction" in my case), which is actually that was something I was aiming for, and will not insert new objects (facts) in session. That is this part in the code:

    // getting the same object that was sent but with filled in values
    trans = (Transaction) result.getResults().get("InputTransaction");
    

    I hope this helps someone.

    Regards, Eddie