/** update the process variables from the the task-instance variables. */
  public void submitParameters(TaskInstance taskInstance) {
    ClassLoader surroundingClassLoader = Thread.currentThread().getContextClassLoader();
    try {
      // set context class loader correctly for delegation class
      // (https://jira.jboss.org/jira/browse/JBPM-1448)
      Thread.currentThread()
          .setContextClassLoader(
              JbpmConfiguration.getProcessClassLoader(
                  taskInstance.getTask().getProcessDefinition()));

      if (taskControllerDelegation != null) {
        TaskControllerHandler taskControllerHandler =
            (TaskControllerHandler) taskControllerDelegation.instantiate();
        ProcessInstance processInstance = taskInstance.getTaskMgmtInstance().getProcessInstance();
        ContextInstance contextInstance =
            (processInstance != null ? processInstance.getContextInstance() : null);
        Token token = taskInstance.getToken();

        if (UserCodeInterceptorConfig.userCodeInterceptor != null) {
          UserCodeInterceptorConfig.userCodeInterceptor.executeTaskControllerSubmission(
              taskControllerHandler, taskInstance, contextInstance, token);
        } else {
          taskControllerHandler.submitTaskVariables(taskInstance, contextInstance, token);
        }

      } else {

        Token token = taskInstance.getToken();
        ProcessInstance processInstance = token.getProcessInstance();
        ContextInstance contextInstance = processInstance.getContextInstance();

        if (variableAccesses != null) {
          String missingTaskVariables = null;
          Iterator iter = variableAccesses.iterator();
          while (iter.hasNext()) {
            VariableAccess variableAccess = (VariableAccess) iter.next();
            String mappedName = variableAccess.getMappedName();
            // first check if the required variableInstances are present
            if ((variableAccess.isRequired()) && (!taskInstance.hasVariableLocally(mappedName))) {
              if (missingTaskVariables == null) {
                missingTaskVariables = mappedName;
              } else {
                missingTaskVariables += ", " + mappedName;
              }
            }
          }

          // if there are missing, required parameters, throw an
          // IllegalArgumentException
          if (missingTaskVariables != null) {
            throw new IllegalArgumentException("missing task variables: " + missingTaskVariables);
          }

          iter = variableAccesses.iterator();
          while (iter.hasNext()) {
            VariableAccess variableAccess = (VariableAccess) iter.next();
            String mappedName = variableAccess.getMappedName();
            String variableName = variableAccess.getVariableName();
            if (variableAccess.isWritable()) {
              Object value = taskInstance.getVariable(mappedName);
              if (value != null) {
                log.debug(
                    "submitting task variable '"
                        + mappedName
                        + "' to process variable '"
                        + variableName
                        + "', value '"
                        + value
                        + "'");
                contextInstance.setVariable(variableName, value, token);
              }
            }
          }
        }
      }
    } finally {
      Thread.currentThread().setContextClassLoader(surroundingClassLoader);
    }
  }
  public void testTimerInCombinationWithAsyncNode() throws Throwable {
    ProcessDefinition subDefinition =
        ProcessDefinition.parseXmlString(
            "<process-definition name='sub'>"
                + "  <start-state name='start'>"
                + "    <transition to='decision'/>"
                + "  </start-state>"
                + "  <decision name='decision'>"
                + "    <handler class='org.jbpm.scenarios.AsyncTimerAndSubProcessDbTest$ToTimedDecisionHandler' />"
                + "    <transition name='default' to='task' />"
                + "  </decision>"
                + "  <task-node name='task'>"
                + "    <task name='do stuff'>"
                + "      <controller>"
                + "        <variable name='a' access='read' />"
                + "      </controller>"
                + "      <assignment actor-id='victim' />"
                + "    </task>"
                + "    <transition to='end'/>"
                + "  </task-node>"
                + "  <end-state name='end' />"
                + "</process-definition>");
    jbpmContext.deployProcessDefinition(subDefinition);
    newTransaction();

    ProcessDefinition superDefinition =
        ProcessDefinition.parseXmlString(
            "<process-definition name='super'>"
                + "  <start-state name='start'>"
                + "    <transition to='decision'/>"
                + "  </start-state>"
                + "  <decision name='decision'>"
                + "    <handler class='org.jbpm.scenarios.AsyncTimerAndSubProcessDbTest$ToTimedDecisionHandler' />"
                + "    <transition name='default' to='timed' />"
                + "  </decision>"
                + "  <state name='timed'>"
                + "    <timer name='reminder' "
                + "           duedate='0 seconds' "
                + "           transition='timer fires' />"
                + "    <transition name='timer fires' to='async'/>"
                + "    <transition name='normal continuation' to='end'/>"
                + "  </state>"
                + "  <node name='async' async='true'>"
                + "    <transition to='subprocess'/>"
                + "  </node>"
                + "  <process-state name='subprocess'>"
                + "    <sub-process name='sub' />"
                + "    <variable name='a'/>"
                + "    <variable name='b'/>"
                + "    <transition to='decision' />"
                + "  </process-state>"
                + "  <end-state name='end' />"
                + "</process-definition>");
    jbpmContext.deployProcessDefinition(superDefinition);
    newTransaction();

    ProcessInstance superInstance = jbpmContext.newProcessInstanceForUpdate("super");
    ContextInstance superContext = superInstance.getContextInstance();
    superContext.setVariable("a", "value a");
    superContext.setVariable("b", "value b");
    superInstance.signal();

    processJobs(5000);

    superInstance = jbpmContext.loadProcessInstance(superInstance.getId());
    assertEquals("subprocess", superInstance.getRootToken().getNode().getName());

    List taskInstances = taskMgmtSession.findTaskInstances("victim");
    assertEquals(1, taskInstances.size());
    TaskInstance taskInstance = (TaskInstance) taskInstances.get(0);
    taskInstance.setVariable("a", "value a updated");
    taskInstance.setVariable("b", "value b updated");
    taskInstance.end();

    jbpmContext.save(taskInstance);
    long taskInstanceId = taskInstance.getId();
    long tokenId = taskInstance.getToken().getId();
    newTransaction();

    taskInstance = jbpmContext.loadTaskInstance(taskInstanceId);
    assertEquals("value a updated", taskInstance.getVariable("a"));
    assertEquals("value b updated", taskInstance.getVariable("b"));

    Token token = jbpmContext.loadToken(tokenId);
    ContextInstance subContextInstance = token.getProcessInstance().getContextInstance();
    assertEquals("value a", subContextInstance.getVariable("a"));
    assertEquals("value b updated", subContextInstance.getVariable("b"));
  }