[rules-users] iterating over objects in a StatelessKnowledgeSession

Mark Proctor mproctor at codehaus.org
Thu Mar 19 12:17:06 EDT 2009


Based on your feedbck I have added support for a GetObjects command and 
a FireAllRules command. So now you can call GetObjects and have it's 
results assigned to an identifier. FireAllrules can now be manually 
called, even for a stateless session. If you manually call fireAllRules 
in a stateless session it will no longer be called automatically at the end.

Here are two unit tests showing the behaviour. I was going to leave this 
till 5.1, but it seems you really need this and the code is safe enough 
that it shouldn't break anything else.

    public void testGetObjects() throws Exception {
        String str = "";
        str += "package org.drools \n";
        str += "import org.drools.Cheese \n";
        str += "rule rule1 \n";
        str += "  when \n";
        str += "    $c : Cheese() \n";
        str += " \n";
        str += "  then \n";
        str += "    $c.setPrice( $c.getPrice() + 5 ); \n";
        str += "end\n";       

        String inXml = "";
        inXml += "<batch-execution>";      
        inXml += "  <insert-elements>";
        inXml += "    <org.drools.Cheese>";
        inXml += "      <type>stilton</type>";
        inXml += "      <price>25</price>";
        inXml += "      <oldPrice>0</oldPrice>";
        inXml += "    </org.drools.Cheese>";
        inXml += "    <org.drools.Cheese>";
        inXml += "      <type>stilton</type>";
        inXml += "      <price>30</price>";
        inXml += "      <oldPrice>0</oldPrice>";
        inXml += "    </org.drools.Cheese>";
        inXml += "  </insert-elements>";
        inXml += "  <get-objects out-identifier='list' />";
        inXml += "</batch-execution>";
       
        StatelessKnowledgeSession ksession = getSession2( 
ResourceFactory.newByteArrayResource( str.getBytes() ) );
        ResultHandlerImpl resultHandler = new ResultHandlerImpl();       
        getPipeline(ksession).insert( inXml, resultHandler );       
        String outXml = ( String ) resultHandler.getObject();
       
        String expectedXml = "";
        expectedXml += "<batch-execution-results>\n";
        expectedXml += "  <result identifier='list'>\n";
        expectedXml += "    <list>\n";
        expectedXml += "      <org.drools.Cheese>\n";
        expectedXml += "        <type>stilton</type>\n";
        expectedXml += "        <price>35</price>\n";       
        expectedXml += "        <oldPrice>0</oldPrice>\n";       
        expectedXml += "      </org.drools.Cheese>\n";
        expectedXml += "      <org.drools.Cheese>\n";
        expectedXml += "        <type>stilton</type>\n";    
        expectedXml += "        <price>30</price>\n";
        expectedXml += "        <oldPrice>0</oldPrice>\n";          
        expectedXml += "      </org.drools.Cheese>\n";
        expectedXml += "    </list>\n";       
        expectedXml += "  </result>\n";
        expectedXml += "</batch-execution-results>\n";
       
        assertXMLEqual( expectedXml, outXml );
       
        BatchExecutionResults result = ( BatchExecutionResults ) 
BatchExecutionHelper.newXStreamMarshaller().fromXML( outXml );
        List list = ( List ) result.getValue( "list" );
        Cheese stilton25 = new Cheese( "stilton", 30);
        Cheese stilton30 = new Cheese( "stilton", 35);
       
        Set expectedList = new HashSet();
        expectedList.add( stilton25 );
        expectedList.add( stilton30 );
       
        assertEquals( expectedList, new HashSet( list ));              
    }

    public void testManualFireAllRules() throws Exception {
        String str = "";
        str += "package org.drools \n";
        str += "import org.drools.Cheese \n";
        str += "global java.util.List list \n";
        str += "rule rule1 \n";
        str += "  when \n";
        str += "    $c : Cheese() \n";
        str += " \n";
        str += "  then \n";
        str += "    $c.setPrice( $c.getPrice() + 5 ); \n";
        str += "    list.add( $c );";
        str += "end\n";       

        String inXml = "";
        inXml += "<batch-execution>";
        inXml += "  <set-global identifier='list' out='true'>";
        inXml += "    <list/>";
        inXml += "  </set-global>";       
        inXml += "  <insert-elements>";
        inXml += "    <org.drools.Cheese>";
        inXml += "      <type>stilton</type>";
        inXml += "      <price>25</price>";
        inXml += "      <oldPrice>0</oldPrice>";
        inXml += "    </org.drools.Cheese>";
        inXml += "    <org.drools.Cheese>";
        inXml += "      <type>stilton</type>";
        inXml += "      <price>30</price>";
        inXml += "      <oldPrice>0</oldPrice>";
        inXml += "    </org.drools.Cheese>";
        inXml += "  </insert-elements>";
        inXml += "  <fire-all-rules />";
        inXml += "  <insert out-identifier='outBrie'>";
        inXml += "    <org.drools.Cheese>";
        inXml += "      <type>brie</type>";
        inXml += "      <price>10</price>";
        inXml += "      <oldPrice>5</oldPrice>";
        inXml += "    </org.drools.Cheese>";
        inXml += "  </insert>";         
        inXml += "</batch-execution>";
       
        StatelessKnowledgeSession ksession = getSession2( 
ResourceFactory.newByteArrayResource( str.getBytes() ) );
        ResultHandlerImpl resultHandler = new ResultHandlerImpl();       
        getPipeline(ksession).insert( inXml, resultHandler );       
        String outXml = ( String ) resultHandler.getObject();
       
        String expectedXml = "";
        expectedXml += "<batch-execution-results>\n";
        expectedXml += "  <result identifier='list'>\n";
        expectedXml += "    <list>\n";
        expectedXml += "      <org.drools.Cheese>\n";
        expectedXml += "        <type>stilton</type>\n";
        expectedXml += "        <price>35</price>\n";       
        expectedXml += "        <oldPrice>0</oldPrice>\n";       
        expectedXml += "      </org.drools.Cheese>\n";
        expectedXml += "      <org.drools.Cheese>\n";
        expectedXml += "        <type>stilton</type>\n";    
        expectedXml += "        <price>30</price>\n";
        expectedXml += "        <oldPrice>0</oldPrice>\n";          
        expectedXml += "      </org.drools.Cheese>\n";
        expectedXml += "    </list>\n";       
        expectedXml += "  </result>\n";
        expectedXml += "  <result identifier='outBrie'>\n";
        expectedXml += "    <org.drools.Cheese>\n";
        expectedXml += "      <type>brie</type>\n";
        expectedXml += "      <price>10</price>\n";
        expectedXml += "      <oldPrice>5</oldPrice>\n";
        expectedXml += "    </org.drools.Cheese>\n";
        expectedXml += "  </result>\n";         
        expectedXml += "</batch-execution-results>\n";
        assertXMLEqual( expectedXml, outXml );
       
        BatchExecutionResults result = ( BatchExecutionResults ) 
BatchExecutionHelper.newXStreamMarshaller().fromXML( outXml );
       
        // brie should not have been added to the list
        List list = ( List ) result.getValue( "list" );
        Cheese stilton25 = new Cheese( "stilton", 30);
        Cheese stilton30 = new Cheese( "stilton", 35);
       
        Set expectedList = new HashSet();
        expectedList.add( stilton25 );
        expectedList.add( stilton30 );
       
        assertEquals( expectedList, new HashSet( list ));

        // brie should not have changed
        Cheese brie10 = new Cheese( "brie", 10);
        brie10.setOldPrice( 5 );
        assertEquals( brie10, result.getValue( "outBrie" ) ); 
    }       





Michal Bali wrote:
> Hi Mark,
>
> I want this for a unit test. It will verify that the stateless session 
> contains only expected objects after execution. I don't want to write 
> a new query that will be used only in the unit test. 
>
> Currently it is possible to iterate over all objects in a 
> StatefulKnowledgeSession through its getObjects method. However it is 
> not supported by default on the StatelessKnowledgeSession.
>
> I've created a custom command for getting the objects. Its execute 
> method looks like this:
> public Iterator< ? > execute(ReteooWorkingMemory session) {
>     Iterator<?> objects = session.iterateObjects( filter );
>     session.getBatchExecutionResult().getResults().put(identifier, 
> objects);
>     return objects;
> }
>
> Another thing to note is that 
> StatelessKnowledgeSession.execute(Command command) method first 
> executes all given commands and then calls session.fireAllRules. So if 
> you want to insert some objects and run a query you'll pass some 
> insert commands and a query command. However the query will be 
> executed before the fireAllRules call and so it won't return anything.
> Alternatively you could pass in a fireAllRules command as well, which 
> will work fine. The fireAllRules will be executed twice but that is 
> not a big deal.
> Another issue is that the query command makes it difficult to pass in 
> query arguments that are known only after the rules execution. Because 
> you have to specify the query before the fireAllRules execution. I 
> guess you could create your own command and do all logic there but 
> this is not very nice.
>
> Just my 2c.
>
> Best Regards,
> Michal
>
>
> 2009/3/17 Mark Proctor <mproctor at codehaus.org 
> <mailto:mproctor at codehaus.org>>
>
>     Michal Bali wrote:
>>     Hi,
>>
>>     I am trying this on trunk. There is currently no way how to
>>     iterate objects in a StatelessKnowledgeSession.
>>
>>     I've tried to use the GetObjectsCommand, however when it is
>>     executes the result is lost in the ether :). The collection of
>>     objects is not handed back to the user.
>>
>>     I guess it should probably be added to the BatchExecutionResults?
>>     It will then be possible to access this collection of objects.
>     You have ot specify what it is you want as an out, either as an
>     'out' on an inserted fact or global or a query.
>>
>>     Please let me know if there is a different way how to iterate
>>     over objects in a StatelessKnowledgeSession. I'd like to use an
>>     ObjectFilter as well.
>     Extend the Query interface and use that to filter the iterator on
>     a returned query.
>>
>>     Best Regards,
>>     Michal
>>     ------------------------------------------------------------------------
>>     _______________________________________________
>>     rules-users mailing list
>>     rules-users at lists.jboss.org <mailto:rules-users at lists.jboss.org>
>>     https://lists.jboss.org/mailman/listinfo/rules-users
>>       
>
>
>     _______________________________________________
>     rules-users mailing list
>     rules-users at lists.jboss.org <mailto:rules-users at lists.jboss.org>
>     https://lists.jboss.org/mailman/listinfo/rules-users
>
>
> ------------------------------------------------------------------------
>
> _______________________________________________
> rules-users mailing list
> rules-users at lists.jboss.org
> https://lists.jboss.org/mailman/listinfo/rules-users
>   

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.jboss.org/pipermail/rules-users/attachments/20090319/22f60d9b/attachment.html 


More information about the rules-users mailing list