[jboss-jira] [JBoss JIRA] (DROOLS-163) NPE when updating a fact of a FromNode
Davide Sottara (JIRA)
jira-events at lists.jboss.org
Wed Jun 5 05:51:54 EDT 2013
[ https://issues.jboss.org/browse/DROOLS-163?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12779423#comment-12779423 ]
Davide Sottara commented on DROOLS-163:
---------------------------------------
The keyword "from" should be used to match patterns against objects which are not (necessarily) in the working memory.
That is, objects that are so "local" to some rule that there is no point in inserting them in the WM. From, in fact,
does not check whether the object is actually in the WM (that would impact performance heavily), beacuse the most likely
answer would be NO.
So, it does not make sense to modify an object returned "from" an expression. We are discussing whether a compilation
error/warning should be generated.
In general, there are several options to write your rule in a more correct form, you should pick the one that makes
most sense for your use case. For example:
1) Modify the parent container rather than the object itself
when
$x : Parent( $z : collection ) $y : Child() from $z
then
$y.set( .. )
modify ( $x ) { .. }
end
2) Use memberOf, which requires the fact to be in the WM:
when
$x : Parent( $z : collection )
$y : Child( this memberOf $z )
then
modify ( $y ) { .. }
end
3) Use ==, which again requires the fact to be in the WM (a bit redundant though)
when
$x : Parent( $z : collection )
$w : Child( .. ) from $z
$y : Child( this == $w )
then
modify ( $y ) { .. }
end
> NPE when updating a fact of a FromNode
> --------------------------------------
>
> Key: DROOLS-163
> URL: https://issues.jboss.org/browse/DROOLS-163
> Project: Drools
> Issue Type: Bug
> Security Level: Public(Everyone can see)
> Affects Versions: 5.5.0.Final, 6.0.0.Beta2
> Environment: Windows7, JDK 1.6.26
> Reporter: Andreas Volz
> Assignee: Mark Proctor
> Labels: EntryPoint, FactHandle, NPE, update
> Attachments: npe.zip
>
>
> A NullPointerException is thrown when updating a fact of a FromNode.
> Here is the corresponding stack trace:
> {code}
> Exception executing consequence for rule "update_TestObjects_from_TestObjectContainer" in de.avo: java.lang.NullPointerException
> at org.drools.core.runtime.rule.impl.DefaultConsequenceExceptionHandler.handleException(DefaultConsequenceExceptionHandler.java:39)
> at org.drools.core.common.DefaultAgenda.fireActivation(DefaultAgenda.java:1424)
> at org.drools.core.common.DefaultAgenda.fireNextItem(DefaultAgenda.java:1343)
> at org.drools.core.common.DefaultAgenda.fireAllRules(DefaultAgenda.java:1561)
> at org.drools.core.common.AbstractWorkingMemory.fireAllRules(AbstractWorkingMemory.java:637)
> at org.drools.core.common.AbstractWorkingMemory.fireAllRules(AbstractWorkingMemory.java:601)
> at de.avo.Builder.fireAllRules(Builder.java:47)
> at de.avo.NPETest.testWrongFiringOrder(NPETest.java:37)
> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
> at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
> at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
> at java.lang.reflect.Method.invoke(Method.java:597)
> at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:59)
> at org.junit.internal.runners.MethodRoadie.runTestMethod(MethodRoadie.java:98)
> at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:79)
> at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:87)
> at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:77)
> at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:42)
> at org.junit.internal.runners.JUnit4ClassRunner.invokeTestMethod(JUnit4ClassRunner.java:88)
> at org.junit.internal.runners.JUnit4ClassRunner.runMethods(JUnit4ClassRunner.java:51)
> at org.junit.internal.runners.JUnit4ClassRunner$1.run(JUnit4ClassRunner.java:44)
> at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:27)
> at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:37)
> at org.junit.internal.runners.JUnit4ClassRunner.run(JUnit4ClassRunner.java:42)
> at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
> at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
> at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
> at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
> at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
> at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
> Caused by: java.lang.NullPointerException
> at org.drools.core.base.DefaultKnowledgeHelper.update(DefaultKnowledgeHelper.java:374)
> at org.drools.core.base.DefaultKnowledgeHelper.update(DefaultKnowledgeHelper.java:439)
> at org.drools.core.base.ModifyInterceptor.doAfter(ModifyInterceptor.java:79)
> at org.mvel2.ast.InterceptorWrapper.getReducedValueAccelerated(InterceptorWrapper.java:40)
> at org.mvel2.MVELRuntime.execute(MVELRuntime.java:85)
> at org.mvel2.compiler.CompiledExpression.getDirectValue(CompiledExpression.java:123)
> at org.mvel2.compiler.CompiledExpression.getValue(CompiledExpression.java:119)
> at org.mvel2.compiler.CompiledExpression.getValue(CompiledExpression.java:113)
> at org.mvel2.MVEL.executeExpression(MVEL.java:930)
> at org.drools.core.base.mvel.MVELConsequence.evaluate(MVELConsequence.java:100)
> at org.drools.core.common.DefaultAgenda.fireActivation(DefaultAgenda.java:1414)
> ... 28 more
> {code}
> By debugging the Drools code (version 6.0.0.Beta2) I've found out that in the class FromNode FactHandles are created; e.g. in the method createRightTuple:
> {code:title=FromNode#createRightTuple}
> ...
> if( _handle != null ) {
> // create a handle with the given id
> handle = workingMemory.getFactHandleFactory().newFactHandle( _handle.getId(),
> object,
> _handle.getRecency(),
> null, // set this to null, otherwise it uses the driver fact's entrypoint
> workingMemory,
> null );
> } else {
> handle = workingMemory.getFactHandleFactory().newFactHandle( object,
> null, // set this to null, otherwise it uses the driver fact's entrypoint
> workingMemory,
> null );
> }
> ...
> {code}
> As one can see in the code snippet above, the EntryPoint of the FactHandle is set to null. The newly created FactHandles are stored in the field {{identityMap}} of a knowledge helper (its type is DefaultKnowledgeHelper).
> When the fact that corresponds to the newly created FactHandle has to be updated, the method {{update(FactHandle handle, long mask, Class<?> modifiedClass)}} is called. In this method the EntryPoint of the FactHandle is used to issue the update. Since this EntryPoint has been set to null by the class FromNode, a NPE is thrown. Here is the code snippet where the NPE is thrown:
> {code:title=DefaultKnowledgeHelper}
> public void update(final FactHandle handle, long mask, Class<?> modifiedClass) {
> InternalFactHandle h = (InternalFactHandle) handle;
> ((InternalWorkingMemoryEntryPoint) h.getEntryPoint()).update( h,
> ((InternalFactHandle)handle).getObject(),
> mask,
> modifiedClass,
> this.activation );
> ...
> {code}
--
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