public static ReteooStatefulSession readSession(
      MarshallerReaderContext context,
      int id,
      ExecutorService executor,
      Environment environment,
      SessionConfiguration config)
      throws IOException, ClassNotFoundException {

    boolean multithread = context.readBoolean();

    long time = context.readLong();

    FactHandleFactory handleFactory =
        context.ruleBase.newFactHandleFactory(context.readInt(), context.readLong());

    long propagationCounter = context.readLong();

    InternalFactHandle initialFactHandle =
        new DefaultFactHandle(
            context.readInt(), // id
            InitialFactImpl.getInstance(),
            context.readLong(),
            null);

    context.handles.put(initialFactHandle.getId(), initialFactHandle);

    DefaultAgenda agenda =
        context
            .ruleBase
            .getConfiguration()
            .getComponentFactory()
            .getAgendaFactory()
            .createAgenda(context.ruleBase, false);

    readAgenda(context, agenda);
    ReteooStatefulSession session =
        new ReteooStatefulSession(
            id,
            context.ruleBase,
            executor,
            handleFactory,
            initialFactHandle,
            propagationCounter,
            config,
            agenda,
            environment);
    new StatefulKnowledgeSessionImpl(session);

    initialFactHandle.setEntryPoint(
        session.getEntryPoints().get(EntryPoint.DEFAULT.getEntryPointId()));

    return readSession(session, agenda, time, multithread, context);
  }
  /**
   * Stream the data into an existing session
   *
   * @param session
   * @param context
   * @return
   * @throws IOException
   * @throws ClassNotFoundException
   */
  public static ReteooStatefulSession readSession(
      ReteooStatefulSession session, MarshallerReaderContext context)
      throws IOException, ClassNotFoundException {
    boolean multithread = context.readBoolean();
    long time = context.readLong();
    int handleId = context.readInt();
    long handleCounter = context.readLong();
    long propagationCounter = context.readLong();

    // these are for the InitialFactHandle, on a reset we just ignore
    context.readInt();
    context.readLong();

    session.reset(handleId, handleCounter, propagationCounter);
    DefaultAgenda agenda = (DefaultAgenda) session.getAgenda();

    readAgenda(context, agenda);

    return readSession(session, agenda, time, multithread, context);
  }
  public static ReteooStatefulSession readSession(
      ReteooStatefulSession session,
      DefaultAgenda agenda,
      long time,
      boolean multithread,
      MarshallerReaderContext context)
      throws IOException, ClassNotFoundException {
    if (session.getTimerService() instanceof PseudoClockScheduler) {
      PseudoClockScheduler clock = (PseudoClockScheduler) session.getTimerService();
      clock.advanceTime(time, TimeUnit.MILLISECONDS);
    }

    // RuleFlowGroups need to reference the session
    for (RuleFlowGroup group : agenda.getRuleFlowGroupsMap().values()) {
      ((RuleFlowGroupImpl) group).setWorkingMemory(session);
    }

    context.wm = session;

    context.handles.put(
        context.wm.getInitialFactHandle().getId(), context.wm.getInitialFactHandle());

    if (context.stream.readBoolean()) {
      InternalFactHandle initialFactHandle = context.wm.getInitialFactHandle();
      int sinkId = context.stream.readInt();
      ObjectTypeNode initialFactNode = (ObjectTypeNode) context.sinks.get(sinkId);
      if (initialFactNode == null) {
        // ------ START RANT ------
        // The following code is as bad as it looks, but since I was so far
        // unable to convince Mark that creating OTNs on demand is really bad,
        // I have to continue doing it :)
        EntryPointNode defaultEPNode =
            context.ruleBase.getRete().getEntryPointNode(EntryPoint.DEFAULT);
        BuildContext buildContext =
            new BuildContext(
                context.ruleBase, context.ruleBase.getReteooBuilder().getIdGenerator());
        buildContext.setPartitionId(RuleBasePartitionId.MAIN_PARTITION);
        buildContext.setObjectTypeNodeMemoryEnabled(true);
        initialFactNode =
            new ObjectTypeNode(
                sinkId, defaultEPNode, ClassObjectType.InitialFact_ObjectType, buildContext);
        // isn't contention something everybody loves?
        context.ruleBase.lock();
        try {
          // Yeah, I know, because one session is being deserialized, we go and lock all of them...
          initialFactNode.attach(buildContext);
        } finally {
          context.ruleBase.unlock();
        }
        // ------- END RANT -----
      }
      ObjectHashSet initialFactMemory = (ObjectHashSet) context.wm.getNodeMemory(initialFactNode);

      initialFactMemory.add(initialFactHandle);
      readRightTuples(initialFactHandle, context);
    }
    while (context.readShort() == PersisterEnums.ENTRY_POINT) {
      String entryPointId = context.stream.readUTF();
      WorkingMemoryEntryPoint wmep = context.wm.getEntryPoints().get(entryPointId);
      readFactHandles(context, ((NamedEntryPoint) wmep).getObjectStore());
    }
    InternalFactHandle handle = context.wm.getInitialFactHandle();
    while (context.stream.readShort() == PersisterEnums.LEFT_TUPLE) {
      LeftTupleSink sink = (LeftTupleSink) context.sinks.get(context.stream.readInt());
      LeftTuple leftTuple = sink.createLeftTuple(handle, sink, true);
      readLeftTuple(leftTuple, context);
    }

    readPropagationContexts(context);

    readActivations(context);

    readActionQueue(context);

    readTruthMaintenanceSystem(context);

    if (processMarshaller != null) {
      processMarshaller.readProcessInstances(context);
    } else {
      short type = context.stream.readShort();
      if (PersisterEnums.END != type) {
        throw new IllegalStateException(
            "No process marshaller, unable to unmarshall type: " + type);
      }
    }

    if (processMarshaller != null) {
      processMarshaller.readWorkItems(context);
    } else {
      short type = context.stream.readShort();
      if (PersisterEnums.END != type) {
        throw new IllegalStateException(
            "No process marshaller, unable to unmarshall type: " + type);
      }
    }

    if (processMarshaller != null) {
      // This actually does ALL timers, due to backwards compatability issues
      // It will read in old JBPM binaries, but always write to the new binary format.
      processMarshaller.readProcessTimers(context);
    } else {
      short type = context.stream.readShort();
      if (PersisterEnums.END != type) {
        throw new IllegalStateException(
            "No process marshaller, unable to unmarshall type: " + type);
      }
    }

    // no legacy jBPM timers, so handle locally
    while (context.readShort() == PersisterEnums.DEFAULT_TIMER) {
      InputMarshaller.readTimer(context);
    }

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

    return session;
  }