Details
-
Bug
-
Resolution: Done
-
Major
-
None
-
6.0.0.CR1
-
None
-
None
Description
Reproduce steps:
Assuming Employee is a subclass of Person...
1. Insert an Employee (say, 'Alice')
2. InsertLogical a Person (say, 'Bob')
3. Serialize and deserialize ksession
4. Insert an Employee (say, 'Claire')
5. Update 'Claire'
It throws an NEP:
Exception executing consequence for rule "Promote" in defaultpkg: java.lang.NullPointerException at org.drools.core.runtime.rule.impl.DefaultConsequenceExceptionHandler.handleException(DefaultConsequenceExceptionHandler.java:39) at org.drools.core.common.DefaultAgenda.fireActivation(DefaultAgenda.java:1026) ... Caused by: java.lang.NullPointerException at org.drools.core.common.NamedEntryPoint.update(NamedEntryPoint.java:434) at org.drools.core.base.DefaultKnowledgeHelper.update(DefaultKnowledgeHelper.java:367) at defaultpkg.Rule_Promote139773612.defaultConsequence(Rule_Promote139773612.java:9) at defaultpkg.Rule_Promote139773612DefaultConsequenceInvokerGenerated.evaluate(Unknown Source) at defaultpkg.Rule_Promote139773612DefaultConsequenceInvoker.evaluate(Unknown Source) at org.drools.core.common.DefaultAgenda.fireActivation(DefaultAgenda.java:1016) ... 37 more
In the step 2, ClassObjectTypeConf of Person[Bob] enables TMS. But at that time, Employee[Alice] creates its EqualityKey and put it to TMS.
NamedEntryPoint.java:
private void enableTMS(Object object, ObjectTypeConf conf) { final Rete source = this.ruleBase.getRete(); final ClassObjectType cot = new ClassObjectType( object.getClass() ); final Map<ObjectType, ObjectTypeNode> map = source.getObjectTypeNodes( EntryPointId.DEFAULT ); final ObjectTypeNode node = map.get( cot ); final ObjectHashSet memory = ((ObjectTypeNodeMemory) this.wm.getNodeMemory( node )).memory; // All objects of this type that are already there were certainly stated, // since this method call happens at the first logical insert, for any given type. org.drools.core.util.Iterator it = memory.iterator(); for ( Object obj = it.next(); obj != null; obj = it.next() ) { org.drools.core.util.ObjectHashSet.ObjectEntry holder = (org.drools.core.util.ObjectHashSet.ObjectEntry) obj; InternalFactHandle handle = (InternalFactHandle) holder.getValue(); if ( handle != null) { EqualityKey key = new EqualityKey( handle ); handle.setEqualityKey( key ); key.setStatus(EqualityKey.STATED); getTruthMaintenanceSystem().put(key); } } // Enable TMS for this type. conf.enableTMS(); }
Then during deserialization, ProtobufInputMarshaller enables TMS for ClassObjectTypeConf of Employee[Alice] and ClassObjectTypeConf of Person[Bob].
ProtobufInputMarshaller.java:
public static void readTruthMaintenanceSystem( MarshallerReaderContext context, RuleData _session ) throws IOException { TruthMaintenanceSystem tms = context.wm.getTruthMaintenanceSystem(); ProtobufMessages.TruthMaintenanceSystem _tms = _session.getTms(); for( ProtobufMessages.EqualityKey _key : _tms.getKeyList() ) { InternalFactHandle handle = (InternalFactHandle) context.handles.get( _key.getHandleId() ); // ObjectTypeConf state is not marshalled, so it needs to be re-determined ObjectTypeConf typeConf = context.wm.getObjectTypeConfigurationRegistry().getObjectTypeConf( ((NamedEntryPoint)handle.getEntryPoint()).getEntryPoint(), handle.getObject() ); if (!typeConf.isTMSEnabled()) { typeConf.enableTMS(); }
Finally, Employee(Claire) is updated. ClassObjectTypeConf of Employee is under TMS but Claire doesn't have EqualityKey hence NPE is thrown.