public static void runTestLifeCycle(
      AsyncTaskService client, Map<String, User> users, Map<String, Group> groups) {
    Map<String, Object> vars = fillVariables(users, groups);

    // One potential owner, should go straight to state Reserved
    String str =
        "(with (new Task()) { priority = 55, taskData = (with( new TaskData()) { workItemId = 1 } ), ";
    str +=
        "peopleAssignments = (with ( new PeopleAssignments() ) { potentialOwners = [users['bobba']], }),";
    //        str += "descriptions = [ new I18NText( 'en-UK', 'This is my description')], ";
    //        str += "subjects = [ new I18NText( 'en-UK', 'This is my subject')], ";
    str += "names = [ new I18NText( 'en-UK', 'This is my task name')] })";

    BlockingAddTaskResponseHandler addTaskResponseHandler = new BlockingAddTaskResponseHandler();
    Task task = (Task) eval(new StringReader(str), vars);
    client.addTask(task, null, addTaskResponseHandler);

    long taskId = addTaskResponseHandler.getTaskId();

    EventKey key = new TaskEventKey(TaskCompletedEvent.class, taskId);
    BlockingEventResponseHandler handler = new BlockingEventResponseHandler();
    client.registerForEvent(key, false, handler);

    BlockingTaskSummaryResponseHandler taskSummaryResponseHandler =
        new BlockingTaskSummaryResponseHandler();
    client.getTasksAssignedAsPotentialOwner(
        users.get("bobba").getId(), "en-UK", taskSummaryResponseHandler);
    List<TaskSummary> tasks = taskSummaryResponseHandler.getResults();
    assertEquals(1, tasks.size());
    assertEquals(Status.Reserved, tasks.get(0).getStatus());

    BlockingTaskOperationResponseHandler responseHandler =
        new BlockingTaskOperationResponseHandler();
    client.start(taskId, users.get("bobba").getId(), responseHandler);

    taskSummaryResponseHandler = new BlockingTaskSummaryResponseHandler();
    client.getTasksAssignedAsPotentialOwner(
        users.get("bobba").getId(), "en-UK", taskSummaryResponseHandler);
    tasks = taskSummaryResponseHandler.getResults();
    assertEquals(1, tasks.size());
    assertEquals(Status.InProgress, tasks.get(0).getStatus());

    responseHandler = new BlockingTaskOperationResponseHandler();
    client.complete(taskId, users.get("bobba").getId(), null, responseHandler);

    taskSummaryResponseHandler = new BlockingTaskSummaryResponseHandler();
    client.getTasksAssignedAsPotentialOwner(
        users.get("bobba").getId(), "en-UK", taskSummaryResponseHandler);
    tasks = taskSummaryResponseHandler.getResults();
    assertEquals(0, tasks.size());

    Payload payload = handler.getPayload();
    TaskCompletedEvent event = (TaskCompletedEvent) payload.get();
    assertNotNull(event);

    BlockingGetTaskResponseHandler getTaskResponseHandler = new BlockingGetTaskResponseHandler();
    client.getTask(taskId, getTaskResponseHandler);
    Task task1 = getTaskResponseHandler.getTask();
    assertEquals(Status.Completed, task1.getTaskData().getStatus());
  }
 @Transactional(readOnly = true)
 @Override
 public Task getTask(Long id) {
   BlockingGetTaskResponseHandler getTaskResponseHandler = new BlockingGetTaskResponseHandler();
   taskClient.getTask(id, getTaskResponseHandler);
   org.jbpm.task.Task task = getTaskResponseHandler.getTask();
   return this.converter.convert(task, Task.class);
 }
  @Override
  public Task convert(org.jbpm.task.query.TaskSummary source) {

    Task target = new Task();

    target.setDescription(source.getDescription());

    if (source.getActualOwner() != null) {
      target.setAssignee(source.getActualOwner().getId());
    }

    if (source.getCreatedOn() != null) {
      target.setCreateTime(convert(source.getCreatedOn(), XMLGregorianCalendar.class));
    }

    if (source.getExpirationTime() != null) {
      target.setDueDate(convert(source.getExpirationTime(), XMLGregorianCalendar.class));
    }
    target.setId(String.valueOf(source.getId()));

    if (source.getName() != null) {
      String[] parts = source.getName().split("/");
      target.setActivityName(parts[0]);
      target.setName(parts[1]);
    }

    target.setState(source.getStatus().name());

    target.setPriority(new Integer(source.getPriority()));
    target.setProcessInstanceId(
        source.getProcessId() + "." + Long.toString(source.getProcessInstanceId()));

    BlockingGetTaskResponseHandler getTaskResponseHandler = new BlockingGetTaskResponseHandler();
    taskClient.getTask(source.getId(), getTaskResponseHandler);
    org.jbpm.task.Task task = getTaskResponseHandler.getTask();

    BlockingGetContentResponseHandler getContentResponseHandler =
        new BlockingGetContentResponseHandler();
    taskClient.getContent(task.getTaskData().getDocumentContentId(), getContentResponseHandler);
    Content content = getContentResponseHandler.getContent();

    Map<String, Object> map =
        (Map<String, Object>) ContentMarshallerHelper.unmarshall(content.getContent(), null);

    for (String key : map.keySet()) {
      log.debug("Key: " + key);
    }

    // add task outcomes using the "Options" variable from the task
    String optionsString = (String) map.get("Options");
    if (optionsString != null) {
      String[] options = ((String) map.get("Options")).split(",");
      target.getOutcomes().addAll(Arrays.asList(options));
    }

    // get ad-hoc variables map

    Map<String, Object> contentMap =
        (Map<String, Object>) map.get(Bpmn20UserTaskNodeBuilder.TASK_INPUT_VARIABLES_NAME);
    if (contentMap != null) {
      for (Entry<String, Object> entry : contentMap.entrySet()) {
        log.debug(entry.getKey() + "=" + entry.getValue());
        addVariable(target, entry.getKey(), entry.getValue());
      }
    } else {
      log.debug("No Content found for task");
    }

    // add variables
    /*Set<String> names = taskService.getVariableNames(source.getId());
    Map<String, Object> variables = taskService.getVariables(source.getId(), names);
    // remove process name var
    variables.remove("_name");
    for (String key : variables.keySet()) {
        Variable var = new Variable();
        var.setName(key);
        // Support strings only.  Other types will cause ClassCastException
        try {
            var.setValue((String) variables.get(key));
        } catch (ClassCastException e) {
            var.setValue("Variable type " + variables.get(key).getClass().getName() + " is not supported");
        }
        addVariable(target, var);
    }

    // Do this only if the task is not an ad-hoc task (as indicated by null executionId)
    if (source.getExecutionId() != null) {

        // name is the 'form' attribute in JPDL
        // this is used in the COW schema to store the display name, as distinct from the system-generated name
        target.setName(source.getFormResourceName());

        // activityName is the 'name' from JPDL
        target.setActivityName(source.getActivityName());

        Execution ex = executionService.findExecutionById(source.getExecutionId());
        target.setProcessInstanceId(ex.getProcessInstance().getId());

        // outcomes
        Set<String> outcomes = taskService.getOutcomes(source.getId());
        for (String outcome : outcomes) {
            target.getOutcomes().add(outcome);
        }

        // Workaround to the fact that we cannot use autowiring here
        if (this.cowTaskService == null) {
            this.cowTaskService = (org.wiredwidgets.cow.server.service.TaskService) this.factory.getBean("taskService");
        }

        // add process level task varibles (
        String executionId = getTopLevelExecutionId(source.getExecutionId());
        org.wiredwidgets.cow.server.api.model.v2.Activity activity = cowTaskService.getWorkflowActivity(executionId, source.getActivityName());
        if (activity != null && activity instanceof org.wiredwidgets.cow.server.api.model.v2.Task) {
            org.wiredwidgets.cow.server.api.model.v2.Task cowTask = (org.wiredwidgets.cow.server.api.model.v2.Task) activity;
            if (cowTask.getVariables() != null) {
                for (org.wiredwidgets.cow.server.api.model.v2.Variable var : cowTask.getVariables().getVariables()) {
                    Variable newVar = new Variable();
                    newVar.setName(var.getName());
                    newVar.setValue(var.getValue());
                    addVariable(target, newVar);
                }
            }
        }
    } else {
        // for ad-hoc tasks
        target.setName(source.getName());
    }*/

    return target;
  }
  // TODO: Check if you can update a task. Can you update task by just adding a task with the same
  // ID?
  private org.jbpm.task.Task createOrUpdateTask(Task source) {

    org.jbpm.task.Task target;
    boolean newTask = false;
    if (source.getId() == null) {
      newTask = true;
      target = new org.jbpm.task.Task();
    } else {
      BlockingGetTaskResponseHandler getTaskResponseHandler = new BlockingGetTaskResponseHandler();
      taskClient.getTask(Long.valueOf(source.getId()), getTaskResponseHandler);
      target = getTaskResponseHandler.getTask();
    }
    if (target == null) {
      return null;
    }
    if (source.getAssignee() != null) {
      PeopleAssignments pa = new PeopleAssignments();
      List<OrganizationalEntity> orgEnt = new ArrayList<OrganizationalEntity>();
      org.jbpm.task.User oe = new org.jbpm.task.User();
      oe.setId(source.getAssignee());
      pa.setTaskInitiator(oe);
      orgEnt.add(oe);
      pa.setPotentialOwners(orgEnt);
      target.setPeopleAssignments(pa);
    }
    if (source.getDescription() != null) {
      List<I18NText> desc = new ArrayList<I18NText>();
      desc.add(new I18NText("en-UK", source.getDescription()));
      target.setDescriptions(desc);
    }
    if (source.getDueDate() != null) {
      Deadlines deadlines = new Deadlines();
      List<Deadline> dls = new ArrayList<Deadline>();
      Deadline dl = new Deadline();
      dl.setDate(this.convert(source.getDueDate()));
      dls.add(dl);
      deadlines.setEndDeadlines(dls);
      target.setDeadlines(deadlines);
    }
    if (source.getName() != null) {
      List<I18NText> names = new ArrayList<I18NText>();
      names.add(new I18NText("en-UK", source.getName()));
      target.setNames(names);
    }
    if (source.getPriority() != null) {
      target.setPriority(source.getPriority());
    }

    TaskData td = new TaskData();
    target.setTaskData(td);
    /*
     * if (source.getProgress() != null) {
     * target.setProgress(source.getProgress()); }
     */

    // convert variables
    /*
     * if (source.getVariables() != null &&
     * source.getVariables().getVariables().size() > 0) { Map<String,
     * Object> variables = new HashMap<String, Object>(); for (Variable
     * variable : source.getVariables().getVariables()) {
     * variables.put(variable.getName(), variable.getValue()); }
     * this.taskService.setVariables(target.getId(), variables); }
     */

    if (newTask) {
      BlockingAddTaskResponseHandler addTaskResponseHandler = new BlockingAddTaskResponseHandler();
      taskClient.addTask(target, null, addTaskResponseHandler);
    }

    return target;
  }
  @Override
  public void completeTask(
      Long id, String assignee, String outcome, Map<String, Object> variables) {
    // should be handled upstream in controller
    assert (assignee != null);

    log.debug(assignee + " starting task with ID: " + id);

    BlockingGetTaskResponseHandler getTaskResponseHandler = new BlockingGetTaskResponseHandler();
    taskClient.getTask(id, getTaskResponseHandler);
    org.jbpm.task.Task task = getTaskResponseHandler.getTask();

    // convert to COW task so we can verify the decision
    Task cowTask = converter.convert(task, Task.class);

    if (cowTask.getOutcomes() != null && cowTask.getOutcomes().size() > 0) {
      // This is a decision task!
      if (outcome == null) {
        throw new RuntimeException("ERROR: no decision provided for a Decision task");
      }
      if (!cowTask.getOutcomes().contains(outcome)) {
        throw new RuntimeException("ERROR: decision value " + outcome + " is not a valid choice.");
      }
    }

    BlockingGetContentResponseHandler getContentResponseHandler =
        new BlockingGetContentResponseHandler();
    taskClient.getContent(task.getTaskData().getDocumentContentId(), getContentResponseHandler);
    Content inputContent = getContentResponseHandler.getContent();

    Map<String, Object> inputMap =
        (Map<String, Object>) ContentMarshallerHelper.unmarshall(inputContent.getContent(), null);

    for (Map.Entry<String, Object> entry : inputMap.entrySet()) {
      log.debug(entry.getKey() + " = " + entry.getValue());
    }

    Map<String, Object> outputMap = new HashMap<String, Object>();

    // put Outcome into the outputMap
    // The InputMap contains a variable that tells us what key to use
    if (inputMap.get(DECISION_VAR_NAME) != null) {
      log.debug("Decision outcome: " + outcome);
      outputMap.put((String) inputMap.get(DECISION_VAR_NAME), outcome);
    }

    Map<String, Object> outputVarsMap = new HashMap<String, Object>();

    // NOTE: obtaining the map from the Task results in a copy of the map as of the
    // time when the task became available.  It's possible that in the meantime (e.g. due to
    // a parallel task) the map has been altered.
    // Map<String, Object> inputVarsMap = (Map<String, Object>)
    // inputMap.get(TASK_INPUT_VARIABLES_NAME);

    // So, instead, we get the current values directly from the process instance, rather than the
    // values copied into the task

    Long processInstanceId = task.getTaskData().getProcessInstanceId();
    Map<String, Object> inputVarsMap = null;

    try {
      WorkflowProcessInstance pi =
          (WorkflowProcessInstance) kSession.getProcessInstance(processInstanceId);
      inputVarsMap = (Map<String, Object>) pi.getVariable(VARIABLES_PROPERTY);
    } catch (Exception e) {
      // not an active process?  look in the dB.
      log.error(e);
      List<VariableInstanceLog> vars =
          JPAProcessInstanceDbLog.findVariableInstances(processInstanceId, VARIABLES_PROPERTY);
      log.info("variable count: " + vars.size());
      if (vars.size() > 0) {
        // why more than one???
        inputVarsMap = (Map<String, Object>) vars.get(0);
      }
    }

    if (inputVarsMap != null) {
      // initialize the output map with the input values
      log.debug("Copying input map: " + inputVarsMap);
      outputVarsMap.putAll(inputVarsMap);
    }

    if (variables != null && variables.size() > 0) {
      log.debug("Adding variables: " + variables);
      // update with any new or modified values
      outputVarsMap.putAll(variables);
    }

    if (outputVarsMap.size() > 0) {
      log.debug("Adding map to output");
      outputMap.put(TASK_OUTPUT_VARIABLES_NAME, outputVarsMap);
    }

    // start the task
    if (task.getTaskData().getStatus().equals(org.jbpm.task.Status.Reserved)) {
      BlockingTaskOperationResponseHandler operationResponseHandler =
          new BlockingTaskOperationResponseHandler();
      // change status to InProgress
      taskClient.start(id, assignee, operationResponseHandler);
    }

    // kSession.getWorkItemManager().completeWorkItem(task.getTaskData().getWorkItemId(), new
    // HashMap<String,Object>());
    BlockingTaskOperationResponseHandler taskResponseHandler =
        new BlockingTaskOperationResponseHandler();
    // TODO: since we're passing the variables map further down, maybe we don't need to pass it
    // here?  Test this.
    ContentData contentData = ContentMarshallerHelper.marshal(outputMap, null);
    taskClient.complete(id, assignee, contentData, taskResponseHandler);
    taskResponseHandler.waitTillDone(1000);

    // note that we have to pass the variables again.
    kSession.getWorkItemManager().completeWorkItem(task.getTaskData().getWorkItemId(), outputMap);

    // update completed date
    // For some reason this does not get updated by default, and
    // there appears to be no JBPM API way to do this!
    org.jbpm.task.Task t = taskRepo.findOne(task.getId());
    t.getTaskData().setCompletedOn(new Date());
    // update the user
    t.getTaskData().setActualOwner(new User(assignee));

    // note that JPA handles updating of this object automatically

  }
  @Test
  public void testTaskDataWithVPSandMAPWithDeadline() throws Exception {

    taskService.setEscalatedDeadlineHandler(buildDeadlineHandler(env));
    // JPA Entity
    EntityManager em = domainEmf.createEntityManager();
    em.getTransaction().begin();
    MyEntity myEntity = new MyEntity("This is a JPA Entity");
    em.persist(myEntity);
    em.getTransaction().commit();

    // Serializable Object
    MyObject myObject = new MyObject("This is a Serializable Object");

    Map<String, Object> content = new HashMap<String, Object>();
    content.put("myJPAEntity", myEntity);
    content.put("mySerializableObject", myObject);

    TestWorkItemManager manager = new TestWorkItemManager();
    ksession.setWorkItemManager(manager);
    WorkItemImpl workItem = new WorkItemImpl();
    workItem.setName("Human Task");
    workItem.setParameter("TaskName", "TaskName");
    workItem.setParameter("Comment", "Comment");
    workItem.setParameter("Priority", "10");
    workItem.setParameter("ActorId", "Darth Vader");
    workItem.setParameter("Content", content);
    workItem.setParameter(
        "NotStartedNotify",
        "[tousers:john|subject:${doc['myJPAEntity'].test}|body:${doc['mySerializableObject'].value}]@[2s]");
    getHandler().executeWorkItem(workItem, manager);

    BlockingTaskSummaryResponseHandler taskSummaryResponseHandler =
        new BlockingTaskSummaryResponseHandler();
    getClient()
        .getTasksAssignedAsPotentialOwner("Darth Vader", "en-UK", taskSummaryResponseHandler);
    List<TaskSummary> tasks = taskSummaryResponseHandler.getResults();
    assertEquals(1, tasks.size());
    TaskSummary taskSummary = tasks.get(0);
    assertEquals("TaskName", taskSummary.getName());
    assertEquals(10, taskSummary.getPriority());
    assertEquals("Comment", taskSummary.getDescription());
    assertEquals(Status.Reserved, taskSummary.getStatus());
    assertEquals("Darth Vader", taskSummary.getActualOwner().getId());

    BlockingGetTaskResponseHandler getTaskResponseHandler = new BlockingGetTaskResponseHandler();
    getClient().getTask(taskSummary.getId(), getTaskResponseHandler);
    Task task = getTaskResponseHandler.getTask();
    assertEquals(AccessType.Inline, task.getTaskData().getDocumentAccessType());
    assertEquals(task.getTaskData().getProcessSessionId(), ksession.getId());
    long contentId = task.getTaskData().getDocumentContentId();
    assertTrue(contentId != -1);

    BlockingGetContentResponseHandler getContentResponseHandler =
        new BlockingGetContentResponseHandler();
    getClient().getContent(contentId, getContentResponseHandler);
    Object data =
        ContentMarshallerHelper.unmarshall(
            getContentResponseHandler.getContent().getContent(), ksession.getEnvironment());
    Map<String, Object> dataMap = (Map<String, Object>) data;

    assertEquals(myEntity.getTest(), ((MyEntity) dataMap.get("myJPAEntity")).getTest());
    assertEquals(myObject.getValue(), ((MyObject) dataMap.get("mySerializableObject")).getValue());

    Thread.sleep(5000);
    assertEquals(2, wiser.getMessages().size());
    assertEquals("*****@*****.**", wiser.getMessages().get(0).getEnvelopeReceiver());
    assertEquals("*****@*****.**", wiser.getMessages().get(1).getEnvelopeReceiver());
    assertEquals(myEntity.getTest(), wiser.getMessages().get(0).getMimeMessage().getSubject());
    assertEquals(myObject.getValue(), wiser.getMessages().get(0).getMimeMessage().getContent());

    BlockingTaskOperationResponseHandler startResponseHandler =
        new BlockingTaskOperationResponseHandler();
    getClient().start(task.getId(), "Darth Vader", startResponseHandler);

    Map<String, Object> results = new HashMap<String, Object>();
    em.getTransaction().begin();
    MyEntity myEntity2 = new MyEntity("This is a JPA Entity 2");
    em.persist(myEntity2);
    em.getTransaction().commit();
    results.put("myEntity2", myEntity2);
    MyObject myObject2 = new MyObject("This is a Serializable Object 2");
    results.put("myObject2", myObject2);

    ContentData result = ContentMarshallerHelper.marshal(results, ksession.getEnvironment());

    BlockingTaskOperationResponseHandler completeResponseHandler =
        new BlockingTaskOperationResponseHandler();
    getClient().complete(task.getId(), "Darth Vader", result, completeResponseHandler);

    assertTrue(manager.waitTillCompleted(MANAGER_COMPLETION_WAIT_TIME));
    Map<String, Object> managerResults = manager.getResults();
    assertNotNull(managerResults);
    assertEquals("Darth Vader", managerResults.get("ActorId"));
    assertEquals(
        myEntity2.getTest(),
        ((MyEntity) ((Map) managerResults.get("Result")).get("myEntity2")).getTest());
    assertEquals(myEntity2.getTest(), ((MyEntity) managerResults.get("myEntity2")).getTest());
    assertEquals(
        myObject2.getValue(),
        ((MyObject) ((Map) managerResults.get("Result")).get("myObject2")).getValue());
    assertEquals(myObject2.getValue(), ((MyObject) managerResults.get("myObject2")).getValue());
  }
  @Test
  public void testTaskDataWithVPSSerializableObjectWithMarshal() throws Exception {
    // Serializable Object
    MyObject myObject = new MyObject("This is a Serializable Object");

    TestWorkItemManager manager = new TestWorkItemManager();
    ksession.setWorkItemManager(manager);
    WorkItemImpl workItem = new WorkItemImpl();
    workItem.setName("Human Task");
    workItem.setParameter("TaskName", "TaskName");
    workItem.setParameter("Comment", "Comment");
    workItem.setParameter("Priority", "10");
    workItem.setParameter("ActorId", "Darth Vader");
    workItem.setParameter("Content", myObject);
    getHandler().executeWorkItem(workItem, manager);

    BlockingTaskSummaryResponseHandler taskSummaryResponseHandler =
        new BlockingTaskSummaryResponseHandler();
    getClient()
        .getTasksAssignedAsPotentialOwner("Darth Vader", "en-UK", taskSummaryResponseHandler);
    List<TaskSummary> tasks = taskSummaryResponseHandler.getResults();
    assertEquals(1, tasks.size());
    TaskSummary taskSummary = tasks.get(0);
    assertEquals("TaskName", taskSummary.getName());
    assertEquals(10, taskSummary.getPriority());
    assertEquals("Comment", taskSummary.getDescription());
    assertEquals(Status.Reserved, taskSummary.getStatus());
    assertEquals("Darth Vader", taskSummary.getActualOwner().getId());

    BlockingGetTaskResponseHandler getTaskResponseHandler = new BlockingGetTaskResponseHandler();
    getClient().getTask(taskSummary.getId(), getTaskResponseHandler);
    Task task = getTaskResponseHandler.getTask();
    assertEquals(AccessType.Inline, task.getTaskData().getDocumentAccessType());

    assertEquals(task.getTaskData().getProcessSessionId(), ksession.getId());
    long contentId = task.getTaskData().getDocumentContentId();
    assertTrue(contentId != -1);

    BlockingGetContentResponseHandler getContentResponseHandler =
        new BlockingGetContentResponseHandler();
    getClient().getContent(contentId, getContentResponseHandler);
    Object data =
        ContentMarshallerHelper.unmarshall(
            getContentResponseHandler.getContent().getContent(), ksession.getEnvironment());
    assertEquals(myObject.getValue(), ((MyObject) data).getValue());

    BlockingTaskOperationResponseHandler startResponseHandler =
        new BlockingTaskOperationResponseHandler();
    getClient().start(task.getId(), "Darth Vader", startResponseHandler);

    MyObject myObject2 = new MyObject("This is a Serializable Object 2");

    ContentData result = ContentMarshallerHelper.marshal(myObject2, ksession.getEnvironment());
    BlockingTaskOperationResponseHandler completeResponseHandler =
        new BlockingTaskOperationResponseHandler();
    getClient().complete(task.getId(), "Darth Vader", result, completeResponseHandler);

    assertTrue(manager.waitTillCompleted(MANAGER_COMPLETION_WAIT_TIME));
    Map<String, Object> results = manager.getResults();
    assertNotNull(results);
    assertEquals("Darth Vader", results.get("ActorId"));
    assertEquals(myObject2.getValue(), ((MyObject) results.get("Result")).getValue());
  }
  public void testAddRemoveComment() {
    Map vars = new HashMap();
    vars.put("users", users);
    vars.put("groups", groups);
    vars.put("now", new Date());

    String str =
        "(with (new Task()) { priority = 55, taskData = (with( new TaskData()) { createdOn = now, activationTime = now}), ";
    str += "deadlines = new Deadlines(),";
    str += "delegation = new Delegation(),";
    str += "peopleAssignments = new PeopleAssignments(),";
    str += "names = [ new I18NText( 'en-UK', 'This is my task name')] })";

    BlockingAddTaskResponseHandler addTaskResponseHandler = new BlockingAddTaskResponseHandler();
    Task task = (Task) eval(new StringReader(str), vars);
    client.addTask(task, null, addTaskResponseHandler);

    long taskId = addTaskResponseHandler.getTaskId();

    Comment comment = new Comment();
    Date addedAt = new Date(System.currentTimeMillis());
    comment.setAddedAt(addedAt);
    comment.setAddedBy(users.get("luke"));
    comment.setText("This is my comment1!!!!!");

    BlockingAddCommentResponseHandler addCommentResponseHandler =
        new BlockingAddCommentResponseHandler();
    client.addComment(taskId, comment, addCommentResponseHandler);
    assertTrue(addCommentResponseHandler.getCommentId() != comment.getId());

    BlockingGetTaskResponseHandler getTaskResponseHandler = new BlockingGetTaskResponseHandler();
    client.getTask(taskId, getTaskResponseHandler);
    Task task1 = getTaskResponseHandler.getTask();
    assertNotSame(task, task1);
    assertFalse(task.equals(task1));

    List<Comment> comments1 = task1.getTaskData().getComments();
    assertEquals(1, comments1.size());
    Comment returnedComment = comments1.get(0);
    assertEquals("This is my comment1!!!!!", returnedComment.getText());
    assertEquals(addedAt, returnedComment.getAddedAt());
    assertEquals(users.get("luke"), returnedComment.getAddedBy());

    assertEquals((long) addCommentResponseHandler.getCommentId(), (long) returnedComment.getId());

    // Make the same as the returned tasks, so we can test equals
    task.getTaskData().setComments(comments1);
    task.getTaskData().setStatus(Status.Created);
    assertEquals(task, task1);

    // test we can have multiple comments
    comment = new Comment();
    addedAt = new Date(System.currentTimeMillis());
    comment.setAddedAt(addedAt);
    comment.setAddedBy(users.get("tony"));
    comment.setText("This is my comment2!!!!!");

    addCommentResponseHandler = new BlockingAddCommentResponseHandler();
    client.addComment(taskId, comment, addCommentResponseHandler);

    getTaskResponseHandler = new BlockingGetTaskResponseHandler();
    client.getTask(taskId, getTaskResponseHandler);
    task1 = getTaskResponseHandler.getTask();
    List<Comment> comments2 = task1.getTaskData().getComments();
    assertEquals(2, comments2.size());

    // make two collections the same and compare
    comments1.add(comment);
    assertTrue(CollectionUtils.equals(comments1, comments2));

    BlockingDeleteCommentResponseHandler deleteCommentResponseHandler =
        new BlockingDeleteCommentResponseHandler();
    client.deleteComment(
        taskId, addCommentResponseHandler.getCommentId(), deleteCommentResponseHandler);
    deleteCommentResponseHandler.waitTillDone(3000);

    getTaskResponseHandler = new BlockingGetTaskResponseHandler();
    client.getTask(taskId, getTaskResponseHandler);
    task1 = getTaskResponseHandler.getTask();
    comments2 = task1.getTaskData().getComments();
    assertEquals(1, comments2.size());

    assertEquals("This is my comment1!!!!!", comments2.get(0).getText());
  }
  public void testAddRemoveAttachment() throws Exception {
    Map vars = new HashMap();
    vars.put("users", users);
    vars.put("groups", groups);
    vars.put("now", new Date());

    String str =
        "(with (new Task()) { priority = 55, taskData = (with( new TaskData()) { createdOn = now, activationTime = now}), ";
    str += "deadlines = new Deadlines(),";
    str += "delegation = new Delegation(),";
    str += "peopleAssignments = new PeopleAssignments(),";
    str += "names = [ new I18NText( 'en-UK', 'This is my task name')] })";

    BlockingAddTaskResponseHandler addTaskResponseHandler = new BlockingAddTaskResponseHandler();
    Task task = (Task) eval(new StringReader(str), vars);
    client.addTask(task, null, addTaskResponseHandler);

    long taskId = addTaskResponseHandler.getTaskId();

    Attachment attachment = new Attachment();
    Date attachedAt = new Date(System.currentTimeMillis());
    attachment.setAttachedAt(attachedAt);
    attachment.setAttachedBy(users.get("luke"));
    attachment.setName("file1.txt");
    attachment.setAccessType(AccessType.Inline);
    attachment.setContentType("txt");

    byte[] bytes = "Ths is my attachment text1".getBytes();
    Content content = new Content();
    content.setContent(bytes);

    BlockingAddAttachmentResponseHandler addAttachmentResponseHandler =
        new BlockingAddAttachmentResponseHandler();
    client.addAttachment(taskId, attachment, content, addAttachmentResponseHandler);
    assertTrue(addAttachmentResponseHandler.getAttachmentId() != attachment.getId());
    assertTrue(addAttachmentResponseHandler.getContentId() != attachment.getAttachmentContentId());

    BlockingGetTaskResponseHandler getTaskResponseHandler = new BlockingGetTaskResponseHandler();
    client.getTask(taskId, getTaskResponseHandler);
    Task task1 = getTaskResponseHandler.getTask();
    assertNotSame(task, task1);
    assertFalse(task.equals(task1));

    List<Attachment> attachments1 = task1.getTaskData().getAttachments();
    assertEquals(1, attachments1.size());
    Attachment returnedAttachment = attachments1.get(0);
    assertEquals(attachedAt, returnedAttachment.getAttachedAt());
    assertEquals(users.get("luke"), returnedAttachment.getAttachedBy());
    assertEquals(AccessType.Inline, returnedAttachment.getAccessType());
    assertEquals("txt", returnedAttachment.getContentType());
    assertEquals("file1.txt", returnedAttachment.getName());
    assertEquals(bytes.length, returnedAttachment.getSize());

    assertEquals(
        (long) addAttachmentResponseHandler.getAttachmentId(), (long) returnedAttachment.getId());
    assertEquals(
        (long) addAttachmentResponseHandler.getContentId(),
        (long) returnedAttachment.getAttachmentContentId());

    // Make the same as the returned tasks, so we can test equals
    task.getTaskData().setAttachments(attachments1);
    task.getTaskData().setStatus(Status.Created);
    assertEquals(task, task1);

    BlockingGetContentResponseHandler getResponseHandler = new BlockingGetContentResponseHandler();
    client.getContent(returnedAttachment.getAttachmentContentId(), getResponseHandler);
    content = getResponseHandler.getContent();
    assertEquals("Ths is my attachment text1", new String(content.getContent()));

    // test we can have multiple attachments

    attachment = new Attachment();
    attachedAt = new Date(System.currentTimeMillis());
    attachment.setAttachedAt(attachedAt);
    attachment.setAttachedBy(users.get("tony"));
    attachment.setName("file2.txt");
    attachment.setAccessType(AccessType.Inline);
    attachment.setContentType("txt");

    bytes = "Ths is my attachment text2".getBytes();
    content = new Content();
    content.setContent(bytes);

    addAttachmentResponseHandler = new BlockingAddAttachmentResponseHandler();
    client.addAttachment(taskId, attachment, content, addAttachmentResponseHandler);

    getTaskResponseHandler = new BlockingGetTaskResponseHandler();
    client.getTask(taskId, getTaskResponseHandler);
    task1 = getTaskResponseHandler.getTask();
    assertNotSame(task, task1);
    assertFalse(task.equals(task1));

    List<Attachment> attachments2 = task1.getTaskData().getAttachments();
    assertEquals(2, attachments2.size());

    getResponseHandler = new BlockingGetContentResponseHandler();
    client.getContent(addAttachmentResponseHandler.getContentId(), getResponseHandler);
    content = getResponseHandler.getContent();
    assertEquals("Ths is my attachment text2", new String(content.getContent()));

    // make two collections the same and compare
    attachment.setSize(26);
    attachment.setAttachmentContentId(addAttachmentResponseHandler.getContentId());
    attachments1.add(attachment);
    assertTrue(CollectionUtils.equals(attachments2, attachments1));

    BlockingDeleteAttachmentResponseHandler deleteCommentResponseHandler =
        new BlockingDeleteAttachmentResponseHandler();
    client.deleteAttachment(
        taskId,
        addAttachmentResponseHandler.getAttachmentId(),
        addAttachmentResponseHandler.getContentId(),
        deleteCommentResponseHandler);
    deleteCommentResponseHandler.waitTillDone(3000);

    Thread.sleep(3000);

    getTaskResponseHandler = new BlockingGetTaskResponseHandler();
    client.getTask(taskId, getTaskResponseHandler);
    task1 = getTaskResponseHandler.getTask();
    attachments2 = task1.getTaskData().getAttachments();
    assertEquals(1, attachments2.size());

    assertEquals("file1.txt", attachments2.get(0).getName());
  }
  public static void runTestLifeCycleMultipleTasks(
      AsyncTaskService client, Map<String, User> users, Map<String, Group> groups) {
    Map<String, Object> vars = fillVariables(users, groups);

    // One potential owner, should go straight to state Reserved
    String str =
        "(with (new Task()) { priority = 55, taskData = (with( new TaskData()) { workItemId = 1 } ), ";
    str +=
        "peopleAssignments = (with ( new PeopleAssignments() ) { potentialOwners = [users['bobba']], }),";
    str += "descriptions = [ new I18NText( 'en-UK', 'This is my description')], ";
    str += "subjects = [ new I18NText( 'en-UK', 'This is my subject')], ";
    str += "names = [ new I18NText( 'en-UK', 'This is my task name')] })";

    // First task
    // In own scope to make sure that no objects in scope can be used in second task
    long taskId = 0;
    BlockingEventResponseHandler handler = new BlockingEventResponseHandler();
    {
      BlockingAddTaskResponseHandler addTaskResponseHandler = new BlockingAddTaskResponseHandler();
      Task task = (Task) eval(new StringReader(str), vars);
      client.addTask(task, null, addTaskResponseHandler);
      taskId = addTaskResponseHandler.getTaskId();
      assertTrue(taskId != 0);

      EventKey key = new TaskEventKey(TaskCompletedEvent.class, taskId);
      client.registerForEvent(key, false, handler);

      BlockingTaskSummaryResponseHandler taskSummaryResponseHandler =
          new BlockingTaskSummaryResponseHandler();
      client.getTasksAssignedAsPotentialOwner(
          users.get("bobba").getId(), "en-UK", taskSummaryResponseHandler);
      List<TaskSummary> tasks = taskSummaryResponseHandler.getResults();
      assertEquals(1, tasks.size());
      assertEquals(Status.Reserved, tasks.get(0).getStatus());

      BlockingTaskOperationResponseHandler responseHandler =
          new BlockingTaskOperationResponseHandler();
      client.start(taskId, users.get("bobba").getId(), responseHandler);

      taskSummaryResponseHandler = new BlockingTaskSummaryResponseHandler();
      client.getTasksAssignedAsPotentialOwner(
          users.get("bobba").getId(), "en-UK", taskSummaryResponseHandler);
      tasks = taskSummaryResponseHandler.getResults();
      assertEquals(1, tasks.size());
      assertEquals(Status.InProgress, tasks.get(0).getStatus());
    }

    // Second task
    // In own scope to make sure that no objects in scope can be used elsewhere
    long taskId2 = 0;
    BlockingEventResponseHandler handler2 = new BlockingEventResponseHandler();
    {
      BlockingAddTaskResponseHandler addTaskResponseHandler2 = new BlockingAddTaskResponseHandler();
      Task task2 = (Task) eval(new StringReader(str), vars);
      client.addTask(task2, null, addTaskResponseHandler2);
      taskId2 = addTaskResponseHandler2.getTaskId();
      assertTrue(taskId2 != 0);
      assertTrue("Tasks should have different ids.", taskId != taskId2);

      EventKey key2 = new TaskEventKey(TaskCompletedEvent.class, taskId2);
      client.registerForEvent(key2, false, handler2);

      BlockingTaskSummaryResponseHandler taskSummaryResponseHandler =
          new BlockingTaskSummaryResponseHandler();
      client.getTasksAssignedAsPotentialOwner(
          users.get("bobba").getId(), "en-UK", taskSummaryResponseHandler);
      List<TaskSummary> tasks = taskSummaryResponseHandler.getResults();
      assertEquals(2, tasks.size());

      BlockingTaskOperationResponseHandler responseHandler =
          new BlockingTaskOperationResponseHandler();
      client.complete(taskId, users.get("bobba").getId(), null, responseHandler);

      responseHandler = new BlockingTaskOperationResponseHandler();
      client.start(taskId2, users.get("bobba").getId(), responseHandler);

      taskSummaryResponseHandler = new BlockingTaskSummaryResponseHandler();
      client.getTasksAssignedAsPotentialOwner(
          users.get("bobba").getId(), "en-UK", taskSummaryResponseHandler);
      tasks = taskSummaryResponseHandler.getResults();
      assertEquals(1, tasks.size());
    }

    Payload payload = handler.getPayload();
    TaskCompletedEvent event = (TaskCompletedEvent) payload.get();
    assertNotNull(event);

    BlockingGetTaskResponseHandler getTaskResponseHandler = new BlockingGetTaskResponseHandler();
    client.getTask(taskId, getTaskResponseHandler);
    Task task = getTaskResponseHandler.getTask();
    assertEquals(Status.Completed, task.getTaskData().getStatus());

    BlockingTaskOperationResponseHandler responseHandler =
        new BlockingTaskOperationResponseHandler();
    client.complete(taskId2, users.get("bobba").getId(), null, responseHandler);

    payload = handler2.getPayload();
    event = (TaskCompletedEvent) payload.get();
    assertNotNull(event);

    BlockingGetTaskResponseHandler getTaskResponseHandler2 = new BlockingGetTaskResponseHandler();
    client.getTask(taskId2, getTaskResponseHandler2);
    Task task2 = getTaskResponseHandler2.getTask();
    assertEquals(Status.Completed, task2.getTaskData().getStatus());
  }
  public void testDelayedReassignmentOnDeadline() throws Exception {
    Map vars = new HashMap();
    vars.put("users", users);
    vars.put("groups", groups);
    vars.put("now", new Date());

    DefaultEscalatedDeadlineHandler notificationHandler =
        new DefaultEscalatedDeadlineHandler(getConf());
    WorkItemManager manager = new DefaultWorkItemManager(null);
    notificationHandler.setManager(manager);

    MockUserInfo userInfo = new MockUserInfo();
    userInfo.getEmails().put(users.get("tony"), "*****@*****.**");
    userInfo.getEmails().put(users.get("luke"), "*****@*****.**");
    userInfo.getEmails().put(users.get("bobba"), "*****@*****.**");
    userInfo.getEmails().put(users.get("jabba"), "*****@*****.**");

    userInfo.getLanguages().put(users.get("tony"), "en-UK");
    userInfo.getLanguages().put(users.get("luke"), "en-UK");
    userInfo.getLanguages().put(users.get("bobba"), "en-UK");
    userInfo.getLanguages().put(users.get("jabba"), "en-UK");
    notificationHandler.setUserInfo(userInfo);

    taskService.setEscalatedDeadlineHandler(notificationHandler);

    Reader reader =
        new InputStreamReader(
            getClass().getResourceAsStream(MvelFilePath.DeadlineWithReassignment));

    BlockingAddTaskResponseHandler addTaskResponseHandler = new BlockingAddTaskResponseHandler();
    Task task = (Task) eval(reader, vars);
    client.addTask(task, null, addTaskResponseHandler);
    long taskId = addTaskResponseHandler.getTaskId();

    // Shouldn't have re-assigned yet
    Thread.sleep(1000);
    BlockingGetTaskResponseHandler getTaskHandler = new BlockingGetTaskResponseHandler();
    client.getTask(taskId, getTaskHandler);
    task = getTaskHandler.getTask();
    List<OrganizationalEntity> potentialOwners = task.getPeopleAssignments().getPotentialOwners();
    List<String> ids = new ArrayList<String>(potentialOwners.size());
    for (OrganizationalEntity entity : potentialOwners) {
      ids.add(entity.getId());
    }
    assertTrue(ids.contains(users.get("tony").getId()));
    assertTrue(ids.contains(users.get("luke").getId()));

    // should have re-assigned by now
    long time = 0;
    while (getWiser().getMessages().size() != 2 && time < 15000) {
      Thread.sleep(500);
      time += 500;
    }

    getTaskHandler = new BlockingGetTaskResponseHandler();
    client.getTask(taskId, getTaskHandler);
    task = getTaskHandler.getTask();
    assertEquals(Status.Ready, task.getTaskData().getStatus());
    potentialOwners = task.getPeopleAssignments().getPotentialOwners();
    System.out.println(potentialOwners);
    ids = new ArrayList<String>(potentialOwners.size());
    for (OrganizationalEntity entity : potentialOwners) {
      ids.add(entity.getId());
    }
    assertTrue(ids.contains(users.get("bobba").getId()));
    assertTrue(ids.contains(users.get("jabba").getId()));
  }