[jboss-jira] [JBoss JIRA] (DROOLS-438) Pattern for "reuse java method" bug

Matteo Mortari (JIRA) issues at jboss.org
Tue Feb 18 16:27:47 EST 2014


Matteo Mortari created DROOLS-438:
-------------------------------------

             Summary: Pattern for "reuse java method" bug
                 Key: DROOLS-438
                 URL: https://issues.jboss.org/browse/DROOLS-438
             Project: Drools
          Issue Type: Bug
      Security Level: Public (Everyone can see)
    Affects Versions: 6.0.1.Final
            Reporter: Matteo Mortari
            Assignee: Mark Proctor


Ciao, in the documentation about "reuse Java methods" Ref. (1) a java.lang static method is used as a pattern.
* A-/ I hereby attach proof Java code to replicate the issue that doing so, rules will functionally work OK, actually, but in the background will increase memory consumption leading to Exception java.lang.OutOfMemoryError: Java heap space
* B-/ I also attach proof of Java code to replicate that by taking the "Java methods" from the pattern and when each one is extracted to their own "conditional element eval", then, it will work OK functionally *and* memory wise.

Therefore, I believe either of the two:
* The reference (1) is wrong, example should be corrected, and I suggest also should be put a warning that each "reuse Java methods" should get their own "conditional element eval"
* If reference (1) is intended to be working fine, then I suspect there is a bug in the background working of the ReteOO/Phreak algorithm, so I hope this helps identify the bug.

h6. References
(1) http://docs.jboss.org/drools/release/6.0.1.Final/drools-docs/html_single/#d0e7102 example {{Person( Math.round( weight / ( height * height ) ) < 25.0 )}}

h5. Java code to replicate
In the attached Maven project, in the src/main/resources there are two .drl files:
* {{package_usingReuseJavaMethodsExample.drl}} this will demonstrate point A above
* {{package_usingCEeval.drl}} this will demonstrate point B above

Leave only one of the two files with the .drl extension, so to decide which point to prove.

I encourage to run the {{AppRealtime.class}} with the following command line parameters: {{-XX:+HeapDumpOnOutOfMemoryError -Xms128m -Xmx128m -ea}}. The other two {{App*}} are left as I originally suspected this bug was due to the pseudo session clock, but it's not, so you can ignore them.

If running to demonstrate point A, it will after 3 minutes or so Exception java.lang.OutOfMemoryError: Java heap space as per attached screenshots.
If running to demonstrate point B, it will run forever, you can attach Java VisualVM as per attached screenshot.

h5. Business Requirements - explanation of the Rule
Sensor data is received as {{OpDatum.java}}, about temperature and heater on/off from xml and instantiated in Java object, put into a list {{AcmeModelListDTO.java}} to be inserted into the Working Memory.
* If temperature is < 9, then the heater must be running, otherwise an {{Alert}} must be raised.
* If temperature is >= 9, or the heater is running, and there was previously raised an {{Alert}}, then the {{Alert}} shall be retracted

The attached code is a minimalistic extraction of a bigger broader application, so there are pieces of Java code which could have been likely optimized, in this version.

h6. Style A
This implementation follows example at http://docs.jboss.org/drools/release/6.0.1.Final/drools-docs/html_single/#d0e7102 example {{Person( Math.round( weight / ( height * height ) ) < 25.0 )}}
Rules will functionally work OK, actually.
You will see that Java asserts in the {{AppRealtime.java}} are always met, and indeed the Working Memory fact count does not explode, the number of facts in the Working Memory is always limited.
But, in the background will increase memory consumption leading to Exception java.lang.OutOfMemoryError: Java heap space
{code}
package com.acme.drools6test.sessionclock;

/*
"reuse Java methods" Ref. [1]
Using analogous example from example "reuse Java methods" in the doc at [1].

This implementation, despite follow example documentation, does NOT work good.
Functionally, actually works OK. The rules behaves as expected indeed.
Problem is however memory consumption is always icreasing, leading to Out of Memory error
 
[1] http://docs.jboss.org/drools/release/6.0.1.Final/drools-docs/html_single/#d0e7102
 */

import org.acme.model.*

declare OpDatum
  @role(event)
  @timestamp(ts)
end

declare Alert
  @role(fact)
  condition : String
end

rule "AB1 Detect"
no-loop
dialect "mvel" 
when
	$oNumeric : OpDatum( id == "temperature", Double.parseDouble(val) < 9 )
	$oBoolean : OpDatum( id == "heater_powered", val == "False" ) 
	not( Alert( condition == "temperature freezing" ) )
then
	Alert a = new Alert();
	a.condition = "temperature freezing";
	insert(a);
	System.out.println( "AB1 Detect Alert : " + a);
end

rule "AB2 Clear"
no-loop
dialect "mvel" 
when
	$a : Alert( condition == "temperature freezing" )
	OpDatum( id == "heater_powered", val == "True" ) or OpDatum( id == "temperature", Double.parseDouble(val) >= 9 ) 
then
	retract($a);
	System.out.println("Alert "+$a+" retracted");
end

rule "OpDatum Housekeeping"
salience 1000
no-loop
dialect "mvel" 
when
    $oldOpDatum : OpDatum( $id : id  )
    $newOpDatum : OpDatum( this after $oldOpDatum, id == $id  )
then
    retract($oldOpDatum);
end
{code}

h6. Style B
This implementation instead take the "Java methods" from the pattern,
and when each one is extracted to their own "conditional element eval", then, it will work OK functionally *and* memory wise.
{code}
package com.acme.drools6test.sessionclock;

/*
"reuse Java methods" Ref. [1]
Using "import function" but then extracted each one is extracted to their own "conditional element eval" Ref. [2],
which is /different/ from example "reuse Java methods" in the doc at [1].

This works OK, functionally and memory wise.
 
[1] http://docs.jboss.org/drools/release/6.0.1.Final/drools-docs/html_single/#d0e7102
[2] http://docs.jboss.org/drools/release/6.0.1.Final/drools-docs/html_single/#d0e8745
 */

import function java.lang.Double.parseDouble

import org.acme.model.*

declare OpDatum
  @role(event)
  @timestamp(ts)
end

declare Alert
  @role(fact)
  condition : String
end

rule "AB1 Detect"
no-loop
dialect "mvel" 
when
	$oNumeric : OpDatum( id == "temperature", $val : val )
	eval( parseDouble($val) < 9 )
	$oBoolean : OpDatum( id == "heater_powered", val == "False" ) 
	not( Alert( condition == "temperature freezing" ) )
then
	Alert a = new Alert();
	a.condition = "temperature freezing";
	insert(a);
	System.out.println( "AB1 Detect Alert : " + a);
end

rule "AB2 Clear"
no-loop
dialect "mvel" 
when
	$a : Alert( condition == "temperature freezing" )
	OpDatum( id == "heater_powered", val == "True" )
		 or ( OpDatum( id == "temperature", $val : val ) and eval ( parseDouble($val) >= 9 ) ) 
then
	retract($a);
	System.out.println("Alert "+$a+" retracted");
end

rule "OpDatum Housekeeping"
salience 1000
no-loop
dialect "mvel" 
when
    $oldOpDatum : OpDatum( $id : id  )
    $newOpDatum : OpDatum( this after $oldOpDatum, id == $id  )
then
    retract($oldOpDatum);
end
{code}

h5. Conclusion
Kindly advise, I hope provided detailed explanation, and useful Java code to replicate. 
Thank you.
Ciao, Matteo

--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators
For more information on JIRA, see: http://www.atlassian.com/software/jira


More information about the jboss-jira mailing list