Search in sources :

Example 21 with ProcessInfo

use of org.alfresco.rest.workflow.api.model.ProcessInfo in project alfresco-remote-api by Alfresco.

the class ProcessesImpl method createProcessInfo.

protected ProcessInfo createProcessInfo(HistoricProcessInstance processInstance) {
    ProcessInfo processInfo = new ProcessInfo(processInstance);
    ProcessDefinition definitionEntity = activitiProcessEngine.getRepositoryService().getProcessDefinition(processInstance.getProcessDefinitionId());
    processInfo.setProcessDefinitionKey(getLocalProcessDefinitionKey(definitionEntity.getKey()));
    return processInfo;
}
Also used : ProcessDefinition(org.activiti.engine.repository.ProcessDefinition) ProcessInfo(org.alfresco.rest.workflow.api.model.ProcessInfo)

Example 22 with ProcessInfo

use of org.alfresco.rest.workflow.api.model.ProcessInfo in project alfresco-remote-api by Alfresco.

the class ProcessesImpl method getProcesses.

@Override
public CollectionWithPagingInfo<ProcessInfo> getProcesses(Parameters parameters) {
    Paging paging = parameters.getPaging();
    MapBasedQueryWalker propertyWalker = new MapBasedQueryWalker(PROCESS_COLLECTION_EQUALS_QUERY_PROPERTIES, null);
    propertyWalker.setSupportedGreaterThanParameters(PROCESS_COLLECTION_GREATERTHAN_QUERY_PROPERTIES);
    propertyWalker.setSupportedLessThanParameters(PROCESS_COLLECTION_LESSTHAN_QUERY_PROPERTIES);
    propertyWalker.enableVariablesSupport(namespaceService, dictionaryService);
    if (parameters.getQuery() != null) {
        QueryHelper.walk(parameters.getQuery(), propertyWalker);
    }
    String status = propertyWalker.getProperty("status", WhereClauseParser.EQUALS);
    String processDefinitionId = propertyWalker.getProperty("processDefinitionId", WhereClauseParser.EQUALS);
    String businessKey = propertyWalker.getProperty("businessKey", WhereClauseParser.EQUALS);
    String processDefinitionKey = propertyWalker.getProperty("processDefinitionKey", WhereClauseParser.EQUALS);
    String startUserId = propertyWalker.getProperty("startUserId", WhereClauseParser.EQUALS);
    Date startedAtGreaterThan = propertyWalker.getProperty("startedAt", WhereClauseParser.GREATERTHAN, Date.class);
    Date startedAtLessThan = propertyWalker.getProperty("startedAt", WhereClauseParser.LESSTHAN, Date.class);
    Date endedAtGreaterThan = propertyWalker.getProperty("endedAt", WhereClauseParser.GREATERTHAN, Date.class);
    Date endedAtLessThan = propertyWalker.getProperty("endedAt", WhereClauseParser.LESSTHAN, Date.class);
    Boolean includeVariables = propertyWalker.getProperty("includeVariables", WhereClauseParser.EQUALS, Boolean.class);
    if (status != null && PROCESS_STATUS_LIST.contains(status) == false) {
        throw new InvalidArgumentException("Invalid status parameter: " + status);
    }
    List<SortColumn> sortList = parameters.getSorting();
    SortColumn sortColumn = null;
    if (sortList != null && sortList.size() > 0) {
        if (sortList.size() != 1) {
            throw new InvalidArgumentException("Only one order by parameter is supported");
        }
        sortColumn = sortList.get(0);
    }
    final HistoricProcessInstanceQuery query = activitiProcessEngine.getHistoryService().createHistoricProcessInstanceQuery();
    if (processDefinitionId != null)
        query.processDefinitionId(processDefinitionId);
    if (businessKey != null)
        query.processInstanceBusinessKey(businessKey);
    if (processDefinitionKey != null) {
        if (tenantService.isEnabled() && deployWorkflowsInTenant) {
            if (processDefinitionKey.startsWith("@" + TenantUtil.getCurrentDomain() + "@")) {
                query.processDefinitionKey(processDefinitionKey);
            } else {
                query.processDefinitionKey("@" + TenantUtil.getCurrentDomain() + "@" + processDefinitionKey);
            }
        } else {
            query.processDefinitionKey(processDefinitionKey);
        }
    }
    if (startUserId != null)
        query.startedBy(startUserId);
    if (startedAtGreaterThan != null)
        query.startedAfter(startedAtGreaterThan);
    if (startedAtLessThan != null)
        query.startedBefore(startedAtLessThan);
    if (endedAtGreaterThan != null)
        query.finishedAfter(endedAtGreaterThan);
    if (endedAtLessThan != null)
        query.finishedBefore(endedAtLessThan);
    if (status == null || PROCESS_STATUS_ACTIVE.equals(status)) {
        query.unfinished();
    } else if (PROCESS_STATUS_COMPLETED.equals(status)) {
        query.finished();
        query.notDeleted();
    } else if (PROCESS_STATUS_DELETED.equals(status)) {
        query.deleted();
    }
    if (includeVariables != null && includeVariables) {
        query.includeProcessVariables();
    }
    List<QueryVariableHolder> variableProperties = propertyWalker.getVariableProperties();
    if (variableProperties != null) {
        for (QueryVariableHolder queryVariableHolder : variableProperties) {
            if (queryVariableHolder.getOperator() == WhereClauseParser.EQUALS) {
                query.variableValueEquals(queryVariableHolder.getPropertyName(), queryVariableHolder.getPropertyValue());
            } else if (queryVariableHolder.getOperator() == WhereClauseParser.GREATERTHAN) {
                query.variableValueGreaterThan(queryVariableHolder.getPropertyName(), queryVariableHolder.getPropertyValue());
            } else if (queryVariableHolder.getOperator() == WhereClauseParser.GREATERTHANOREQUALS) {
                query.variableValueGreaterThanOrEqual(queryVariableHolder.getPropertyName(), queryVariableHolder.getPropertyValue());
            } else if (queryVariableHolder.getOperator() == WhereClauseParser.LESSTHAN) {
                query.variableValueLessThan(queryVariableHolder.getPropertyName(), queryVariableHolder.getPropertyValue());
            } else if (queryVariableHolder.getOperator() == WhereClauseParser.LESSTHANOREQUALS) {
                query.variableValueLessThanOrEqual(queryVariableHolder.getPropertyName(), queryVariableHolder.getPropertyValue());
            } else if (queryVariableHolder.getOperator() == WhereClauseParser.MATCHES) {
                if (queryVariableHolder.getPropertyValue() instanceof String == false) {
                    throw new InvalidArgumentException("the matches operator can only be used with a String value for property " + queryVariableHolder.getPropertyName());
                }
                if (((String) queryVariableHolder.getPropertyValue()).startsWith("(?i)")) {
                    query.variableValueLikeIgnoreCase(queryVariableHolder.getPropertyName(), ((String) queryVariableHolder.getPropertyValue()).substring("(?i)".length()).toLowerCase());
                } else {
                    query.variableValueLike(queryVariableHolder.getPropertyName(), (String) queryVariableHolder.getPropertyValue());
                }
            } else if (queryVariableHolder.getOperator() == WhereClauseParser.NEGATION) {
                query.variableValueNotEquals(queryVariableHolder.getPropertyName(), queryVariableHolder.getPropertyValue());
            } else {
                throw new InvalidArgumentException("variable " + queryVariableHolder.getPropertyName() + " can only be used with an =, >, >=, <=, <, not, matches comparison type");
            }
        }
    }
    if (authorityService.isAdminAuthority(AuthenticationUtil.getRunAsUser())) {
        // Admin is allowed to read all processes in the current tenant
        if (tenantService.isEnabled()) {
            query.variableValueEquals(ActivitiConstants.VAR_TENANT_DOMAIN, TenantUtil.getCurrentDomain());
        }
    } else {
        // If non-admin user, involvement in the process is required (either owner, assignee or externally involved).
        query.involvedUser(AuthenticationUtil.getRunAsUser());
    }
    if (sortColumn != null) {
        if (PROCESS_COLLECTION_SORT_PROPERTIES.contains(sortColumn.column)) {
            if ("processDefinitionId".equalsIgnoreCase(sortColumn.column)) {
                query.orderByProcessDefinitionId();
            } else if ("id".equalsIgnoreCase(sortColumn.column)) {
                query.orderByProcessInstanceId();
            } else if ("businessKey".equalsIgnoreCase(sortColumn.column)) {
                query.orderByProcessInstanceBusinessKey();
            } else if ("startedAt".equalsIgnoreCase(sortColumn.column)) {
                query.orderByProcessInstanceStartTime();
            } else if ("endedAt".equalsIgnoreCase(sortColumn.column)) {
                query.orderByProcessInstanceEndTime();
            } else if ("durationInMillis".equalsIgnoreCase(sortColumn.column)) {
                query.orderByProcessInstanceDuration();
            }
        } else {
            throw new InvalidArgumentException("sort " + sortColumn.column + " is not supported, supported items are " + Arrays.toString(PROCESS_COLLECTION_SORT_PROPERTIES.toArray()));
        }
        if (sortColumn.asc) {
            query.asc();
        } else {
            query.desc();
        }
    } else {
        query.orderByProcessInstanceStartTime().desc();
    }
    List<HistoricProcessInstance> processInstances = query.listPage(paging.getSkipCount(), paging.getMaxItems());
    int totalCount = (int) query.count();
    List<ProcessInfo> page = new ArrayList<ProcessInfo>(processInstances.size());
    Map<String, TypeDefinition> definitionTypeMap = new HashMap<String, TypeDefinition>();
    for (HistoricProcessInstance processInstance : processInstances) {
        ProcessInfo processInfo = createProcessInfo(processInstance);
        if (includeVariables != null && includeVariables) {
            if (definitionTypeMap.containsKey(processInfo.getProcessDefinitionId()) == false) {
                StartFormData startFormData = activitiProcessEngine.getFormService().getStartFormData(processInfo.getProcessDefinitionId());
                if (startFormData != null) {
                    String formKey = startFormData.getFormKey();
                    definitionTypeMap.put(processInfo.getProcessDefinitionId(), getWorkflowFactory().getTaskFullTypeDefinition(formKey, true));
                }
            }
            if (definitionTypeMap.containsKey(processInfo.getProcessDefinitionId())) {
                // Convert raw variables to Variable objects
                List<Variable> resultingVariables = restVariableHelper.getVariables(processInstance.getProcessVariables(), definitionTypeMap.get(processInfo.getProcessDefinitionId()));
                processInfo.setProcessVariables(resultingVariables);
            }
        }
        page.add(processInfo);
    }
    return CollectionWithPagingInfo.asPaged(paging, page, (page.size() + paging.getSkipCount()) < totalCount, totalCount);
}
Also used : Variable(org.alfresco.rest.workflow.api.model.Variable) HistoricProcessInstanceQuery(org.activiti.engine.history.HistoricProcessInstanceQuery) HashMap(java.util.HashMap) Paging(org.alfresco.rest.framework.resource.parameters.Paging) HistoricProcessInstance(org.activiti.engine.history.HistoricProcessInstance) ArrayList(java.util.ArrayList) QueryVariableHolder(org.alfresco.rest.workflow.api.impl.MapBasedQueryWalker.QueryVariableHolder) ProcessInfo(org.alfresco.rest.workflow.api.model.ProcessInfo) SortColumn(org.alfresco.rest.framework.resource.parameters.SortColumn) Date(java.util.Date) TypeDefinition(org.alfresco.service.cmr.dictionary.TypeDefinition) DataTypeDefinition(org.alfresco.service.cmr.dictionary.DataTypeDefinition) InvalidArgumentException(org.alfresco.rest.framework.core.exceptions.InvalidArgumentException) StartFormData(org.activiti.engine.form.StartFormData)

Example 23 with ProcessInfo

use of org.alfresco.rest.workflow.api.model.ProcessInfo in project alfresco-remote-api by Alfresco.

the class TaskWorkflowApiTest method testAddTaskItem.

@Test
@SuppressWarnings("unchecked")
public void testAddTaskItem() throws Exception {
    final RequestContext requestContext = initApiClientWithTestUser();
    String otherPerson = getOtherPersonInNetwork(requestContext.getRunAsUser(), requestContext.getNetworkId()).getId();
    RequestContext otherContext = new RequestContext(requestContext.getNetworkId(), otherPerson);
    String tenantAdmin = AuthenticationUtil.getAdminUserName() + "@" + requestContext.getNetworkId();
    RequestContext adminContext = new RequestContext(requestContext.getNetworkId(), tenantAdmin);
    // Create test-document and add to package
    NodeRef[] docNodeRefs = createTestDocuments(requestContext);
    ProcessInfo processInfo = startAdhocProcess(requestContext, null);
    final Task task = activitiProcessEngine.getTaskService().createTaskQuery().processInstanceId(processInfo.getId()).singleResult();
    assertNotNull(task);
    activitiProcessEngine.getTaskService().setAssignee(task.getId(), null);
    try {
        TasksClient tasksClient = publicApiClient.tasksClient();
        JSONObject createItemObject = new JSONObject();
        createItemObject.put("id", docNodeRefs[0].getId());
        JSONObject result = tasksClient.addTaskItem(task.getId(), createItemObject.toJSONString());
        assertNotNull(result);
        assertEquals(docNodeRefs[0].getId(), result.get("id"));
        assertEquals("Test Doc1", result.get("name"));
        assertEquals("Test Doc1 Title", result.get("title"));
        assertEquals("Test Doc1 Description", result.get("description"));
        assertNotNull(result.get("createdAt"));
        assertEquals(requestContext.getRunAsUser(), result.get("createdBy"));
        assertNotNull(result.get("modifiedAt"));
        assertEquals(requestContext.getRunAsUser(), result.get("modifiedBy"));
        assertNotNull(result.get("size"));
        assertNotNull(result.get("mimeType"));
        JSONObject itemJSON = tasksClient.findTaskItem(task.getId(), docNodeRefs[0].getId());
        assertEquals(docNodeRefs[0].getId(), itemJSON.get("id"));
        tasksClient.deleteTaskItem(task.getId(), docNodeRefs[0].getId());
        try {
            tasksClient.findTaskItem(task.getId(), docNodeRefs[0].getId());
            fail("Expected exception");
        } catch (PublicApiException e) {
            assertEquals(404, e.getHttpResponse().getStatusCode());
        }
        // add item as admin
        publicApiClient.setRequestContext(adminContext);
        result = tasksClient.addTaskItem(task.getId(), createItemObject.toJSONString());
        assertNotNull(result);
        assertEquals(docNodeRefs[0].getId(), result.get("id"));
        assertEquals("Test Doc1", result.get("name"));
        itemJSON = tasksClient.findTaskItem(task.getId(), docNodeRefs[0].getId());
        assertEquals(docNodeRefs[0].getId(), itemJSON.get("id"));
        tasksClient.deleteTaskItem(task.getId(), docNodeRefs[0].getId());
        try {
            tasksClient.findTaskItem(task.getId(), docNodeRefs[0].getId());
            fail("Expected exception");
        } catch (PublicApiException e) {
            assertEquals(404, e.getHttpResponse().getStatusCode());
        }
        // add item with candidate user
        activitiProcessEngine.getTaskService().addCandidateUser(task.getId(), otherPerson);
        publicApiClient.setRequestContext(otherContext);
        result = tasksClient.addTaskItem(task.getId(), createItemObject.toJSONString());
        assertNotNull(result);
        assertEquals(docNodeRefs[0].getId(), result.get("id"));
        assertEquals("Test Doc1", result.get("name"));
        itemJSON = tasksClient.findTaskItem(task.getId(), docNodeRefs[0].getId());
        assertEquals(docNodeRefs[0].getId(), itemJSON.get("id"));
        tasksClient.deleteTaskItem(task.getId(), docNodeRefs[0].getId());
        try {
            tasksClient.findTaskItem(task.getId(), docNodeRefs[0].getId());
            fail("Expected exception");
        } catch (PublicApiException e) {
            assertEquals(404, e.getHttpResponse().getStatusCode());
        }
        // add item with not involved user
        activitiProcessEngine.getTaskService().deleteCandidateUser(task.getId(), otherPerson);
        publicApiClient.setRequestContext(otherContext);
        try {
            tasksClient.addTaskItem(task.getId(), createItemObject.toJSONString());
            fail("Expected exception");
        } catch (PublicApiException e) {
            assertEquals(403, e.getHttpResponse().getStatusCode());
        }
        // add item with user from candidate group with no assignee
        List<MemberOfSite> memberships = getTestFixture().getNetwork(otherContext.getNetworkId()).getSiteMemberships(otherContext.getRunAsUser());
        assertTrue(memberships.size() > 0);
        MemberOfSite memberOfSite = memberships.get(0);
        String group = "GROUP_site_" + memberOfSite.getSiteId() + "_" + memberOfSite.getRole().name();
        activitiProcessEngine.getTaskService().deleteCandidateUser(task.getId(), otherContext.getRunAsUser());
        activitiProcessEngine.getTaskService().addCandidateGroup(task.getId(), group);
        publicApiClient.setRequestContext(otherContext);
        result = tasksClient.addTaskItem(task.getId(), createItemObject.toJSONString());
        assertNotNull(result);
        assertEquals(docNodeRefs[0].getId(), result.get("id"));
        assertEquals("Test Doc1", result.get("name"));
        itemJSON = tasksClient.findTaskItem(task.getId(), docNodeRefs[0].getId());
        assertEquals(docNodeRefs[0].getId(), itemJSON.get("id"));
        tasksClient.deleteTaskItem(task.getId(), docNodeRefs[0].getId());
        try {
            tasksClient.findTaskItem(task.getId(), docNodeRefs[0].getId());
            fail("Expected exception");
        } catch (PublicApiException e) {
            assertEquals(404, e.getHttpResponse().getStatusCode());
        }
        // add item with user from candidate group with assignee
        activitiProcessEngine.getTaskService().setAssignee(task.getId(), requestContext.getRunAsUser());
        publicApiClient.setRequestContext(otherContext);
        try {
            tasksClient.addTaskItem(task.getId(), createItemObject.toJSONString());
            fail("Expected exception");
        } catch (PublicApiException e) {
            assertEquals(403, e.getHttpResponse().getStatusCode());
        }
        // invalid task id
        publicApiClient.setRequestContext(requestContext);
        try {
            tasksClient.addTaskItem("fakeid", createItemObject.toJSONString());
            fail("Expected exception");
        } catch (PublicApiException e) {
            assertEquals(404, e.getHttpResponse().getStatusCode());
        }
        // invalid item id
        createItemObject = new JSONObject();
        createItemObject.put("id", "fakeid");
        try {
            tasksClient.addTaskItem(task.getId(), createItemObject.toJSONString());
            fail("Expected exception");
        } catch (PublicApiException e) {
            assertEquals(404, e.getHttpResponse().getStatusCode());
        }
        // add item to completed task
        TenantUtil.runAsUserTenant(new TenantRunAsWork<Void>() {

            @Override
            public Void doWork() throws Exception {
                activitiProcessEngine.getTaskService().complete(task.getId());
                return null;
            }
        }, requestContext.getRunAsUser(), requestContext.getNetworkId());
        createItemObject = new JSONObject();
        createItemObject.put("id", docNodeRefs[0].getId());
        try {
            tasksClient.addTaskItem(task.getId(), createItemObject.toJSONString());
            fail("Expected exception");
        } catch (PublicApiException e) {
            assertEquals(404, e.getHttpResponse().getStatusCode());
        }
    } finally {
        cleanupProcessInstance(processInfo.getId());
    }
}
Also used : Task(org.activiti.engine.task.Task) TasksClient(org.alfresco.rest.workflow.api.tests.WorkflowApiClient.TasksClient) MemberOfSite(org.alfresco.rest.api.tests.client.data.MemberOfSite) ProcessInfo(org.alfresco.rest.workflow.api.model.ProcessInfo) PublicApiException(org.alfresco.rest.api.tests.client.PublicApiException) PublicApiException(org.alfresco.rest.api.tests.client.PublicApiException) NodeRef(org.alfresco.service.cmr.repository.NodeRef) JSONObject(org.json.simple.JSONObject) RequestContext(org.alfresco.rest.api.tests.client.RequestContext) Test(org.junit.Test)

Example 24 with ProcessInfo

use of org.alfresco.rest.workflow.api.model.ProcessInfo in project alfresco-remote-api by Alfresco.

the class TaskWorkflowApiTest method testGetTasksWithParams.

@Test
public void testGetTasksWithParams() throws Exception {
    RequestContext requestContext = initApiClientWithTestUser();
    String otherPerson = getOtherPersonInNetwork(requestContext.getRunAsUser(), requestContext.getNetworkId()).getId();
    RequestContext otherContext = new RequestContext(requestContext.getNetworkId(), otherPerson);
    Calendar taskCreated = Calendar.getInstance();
    taskCreated.set(Calendar.MILLISECOND, 0);
    String businessKey = UUID.randomUUID().toString();
    ProcessInstance processInstance = startAdhocProcess(requestContext.getRunAsUser(), requestContext.getNetworkId(), businessKey);
    ProcessInfo otherInstance = startReviewPooledProcess(otherContext);
    try {
        // Complete the adhoc task
        final Task completedTask = activitiProcessEngine.getTaskService().createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
        assertNotNull(completedTask);
        // Find the review pooled task
        final Task reviewPooledTask = activitiProcessEngine.getTaskService().createTaskQuery().processInstanceId(otherInstance.getId()).singleResult();
        assertNotNull(reviewPooledTask);
        // MNT-12221 case, due date should be set as task property, not as variable!!!
        assertNotNull("Due date was not set for review pooled task.", reviewPooledTask.getDueDate());
        String anotherUserId = UUID.randomUUID().toString();
        Calendar completedTaskDue = Calendar.getInstance();
        completedTaskDue.add(Calendar.HOUR, 1);
        completedTaskDue.set(Calendar.MILLISECOND, 0);
        completedTask.setOwner(requestContext.getRunAsUser());
        completedTask.setPriority(3);
        completedTask.setDueDate(completedTaskDue.getTime());
        completedTask.setAssignee(anotherUserId);
        completedTask.setName("Another task name");
        completedTask.setDescription("This is another test description");
        activitiProcessEngine.getTaskService().saveTask(completedTask);
        // Complete task in correct tenant
        TenantUtil.runAsUserTenant(new TenantRunAsWork<Void>() {

            @Override
            public Void doWork() throws Exception {
                activitiProcessEngine.getTaskService().complete(completedTask.getId());
                return null;
            }
        }, requestContext.getRunAsUser(), requestContext.getNetworkId());
        // Active task is the second task in the adhoc-process (Verify task completed)
        Task activeTask = activitiProcessEngine.getTaskService().createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
        assertNotNull(activeTask);
        Calendar activeTaskDue = Calendar.getInstance();
        activeTaskDue.add(Calendar.HOUR, 2);
        activeTaskDue.set(Calendar.MILLISECOND, 0);
        activeTask.setDueDate(activeTaskDue.getTime());
        activeTask.setName("Task name");
        activeTask.setDescription("This is a test description");
        activeTask.setOwner(requestContext.getRunAsUser());
        activeTask.setPriority(2);
        activeTask.setAssignee(requestContext.getRunAsUser());
        activitiProcessEngine.getTaskService().saveTask(activeTask);
        activitiProcessEngine.getTaskService().addCandidateUser(activeTask.getId(), anotherUserId);
        activitiProcessEngine.getTaskService().addCandidateGroup(activeTask.getId(), "sales");
        activitiProcessEngine.getTaskService().setVariableLocal(activeTask.getId(), "numberVar", 10);
        final Task otherTask = activitiProcessEngine.getTaskService().createTaskQuery().processInstanceId(otherInstance.getId()).singleResult();
        TasksClient tasksClient = publicApiClient.tasksClient();
        // Test status filtering - active
        Map<String, String> params = new HashMap<String, String>();
        params.put("where", "(status = 'active' AND processId = '" + processInstance.getId() + "')");
        assertTasksPresentInTaskQuery(params, tasksClient, false, activeTask.getId());
        // Test status filtering - completed
        params.clear();
        params.put("where", "(status = 'completed' AND processId = '" + processInstance.getId() + "')");
        params.put("orderBy", "dueAt DESC");
        assertTasksPresentInTaskQuery(params, tasksClient, false, completedTask.getId());
        // Test status filtering - any
        params.clear();
        params.put("where", "(status = 'any' AND processId = '" + processInstance.getId() + "')");
        assertTasksPresentInTaskQuery(params, tasksClient, false, activeTask.getId(), completedTask.getId());
        // Test status filtering - no value should default to 'active'
        params.clear();
        params.put("where", "(processId = '" + processInstance.getId() + "')");
        assertTasksPresentInTaskQuery(params, tasksClient, false, activeTask.getId());
        // Test status filtering - illegal status
        params.clear();
        params.put("where", "(status = 'alfrescorocks')");
        try {
            tasksClient.findTasks(params);
            fail("Exception expected");
        } catch (PublicApiException expected) {
            assertEquals(HttpStatus.BAD_REQUEST.value(), expected.getHttpResponse().getStatusCode());
            assertErrorSummary("Invalid status parameter: alfrescorocks", expected.getHttpResponse());
        }
        // Next, we test all filtering for active, complete and any tasks
        // Assignee filtering
        params.clear();
        params.put("where", "(status = 'active' AND assignee = '" + requestContext.getRunAsUser() + "')");
        assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId());
        params.put("where", "(status = 'completed' AND assignee = '" + anotherUserId + "')");
        params.put("orderBy", "endedAt");
        assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId());
        params.put("where", "(status = 'any' AND assignee = '" + anotherUserId + "')");
        assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId());
        // Owner filtering
        params.clear();
        params.put("where", "(status = 'active' AND owner = '" + requestContext.getRunAsUser() + "')");
        assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId());
        params.put("where", "(status = 'completed' AND owner = '" + requestContext.getRunAsUser() + "')");
        assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId());
        params.put("where", "(status = 'any' AND owner = '" + requestContext.getRunAsUser() + "')");
        assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId(), completedTask.getId());
        // Candidate user filtering, only available for active tasks. When used with completed/any 400 is returned
        params.clear();
        params.put("where", "(status = 'active' AND candidateUser = '" + anotherUserId + "')");
        // No tasks expected since assignee is set
        assertEquals(0L, getResultSizeForTaskQuery(params, tasksClient));
        // Clear assignee
        activitiProcessEngine.getTaskService().setAssignee(activeTask.getId(), null);
        assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId());
        // Candidate user with candidate group
        params.clear();
        params.put("where", "(status = 'active' AND candidateUser = '" + otherContext.getRunAsUser() + "')");
        // No tasks expected since assignee is set
        assertEquals(1L, getResultSizeForTaskQuery(params, tasksClient));
        params.clear();
        params.put("where", "(status = 'completed' AND candidateUser = '" + anotherUserId + "')");
        try {
            tasksClient.findTasks(params);
            fail("Exception expected");
        } catch (PublicApiException expected) {
            assertEquals(HttpStatus.BAD_REQUEST.value(), expected.getHttpResponse().getStatusCode());
            assertErrorSummary("Filtering on candidateUser is only allowed in combination with status-parameter 'active'", expected.getHttpResponse());
        }
        params.clear();
        params.put("where", "(status = 'any' AND candidateUser = '" + anotherUserId + "')");
        try {
            tasksClient.findTasks(params);
            fail("Exception expected");
        } catch (PublicApiException expected) {
            assertEquals(HttpStatus.BAD_REQUEST.value(), expected.getHttpResponse().getStatusCode());
            assertErrorSummary("Filtering on candidateUser is only allowed in combination with status-parameter 'active'", expected.getHttpResponse());
        }
        // Candidate group filtering, only available for active tasks. When used with completed/any 400 is returned
        params.clear();
        params.put("where", "(status = 'active' AND candidateGroup = 'sales' AND processId='" + processInstance.getId() + "')");
        assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId());
        params.clear();
        params.put("where", "(status = 'completed' AND candidateGroup = 'sales' AND processId='" + processInstance.getId() + "')");
        try {
            tasksClient.findTasks(params);
            fail("Exception expected");
        } catch (PublicApiException expected) {
            assertEquals(HttpStatus.BAD_REQUEST.value(), expected.getHttpResponse().getStatusCode());
            assertErrorSummary("Filtering on candidateGroup is only allowed in combination with status-parameter 'active'", expected.getHttpResponse());
        }
        params.clear();
        params.put("where", "(status = 'any' AND candidateGroup = 'sales' AND processId='" + processInstance.getId() + "')");
        try {
            tasksClient.findTasks(params);
            fail("Exception expected");
        } catch (PublicApiException expected) {
            assertEquals(HttpStatus.BAD_REQUEST.value(), expected.getHttpResponse().getStatusCode());
            assertErrorSummary("Filtering on candidateGroup is only allowed in combination with status-parameter 'active'", expected.getHttpResponse());
        }
        // Name filtering
        params.clear();
        params.put("where", "(status = 'active' AND name = 'Task name' AND processId='" + processInstance.getId() + "')");
        assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId());
        params.clear();
        params.put("where", "(status = 'completed' AND name = 'Another task name' AND processId='" + processInstance.getId() + "')");
        assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId());
        params.clear();
        params.put("where", "(status = 'any' AND name = 'Another task name' AND processId='" + processInstance.getId() + "')");
        assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId());
        // Description filtering
        params.clear();
        params.put("where", "(status = 'active' AND description = 'This is a test description' AND processId='" + processInstance.getId() + "')");
        assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId());
        params.clear();
        params.put("where", "(status = 'completed' AND description = 'This is another test description' AND processId='" + processInstance.getId() + "')");
        assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId());
        params.clear();
        params.put("where", "(status = 'any' AND description = 'This is another test description' AND processId='" + processInstance.getId() + "')");
        assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId());
        // Priority filtering
        params.clear();
        params.put("where", "(status = 'active' AND priority = 2 AND processId='" + processInstance.getId() + "')");
        assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId());
        params.put("where", "(status = 'completed' AND priority = 3 AND processId='" + processInstance.getId() + "')");
        assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId());
        params.put("where", "(status = 'any' AND priority = 3 AND processId='" + processInstance.getId() + "')");
        assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId());
        // Process instance business-key filtering
        params.clear();
        params.put("where", "(status = 'active' AND processBusinessKey = '" + businessKey + "')");
        assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId());
        params.clear();
        params.put("where", "(status = 'completed' AND processBusinessKey = '" + businessKey + "')");
        assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId());
        params.clear();
        params.put("where", "(status = 'any' AND processBusinessKey = '" + businessKey + "')");
        assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId(), activeTask.getId());
        params.clear();
        params.put("where", "(status = 'any' AND processBusinessKey MATCHES('" + businessKey + "'))");
        assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId(), activeTask.getId());
        params.clear();
        params.put("where", "(status = 'any' AND processBusinessKey MATCHES('" + businessKey.substring(0, businessKey.length() - 2) + "%'))");
        assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId(), activeTask.getId());
        // Activity definition id filtering
        params.clear();
        params.put("where", "(status = 'active' AND activityDefinitionId = 'verifyTaskDone' AND processId='" + processInstance.getId() + "')");
        assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId());
        params.clear();
        params.put("where", "(status = 'completed' AND activityDefinitionId = 'adhocTask' AND processId='" + processInstance.getId() + "')");
        assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId());
        params.clear();
        params.put("where", "(status = 'any' AND activityDefinitionId = 'adhocTask' AND processId='" + processInstance.getId() + "')");
        assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId());
        // Process definition id filtering
        params.clear();
        params.put("where", "(status = 'active' AND processDefinitionId = '" + processInstance.getProcessDefinitionId() + "' AND processId='" + processInstance.getId() + "')");
        assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId());
        params.clear();
        params.put("where", "(status = 'completed' AND processDefinitionId = '" + processInstance.getProcessDefinitionId() + "' AND processId='" + processInstance.getId() + "')");
        assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId());
        params.clear();
        params.put("where", "(status = 'any' AND processDefinitionId = '" + processInstance.getProcessDefinitionId() + "' AND processId='" + processInstance.getId() + "')");
        assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId(), completedTask.getId());
        // Process definition name filtering
        params.clear();
        params.put("where", "(status = 'active' AND processDefinitionName = 'Adhoc Activiti Process' AND processId='" + processInstance.getId() + "')");
        assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId());
        params.clear();
        params.put("where", "(status = 'completed' AND processDefinitionName = 'Adhoc Activiti Process' AND processId='" + processInstance.getId() + "')");
        assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId());
        params.clear();
        params.put("where", "(status = 'any' AND processDefinitionName = 'Adhoc Activiti Process' AND processId='" + processInstance.getId() + "')");
        assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId(), completedTask.getId());
        // Due date filtering
        params.clear();
        params.put("where", "(status = 'active' AND dueAt = '" + ISO8601DateFormat.format(activeTaskDue.getTime()) + "')");
        assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId());
        params.clear();
        params.put("where", "(status = 'completed' AND dueAt = '" + ISO8601DateFormat.format(completedTaskDue.getTime()) + "')");
        assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId());
        params.clear();
        params.put("where", "(status = 'any' AND dueAt = '" + ISO8601DateFormat.format(completedTaskDue.getTime()) + "')");
        assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId());
        // Started filtering
        Calendar compareCal = Calendar.getInstance();
        compareCal.set(Calendar.MILLISECOND, 0);
        compareCal.add(Calendar.DAY_OF_YEAR, -1);
        params.clear();
        params.put("where", "(status = 'active' AND startedAt > '" + ISO8601DateFormat.format(compareCal.getTime()) + "')");
        assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId(), otherTask.getId());
        params.clear();
        params.put("where", "(status = 'completed' AND startedAt > '" + ISO8601DateFormat.format(compareCal.getTime()) + "')");
        assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId());
        params.clear();
        params.put("where", "(status = 'any' AND startedAt > '" + ISO8601DateFormat.format(compareCal.getTime()) + "')");
        assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId(), activeTask.getId(), otherTask.getId());
        params.clear();
        params.put("where", "(status = 'any' AND startedAt < '" + ISO8601DateFormat.format(compareCal.getTime()) + "')");
        assertEquals(0, getResultSizeForTaskQuery(params, tasksClient));
        params.clear();
        params.put("where", "(variables/local/numberVar > 'd:int 5')");
        assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId());
        params.clear();
        params.put("where", "(variables/local/numberVar > 'd:int 10')");
        assertEquals(0, getResultSizeForTaskQuery(params, tasksClient));
        params.clear();
        params.put("where", "(variables/local/numberVar >= 'd_int 10')");
        assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId());
        params.clear();
        params.put("where", "(variables/local/numberVar >= 'd:int 11')");
        assertEquals(0, getResultSizeForTaskQuery(params, tasksClient));
        params.clear();
        params.put("where", "(variables/local/numberVar <= 'd:int 10')");
        assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId());
        params.clear();
        params.put("where", "(variables/local/numberVar <= 'd:int 9')");
        assertEquals(0, getResultSizeForTaskQuery(params, tasksClient));
        params.clear();
        params.put("where", "(variables/local/numberVar < 'd_int 15')");
        assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId());
        params.clear();
        params.put("where", "(variables/local/numberVar < 'd:int 10')");
        assertEquals(0, getResultSizeForTaskQuery(params, tasksClient));
        params.clear();
        params.put("where", "(variables/global/numberVar > 'd:int 5')");
        assertEquals(0, getResultSizeForTaskQuery(params, tasksClient));
        params.clear();
        params.put("where", "(variables/numberVar > 'd:int 5')");
        assertEquals(0, getResultSizeForTaskQuery(params, tasksClient));
        params.clear();
        params.put("where", "(variables/bpm_dueDate = 'd:datetime " + ISO8601DateFormat.format(new Date()) + "')");
        assertEquals(0, getResultSizeForTaskQuery(params, tasksClient));
        params.clear();
        params.put("where", "(variables/bpm_dueDate = 'd:datetime 2013-09-15T12:22:31.866+0000')");
        assertEquals(0, getResultSizeForTaskQuery(params, tasksClient));
        params.clear();
        params.put("where", "(variables/bpm_dueDate > 'd:datetime 2013-09-15T12:22:31.866+0000')");
        // MNT-12221 fix, due date is not saved as variable for review pooled workflow, so nothing should be found
        assertEquals(0, getResultSizeForTaskQuery(params, tasksClient));
        params.clear();
        params.put("where", "(dueAt = '" + ISO8601DateFormat.format(reviewPooledTask.getDueDate()) + "')");
        assertEquals(1, getResultSizeForTaskQuery(params, tasksClient));
        params.clear();
        params.put("where", "(variables/bpm_comment MATCHES ('test%'))");
        assertEquals(0, getResultSizeForTaskQuery(params, tasksClient));
        // test with OR operator
        params.clear();
        params.put("where", "(status = 'any' OR candidateGroup = 'sales')");
        try {
            tasksClient.findTasks(params);
            fail("Exception expected");
        } catch (PublicApiException expected) {
            assertEquals(HttpStatus.BAD_REQUEST.value(), expected.getHttpResponse().getStatusCode());
        }
        params.clear();
        params.put("where", "(status = 'completed' AND processDefinitionName = 'Adhoc Activiti Process')");
        JSONObject response = publicApiClient.processesClient().getTasks(processInstance.getId(), params);
        assertNotNull(response);
        JSONObject paginationJSON = (JSONObject) response.get("pagination");
        assertEquals(1l, paginationJSON.get("count"));
        params.clear();
        params.put("where", "(status = 'any' AND variables/numberVar < 'd:int 5')");
        assertEquals(0, getResultSizeForTaskQuery(params, tasksClient));
    } finally {
        cleanupProcessInstance(processInstance.getId(), otherInstance.getId());
    }
}
Also used : Task(org.activiti.engine.task.Task) HashMap(java.util.HashMap) Calendar(java.util.Calendar) TasksClient(org.alfresco.rest.workflow.api.tests.WorkflowApiClient.TasksClient) ProcessInfo(org.alfresco.rest.workflow.api.model.ProcessInfo) PublicApiException(org.alfresco.rest.api.tests.client.PublicApiException) Date(java.util.Date) PublicApiException(org.alfresco.rest.api.tests.client.PublicApiException) JSONObject(org.json.simple.JSONObject) ProcessInstance(org.activiti.engine.runtime.ProcessInstance) RequestContext(org.alfresco.rest.api.tests.client.RequestContext) Test(org.junit.Test)

Example 25 with ProcessInfo

use of org.alfresco.rest.workflow.api.model.ProcessInfo in project alfresco-remote-api by Alfresco.

the class TaskWorkflowApiTest method testUpdateTaskVariableWithWrongType.

@SuppressWarnings("unchecked")
@Test
public void testUpdateTaskVariableWithWrongType() throws Exception {
    final RequestContext requestContext = initApiClientWithTestUser();
    ProcessInfo processRest = startParallelReviewProcess(requestContext);
    try {
        List<Task> tasks = activitiProcessEngine.getTaskService().createTaskQuery().processInstanceId(processRest.getId()).list();
        assertNotNull(tasks);
        String taskId = tasks.get(0).getId();
        // Update an existing variable with wrong type
        JSONObject variableJson = new JSONObject();
        variableJson.put("name", "wf_requiredApprovePercent");
        variableJson.put("value", 55.99);
        variableJson.put("type", "d:double");
        variableJson.put("scope", "global");
        try {
            publicApiClient.tasksClient().updateTaskVariable(taskId, "wf_requiredApprovePercent", variableJson);
            fail("Exception expected");
        } catch (PublicApiException e) {
            assertEquals(HttpStatus.BAD_REQUEST.value(), e.getHttpResponse().getStatusCode());
        }
        variableJson = new JSONObject();
        variableJson.put("name", "wf_requiredApprovePercent");
        variableJson.put("value", 55.99);
        variableJson.put("type", "d:int");
        variableJson.put("scope", "global");
        JSONObject resultEntry = publicApiClient.tasksClient().updateTaskVariable(taskId, "wf_requiredApprovePercent", variableJson);
        assertNotNull(resultEntry);
        JSONObject result = (JSONObject) resultEntry.get("entry");
        assertEquals("wf_requiredApprovePercent", result.get("name"));
        assertEquals(55l, result.get("value"));
        assertEquals("d:int", result.get("type"));
        assertEquals(55, activitiProcessEngine.getRuntimeService().getVariable(processRest.getId(), "wf_requiredApprovePercent"));
        JSONObject taskVariables = publicApiClient.tasksClient().findTaskVariables(taskId);
        assertNotNull(taskVariables);
        JSONObject list = (JSONObject) taskVariables.get("list");
        assertNotNull(list);
        // Add process variables to map for easy lookup
        Map<String, JSONObject> variablesByName = new HashMap<String, JSONObject>();
        JSONObject entry = null;
        JSONArray entries = (JSONArray) list.get("entries");
        assertNotNull(entries);
        for (int i = 0; i < entries.size(); i++) {
            entry = (JSONObject) entries.get(i);
            assertNotNull(entry);
            entry = (JSONObject) entry.get("entry");
            assertNotNull(entry);
            variablesByName.put((String) entry.get("name"), entry);
        }
        JSONObject approvePercentObject = variablesByName.get("wf_requiredApprovePercent");
        assertNotNull(approvePercentObject);
        assertEquals(55l, approvePercentObject.get("value"));
        assertEquals("d:int", approvePercentObject.get("type"));
        // set a new variable
        variableJson = new JSONObject();
        variableJson.put("name", "testVariable");
        variableJson.put("value", "text");
        variableJson.put("type", "d:text");
        variableJson.put("scope", "local");
        resultEntry = publicApiClient.tasksClient().updateTaskVariable(taskId, "testVariable", variableJson);
        assertNotNull(resultEntry);
        result = (JSONObject) resultEntry.get("entry");
        assertEquals("testVariable", result.get("name"));
        assertEquals("text", result.get("value"));
        assertEquals("d:text", result.get("type"));
        assertEquals("text", activitiProcessEngine.getTaskService().getVariable(taskId, "testVariable"));
        // change the variable value and type (should be working because no content model type)
        variableJson = new JSONObject();
        variableJson.put("name", "testVariable");
        variableJson.put("value", 123);
        variableJson.put("type", "d:int");
        variableJson.put("scope", "local");
        resultEntry = publicApiClient.tasksClient().updateTaskVariable(taskId, "testVariable", variableJson);
        assertNotNull(resultEntry);
        result = (JSONObject) resultEntry.get("entry");
        assertEquals("testVariable", result.get("name"));
        assertEquals(123l, result.get("value"));
        assertEquals("d:int", result.get("type"));
        assertEquals(123, activitiProcessEngine.getTaskService().getVariable(taskId, "testVariable"));
        // change the variable value for a list of noderefs (bpm_assignees)
        final JSONObject updateAssigneesJson = new JSONObject();
        updateAssigneesJson.put("name", "bpm_assignees");
        updateAssigneesJson.put("type", "d:noderef");
        updateAssigneesJson.put("scope", "global");
        TenantUtil.runAsUserTenant(new TenantRunAsWork<Void>() {

            @Override
            public Void doWork() throws Exception {
                JSONArray assigneeArray = new JSONArray();
                assigneeArray.add(requestContext.getRunAsUser());
                updateAssigneesJson.put("value", assigneeArray);
                return null;
            }
        }, requestContext.getRunAsUser(), requestContext.getNetworkId());
        resultEntry = publicApiClient.tasksClient().updateTaskVariable(taskId, "bpm_assignees", updateAssigneesJson);
        assertNotNull(resultEntry);
        final JSONObject updateAssigneeResult = (JSONObject) resultEntry.get("entry");
        assertEquals("bpm_assignees", updateAssigneeResult.get("name"));
        TenantUtil.runAsUserTenant(new TenantRunAsWork<Void>() {

            @Override
            public Void doWork() throws Exception {
                JSONArray assigneeArray = (JSONArray) updateAssigneeResult.get("value");
                assertNotNull(assigneeArray);
                assertEquals(1, assigneeArray.size());
                return null;
            }
        }, requestContext.getRunAsUser(), requestContext.getNetworkId());
        assertEquals("d:noderef", updateAssigneeResult.get("type"));
        // update the bpm_assignees with a single entry, should result in an error
        final JSONObject updateAssigneeJson = new JSONObject();
        updateAssigneeJson.put("name", "bpm_assignees");
        updateAssigneeJson.put("type", "d:noderef");
        updateAssigneeJson.put("scope", "global");
        TenantUtil.runAsUserTenant(new TenantRunAsWork<Void>() {

            @Override
            public Void doWork() throws Exception {
                updateAssigneeJson.put("value", requestContext.getRunAsUser());
                return null;
            }
        }, requestContext.getRunAsUser(), requestContext.getNetworkId());
        try {
            publicApiClient.tasksClient().updateTaskVariable(taskId, "bpm_assignees", updateAssigneeJson);
            fail("Exception expected");
        } catch (PublicApiException e) {
            assertEquals(HttpStatus.BAD_REQUEST.value(), e.getHttpResponse().getStatusCode());
        }
    } finally {
        cleanupProcessInstance(processRest.getId());
    }
}
Also used : Task(org.activiti.engine.task.Task) HashMap(java.util.HashMap) JSONArray(org.json.simple.JSONArray) ProcessInfo(org.alfresco.rest.workflow.api.model.ProcessInfo) PublicApiException(org.alfresco.rest.api.tests.client.PublicApiException) PublicApiException(org.alfresco.rest.api.tests.client.PublicApiException) JSONObject(org.json.simple.JSONObject) RequestContext(org.alfresco.rest.api.tests.client.RequestContext) Test(org.junit.Test)

Aggregations

ProcessInfo (org.alfresco.rest.workflow.api.model.ProcessInfo)40 RequestContext (org.alfresco.rest.api.tests.client.RequestContext)36 Test (org.junit.Test)36 PublicApiException (org.alfresco.rest.api.tests.client.PublicApiException)26 JSONObject (org.json.simple.JSONObject)26 ProcessesClient (org.alfresco.rest.workflow.api.tests.WorkflowApiClient.ProcessesClient)16 Task (org.activiti.engine.task.Task)13 HashMap (java.util.HashMap)12 JSONArray (org.json.simple.JSONArray)11 NodeRef (org.alfresco.service.cmr.repository.NodeRef)10 TasksClient (org.alfresco.rest.workflow.api.tests.WorkflowApiClient.TasksClient)8 ArrayList (java.util.ArrayList)6 MemberOfSite (org.alfresco.rest.api.tests.client.data.MemberOfSite)5 HistoricProcessInstance (org.activiti.engine.history.HistoricProcessInstance)4 TestNetwork (org.alfresco.rest.api.tests.RepoService.TestNetwork)4 Date (java.util.Date)3 List (java.util.List)3 HttpResponse (org.alfresco.rest.api.tests.client.HttpResponse)3 Variable (org.alfresco.rest.workflow.api.model.Variable)3 Calendar (java.util.Calendar)2