/*
* Copyright 2010 JBoss Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.drools.marshalling.impl;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.Map.Entry;
import org.drools.InitialFact;
import org.drools.base.ClassObjectType;
import org.drools.common.AgendaItem;
import org.drools.common.DefaultAgenda;
import org.drools.common.EqualityKey;
import org.drools.common.InternalFactHandle;
import org.drools.common.InternalRuleBase;
import org.drools.common.InternalWorkingMemory;
import org.drools.common.InternalWorkingMemoryEntryPoint;
import org.drools.common.LogicalDependency;
import org.drools.common.NodeMemory;
import org.drools.common.ObjectStore;
import org.drools.common.RuleFlowGroupImpl;
import org.drools.common.WorkingMemoryAction;
import org.drools.core.util.ObjectHashMap;
import org.drools.core.util.ObjectHashSet;
import org.drools.marshalling.ObjectMarshallingStrategy;
import org.drools.process.instance.WorkItem;
import org.drools.reteoo.BetaNode;
import org.drools.reteoo.LeftTuple;
import org.drools.reteoo.LeftTuple;
import org.drools.reteoo.LeftTupleSink;
import org.drools.reteoo.NodeTypeEnums;
import org.drools.reteoo.ObjectTypeNode;
import org.drools.reteoo.ReteooWorkingMemory;
import org.drools.reteoo.RightTuple;
import org.drools.reteoo.RuleTerminalNode;
import org.drools.reteoo.AccumulateNode.AccumulateContext;
import org.drools.reteoo.AccumulateNode.AccumulateMemory;
import org.drools.reteoo.FromNode.FromMemory;
import org.drools.rule.EntryPoint;
import org.drools.rule.Rule;
import org.drools.spi.Activation;
import org.drools.spi.ActivationGroup;
import org.drools.spi.AgendaGroup;
import org.drools.spi.PropagationContext;
import org.drools.spi.RuleFlowGroup;
public class OutputMarshaller {
private static ProcessMarshaller processMarshaller = createProcessMarshaller();
private static ProcessMarshaller createProcessMarshaller() {
try {
return ProcessMarshallerFactory.newProcessMarshaller();
} catch (IllegalArgumentException e) {
return null;
}
}
public static void writeSession(MarshallerWriteContext context) throws IOException {
ReteooWorkingMemory wm = (ReteooWorkingMemory) context.wm;
final boolean multithread = wm.isPartitionManagersActive();
// is multi-thread active?
if( multithread ) {
context.writeBoolean( true );
wm.stopPartitionManagers();
} else {
context.writeBoolean( false );
}
context.writeInt( wm.getFactHandleFactory().getId() );
context.writeLong( wm.getFactHandleFactory().getRecency() );
////context.out.println( "FactHandleFactory int:" + wm.getFactHandleFactory().getId() + " long:" + wm.getFactHandleFactory().getRecency() );
InternalFactHandle handle = context.wm.getInitialFactHandle();
context.writeInt( handle.getId() );
context.writeLong( handle.getRecency() );
//context.out.println( "InitialFact int:" + handle.getId() + " long:" + handle.getRecency() );
context.writeLong( wm.getPropagationIdCounter() );
//context.out.println( "PropagationCounter long:" + wm.getPropagationIdCounter() );
writeAgenda( context );
writeFactHandles( context );
writeActionQueue( context );
writeTruthMaintenanceSystem( context );
if ( context.marshalProcessInstances && processMarshaller != null ) {
processMarshaller.writeProcessInstances( context );
}
if ( context.marshalWorkItems && processMarshaller != null ) {
processMarshaller.writeWorkItems( context );
}
if ( processMarshaller != null ) {
processMarshaller.writeProcessTimers( context );
}
if( multithread ) {
wm.startPartitionManagers();
}
}
public static void writeAgenda(MarshallerWriteContext context) throws IOException {
InternalWorkingMemory wm = context.wm;
DefaultAgenda agenda = (DefaultAgenda) wm.getAgenda();
Map<String, ActivationGroup> activationGroups = agenda.getActivationGroupsMap();
AgendaGroup[] agendaGroups = (AgendaGroup[]) agenda.getAgendaGroupsMap().values().toArray( new AgendaGroup[agenda.getAgendaGroupsMap().size()] );
Arrays.sort( agendaGroups,
AgendaGroupSorter.instance );
for ( AgendaGroup group : agendaGroups ) {
context.writeShort( PersisterEnums.AGENDA_GROUP );
context.writeUTF( group.getName() );
context.writeBoolean( group.isActive() );
}
context.writeShort( PersisterEnums.END );
LinkedList<AgendaGroup> focusStack = agenda.getStackList();
for ( Iterator<AgendaGroup> it = focusStack.iterator(); it.hasNext(); ) {
AgendaGroup group = it.next();
context.writeShort( PersisterEnums.AGENDA_GROUP );
context.writeUTF( group.getName() );
}
context.writeShort( PersisterEnums.END );
RuleFlowGroupImpl[] ruleFlowGroups = (RuleFlowGroupImpl[]) agenda.getRuleFlowGroupsMap().values().toArray( new RuleFlowGroupImpl[agenda.getRuleFlowGroupsMap().size()] );
Arrays.sort( ruleFlowGroups,
RuleFlowGroupSorter.instance );
for ( RuleFlowGroupImpl group : ruleFlowGroups ) {
context.writeShort( PersisterEnums.RULE_FLOW_GROUP );
//group.write( context );
context.writeUTF( group.getName() );
context.writeBoolean( group.isActive() );
context.writeBoolean( group.isAutoDeactivate() );
Map<Long, String> nodeInstances = group.getNodeInstances();
context.writeInt( nodeInstances.size() );
for (Map.Entry<Long, String> entry: nodeInstances.entrySet()) {
context.writeLong( entry.getKey() );
context.writeUTF( entry.getValue() );
}
}
context.writeShort( PersisterEnums.END );
}
public static class AgendaGroupSorter
implements
Comparator<AgendaGroup> {
public static final AgendaGroupSorter instance = new AgendaGroupSorter();
public int compare(AgendaGroup group1,
AgendaGroup group2) {
return group1.getName().compareTo( group2.getName() );
}
}
public static class RuleFlowGroupSorter
implements
Comparator<RuleFlowGroup> {
public static final RuleFlowGroupSorter instance = new RuleFlowGroupSorter();
public int compare(RuleFlowGroup group1,
RuleFlowGroup group2) {
return group1.getName().compareTo( group2.getName() );
}
}
public static void writeActionQueue(MarshallerWriteContext context) throws IOException {
ReteooWorkingMemory wm = (ReteooWorkingMemory) context.wm;
WorkingMemoryAction[] queue = wm.getActionQueue().toArray( new WorkingMemoryAction[wm.getActionQueue().size()] );
for ( int i = queue.length - 1; i >= 0; i-- ) {
context.writeShort( PersisterEnums.WORKING_MEMORY_ACTION );
queue[i].write( context );
}
context.writeShort( PersisterEnums.END );
}
public static void writeTruthMaintenanceSystem(MarshallerWriteContext context) throws IOException {
ObjectOutputStream stream = context.stream;
ObjectHashMap assertMap = context.wm.getTruthMaintenanceSystem().getAssertMap();
EqualityKey[] keys = new EqualityKey[assertMap.size()];
org.drools.core.util.Iterator it = assertMap.iterator();
int i = 0;
for ( org.drools.core.util.ObjectHashMap.ObjectEntry entry = (org.drools.core.util.ObjectHashMap.ObjectEntry) it.next(); entry != null; entry = (org.drools.core.util.ObjectHashMap.ObjectEntry) it.next() ) {
EqualityKey key = (EqualityKey) entry.getKey();
keys[i++] = key;
}
Arrays.sort( keys,
EqualityKeySorter.instance );
// write the assert map of Equality keys
for ( EqualityKey key : keys ) {
stream.writeShort( PersisterEnums.EQUALITY_KEY );
stream.writeInt( key.getStatus() );
InternalFactHandle handle = key.getFactHandle();
stream.writeInt( handle.getId() );
//context.out.println( "EqualityKey int:" + key.getStatus() + " int:" + handle.getId() );
if ( key.getOtherFactHandle() != null && !key.getOtherFactHandle().isEmpty() ) {
for ( InternalFactHandle handle2 : key.getOtherFactHandle() ) {
stream.writeShort( PersisterEnums.FACT_HANDLE );
stream.writeInt( handle2.getId() );
//context.out.println( "OtherHandle int:" + handle2.getId() );
}
}
stream.writeShort( PersisterEnums.END );
}
stream.writeShort( PersisterEnums.END );
}
public static class EqualityKeySorter
implements
Comparator<EqualityKey> {
public static final EqualityKeySorter instance = new EqualityKeySorter();
public int compare(EqualityKey key1,
EqualityKey key2) {
return key1.getFactHandle().getId() - key2.getFactHandle().getId();
}
}
public static void writeFactHandles(MarshallerWriteContext context) throws IOException {
ObjectOutputStream stream = context.stream;
InternalWorkingMemory wm = context.wm;
ObjectMarshallingStrategyStore objectMarshallingStrategyStore = context.objectMarshallingStrategyStore;
writeInitialFactHandleRightTuples( context );
stream.writeInt( wm.getObjectStore().size() );
// Write out FactHandles
for ( InternalFactHandle handle : orderFacts( wm.getObjectStore() ) ) {
//stream.writeShort( PersisterEnums.FACT_HANDLE );
//InternalFactHandle handle = (InternalFactHandle) it.next();
writeFactHandle( context,
stream,
objectMarshallingStrategyStore,
handle );
writeRightTuples( handle,
context );
}
writeInitialFactHandleLeftTuples( context );
writeLeftTuples( context );
writePropagationContexts( context );
writeActivations( context );
}
private static void writeFactHandle(MarshallerWriteContext context,
ObjectOutputStream stream,
ObjectMarshallingStrategyStore objectMarshallingStrategyStore,
int type,
InternalFactHandle handle) throws IOException {
stream.writeInt( type );
stream.writeInt( handle.getId() );
stream.writeLong( handle.getRecency() );
//context.out.println( "Object : int:" + handle.getId() + " long:" + handle.getRecency() );
//context.out.println( handle.getObject() );
Object object = handle.getObject();
int index = objectMarshallingStrategyStore.getStrategy( object );
ObjectMarshallingStrategy strategy = objectMarshallingStrategyStore.getStrategy( index );
stream.writeInt( index );
strategy.write( stream,
object );
if( handle.getEntryPoint() instanceof InternalWorkingMemoryEntryPoint ){
String entryPoint = ((InternalWorkingMemoryEntryPoint)handle.getEntryPoint()).getEntryPoint().getEntryPointId();
if(entryPoint!=null && !entryPoint.equals("")){
stream.writeBoolean(true);
stream.writeUTF(entryPoint);
}
else{
stream.writeBoolean(false);
}
}else{
stream.writeBoolean(false);
}
}
private static void writeFactHandle(MarshallerWriteContext context,
ObjectOutputStream stream,
ObjectMarshallingStrategyStore objectMarshallingStrategyStore,
InternalFactHandle handle) throws IOException {
writeFactHandle( context, stream, objectMarshallingStrategyStore, 0, handle );
}
public static InternalFactHandle[] orderFacts(ObjectStore objectStore) {
// this method is just needed for testing purposes, to allow round tripping
int size = objectStore.size();
InternalFactHandle[] handles = new InternalFactHandle[size];
int i = 0;
for ( Iterator it = objectStore.iterateFactHandles(); it.hasNext(); ) {
handles[i++] = (InternalFactHandle) it.next();
}
Arrays.sort( handles,
new HandleSorter() );
return handles;
}
public static class HandleSorter
implements
Comparator<InternalFactHandle> {
public int compare(InternalFactHandle h1,
InternalFactHandle h2) {
return h1.getId() - h2.getId();
}
}
public static void writeInitialFactHandleRightTuples(MarshallerWriteContext context) throws IOException {
ObjectOutputStream stream = context.stream;
InternalRuleBase ruleBase = context.ruleBase;
ObjectTypeNode initialFactNode = ruleBase.getRete().getEntryPointNode( EntryPoint.DEFAULT ).getObjectTypeNodes().get( ClassObjectType.InitialFact_ObjectType );
// do we write the fact to the objecttypenode memory
if ( initialFactNode != null ) {
ObjectHashSet initialFactMemory = (ObjectHashSet) context.wm.getNodeMemory( initialFactNode );
if ( initialFactMemory != null && !initialFactMemory.isEmpty() ) {
//context.out.println( "InitialFactMemory true int:" + initialFactNode.getId() );
stream.writeBoolean( true );
stream.writeInt( initialFactNode.getId() );
//context.out.println( "InitialFact RightTuples" );
writeRightTuples( context.wm.getInitialFactHandle(),
context );
} else {
//context.out.println( "InitialFactMemory false " );
stream.writeBoolean( false );
}
} else {
//context.out.println( "InitialFactMemory false " );
stream.writeBoolean( false );
}
}
public static void writeInitialFactHandleLeftTuples(MarshallerWriteContext context) throws IOException {
ObjectOutputStream stream = context.stream;
//context.out.println( "InitialFact LeftTuples Start" );
InternalFactHandle handle = context.wm.getInitialFactHandle();
for ( LeftTuple leftTuple = handle.getFirstLeftTuple(); leftTuple != null; leftTuple = (LeftTuple) leftTuple.getLeftParentNext() ) {
stream.writeShort( PersisterEnums.LEFT_TUPLE );
stream.writeInt( leftTuple.getLeftTupleSink().getId() );
//context.out.println( "LeftTuple sinkId:" + leftTuple.getLeftTupleSink().getId() );
writeLeftTuple( leftTuple,
context,
true );
}
stream.writeShort( PersisterEnums.END );
//context.out.println( "InitialFact LeftTuples End" );
}
public static void writeRightTuples(InternalFactHandle handle,
MarshallerWriteContext context) throws IOException {
ObjectOutputStream stream = context.stream;
//context.out.println( "RightTuples Start" );
for (RightTuple rightTuple = handle.getFirstRightTuple(); rightTuple != null; rightTuple = (RightTuple) rightTuple.getHandleNext() ) {
stream.writeShort( PersisterEnums.RIGHT_TUPLE );
writeRightTuple( rightTuple,
context );
}
stream.writeShort( PersisterEnums.END );
//context.out.println( "RightTuples END" );
}
public static void writeRightTuple(RightTuple rightTuple,
MarshallerWriteContext context) throws IOException {
ObjectOutputStream stream = context.stream;
InternalWorkingMemory wm = context.wm;
// right tuples created in a "FromNode" have no sink, so we need to handle that appropriatelly
int id = rightTuple.getRightTupleSink() != null ? rightTuple.getRightTupleSink().getId() : -1;
stream.writeInt( id );
//context.out.println( "RightTuple sinkId:" + (rightTuple.getRightTupleSink() != null ? rightTuple.getRightTupleSink().getId() : -1) );
}
public static void writeLeftTuples(MarshallerWriteContext context) throws IOException {
ObjectOutputStream stream = context.stream;
InternalWorkingMemory wm = context.wm;
// Write out LeftTuples
//context.out.println( "LeftTuples Start" );
for ( InternalFactHandle handle : orderFacts( wm.getObjectStore() ) ) {
//InternalFactHandle handle = (InternalFactHandle) it.next();
for ( LeftTuple leftTuple = handle.getFirstLeftTuple(); leftTuple != null; leftTuple = (LeftTuple) leftTuple.getLeftParentNext() ) {
stream.writeShort( PersisterEnums.LEFT_TUPLE );
stream.writeInt( leftTuple.getLeftTupleSink().getId() );
stream.writeInt( handle.getId() );
//context.out.println( "LeftTuple sinkId:" + leftTuple.getLeftTupleSink().getId() + " handleId:" + handle.getId() );
writeLeftTuple( leftTuple,
context,
true );
}
}
stream.writeShort( PersisterEnums.END );
//context.out.println( "LeftTuples End" );
}
public static void writeLeftTuple(LeftTuple leftTuple,
MarshallerWriteContext context,
boolean recurse) throws IOException {
ObjectOutputStream stream = context.stream;
InternalRuleBase ruleBase = context.ruleBase;
InternalWorkingMemory wm = context.wm;
LeftTupleSink sink = leftTuple.getLeftTupleSink();
switch ( sink.getType() ) {
case NodeTypeEnums.JoinNode : {
//context.out.println( "JoinNode" );
for ( LeftTuple childLeftTuple = leftTuple.getFirstChild(); childLeftTuple != null; childLeftTuple = (LeftTuple) childLeftTuple.getLeftParentNext() ) {
stream.writeShort( PersisterEnums.RIGHT_TUPLE );
stream.writeInt( childLeftTuple.getLeftTupleSink().getId() );
stream.writeInt( childLeftTuple.getRightParent().getFactHandle().getId() );
//context.out.println( "RightTuple int:" + childLeftTuple.getLeftTupleSink().getId() + " int:" + childLeftTuple.getRightParent().getFactHandle().getId() );
writeLeftTuple( childLeftTuple,
context,
recurse );
}
stream.writeShort( PersisterEnums.END );
//context.out.println( "JoinNode --- END" );
break;
}
case NodeTypeEnums.EvalConditionNode : {
//context.out.println( ".... EvalConditionNode" );
for ( LeftTuple childLeftTuple = leftTuple.getFirstChild(); childLeftTuple != null; childLeftTuple = (LeftTuple) childLeftTuple.getLeftParentNext() ) {
stream.writeShort( PersisterEnums.LEFT_TUPLE );
stream.writeInt( childLeftTuple.getLeftTupleSink().getId() );
writeLeftTuple( childLeftTuple,
context,
recurse );
}
stream.writeShort( PersisterEnums.END );
//context.out.println( "---- EvalConditionNode --- END" );
break;
}
case NodeTypeEnums.NotNode :
case NodeTypeEnums.ForallNotNode : {
if ( leftTuple.getBlocker() == null ) {
// is not blocked so has children
stream.writeShort( PersisterEnums.LEFT_TUPLE_NOT_BLOCKED );
for ( LeftTuple childLeftTuple = leftTuple.getFirstChild(); childLeftTuple != null; childLeftTuple = (LeftTuple) childLeftTuple.getLeftParentNext() ) {
stream.writeShort( PersisterEnums.LEFT_TUPLE );
stream.writeInt( childLeftTuple.getLeftTupleSink().getId() );
writeLeftTuple( childLeftTuple,
context,
recurse );
}
stream.writeShort( PersisterEnums.END );
} else {
stream.writeShort( PersisterEnums.LEFT_TUPLE_BLOCKED );
stream.writeInt( leftTuple.getBlocker().getFactHandle().getId() );
}
break;
}
case NodeTypeEnums.ExistsNode : {
if ( leftTuple.getBlocker() == null ) {
// is blocked so has children
stream.writeShort( PersisterEnums.LEFT_TUPLE_NOT_BLOCKED );
} else {
stream.writeShort( PersisterEnums.LEFT_TUPLE_BLOCKED );
stream.writeInt( leftTuple.getBlocker().getFactHandle().getId() );
for ( LeftTuple childLeftTuple = leftTuple.getFirstChild(); childLeftTuple != null; childLeftTuple = (LeftTuple) childLeftTuple.getLeftParentNext() ) {
stream.writeShort( PersisterEnums.LEFT_TUPLE );
stream.writeInt( childLeftTuple.getLeftTupleSink().getId() );
writeLeftTuple( childLeftTuple,
context,
recurse );
}
stream.writeShort( PersisterEnums.END );
}
break;
}
case NodeTypeEnums.AccumulateNode : {
//context.out.println( ".... AccumulateNode" );
// accumulate nodes generate new facts on-demand and need special procedures when serializing to persistent storage
AccumulateMemory memory = (AccumulateMemory) context.wm.getNodeMemory( (BetaNode) sink );
AccumulateContext accctx = (AccumulateContext) memory.betaMemory.getCreatedHandles().get( leftTuple );
// first we serialize the generated fact handle
writeFactHandle( context,
stream,
context.objectMarshallingStrategyStore,
accctx.result.getFactHandle() );
// then we serialize the associated accumulation context
stream.writeObject( accctx.context );
// then we serialize the boolean propagated flag
stream.writeBoolean( accctx.propagated );
// then we serialize all the propagated tuples
for ( LeftTuple childLeftTuple = leftTuple.getFirstChild(); childLeftTuple != null; childLeftTuple = (LeftTuple) childLeftTuple.getLeftParentNext() ) {
if( leftTuple.getLeftTupleSink().getId() == childLeftTuple.getLeftTupleSink().getId()) {
// this is a matching record, so, associate the right tuples
//context.out.println( "RightTuple(match) int:" + childLeftTuple.getLeftTupleSink().getId() + " int:" + childLeftTuple.getRightParent().getFactHandle().getId() );
stream.writeShort( PersisterEnums.RIGHT_TUPLE );
stream.writeInt( childLeftTuple.getRightParent().getFactHandle().getId() );
} else {
// this is a propagation record
//context.out.println( "RightTuple(propagation) int:" + childLeftTuple.getLeftTupleSink().getId() + " int:" + childLeftTuple.getRightParent().getFactHandle().getId() );
stream.writeShort( PersisterEnums.LEFT_TUPLE );
stream.writeInt( childLeftTuple.getLeftTupleSink().getId() );
writeLeftTuple( childLeftTuple,
context,
recurse );
}
}
stream.writeShort( PersisterEnums.END );
//context.out.println( "---- AccumulateNode --- END" );
break;
}
case NodeTypeEnums.RightInputAdaterNode : {
//context.out.println( ".... RightInputAdapterNode" );
// RIANs generate new fact handles on-demand to wrap tuples and need special procedures when serializing to persistent storage
ObjectHashMap memory = (ObjectHashMap) context.wm.getNodeMemory( (NodeMemory) sink );
InternalFactHandle ifh = (InternalFactHandle) memory.get( leftTuple );
// first we serialize the generated fact handle ID
//context.out.println( "FactHandle id:"+ifh.getId() );
stream.writeInt( ifh.getId() );
stream.writeLong( ifh.getRecency() );
writeRightTuples( ifh, context );
stream.writeShort( PersisterEnums.END );
//context.out.println( "---- RightInputAdapterNode --- END" );
break;
}
case NodeTypeEnums.FromNode: {
//context.out.println( ".... FromNode" );
// FNs generate new fact handles on-demand to wrap objects and need special procedures when serializing to persistent storage
FromMemory memory = (FromMemory) context.wm.getNodeMemory( (NodeMemory) sink );
Map<Object, RightTuple> matches = (Map<Object, RightTuple>) memory.betaMemory.getCreatedHandles().get( leftTuple );
for ( RightTuple rightTuples : matches.values() ) {
// first we serialize the generated fact handle ID
stream.writeShort( PersisterEnums.FACT_HANDLE );
writeFactHandle( context,
stream,
context.objectMarshallingStrategyStore,
rightTuples.getFactHandle() );
writeRightTuples( rightTuples.getFactHandle(),
context );
}
stream.writeShort( PersisterEnums.END );
for ( LeftTuple childLeftTuple = leftTuple.getFirstChild(); childLeftTuple != null; childLeftTuple = (LeftTuple) childLeftTuple.getLeftParentNext() ) {
stream.writeShort( PersisterEnums.RIGHT_TUPLE );
stream.writeInt( childLeftTuple.getLeftTupleSink().getId() );
stream.writeInt( childLeftTuple.getRightParent().getFactHandle().getId() );
//context.out.println( "RightTuple int:" + childLeftTuple.getLeftTupleSink().getId() + " int:" + childLeftTuple.getRightParent().getFactHandle().getId() );
writeLeftTuple( childLeftTuple,
context,
recurse );
}
stream.writeShort( PersisterEnums.END );
//context.out.println( "---- FromNode --- END" );
break;
}
case NodeTypeEnums.UnificationNode : {
//context.out.println( ".... UnificationNode" );
for ( LeftTuple childLeftTuple = leftTuple.getFirstChild(); childLeftTuple != null; childLeftTuple = (LeftTuple) childLeftTuple.getLeftParentNext() ) {
stream.writeShort( PersisterEnums.LEFT_TUPLE );
stream.writeInt( childLeftTuple.getLeftTupleSink().getId() );
writeFactHandle( context,
stream,
context.objectMarshallingStrategyStore,
1,
childLeftTuple.getLastHandle() );
writeLeftTuple( childLeftTuple,
context,
recurse );
}
stream.writeShort( PersisterEnums.END );
//context.out.println( "---- EvalConditionNode --- END" );
break;
}
case NodeTypeEnums.RuleTerminalNode : {
//context.out.println( "RuleTerminalNode" );
int pos = context.terminalTupleMap.size();
context.terminalTupleMap.put( leftTuple,
pos );
break;
}
}
}
public static void writeActivations(MarshallerWriteContext context) throws IOException {
ObjectOutputStream stream = context.stream;
Entry<LeftTuple, Integer>[] entries = context.terminalTupleMap.entrySet().toArray( new Entry[context.terminalTupleMap.size()] );
Arrays.sort( entries,
TupleSorter.instance );
//Map<LeftTuple, Integer> tuples = context.terminalTupleMap;
if ( entries.length != 0 ) {
for ( Entry<LeftTuple, Integer> entry : entries ) {
if (entry.getKey().getObject() != null) {
LeftTuple leftTuple = entry.getKey();
stream.writeShort(PersisterEnums.ACTIVATION);
writeActivation(context, leftTuple, (AgendaItem) leftTuple
.getObject(), (RuleTerminalNode) leftTuple
.getLeftTupleSink());
}
}
}
stream.writeShort( PersisterEnums.END );
}
public static class TupleSorter
implements
Comparator<Entry<LeftTuple, Integer>> {
public static final TupleSorter instance = new TupleSorter();
public int compare(Entry<LeftTuple, Integer> e1,
Entry<LeftTuple, Integer> e2) {
return e1.getValue() - e2.getValue();
}
}
public static void writeActivation(MarshallerWriteContext context,
LeftTuple leftTuple,
AgendaItem agendaItem,
RuleTerminalNode ruleTerminalNode) throws IOException {
ObjectOutputStream stream = context.stream;
stream.writeLong( agendaItem.getActivationNumber() );
stream.writeInt( context.terminalTupleMap.get( leftTuple ) );
stream.writeInt( agendaItem.getSalience() );
Rule rule = agendaItem.getRule();
stream.writeUTF( rule.getPackage() );
stream.writeUTF( rule.getName() );
//context.out.println( "Rule " + rule.getPackage() + "." + rule.getName() );
//context.out.println( "AgendaItem long:" + agendaItem.getPropagationContext().getPropagationNumber() );
stream.writeLong( agendaItem.getPropagationContext().getPropagationNumber() );
if ( agendaItem.getActivationGroupNode() != null ) {
stream.writeBoolean( true );
//context.out.println( "ActivationGroup bool:" + true );
stream.writeUTF( agendaItem.getActivationGroupNode().getActivationGroup().getName() );
//context.out.println( "ActivationGroup string:" + agendaItem.getActivationGroupNode().getActivationGroup().getName() );
} else {
stream.writeBoolean( false );
//context.out.println( "ActivationGroup bool:" + false );
}
stream.writeBoolean( agendaItem.isActivated() );
//context.out.println( "AgendaItem bool:" + agendaItem.isActivated() );
org.drools.core.util.LinkedList list = agendaItem.getLogicalDependencies();
if ( list != null && !list.isEmpty() ) {
for ( LogicalDependency node = (LogicalDependency) list.getFirst(); node != null; node = (LogicalDependency) node.getNext() ) {
stream.writeShort( PersisterEnums.LOGICAL_DEPENDENCY );
stream.writeInt( ((InternalFactHandle) node.getFactHandle()).getId() );
//context.out.println( "Logical Depenency : int " + ((InternalFactHandle) node.getFactHandle()).getId() );
}
}
stream.writeShort( PersisterEnums.END );
}
public static void writePropagationContexts(MarshallerWriteContext context) throws IOException {
ObjectOutputStream stream = context.stream;
Entry<LeftTuple, Integer>[] entries = context.terminalTupleMap.entrySet().toArray( new Entry[context.terminalTupleMap.size()] );
Arrays.sort( entries,
TupleSorter.instance );
//Map<LeftTuple, Integer> tuples = context.terminalTupleMap;
if ( entries.length != 0 ) {
Map<Long, PropagationContext> pcMap = new HashMap<Long, PropagationContext>();
for ( Entry<LeftTuple, Integer> entry : entries ) {
LeftTuple leftTuple = entry.getKey();
if (leftTuple.getObject() != null) {
PropagationContext pc = ((Activation)leftTuple.getObject()).getPropagationContext();
if (!pcMap.containsKey(pc.getPropagationNumber())) {
stream.writeShort(PersisterEnums.PROPAGATION_CONTEXT);
writePropagationContext(context, pc);
pcMap.put(pc.getPropagationNumber(), pc);
}
}
}
}
stream.writeShort( PersisterEnums.END );
}
public static void writePropagationContext(MarshallerWriteContext context,
PropagationContext pc) throws IOException {
ObjectOutputStream stream = context.stream;
Map<LeftTuple, Integer> tuples = context.terminalTupleMap;
stream.writeInt( pc.getType() );
Rule ruleOrigin = pc.getRuleOrigin();
if ( ruleOrigin != null ) {
stream.writeBoolean( true );
stream.writeUTF( ruleOrigin.getPackage() );
stream.writeUTF( ruleOrigin.getName() );
} else {
stream.writeBoolean( false );
}
LeftTuple tupleOrigin = pc.getLeftTupleOrigin();
if ( tupleOrigin != null && tuples.containsKey( tupleOrigin )) {
stream.writeBoolean( true );
stream.writeInt( tuples.get( tupleOrigin ) );
} else {
stream.writeBoolean( false );
}
stream.writeLong( pc.getPropagationNumber() );
if ( pc.getFactHandleOrigin() != null ) {
stream.writeInt( ((InternalFactHandle)pc.getFactHandleOrigin()).getId() );
} else {
stream.writeInt( -1 );
}
stream.writeInt( pc.getActiveActivations() );
stream.writeInt( pc.getDormantActivations() );
stream.writeUTF( pc.getEntryPoint().getEntryPointId() );
}
public static void writeWorkItem(MarshallerWriteContext context,
WorkItem workItem) throws IOException {
ObjectOutputStream stream = context.stream;
stream.writeLong(workItem.getId());
stream.writeLong(workItem.getProcessInstanceId());
stream.writeUTF(workItem.getName());
stream.writeInt(workItem.getState());
//Work Item Parameters
Map<String, Object> parameters = workItem.getParameters();
Collection<Object> notNullValues = new ArrayList<Object>();
for(Object value: parameters.values()){
if(value != null){
notNullValues.add(value);
}
}
stream.writeInt(notNullValues.size());
for (String key : parameters.keySet()) {
Object object = parameters.get(key);
if(object != null){
stream.writeUTF(key);
int index = context.objectMarshallingStrategyStore.getStrategy(object);
stream.writeInt(index);
ObjectMarshallingStrategy strategy = context.objectMarshallingStrategyStore.getStrategy(index);
if(strategy.accept(object)){
strategy.write(stream, object);
}
}
}
}
}