// Output methods
  public JBPMMessages.ProcessInstance writeProcessInstance(
      MarshallerWriteContext context, ProcessInstance processInstance) throws IOException {
    WorkflowProcessInstanceImpl workFlow = (WorkflowProcessInstanceImpl) processInstance;

    JBPMMessages.ProcessInstance.Builder _instance =
        JBPMMessages.ProcessInstance.newBuilder()
            .setId(workFlow.getId())
            .setProcessId(workFlow.getProcessId())
            .setState(workFlow.getState())
            .setNodeInstanceCounter(workFlow.getNodeInstanceCounter())
            .setProcessType(workFlow.getProcess().getType());
    if (workFlow.getProcessXml() != null) {
      _instance.setProcessXml(workFlow.getProcessXml());
    }

    SwimlaneContextInstance swimlaneContextInstance =
        (SwimlaneContextInstance) workFlow.getContextInstance(SwimlaneContext.SWIMLANE_SCOPE);
    if (swimlaneContextInstance != null) {
      Map<String, String> swimlaneActors = swimlaneContextInstance.getSwimlaneActors();
      for (Map.Entry<String, String> entry : swimlaneActors.entrySet()) {
        _instance.addSwimlaneContext(
            JBPMMessages.ProcessInstance.SwimlaneContextInstance.newBuilder()
                .setSwimlane(entry.getKey())
                .setActorId(entry.getValue())
                .build());
      }
    }

    List<NodeInstance> nodeInstances = new ArrayList<NodeInstance>(workFlow.getNodeInstances());
    Collections.sort(
        nodeInstances,
        new Comparator<NodeInstance>() {

          public int compare(NodeInstance o1, NodeInstance o2) {
            return (int) (o1.getId() - o2.getId());
          }
        });
    for (NodeInstance nodeInstance : nodeInstances) {
      _instance.addNodeInstance(writeNodeInstance(context, nodeInstance));
    }

    List<ContextInstance> exclusiveGroupInstances =
        workFlow.getContextInstances(ExclusiveGroup.EXCLUSIVE_GROUP);
    if (exclusiveGroupInstances != null) {
      for (ContextInstance contextInstance : exclusiveGroupInstances) {
        JBPMMessages.ProcessInstance.ExclusiveGroupInstance.Builder _exclusive =
            JBPMMessages.ProcessInstance.ExclusiveGroupInstance.newBuilder();
        ExclusiveGroupInstance exclusiveGroupInstance = (ExclusiveGroupInstance) contextInstance;
        Collection<NodeInstance> groupNodeInstances = exclusiveGroupInstance.getNodeInstances();
        for (NodeInstance nodeInstance : groupNodeInstances) {
          _exclusive.addGroupNodeInstanceId(nodeInstance.getId());
        }
        _instance.addExclusiveGroup(_exclusive.build());
      }
    }

    VariableScopeInstance variableScopeInstance =
        (VariableScopeInstance) workFlow.getContextInstance(VariableScope.VARIABLE_SCOPE);
    List<Map.Entry<String, Object>> variables =
        new ArrayList<Map.Entry<String, Object>>(variableScopeInstance.getVariables().entrySet());
    Collections.sort(
        variables,
        new Comparator<Map.Entry<String, Object>>() {
          public int compare(Map.Entry<String, Object> o1, Map.Entry<String, Object> o2) {
            return o1.getKey().compareTo(o2.getKey());
          }
        });

    for (Map.Entry<String, Object> variable : variables) {
      if (variable.getValue() != null) {
        _instance.addVariable(
            ProtobufProcessMarshaller.marshallVariable(
                context, variable.getKey(), variable.getValue()));
      }
    }

    return _instance.build();
  }
  // Input methods
  public ProcessInstance readProcessInstance(MarshallerReaderContext context) throws IOException {
    InternalRuleBase ruleBase = context.ruleBase;
    InternalWorkingMemory wm = context.wm;

    JBPMMessages.ProcessInstance _instance =
        (org.jbpm.marshalling.impl.JBPMMessages.ProcessInstance) context.parameterObject;
    if (_instance == null) {
      // try to parse from the stream
      ExtensionRegistry registry = PersisterHelper.buildRegistry(context, null);
      Header _header;
      try {
        _header = PersisterHelper.readFromStreamWithHeader(context, registry);
      } catch (ClassNotFoundException e) {
        // Java 5 does not accept [new IOException(String, Throwable)]
        IOException ioe = new IOException("Error deserializing process instance.");
        ioe.initCause(e);
        throw ioe;
      }
      _instance = JBPMMessages.ProcessInstance.parseFrom(_header.getPayload(), registry);
    }

    WorkflowProcessInstanceImpl processInstance = createProcessInstance();
    processInstance.setId(_instance.getId());
    String processId = _instance.getProcessId();
    processInstance.setProcessId(processId);
    String processXml = _instance.getProcessXml();
    Process process = null;
    if (processXml != null && processXml.trim().length() > 0) {
      processInstance.setProcessXml(processXml);
      process = processInstance.getProcess();
    } else {
      process = ruleBase.getProcess(processId);
      processInstance.setProcess(process);
    }
    processInstance.setState(_instance.getState());
    long nodeInstanceCounter = _instance.getNodeInstanceCounter();
    processInstance.setKnowledgeRuntime(wm.getKnowledgeRuntime());

    if (_instance.getSwimlaneContextCount() > 0) {
      Context swimlaneContext =
          ((org.jbpm.process.core.Process) process)
              .getDefaultContext(SwimlaneContext.SWIMLANE_SCOPE);
      SwimlaneContextInstance swimlaneContextInstance =
          (SwimlaneContextInstance) processInstance.getContextInstance(swimlaneContext);
      for (JBPMMessages.ProcessInstance.SwimlaneContextInstance _swimlane :
          _instance.getSwimlaneContextList()) {
        swimlaneContextInstance.setActorId(_swimlane.getSwimlane(), _swimlane.getActorId());
      }
    }

    for (JBPMMessages.ProcessInstance.NodeInstance _node : _instance.getNodeInstanceList()) {
      context.parameterObject = _node;
      readNodeInstance(context, processInstance, processInstance);
    }

    for (JBPMMessages.ProcessInstance.ExclusiveGroupInstance _excl :
        _instance.getExclusiveGroupList()) {
      ExclusiveGroupInstance exclusiveGroupInstance = new ExclusiveGroupInstance();
      processInstance.addContextInstance(ExclusiveGroup.EXCLUSIVE_GROUP, exclusiveGroupInstance);
      for (Long nodeInstanceId : _excl.getGroupNodeInstanceIdList()) {
        NodeInstance nodeInstance = processInstance.getNodeInstance(nodeInstanceId);
        if (nodeInstance == null) {
          throw new IllegalArgumentException(
              "Could not find node instance when deserializing exclusive group instance: "
                  + nodeInstanceId);
        }
        exclusiveGroupInstance.addNodeInstance(nodeInstance);
      }
    }

    if (_instance.getVariableCount() > 0) {
      Context variableScope =
          ((org.jbpm.process.core.Process) process).getDefaultContext(VariableScope.VARIABLE_SCOPE);
      VariableScopeInstance variableScopeInstance =
          (VariableScopeInstance) processInstance.getContextInstance(variableScope);
      for (JBPMMessages.Variable _variable : _instance.getVariableList()) {
        try {
          Object _value = ProtobufProcessMarshaller.unmarshallVariableValue(context, _variable);
          variableScopeInstance.internalSetVariable(_variable.getName(), _value);
        } catch (ClassNotFoundException e) {
          throw new IllegalArgumentException("Could not reload variable " + _variable.getName());
        }
      }
    }
    processInstance.internalSetNodeInstanceCounter(nodeInstanceCounter);
    if (wm != null) {
      processInstance.reconnect();
    }
    return processInstance;
  }