Package org.drools.marshalling.impl

Source Code of org.drools.marshalling.impl.ProtobufOutputMarshaller$HandleSorter

/*
* 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.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.drools.InitialFact;
import org.drools.common.ActivationIterator;
import org.drools.common.AgendaItem;
import org.drools.common.DefaultAgenda;
import org.drools.common.EqualityKey;
import org.drools.common.EventFactHandle;
import org.drools.common.InternalFactHandle;
import org.drools.common.InternalWorkingMemory;
import org.drools.common.InternalWorkingMemoryEntryPoint;
import org.drools.common.LeftTupleIterator;
import org.drools.common.LogicalDependency;
import org.drools.common.Memory;
import org.drools.common.NamedEntryPoint;
import org.drools.common.NodeMemories;
import org.drools.common.ObjectStore;
import org.drools.common.ObjectTypeConfigurationRegistry;
import org.drools.common.QueryElementFactHandle;
import org.drools.common.RuleFlowGroupImpl;
import org.drools.common.WorkingMemoryAction;
import org.drools.core.util.LinkedListEntry;
import org.drools.core.util.ObjectHashMap;
import org.drools.core.util.ObjectHashMap.ObjectEntry;
import org.drools.marshalling.ObjectMarshallingStrategy;
import org.drools.marshalling.ObjectMarshallingStrategyStore;
import org.drools.marshalling.impl.ProtobufMessages.FactHandle;
import org.drools.marshalling.impl.ProtobufMessages.ObjectTypeConfiguration;
import org.drools.marshalling.impl.ProtobufMessages.ProcessData.Builder;
import org.drools.marshalling.impl.ProtobufMessages.Timers;
import org.drools.marshalling.impl.ProtobufMessages.Timers.Timer;
import org.drools.reteoo.AccumulateNode.AccumulateContext;
import org.drools.reteoo.AccumulateNode.AccumulateMemory;
import org.drools.reteoo.FromNode.FromMemory;
import org.drools.reteoo.LeftTuple;
import org.drools.reteoo.NodeTypeEnums;
import org.drools.reteoo.ObjectTypeConf;
import org.drools.reteoo.ObjectTypeNode.ObjectTypeNodeMemory;
import org.drools.reteoo.QueryElementNode.QueryElementNodeMemory;
import org.drools.reteoo.ReteooWorkingMemory;
import org.drools.reteoo.RightInputAdapterNode.RIAMemory;
import org.drools.reteoo.RightTuple;
import org.drools.rule.Rule;
import org.drools.runtime.rule.WorkingMemoryEntryPoint;
import org.drools.spi.AgendaGroup;
import org.drools.spi.RuleFlowGroup;
import org.drools.time.JobContext;
import org.drools.time.SelfRemovalJobContext;
import org.drools.time.Trigger;
import org.drools.time.impl.CronTrigger;
import org.drools.time.impl.IntervalTrigger;
import org.drools.time.impl.PointInTimeTrigger;
import org.drools.time.impl.PseudoClockScheduler;
import org.drools.time.impl.TimerJobInstance;

import com.google.protobuf.ByteString;

/**
* An output marshaller that uses ProtoBuf as the marshalling framework in order
* to provide backward compatibility with marshalled sessions
*
* @author etirelli
*/
public class ProtobufOutputMarshaller {

  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 {

    ProtobufMessages.KnowledgeSession _session = serializeSession(context);

    PersisterHelper.writeToStreamWithHeader(context, _session);
  }

  private static ProtobufMessages.KnowledgeSession serializeSession(
      MarshallerWriteContext context) throws IOException {
    ReteooWorkingMemory wm = (ReteooWorkingMemory) context.wm;
    wm.getAgenda().unstageActivations();

    ProtobufMessages.RuleData.Builder _ruleData = ProtobufMessages.RuleData
        .newBuilder();

    final boolean multithread = wm.isPartitionManagersActive();
    if (multithread) {
      wm.stopPartitionManagers();
    }

    long time = 0;
    if (context.wm.getTimerService() instanceof PseudoClockScheduler) {
      time = context.clockTime;
    }
    _ruleData.setLastId(wm.getFactHandleFactory().getId());
    _ruleData.setLastRecency(wm.getFactHandleFactory().getRecency());

    InternalFactHandle handle = context.wm.getInitialFactHandle();
    ProtobufMessages.FactHandle _ifh = ProtobufMessages.FactHandle
        .newBuilder()
        .setType(ProtobufMessages.FactHandle.HandleType.INITIAL_FACT)
        .setId(handle.getId()).setRecency(handle.getRecency()).build();
    _ruleData.setInitialFact(_ifh);

    writeAgenda(context, _ruleData);

    writeNodeMemories(context, _ruleData);

    for (WorkingMemoryEntryPoint wmep : wm.getEntryPoints().values()) {
      org.drools.marshalling.impl.ProtobufMessages.EntryPoint.Builder _epb = ProtobufMessages.EntryPoint
          .newBuilder();
      _epb.setEntryPointId(wmep.getEntryPointId());
     
          writeObjectTypeConfiguration( context,
                   ((InternalWorkingMemoryEntryPoint)wmep).getObjectTypeConfigurationRegistry(),
                   _epb );

      writeFactHandles(context, _epb,
          ((NamedEntryPoint) wmep).getObjectStore());
      _ruleData.addEntryPoint(_epb.build());
    }

    writeActionQueue(context, _ruleData);

    writeTruthMaintenanceSystem(context, _ruleData);

    ProtobufMessages.KnowledgeSession.Builder _session = ProtobufMessages.KnowledgeSession
        .newBuilder().setMultithread(multithread).setTime(time)
        .setRuleData(_ruleData.build());

    if (processMarshaller != null) {
      Builder _pdata = ProtobufMessages.ProcessData.newBuilder();
      if (context.marshalProcessInstances) {
        context.parameterObject = _pdata;
        processMarshaller.writeProcessInstances(context);
      }

      if (context.marshalWorkItems) {
        context.parameterObject = _pdata;
        processMarshaller.writeWorkItems(context);
      }

      // this now just assigns the writer, it will not write out any timer
      // information
      context.parameterObject = _pdata;
      processMarshaller.writeProcessTimers(context);

      _session.setProcessData(_pdata.build());
    }

    Timers _timers = writeTimers(context.wm.getTimerService()
        .getTimerJobInstances(), context);
    if (_timers != null) {
      _session.setTimers(_timers);
    }

    if (multithread) {
      wm.startPartitionManagers();
    }

    return _session.build();
  }

  private static void writeAgenda(MarshallerWriteContext context,
      ProtobufMessages.RuleData.Builder _ksb) throws IOException {
    InternalWorkingMemory wm = context.wm;
    DefaultAgenda agenda = (DefaultAgenda) wm.getAgenda();

    org.drools.marshalling.impl.ProtobufMessages.Agenda.Builder _ab = ProtobufMessages.Agenda
        .newBuilder();

    AgendaGroup[] agendaGroups = (AgendaGroup[]) agenda
        .getAgendaGroupsMap().values()
        .toArray(new AgendaGroup[agenda.getAgendaGroupsMap().size()]);
    Arrays.sort(agendaGroups, AgendaGroupSorter.instance);
    for (AgendaGroup group : agendaGroups) {
      org.drools.marshalling.impl.ProtobufMessages.Agenda.AgendaGroup.Builder _agb = ProtobufMessages.Agenda.AgendaGroup
          .newBuilder();
      _agb.setName(group.getName());
      _agb.setIsActive(group.isActive());
      _ab.addAgendaGroup(_agb.build());

    }

    org.drools.marshalling.impl.ProtobufMessages.Agenda.FocusStack.Builder _fsb = ProtobufMessages.Agenda.FocusStack
        .newBuilder();
    LinkedList<AgendaGroup> focusStack = agenda.getStackList();
    for (Iterator<AgendaGroup> it = focusStack.iterator(); it.hasNext();) {
      AgendaGroup group = it.next();
      _fsb.addGroupName(group.getName());
    }
    _ab.setFocusStack(_fsb.build());

    RuleFlowGroupImpl[] ruleFlowGroups = (RuleFlowGroupImpl[]) agenda
        .getRuleFlowGroupsMap()
        .values()
        .toArray(
            new RuleFlowGroupImpl[agenda.getRuleFlowGroupsMap()
                .size()]);
    Arrays.sort(ruleFlowGroups, RuleFlowGroupSorter.instance);
    for (RuleFlowGroupImpl group : ruleFlowGroups) {
      org.drools.marshalling.impl.ProtobufMessages.Agenda.RuleFlowGroup.Builder _rfgb = ProtobufMessages.Agenda.RuleFlowGroup
          .newBuilder();
      _rfgb.setName(group.getName());
      _rfgb.setIsActive(group.isActive());
      _rfgb.setIsAutoDeactivate(group.isAutoDeactivate());

      Map<Long, String> nodeInstances = group.getNodeInstances();
      for (Map.Entry<Long, String> entry : nodeInstances.entrySet()) {
        org.drools.marshalling.impl.ProtobufMessages.Agenda.RuleFlowGroup.NodeInstance.Builder _nib = ProtobufMessages.Agenda.RuleFlowGroup.NodeInstance
            .newBuilder();
        _nib.setProcessInstanceId(entry.getKey());
        _nib.setNodeInstanceId(entry.getValue());
        _rfgb.addNodeInstance(_nib.build());
      }
      _ab.addRuleFlowGroup(_rfgb.build());
    }

    // serialize all dormant activations
    ActivationIterator it = ActivationIterator.iterator(wm);
    List<org.drools.spi.Activation> dormant = new ArrayList<org.drools.spi.Activation>();
    for (org.drools.spi.Activation item = (org.drools.spi.Activation) it
        .next(); item != null; item = (org.drools.spi.Activation) it
        .next()) {
      if (!item.isActive()) {
        dormant.add(item);
      }
    }
    Collections.sort(dormant, ActivationsSorter.INSTANCE);
    for (org.drools.spi.Activation activation : dormant) {
      _ab.addActivation(writeActivation(context, (AgendaItem) activation));
    }

    _ksb.setAgenda(_ab.build());
  }

  private static void writeNodeMemories(MarshallerWriteContext context,
      ProtobufMessages.RuleData.Builder _ksb) throws IOException {
    InternalWorkingMemory wm = context.wm;
    NodeMemories memories = wm.getNodeMemories();
    // only some of the node memories require special serialization handling
    // so we iterate over all of them and process only those that require it
    for (int i = 0; i < memories.length(); i++) {
      Memory memory = memories.peekNodeMemory(i);
      // some nodes have no memory, so we need to check for nulls
      if (memory != null) {
        ProtobufMessages.NodeMemory _node = null;
        switch (memory.getNodeType()) {
        case NodeTypeEnums.AccumulateNode: {
          _node = writeAccumulateNodeMemory(i, memory);
          break;
        }
        case NodeTypeEnums.RightInputAdaterNode: {
          _node = writeRIANodeMemory(i, memory);
          break;
        }
        case NodeTypeEnums.FromNode: {
          _node = writeFromNodeMemory(i, memory);
          break;
        }
        case NodeTypeEnums.QueryElementNode: {
          _node = writeQueryElementNodeMemory(i, memory, wm);
          break;
        }
        }
        if (_node != null) {
          // not all node memories require serialization
          _ksb.addNodeMemory(_node);
        }
      }
    }

  }

  private static ProtobufMessages.NodeMemory writeAccumulateNodeMemory(
      final int nodeId, final Memory memory) {
    // for accumulate nodes, we need to store the ID of created (result)
    // handles
    AccumulateMemory accmem = (AccumulateMemory) memory;
    if (accmem.betaMemory.getLeftTupleMemory().size() > 0) {
      ProtobufMessages.NodeMemory.AccumulateNodeMemory.Builder _accumulate = ProtobufMessages.NodeMemory.AccumulateNodeMemory
          .newBuilder();

      final org.drools.core.util.Iterator tupleIter = accmem.betaMemory
          .getLeftTupleMemory().iterator();
      for (LeftTuple leftTuple = (LeftTuple) tupleIter.next(); leftTuple != null; leftTuple = (LeftTuple) tupleIter
          .next()) {
        AccumulateContext accctx = (AccumulateContext) leftTuple
            .getObject();
        if (accctx.result != null) {
          FactHandle _handle = ProtobufMessages.FactHandle
              .newBuilder()
              .setId(accctx.result.getFactHandle().getId())
              .setRecency(
                  accctx.result.getFactHandle().getRecency())
              .build();
          _accumulate
              .addContext(ProtobufMessages.NodeMemory.AccumulateNodeMemory.AccumulateContext
                  .newBuilder()
                  .setTuple(
                      PersisterHelper
                          .createTuple(leftTuple))
                  .setResultHandle(_handle).build());
        }
      }

      return ProtobufMessages.NodeMemory
          .newBuilder()
          .setNodeId(nodeId)
          .setNodeType(
              ProtobufMessages.NodeMemory.NodeType.ACCUMULATE)
          .setAccumulate(_accumulate.build()).build();
    }
    return null;
  }

  private static ProtobufMessages.NodeMemory writeRIANodeMemory(
      final int nodeId, final Memory memory) {
    // for RIA nodes, we need to store the ID of the created handles
    RIAMemory mem = (RIAMemory) memory;
    if (!mem.memory.isEmpty()) {
      ProtobufMessages.NodeMemory.RIANodeMemory.Builder _ria = ProtobufMessages.NodeMemory.RIANodeMemory
          .newBuilder();

      final org.drools.core.util.Iterator it = mem.memory.iterator();
      // iterates over all propagated handles and assert them to the new
      // sink
      for (ObjectEntry entry = (ObjectEntry) it.next(); entry != null; entry = (ObjectEntry) it
          .next()) {
        LeftTuple leftTuple = (LeftTuple) entry.getKey();
        InternalFactHandle handle = (InternalFactHandle) entry
            .getValue();
        FactHandle _handle = ProtobufMessages.FactHandle.newBuilder()
            .setId(handle.getId()).setRecency(handle.getRecency())
            .build();
        _ria.addContext(ProtobufMessages.NodeMemory.RIANodeMemory.RIAContext
            .newBuilder()
            .setTuple(PersisterHelper.createTuple(leftTuple))
            .setResultHandle(_handle).build());
      }

      return ProtobufMessages.NodeMemory.newBuilder().setNodeId(nodeId)
          .setNodeType(ProtobufMessages.NodeMemory.NodeType.RIA)
          .setRia(_ria.build()).build();
    }
    return null;
  }

  @SuppressWarnings("unchecked")
  private static ProtobufMessages.NodeMemory writeFromNodeMemory(
      final int nodeId, final Memory memory) {
    FromMemory fromMemory = (FromMemory) memory;

    if (fromMemory.betaMemory.getLeftTupleMemory().size() > 0) {
      ProtobufMessages.NodeMemory.FromNodeMemory.Builder _from = ProtobufMessages.NodeMemory.FromNodeMemory
          .newBuilder();

      final org.drools.core.util.Iterator tupleIter = fromMemory.betaMemory
          .getLeftTupleMemory().iterator();
      for (LeftTuple leftTuple = (LeftTuple) tupleIter.next(); leftTuple != null; leftTuple = (LeftTuple) tupleIter
          .next()) {
        Map<Object, RightTuple> matches = (Map<Object, RightTuple>) leftTuple
            .getObject();
        ProtobufMessages.NodeMemory.FromNodeMemory.FromContext.Builder _context = ProtobufMessages.NodeMemory.FromNodeMemory.FromContext
            .newBuilder().setTuple(
                PersisterHelper.createTuple(leftTuple));
        for (RightTuple rightTuple : matches.values()) {
          FactHandle _handle = ProtobufMessages.FactHandle
              .newBuilder()
              .setId(rightTuple.getFactHandle().getId())
              .setRecency(rightTuple.getFactHandle().getRecency())
              .build();
          _context.addHandle(_handle);
        }
        _from.addContext(_context.build());
      }

      return ProtobufMessages.NodeMemory.newBuilder().setNodeId(nodeId)
          .setNodeType(ProtobufMessages.NodeMemory.NodeType.FROM)
          .setFrom(_from.build()).build();
    }
    return null;
  }

  private static ProtobufMessages.NodeMemory writeQueryElementNodeMemory(
      final int nodeId, final Memory memory,
      final InternalWorkingMemory wm) {
    LeftTupleIterator it = LeftTupleIterator.iterator(wm,
        ((QueryElementNodeMemory) memory).node);

    ProtobufMessages.NodeMemory.QueryElementNodeMemory.Builder _query = ProtobufMessages.NodeMemory.QueryElementNodeMemory
        .newBuilder();
    for (LeftTuple leftTuple = (LeftTuple) it.next(); leftTuple != null; leftTuple = (LeftTuple) it
        .next()) {
      InternalFactHandle handle = (InternalFactHandle) leftTuple
          .getObject();
      FactHandle _handle = ProtobufMessages.FactHandle.newBuilder()
          .setId(handle.getId()).setRecency(handle.getRecency())
          .build();

      ProtobufMessages.NodeMemory.QueryElementNodeMemory.QueryContext.Builder _context = ProtobufMessages.NodeMemory.QueryElementNodeMemory.QueryContext
          .newBuilder()
          .setTuple(PersisterHelper.createTuple(leftTuple))
          .setHandle(_handle);

      LeftTuple childLeftTuple = leftTuple.getFirstChild();
      while (childLeftTuple != null) {
        RightTuple rightParent = childLeftTuple.getRightParent();
        _context.addResult(ProtobufMessages.FactHandle.newBuilder()
            .setId(rightParent.getFactHandle().getId())
            .setRecency(rightParent.getFactHandle().getRecency())
            .build());
        while (childLeftTuple != null
            && childLeftTuple.getRightParent() == rightParent) {
          // skip to the next child that has a different right parent
          childLeftTuple = childLeftTuple.getLeftParentNext();
        }
      }
      _query.addContext(_context.build());
    }

    return _query.getContextCount() > 0 ? ProtobufMessages.NodeMemory
        .newBuilder()
        .setNodeId(nodeId)
        .setNodeType(ProtobufMessages.NodeMemory.NodeType.QUERY_ELEMENT)
        .setQueryElement(_query.build()).build()
        : null;
  }

  private 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());
    }
  }

  private 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,
      ProtobufMessages.RuleData.Builder _session) throws IOException {

    ReteooWorkingMemory wm = (ReteooWorkingMemory) context.wm;
    if (!wm.getActionQueue().isEmpty()) {
      ProtobufMessages.ActionQueue.Builder _queue = ProtobufMessages.ActionQueue
          .newBuilder();

      WorkingMemoryAction[] queue = wm.getActionQueue().toArray(
          new WorkingMemoryAction[wm.getActionQueue().size()]);
      for (int i = queue.length - 1; i >= 0; i--) {
        _queue.addAction(queue[i].serialize(context));
      }
      _session.setActionQueue(_queue.build());
    }
  }

  public static void writeTruthMaintenanceSystem(
      MarshallerWriteContext context,
      ProtobufMessages.RuleData.Builder _session) throws IOException {
    ObjectHashMap assertMap = context.wm.getTruthMaintenanceSystem()
        .getAssertMap();
    ObjectHashMap justifiedMap = context.wm.getTruthMaintenanceSystem()
        .getJustifiedMap();

    if (!assertMap.isEmpty() || !justifiedMap.isEmpty()) {
      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);

      ProtobufMessages.TruthMaintenanceSystem.Builder _tms = ProtobufMessages.TruthMaintenanceSystem
          .newBuilder();

      // write the assert map of Equality keys
      for (EqualityKey key : keys) {
        ProtobufMessages.EqualityKey.Builder _key = ProtobufMessages.EqualityKey
            .newBuilder();
        _key.setStatus(key.getStatus());
        _key.setHandleId(key.getFactHandle().getId());
        if (key.getOtherFactHandle() != null
            && !key.getOtherFactHandle().isEmpty()) {
          for (InternalFactHandle handle : key.getOtherFactHandle()) {
            _key.addOtherHandle(handle.getId());
          }
        }
        _tms.addKey(_key.build());
      }

      it = justifiedMap.iterator();
      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()) {
        ProtobufMessages.Justification.Builder _justification = ProtobufMessages.Justification
            .newBuilder();
        _justification.setHandleId(((Integer) entry.getKey())
            .intValue());

        org.drools.core.util.LinkedList list = (org.drools.core.util.LinkedList) entry
            .getValue();
        for (LinkedListEntry node = (LinkedListEntry) list.getFirst(); node != null; node = (LinkedListEntry) node
            .getNext()) {
          LogicalDependency dependency = (LogicalDependency) node
              .getObject();
          org.drools.spi.Activation activation = dependency
              .getJustifier();
          ProtobufMessages.Activation _activation = ProtobufMessages.Activation
              .newBuilder()
              .setPackageName(activation.getRule().getPackage())
              .setRuleName(activation.getRule().getName())
              .setTuple(
                  PersisterHelper.createTuple(activation
                      .getTuple())).build();
          _justification.addActivation(_activation);
        }
        _tms.addJustification(_justification.build());
      }
      _session.setTms(_tms.build());
    }
  }

  private static void writeObjectTypeConfiguration( MarshallerWriteContext context,
                                                ObjectTypeConfigurationRegistry otcr,
                                                org.drools.marshalling.impl.ProtobufMessages.EntryPoint.Builder _epb) {
    for (ObjectTypeConf otc : otcr.values()) {
      final ObjectTypeNodeMemory memory = (ObjectTypeNodeMemory) context.wm
          .getNodeMemory(otc.getConcreteObjectTypeNode());
      if (memory != null && !memory.memory.isEmpty()) {
        ObjectTypeConfiguration _otc = ObjectTypeConfiguration
            .newBuilder().setType(otc.getTypeName())
            .setTmsEnabled(otc.isTMSEnabled()).build();
        _epb.addOtc(_otc);
      }
    }
  }

  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();
    }
  }

  private static void writeFactHandles(
      MarshallerWriteContext context,
      org.drools.marshalling.impl.ProtobufMessages.EntryPoint.Builder _epb,
      ObjectStore objectStore) throws IOException {
    ObjectMarshallingStrategyStore objectMarshallingStrategyStore = context.objectMarshallingStrategyStore;

    // Write out FactHandles
    for (InternalFactHandle handle : orderFacts(objectStore)) {
      ProtobufMessages.FactHandle _handle = writeFactHandle(context,
          objectMarshallingStrategyStore, handle);

      _epb.addHandle(_handle);
    }
  }

  private static ProtobufMessages.FactHandle writeFactHandle(
      MarshallerWriteContext context,
      ObjectMarshallingStrategyStore objectMarshallingStrategyStore,
      InternalFactHandle handle) throws IOException {
    ProtobufMessages.FactHandle.Builder _handle = ProtobufMessages.FactHandle
        .newBuilder();

    _handle.setType(getHandleType(handle));
    _handle.setId(handle.getId());
    _handle.setRecency(handle.getRecency());

    if (_handle.getType() == ProtobufMessages.FactHandle.HandleType.EVENT) {
      // is event
      EventFactHandle efh = (EventFactHandle) handle;
      _handle.setTimestamp(efh.getStartTimestamp());
      _handle.setDuration(efh.getDuration());
      _handle.setIsExpired(efh.isExpired());
      _handle.setActivationsCount(efh.getActivationsCount());
    }

    Object object = handle.getObject();

    if (object != null) {
      ObjectMarshallingStrategy strategy = objectMarshallingStrategyStore
          .getStrategyObject(object);

      Integer index = context.getStrategyIndex(strategy);
      _handle.setStrategyIndex(index.intValue());
      _handle.setObject(ByteString.copyFrom(strategy.marshal(
          context.strategyContext.get(strategy), context, object)));
    }

    return _handle.build();
  }

  private static ProtobufMessages.FactHandle.HandleType getHandleType(
      InternalFactHandle handle) {
    if (handle instanceof EventFactHandle) {
      return ProtobufMessages.FactHandle.HandleType.EVENT;
    } else if (handle instanceof QueryElementFactHandle) {
      return ProtobufMessages.FactHandle.HandleType.QUERY;
    } else if (handle.getObject() instanceof InitialFact) {
      return ProtobufMessages.FactHandle.HandleType.INITIAL_FACT;
    }
    return ProtobufMessages.FactHandle.HandleType.FACT;
  }

  public static InternalFactHandle[] orderFacts(ObjectStore objectStore) {
    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 InternalFactHandle[] orderFacts(
      List<InternalFactHandle> handlesList) {
    // this method is just needed for testing purposes, to allow round
    // tripping
    int size = handlesList.size();
    InternalFactHandle[] handles = handlesList
        .toArray(new InternalFactHandle[size]);
    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 class ActivationsSorter implements
      Comparator<org.drools.spi.Activation> {
    public static final ActivationsSorter INSTANCE = new ActivationsSorter();

    public int compare(org.drools.spi.Activation o1,
        org.drools.spi.Activation o2) {
      int result = o1.getRule().getName()
          .compareTo(o2.getRule().getName());
      if (result == 0) {
        LeftTuple t1 = o1.getTuple();
        LeftTuple t2 = o2.getTuple();
        while (result == 0 && t1 != null && t2 != null) {
          result = t1.getLastHandle().getId()
              - t2.getLastHandle().getId();
          t1 = t1.getParent();
          t2 = t2.getParent();
        }
      }
      return result;
    }
  }

  public static ProtobufMessages.Activation writeActivation(
      MarshallerWriteContext context, AgendaItem agendaItem) {
    ProtobufMessages.Activation.Builder _activation = ProtobufMessages.Activation
        .newBuilder();

    Rule rule = agendaItem.getRule();
    _activation.setPackageName(rule.getPackage());
    _activation.setRuleName(rule.getName());

    ProtobufMessages.Tuple.Builder _tb = ProtobufMessages.Tuple
        .newBuilder();
    for (LeftTuple entry = agendaItem.getTuple(); entry != null; entry = entry
        .getParent()) {
      InternalFactHandle handle = entry.getLastHandle();
      _tb.addHandleId(handle.getId());
    }
    _activation.setTuple(_tb.build());

    _activation.setSalience(agendaItem.getSalience());
    _activation.setIsActivated(agendaItem.isActivated());

    if (agendaItem.getActivationGroupNode() != null) {
      _activation.setActivationGroup(agendaItem.getActivationGroupNode()
          .getActivationGroup().getName());
    }

    if (agendaItem.getFactHandle() != null) {
      _activation.setHandleId(agendaItem.getFactHandle().getId());
    }

    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()) {
        _activation.addLogicalDependency(((InternalFactHandle) node
            .getJustified()).getId());
      }
    }
    return _activation.build();
  }

  private static ProtobufMessages.Timers writeTimers(
      Collection<TimerJobInstance> timers, MarshallerWriteContext outCtx) {
    if (!timers.isEmpty()) {
      List<TimerJobInstance> sortedTimers = new ArrayList<TimerJobInstance>(
          timers);
      Collections.sort(sortedTimers, new Comparator<TimerJobInstance>() {
        public int compare(TimerJobInstance o1, TimerJobInstance o2) {
          return (int) (o1.getJobHandle().getId() - o2.getJobHandle()
              .getId());
        }
      });

      ProtobufMessages.Timers.Builder _timers = ProtobufMessages.Timers
          .newBuilder();
      for (TimerJobInstance timer : sortedTimers) {
        JobContext jctx = ((SelfRemovalJobContext) timer
            .getJobContext()).getJobContext();
        TimersOutputMarshaller writer = outCtx.writersByClass.get(jctx
            .getClass());
        Timer _timer = writer.serialize(jctx, outCtx);
        _timers.addTimer(_timer);
      }
      return _timers.build();
    }
    return null;
  }

  public static ProtobufMessages.Trigger writeTrigger(Trigger trigger,
      MarshallerWriteContext outCtx) {
    if (trigger instanceof CronTrigger) {
      CronTrigger cronTrigger = (CronTrigger) trigger;
      ProtobufMessages.Trigger.CronTrigger.Builder _cron = ProtobufMessages.Trigger.CronTrigger
          .newBuilder()
          .setStartTime(cronTrigger.getStartTime().getTime())
          .setRepeatLimit(cronTrigger.getRepeatLimit())
          .setRepeatCount(cronTrigger.getRepeatCount())
          .setCronExpression(
              cronTrigger.getCronEx().getCronExpression());
      if (cronTrigger.getEndTime() != null) {
        _cron.setEndTime(cronTrigger.getEndTime().getTime());
      }
      if (cronTrigger.getNextFireTime() != null) {
        _cron.setNextFireTime(cronTrigger.getNextFireTime().getTime());
      }
      if (cronTrigger.getCalendarNames() != null) {
        for (String calendarName : cronTrigger.getCalendarNames()) {
          _cron.addCalendarName(calendarName);
        }
      }
      return ProtobufMessages.Trigger.newBuilder()
          .setType(ProtobufMessages.Trigger.TriggerType.CRON)
          .setCron(_cron.build()).build();
    } else if (trigger instanceof IntervalTrigger) {
      IntervalTrigger intTrigger = (IntervalTrigger) trigger;
      ProtobufMessages.Trigger.IntervalTrigger.Builder _interval = ProtobufMessages.Trigger.IntervalTrigger
          .newBuilder()
          .setStartTime(intTrigger.getStartTime().getTime())
          .setRepeatLimit(intTrigger.getRepeatLimit())
          .setRepeatCount(intTrigger.getRepeatCount())
          .setPeriod(intTrigger.getPeriod());
      if (intTrigger.getEndTime() != null) {
        _interval.setEndTime(intTrigger.getEndTime().getTime());
      }
      if (intTrigger.getNextFireTime() != null) {
        _interval.setNextFireTime(intTrigger.getNextFireTime()
            .getTime());
      }
      if (intTrigger.getCalendarNames() != null) {
        for (String calendarName : intTrigger.getCalendarNames()) {
          _interval.addCalendarName(calendarName);
        }
      }
      return ProtobufMessages.Trigger.newBuilder()
          .setType(ProtobufMessages.Trigger.TriggerType.INTERVAL)
          .setInterval(_interval.build()).build();
    } else if (trigger instanceof PointInTimeTrigger) {
      PointInTimeTrigger pinTrigger = (PointInTimeTrigger) trigger;
      return ProtobufMessages.Trigger
          .newBuilder()
          .setType(ProtobufMessages.Trigger.TriggerType.POINT_IN_TIME)
          .setPit(ProtobufMessages.Trigger.PointInTimeTrigger
              .newBuilder()
              .setNextFireTime(
                  pinTrigger.hasNextFireTime().getTime())
              .build()).build();
    }
    throw new RuntimeException("Unable to serialize Trigger for type: "
        + trigger.getClass());
  }

}
TOP

Related Classes of org.drools.marshalling.impl.ProtobufOutputMarshaller$HandleSorter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.