/**
   * Executes an external visual.
   *
   * @param visual The visual to be executed
   * @param context The token context
   * @param entrySocket Entry socket of the visual
   * @return null
   */
  public String executeVisual(VisualItem visual, TokenContext context, NodeSocket entrySocket)
      throws Exception {
    // TODO Fix 4 Save visual name to session context

    // Log that we're delegating to the driver.
    LogUtil.debug(
        getClass(), "Setting current visual for external ui adapter to $0.", visual.getQualifier());

    // Returning null will cause the process to stop
    return null;
  }
  /**
   * @see org.openbp.server.context.serializer.ContextObjectSerializer#writeContextObject(Object
   *     object, ObjectOutputStream out, TokenContext context, String key)
   */
  public void writeContextObject(
      Object object, ObjectOutputStream out, TokenContext context, String key) throws IOException {
    if (!(object instanceof Serializable)) {
      String msg =
          LogUtil.error(
              getClass(),
              "Process variable value $0 cannot be persisted because it does not implement the java.io.Serializable interface (value class: $1).",
              key,
              object.getClass().getName());
      throw new IOException(msg);
    }

    out.writeObject(object);
  }
  public void execute(JobExecutionContext context) throws JobExecutionException {
    Object tokenId = "?";

    try {
      ProcessFacade processFacade = processServer.getProcessFacade();

      // TODO Fix 3 This should be JobDataMap dataMap = context.getJobDataMap();
      JobDataMap dataMap = context.getJobDetail().getJobDataMap();

      boolean disabled = dataMap.getBoolean(KEY_DISABLED);
      if (disabled) return;

      TokenContext tc = null;
      tokenId = dataMap.get(KEY_TOKEN_ID);
      if (tokenId == null) {
        // No token given, create new one
        tc = processFacade.createToken();
        processFacade.prepareTokenForScheduler(tc);
        tokenId = tc.getId();
      } else {
        // Use existing token
        tc = processFacade.getTokenById(tokenId);
        if (tc == null) {
          String msg =
              LogUtil.error(
                  getClass(),
                  "Cannot find the scheduled token context (id $0) for job $1.",
                  tokenId,
                  context.getJobDetail().getGroup() + "." + context.getJobDetail().getName());
          JobExecutionException ex = new JobExecutionException(msg);
          ex.setUnscheduleAllTriggers(true);
          throw ex;
        }
      }

      String positionRef = dataMap.getString(KEY_POSITION_REF);
      String executionMode = dataMap.getString(KEY_EXECUTION_MODE);
      String startMode = dataMap.getString(KEY_START_MODE);

      Map inputParamValues = null;

      for (Iterator it = dataMap.entrySet().iterator(); it.hasNext(); ) {
        Map.Entry entry = (Map.Entry) it.next();

        String key = (String) entry.getKey();
        if (key.startsWith(KEY_PARAM_PREFIX)) {
          if (inputParamValues == null) {
            inputParamValues = new HashMap();
          }
          key = key.substring(KEY_PARAM_PREFIX.length());
          inputParamValues.put(key, entry.getValue());
        } else if (key.startsWith(KEY_RUNTIME_ATRIBUTE_PREFIX)) {
          key = key.substring(KEY_RUNTIME_ATRIBUTE_PREFIX.length());
          tc.setRuntimeAttribute(key, entry.getValue());
        }
      }

      Engine engine = processServer.getEngine();

      if (ProcessJobDescriptor.START_MODE_RESUME.equals(startMode)) {
        // Resume an existing token
        if (engine.hasActiveObservers(SchedulerEngineEvent.RESUME_JOB, tc)) {
          ProcessJobDescriptor desc =
              ((QuartzProcessScheduler) processServer.getProcessScheduler())
                  .createJobDescriptor(context.getJobDetail());
          engine.fireEngineEvent(
              new SchedulerEngineEvent(SchedulerEngineEvent.RESUME_JOB, tc, desc, engine));
        }
        processFacade.resumeToken(tc, positionRef, inputParamValues);
      } else {
        // Start a new token
        if (engine.hasActiveObservers(SchedulerEngineEvent.START_JOB, tc)) {
          ProcessJobDescriptor desc =
              ((QuartzProcessScheduler) processServer.getProcessScheduler())
                  .createJobDescriptor(context.getJobDetail());
          engine.fireEngineEvent(
              new SchedulerEngineEvent(SchedulerEngineEvent.START_JOB, tc, desc, engine));
        }
        processFacade.startToken(tc, positionRef, inputParamValues);
      }

      // Process the token immediately if desired, otherwise let the execution thread pool do this.
      if (ProcessJobDescriptor.EXECUTION_MODE_SYNCHRONOUS.equals(executionMode)) {
        // We do not need to set the lifecycle to LifecycleState.SELECTED, it will be set to
        // LifecycleState.RUNNING by the executeContext method
        tc = processFacade.getTokenById(tokenId);
        if (tc == null) {
          String msg =
              LogUtil.error(
                  getClass(),
                  "Cannot find the scheduled token context (id $0) for job $1.",
                  tokenId,
                  context.getJobDetail().getGroup() + context.getJobDetail().getName());
          JobExecutionException ex = new JobExecutionException(msg);
          ex.setUnscheduleAllTriggers(true);
          throw ex;
        }
        engine.executeContext(tc);
        processFacade.commitTokenContextTransaction();
      }
    } catch (Exception e) {
      JobExecutionException jex = null;
      if (e instanceof JobExecutionException) {
        jex = (JobExecutionException) e;
      } else {
        String msg =
            LogUtil.error(
                getClass(),
                "Error occured while processing scheduled token context (id $0) for job $1.",
                tokenId,
                context.getJobDetail().getGroup() + context.getJobDetail().getName(),
                e);
        jex = new JobExecutionException(msg, e, true);
      }
      jex.setUnscheduleAllTriggers(true);
      // TODO This will lead to an endless loop
      // throw jex;
    }
  }