public void testStartProcessWithLinking() {
    LogUtil.info(getClass().getName(), ">>> testStartProcessWithLinking");

    // start and get instant id of 1st process
    String packageVersion = workflowManager.getCurrentPackageVersion(packageId);
    WorkflowProcessResult result =
        workflowManager.processStart(packageId + "#" + packageVersion + "#" + processId);
    String process1Id = result.getProcess().getInstanceId();
    LogUtil.info(
        getClass().getName(), "-------------  process one id : " + process1Id + "  -------------");

    // start 2nd process with 1st process instant id and get 2nd process instant id
    WorkflowProcessResult nextResult =
        workflowManager.processStartWithLinking(
            packageId + "#" + packageVersion + "#" + processId, null, null, process1Id);
    String process2Id = nextResult.getProcess().getInstanceId();
    LogUtil.info(
        getClass().getName(), "-------------  process two id : " + process2Id + "  -------------");

    // check process linking data is correct or not
    WorkflowProcessLink link = workflowManager.getWorkflowProcessLink(process2Id);
    LogUtil.info(
        getClass().getName(),
        "-------------  origin process id : " + link.getOriginProcessId() + "  -------------");
    workflowManager.internalDeleteWorkflowProcessLink(link);
    Assert.assertNotNull(link);
    Assert.assertTrue(
        process1Id.equals(link.getOriginProcessId())
            && process1Id.equals(link.getParentProcessId()));
  }
  public void testCopyProcess() {
    LogUtil.info(getClass().getName(), ">>> testCopyProcess");

    boolean valid = false;

    // start and get instance id of the 1st process
    String packageVersion = workflowManager.getCurrentPackageVersion(packageId);
    WorkflowProcessResult result =
        workflowManager.processStart(packageId + "#" + packageVersion + "#" + processId);
    String processInstanceId = result.getProcess().getInstanceId();
    LogUtil.info(
        getClass().getName(),
        "-------------  process one id : " + processInstanceId + "  -------------");

    // abort running activities and start activity B
    String firstActivityDef = "A";
    String desiredActivityDef = "B";
    boolean started = workflowManager.activityStart(processInstanceId, desiredActivityDef, true);

    if (started) {
      // start 2nd process from the 1st process instance id
      WorkflowProcessResult nextResult =
          workflowManager.processCopyFromInstanceId(
              processInstanceId, packageId + "#" + packageVersion + "#" + processId, true);
      WorkflowProcess processStarted = nextResult.getProcess();

      if (processStarted != null) {
        // check for the aborted and running activities
        String newProcessId = processStarted.getInstanceId();
        Collection<WorkflowActivity> activityList =
            workflowManager.getActivityList(newProcessId, 0, 1000, null, null);
        for (WorkflowActivity act : activityList) {
          if (act.getState().startsWith("open")) {
            if (firstActivityDef.equals(act.getActivityDefId())) {
              valid = false;
              break;
            }
            if (desiredActivityDef.equals(act.getActivityDefId())) {
              valid = true;
            }
          }
        }
        LogUtil.info(
            getClass().getName(),
            "-------------  new process id : " + newProcessId + "  ------------- " + valid);

        // cleanup
        WorkflowProcessLink link = workflowManager.getWorkflowProcessLink(newProcessId);
        workflowManager.internalDeleteWorkflowProcessLink(link);
      }
    }

    Assert.assertTrue(valid);
  }
  @RequestMapping("/client/app/(*:appId)/(~:version)/process/(*:processDefId)/start")
  public String clientProcessStart(
      HttpServletRequest request,
      ModelMap model,
      @RequestParam("appId") String appId,
      @RequestParam(required = false) String version,
      @RequestParam(required = false) String recordId,
      @RequestParam String processDefId) {

    // clean process def
    processDefId = WorkflowUtil.getProcessDefIdWithoutVersion(processDefId);

    // set app and process details
    AppDefinition appDef = appService.getAppDefinition(appId, version);
    WorkflowProcess processDef =
        appService.getWorkflowProcessForApp(appId, appDef.getVersion().toString(), processDefId);
    String processDefIdWithVersion = processDef.getId();
    model.addAttribute("appId", appId);
    model.addAttribute("appVersion", appDef.getVersion());
    model.addAttribute("appDefinition", appDef);
    model.addAttribute("process", processDef);

    // check for permission
    if (!workflowManager.isUserInWhiteList(processDef.getId())) {
      return "client/app/processUnauthorized";
    }

    // extract form values from request
    FormData formData = new FormData();
    formData.setPrimaryKeyValue(recordId);
    formData = formService.retrieveFormDataFromRequest(formData, request);

    // get workflow variables
    Map<String, String> variableMap = AppUtil.retrieveVariableDataFromRequest(request);
    String formUrl =
        AppUtil.getRequestContextPath()
            + "/web/client/app/"
            + appId
            + "/"
            + appDef.getVersion()
            + "/process/"
            + processDefId
            + "/start";
    if (recordId != null) {
      formUrl += "?recordId=" + recordId;
    }
    PackageActivityForm startFormDef =
        appService.viewStartProcessForm(
            appId, appDef.getVersion().toString(), processDefId, formData, formUrl);
    WorkflowProcessResult result =
        appService.submitFormToStartProcess(
            appId, version, processDefId, formData, variableMap, recordId, formUrl);
    if (startFormDef != null
        && (startFormDef.getForm() != null
            || PackageActivityForm.ACTIVITY_FORM_TYPE_EXTERNAL.equals(startFormDef.getType()))) {
      if (result == null) {
        // validation error, get form
        Form startForm = startFormDef.getForm();

        // generate form HTML
        String formHtml = formService.retrieveFormErrorHtml(startForm, formData);
        String formJson = formService.generateElementJson(startForm);

        // show form
        model.addAttribute("form", startForm);
        model.addAttribute("formJson", formJson);
        model.addAttribute("formHtml", formHtml);
        model.addAttribute("activityForm", startFormDef);
        return "client/app/processFormStart";
      }
    } else {
      // start process - TODO: handle process linking
      result =
          workflowManager.processStart(
              processDefIdWithVersion, null, variableMap, null, recordId, false);
    }

    // set result
    if (result != null) {
      WorkflowProcess process = result.getProcess();
      model.addAttribute("process", process);

      // redirect to next activity if available
      Collection<WorkflowActivity> activities = result.getActivities();
      if (activities != null && !activities.isEmpty()) {
        WorkflowActivity nextActivity = activities.iterator().next();
        String assignmentUrl =
            "/web/client/app/"
                + appId
                + "/"
                + appDef.getVersion()
                + "/assignment/"
                + nextActivity.getId()
                + "?"
                + request.getQueryString();
        return "redirect:" + assignmentUrl;
      }
    }

    return "client/app/processStarted";
  }
 public void testStartProcess() {
   LogUtil.info(getClass().getName(), ">>> testStartProcess");
   String packageVersion = workflowManager.getCurrentPackageVersion(packageId);
   workflowManager.processStart(packageId + "#" + packageVersion + "#" + processId);
 }