@Override
  public String endTask(
      CoreSession coreSession,
      NuxeoPrincipal principal,
      Task task,
      String comment,
      String eventName,
      boolean isValidated)
      throws ClientException {

    // put user comment on the task
    if (!StringUtils.isEmpty(comment)) {
      task.addComment(principal.getName(), comment);
    }

    // end the task, adding boolean marker that task was validated or
    // rejected
    task.setVariable(TaskService.VariableName.validated.name(), String.valueOf(isValidated));
    task.end(coreSession);
    coreSession.saveDocument(task.getDocument());
    // notify
    Map<String, Serializable> eventProperties = new HashMap<String, Serializable>();
    ArrayList<String> notificationRecipients = new ArrayList<String>();
    notificationRecipients.add(task.getInitiator());
    notificationRecipients.addAll(task.getActors());
    eventProperties.put(NotificationConstants.RECIPIENTS_KEY, notificationRecipients);
    // try to resolve document when notifying
    DocumentModel document = null;
    String docId = task.getVariable(TaskService.VariableName.documentId.name());
    String docRepo = task.getVariable(TaskService.VariableName.documentRepositoryName.name());
    if (coreSession.getRepositoryName().equals(docRepo)) {
      try {
        document = coreSession.getDocument(new IdRef(docId));
      } catch (Exception e) {
        log.error(
            String.format(
                "Could not fetch document with id '%s:%s' for notification", docRepo, docId),
            e);
      }
    } else {
      log.error(
          String.format(
              "Could not resolve document for notification: "
                  + "document is on repository '%s' and given session is on "
                  + "repository '%s'",
              docRepo, coreSession.getRepositoryName()));
    }

    TaskEventNotificationHelper.notifyEvent(
        coreSession, document, principal, task, eventName, eventProperties, comment, null);

    String seamEventName =
        isValidated
            ? TaskEventNames.WORKFLOW_TASK_COMPLETED
            : TaskEventNames.WORKFLOW_TASK_REJECTED;
    return seamEventName;
  }
  @Test
  public void testCreateSingleTaskChain() throws Exception {
    OperationContext ctx = new OperationContext(coreSession);
    ctx.setInput(document);

    List<Task> tasks = taskService.getTaskInstances(document, (NuxeoPrincipal) null, coreSession);
    assertNotNull(tasks);
    assertEquals(0, tasks.size());

    automationService.run(ctx, "createSingleTaskChain");

    tasks = taskService.getTaskInstances(document, (NuxeoPrincipal) null, coreSession);
    assertEquals(1, tasks.size());

    Task task = tasks.get(0);
    assertEquals("single test task", task.getName());

    List<String> pooledActorIds = task.getActors();
    assertEquals(3, pooledActorIds.size());
    assertTrue(pooledActorIds.contains(SecurityConstants.MEMBERS));
    assertTrue(pooledActorIds.contains("myuser"));
    assertTrue(pooledActorIds.contains(SecurityConstants.ADMINISTRATOR));

    List<TaskComment> comments = task.getComments();
    assertEquals(1, comments.size());

    TaskComment comment = comments.get(0);
    assertEquals(SecurityConstants.ADMINISTRATOR, comment.getAuthor());
    assertEquals("test comment", comment.getText());

    Calendar calendar = Calendar.getInstance();
    calendar.set(2006, 6, 6, 15, 10, 15);
    calendar.set(Calendar.MILLISECOND, 0);
    calendar.setTimeZone(TimeZone.getTimeZone("UTC"));
    assertEquals(calendar.getTime(), task.getDueDate());
    // task status
    assertTrue(task.isOpened());
    assertFalse(task.isCancelled());
    assertFalse(task.hasEnded());
    assertEquals(6, task.getVariables().size());
    assertEquals(
        document.getRepositoryName(),
        task.getVariable(TaskService.VariableName.documentRepositoryName.name()));
    assertEquals(document.getId(), task.getVariable(TaskService.VariableName.documentId.name()));
    assertEquals("test directive", task.getVariable(TaskService.VariableName.directive.name()));
    assertEquals(
        "true", task.getVariable(OperationTaskVariableName.createdFromCreateTaskOperation.name()));
    assertEquals("true", task.getVariable(TaskService.VariableName.createdFromTaskService.name()));
    assertEquals(SecurityConstants.ADMINISTRATOR, task.getInitiator());

    // accept task
    taskService.acceptTask(
        coreSession, (NuxeoPrincipal) coreSession.getPrincipal(), task, "ok i'm in");
    coreSession.save();
    // test task again
    tasks = taskService.getTaskInstances(document, (NuxeoPrincipal) null, coreSession);
    // ended tasks are filtered
    assertEquals(0, tasks.size());

    // check document metadata
    assertNull(document.getPropertyValue("dc:description"));
  }
  @Test
  public void testCreateSeveralTasksChain() throws Exception {
    OperationContext ctx = new OperationContext(coreSession);
    ctx.setInput(document);

    List<Task> tasks = taskService.getTaskInstances(document, (NuxeoPrincipal) null, coreSession);
    assertNotNull(tasks);
    assertEquals(0, tasks.size());

    automationService.run(ctx, "createSeveralTasksChain");

    tasks = taskService.getTaskInstances(document, (NuxeoPrincipal) null, coreSession);
    Collections.sort(tasks, new TaskInstanceComparator());
    assertEquals(3, tasks.size());

    Task task1 = tasks.get(0);
    assertEquals("several test tasks", task1.getName());

    List<String> pooledActorIds = task1.getActors();
    assertEquals(1, pooledActorIds.size());
    assertEquals(SecurityConstants.ADMINISTRATOR, pooledActorIds.get(0));

    List<TaskComment> comments = task1.getComments();
    assertEquals(0, comments.size());
    // task status
    assertTrue(task1.isOpened());
    assertFalse(task1.isCancelled());
    assertFalse(task1.hasEnded());
    assertEquals(5, task1.getVariables().size());
    assertEquals(
        document.getRepositoryName(),
        task1.getVariable(TaskService.VariableName.documentRepositoryName.name()));
    assertEquals(document.getId(), task1.getVariable(TaskService.VariableName.documentId.name()));
    assertNull(task1.getVariable(TaskService.VariableName.directive.name()));
    assertEquals(
        "true", task1.getVariable(OperationTaskVariableName.createdFromCreateTaskOperation.name()));
    assertEquals("true", task1.getVariable(TaskService.VariableName.createdFromTaskService.name()));

    assertEquals(SecurityConstants.ADMINISTRATOR, task1.getInitiator());
    // accept task
    taskService.acceptTask(
        coreSession, (NuxeoPrincipal) coreSession.getPrincipal(), task1, "ok i'm in");
    coreSession.save();
    // test task again
    tasks = taskService.getTaskInstances(document, (NuxeoPrincipal) null, coreSession);
    // ended tasks are filtered
    assertEquals(2, tasks.size());

    Collections.sort(tasks, new TaskInstanceComparator());

    // check other tasks
    Task task2 = tasks.get(0);
    assertEquals("several test tasks", task2.getName());

    pooledActorIds = task2.getActors();
    assertEquals(1, pooledActorIds.size());
    assertEquals(SecurityConstants.MEMBERS, pooledActorIds.get(0));

    comments = task2.getComments();
    assertEquals(0, comments.size());
    // task status
    assertTrue(task2.isOpened());
    assertFalse(task2.isCancelled());
    assertFalse(task2.hasEnded());
    assertEquals(5, task2.getVariables().size());
    assertEquals(
        document.getRepositoryName(),
        task2.getVariable(TaskService.VariableName.documentRepositoryName.name()));
    assertEquals(document.getId(), task2.getVariable(TaskService.VariableName.documentId.name()));
    assertNull(task2.getVariable(TaskService.VariableName.directive.name()));
    assertEquals(
        "true", task2.getVariable(OperationTaskVariableName.createdFromCreateTaskOperation.name()));
    assertEquals("true", task2.getVariable(TaskService.VariableName.createdFromTaskService.name()));

    assertEquals(SecurityConstants.ADMINISTRATOR, task2.getInitiator());
    Task task3 = tasks.get(1);
    assertEquals("several test tasks", task3.getName());

    pooledActorIds = task3.getActors();
    assertEquals(1, pooledActorIds.size());
    assertEquals("myuser", pooledActorIds.get(0));

    comments = task3.getComments();
    assertEquals(0, comments.size());
    // task status
    assertTrue(task3.isOpened());
    assertFalse(task3.isCancelled());
    assertFalse(task3.hasEnded());
    assertEquals(5, task3.getVariables().size());
    assertEquals(
        document.getRepositoryName(),
        task3.getVariable(TaskService.VariableName.documentRepositoryName.name()));
    assertEquals(document.getId(), task3.getVariable(TaskService.VariableName.documentId.name()));
    assertNull(task3.getVariable(TaskService.VariableName.directive.name()));
    assertEquals(
        "true", task3.getVariable(OperationTaskVariableName.createdFromCreateTaskOperation.name()));
    assertEquals("true", task3.getVariable(TaskService.VariableName.createdFromTaskService.name()));

    assertEquals(SecurityConstants.ADMINISTRATOR, task3.getInitiator());
    // check document metadata
    assertNull(document.getPropertyValue("dc:description"));
  }