diff --git a/source/java/org/alfresco/repo/workflow/AbstractWorkflowServiceIntegrationTest.java b/source/java/org/alfresco/repo/workflow/AbstractWorkflowServiceIntegrationTest.java index 232b20b4a4..1040c27180 100644 --- a/source/java/org/alfresco/repo/workflow/AbstractWorkflowServiceIntegrationTest.java +++ b/source/java/org/alfresco/repo/workflow/AbstractWorkflowServiceIntegrationTest.java @@ -592,7 +592,7 @@ public abstract class AbstractWorkflowServiceIntegrationTest extends BaseSpringT workflowService.updateTask(theTask.getId(), params, null, null); // Test all query features for running tasks - checkTaskQueryInProgress(workflowInstanceId, theTask); + checkTaskQueryInProgress(workflowInstanceId, theTask, workflowInstanceId); // Test all query features for the start-task checkTaskQueryStartTaskCompleted(workflowInstanceId, startTask); @@ -637,6 +637,7 @@ public abstract class AbstractWorkflowServiceIntegrationTest extends BaseSpringT protected void checkQueryTasksInactiveWorkflow(String workflowInstanceId) { WorkflowTaskQuery taskQuery = createWorkflowTaskQuery(WorkflowTaskState.COMPLETED); taskQuery.setActive(false); + taskQuery.setProcessId(workflowInstanceId); List tasks = workflowService.queryTasks(taskQuery); assertNotNull(tasks); @@ -644,30 +645,30 @@ public abstract class AbstractWorkflowServiceIntegrationTest extends BaseSpringT taskQuery = createWorkflowTaskQuery(WorkflowTaskState.COMPLETED); taskQuery.setActive(true); + taskQuery.setProcessId(workflowInstanceId); checkNoTasksFoundUsingQuery(taskQuery); } - protected void checkTaskQueryTaskCompleted(String workflowInstanceId, - WorkflowTask theTask, WorkflowTask startTask) + protected void checkTaskQueryTaskCompleted(String workflowInstanceId, WorkflowTask theTask, WorkflowTask startTask) { List expectedTasks = Arrays.asList(theTask.getId(), startTask.getId()); checkProcessIdQuery(workflowInstanceId, expectedTasks, WorkflowTaskState.COMPLETED); // Adhoc task should only be returned QName taskName = QName.createQName(NamespaceService.WORKFLOW_MODEL_1_0_URI, "adhocTask"); - checkTaskNameQuery(taskName, Arrays.asList(theTask.getId()), WorkflowTaskState.COMPLETED, null); + checkTaskNameQuery(taskName, Arrays.asList(theTask.getId()), WorkflowTaskState.COMPLETED, workflowInstanceId); // Completed adhocTask is assigned to USER2 checkActorIdQuery(USER2, Arrays.asList(theTask.getId()), WorkflowTaskState.COMPLETED, null); // Workflow is still active, both tasks will be returned - checkIsActiveQuery(expectedTasks, WorkflowTaskState.COMPLETED, null); + checkIsActiveQuery(expectedTasks, WorkflowTaskState.COMPLETED, workflowInstanceId); // Both tasks have custom property set checkTaskPropsQuery(expectedTasks, WorkflowTaskState.COMPLETED, null); } - protected void checkTaskQueryInProgress(String workflowInstanceId, WorkflowTask expectedTask) + protected void checkTaskQueryInProgress(String workflowInstanceId, WorkflowTask expectedTask, String workflowInstanceId2) { List expectedTasks = Arrays.asList(expectedTask.getId()); @@ -677,7 +678,7 @@ public abstract class AbstractWorkflowServiceIntegrationTest extends BaseSpringT QName taskName = QName.createQName(NamespaceService.WORKFLOW_MODEL_1_0_URI, "adhocTask"); checkTaskNameQuery(taskName, expectedTasks, WorkflowTaskState.IN_PROGRESS, null); checkActorIdQuery(USER2, expectedTasks, WorkflowTaskState.IN_PROGRESS, null); - checkIsActiveQuery(expectedTasks, WorkflowTaskState.IN_PROGRESS, null); + checkIsActiveQuery(expectedTasks, WorkflowTaskState.IN_PROGRESS, workflowInstanceId); checkTaskPropsQuery(expectedTasks, WorkflowTaskState.IN_PROGRESS, null); checkProcessPropsQuery(expectedTasks, WorkflowTaskState.IN_PROGRESS); } @@ -691,7 +692,7 @@ public abstract class AbstractWorkflowServiceIntegrationTest extends BaseSpringT QName startTaskName = QName.createQName(NamespaceService.WORKFLOW_MODEL_1_0_URI, "submitAdhocTask"); checkTaskNameQuery(startTaskName, expectedTasks, WorkflowTaskState.COMPLETED, null); checkActorIdQuery(USER1, expectedTasks, WorkflowTaskState.COMPLETED, null); - checkIsActiveQuery(expectedTasks, WorkflowTaskState.COMPLETED, null); + checkIsActiveQuery(expectedTasks, WorkflowTaskState.COMPLETED, workflowInstanceId); checkTaskPropsQuery(expectedTasks, WorkflowTaskState.COMPLETED, null); } @@ -890,8 +891,7 @@ public abstract class AbstractWorkflowServiceIntegrationTest extends BaseSpringT checkNoTasksFoundUsingQuery(taskQuery); } - protected void checkIsActiveQuery(List expectedTaskIds, WorkflowTaskState state, - String optionalProcessId) + protected void checkIsActiveQuery(List expectedTaskIds, WorkflowTaskState state, String optionalProcessId) { WorkflowTaskQuery taskQuery = createWorkflowTaskQuery(state); taskQuery.setActive(true); diff --git a/source/java/org/alfresco/repo/workflow/activiti/ActivitiWorkflowEngine.java b/source/java/org/alfresco/repo/workflow/activiti/ActivitiWorkflowEngine.java index 514d56a26d..8e9115e641 100644 --- a/source/java/org/alfresco/repo/workflow/activiti/ActivitiWorkflowEngine.java +++ b/source/java/org/alfresco/repo/workflow/activiti/ActivitiWorkflowEngine.java @@ -24,6 +24,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.Serializable; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Date; @@ -98,6 +99,9 @@ import org.alfresco.service.cmr.workflow.WorkflowTimer; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; import org.alfresco.util.GUID; +import org.alfresco.util.collections.CollectionUtils; +import org.alfresco.util.collections.Filter; +import org.alfresco.util.collections.Function; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.apache.xerces.parsers.DOMParser; @@ -1775,138 +1779,208 @@ public class ActivitiWorkflowEngine extends BPMEngine implements WorkflowEngine } } - private List queryStartTasks(WorkflowTaskQuery query) - { - List startTasks = new ArrayList(); - - String processInstanceId = null; - String taskId = query.getTaskId(); - if(taskId != null ) - { - String localTaskId = createLocalId(taskId); - if(localTaskId.startsWith(ActivitiConstants.START_TASK_PREFIX)) - processInstanceId = localTaskId.substring(ActivitiConstants.START_TASK_PREFIX.length()); - } - else - { - String processId = query.getProcessId(); - if(processId != null) - { - // Start task for a specific process - processInstanceId = createLocalId(processId); - } - } - - // Only return start-task when a process or task id is set - if(processInstanceId != null) - { - // Extract processInstanceId - WorkflowTask workflowTask = getVirtualStartTaskForProcessInstance(processInstanceId); - if(workflowTask != null) - { - boolean startTaskMatches = isStartTaskMatching(workflowTask, query); - if(startTaskMatches) - { - startTasks.add(workflowTask); - } - } - } - return startTasks; - } - - - private boolean isStartTaskMatching(WorkflowTask workflowTask, - WorkflowTaskQuery query) { - - if(query.isActive() != null) - { - if(query.isActive() && !workflowTask.getPath().isActive()) - { - return false; - } - if(!query.isActive() && workflowTask.getPath().isActive()) - { - return false; - } - } - - if(query.getActorId() != null && !query.getActorId().equals(workflowTask.getProperties().get(ContentModel.PROP_OWNER))) - { - return false; - } - - if(query.getProcessCustomProps() != null) - { - // Get properties for process instance, based on path of start task, which is process-instance - Map props = getPathProperties(workflowTask.getPath().getId()); - if(!checkPropertiesPresent(query.getProcessCustomProps(), props)) - { - return false; - } - } - - if(query.getProcessId() != null) - { - if(!query.getProcessId().equals(workflowTask.getPath().getInstance().getId())) - { - return false; - } - } - - // Query by process name deprecated, but still implemented. - if(query.getProcessName() != null) - { - String processName = factory.mapQNameToName(query.getProcessName()); - if(!processName.equals(workflowTask.getPath().getInstance().getDefinition().getName())) - { - return false; - } - } - - if(query.getWorkflowDefinitionName() != null) + private List queryStartTasks(WorkflowTaskQuery query) + { + List startTasks = Collections.emptyList(); + String taskId = query.getTaskId(); + if (taskId != null) { - if(!query.getWorkflowDefinitionName().equals(workflowTask.getPath().getInstance().getDefinition().getName())) + String localTaskId = createLocalId(taskId); + if (localTaskId.startsWith(ActivitiConstants.START_TASK_PREFIX)) + { + String processId = localTaskId.substring(ActivitiConstants.START_TASK_PREFIX.length()); + WorkflowTask startTask = getVirtualStartTaskForProcessInstance(processId); + startTasks = Arrays.asList(startTask); + } + } + else + { + QName taskName = query.getTaskName(); + if(taskName != null) + { + startTasks = getStartTasksWithName(taskName); + } + } + return filterStartTasks(startTasks, query); + } + + private List getStartTasksWithName(final QName taskName) + { + List definitions = getDefinitionsWithStartTaskName(taskName); + return CollectionUtils.transformFlat(definitions, new Function>() + { + public Collection apply(WorkflowDefinition definition) + { + List instanceIds = getInstanceIds(definition.getId()); + return CollectionUtils.transform(instanceIds, toStartTask()); + } + }); + } + + private List getInstanceIds(String definitionId) + { + String localDefId = createLocalId(definitionId); + List ids = getHistoricInstanceIds(localDefId); + List runtimeIds = getRuntimeInstanceIds(localDefId); + ids.addAll(runtimeIds); + return ids; + } + + private List getRuntimeInstanceIds(String efinitionId) + { + List runtimeInstances = getRuntimeProcessInstances(efinitionId); + return CollectionUtils.transform(runtimeInstances, new Function() + { + public String apply(ProcessInstance instance) + { + return createGlobalId(instance.getId()); + } + }); + } + + private List getHistoricInstanceIds(String efinitionId) + { + List historicInstances = getHistoricProcessInstances(efinitionId); + return CollectionUtils.transform(historicInstances, new Function() + { + public String apply(HistoricProcessInstance instance) + { + return createGlobalId(instance.getId()); + } + }); + } + + private Function toStartTask() + { + return new Function() + { + public WorkflowTask apply(String id) + { + return getStartTask(id); + } + }; + } + + private List getDefinitionsWithStartTaskName(final QName name) + { + List definitions = getAllDefinitions(); + return CollectionUtils.filter(definitions, new Filter() + { + public Boolean apply(WorkflowDefinition definition) + { + QName startTaskName = definition.getStartTaskDefinition().getMetadata().getName(); + return startTaskName.equals(name); + } + }); + } + + private List filterStartTasks(List tasks, final WorkflowTaskQuery query) + { + return CollectionUtils.filter(tasks, new Filter() + { + public Boolean apply(WorkflowTask workflowTask) + { + return isMatchingStartTask(workflowTask, query); + } + + + }); + + } + + private Boolean isMatchingStartTask(WorkflowTask workflowTask, WorkflowTaskQuery query) + { + String queryProcessId = query.getProcessId(); + if (queryProcessId != null) + { + if (!queryProcessId.equals(workflowTask.getPath().getInstance().getId())) { return false; } } - - if(query.getTaskCustomProps() != null) - { - if(!checkPropertiesPresent(query.getTaskCustomProps(), workflowTask.getProperties())) - { - return false; - } - } - - if(query.getTaskId() != null) - { - if(!query.getTaskId().equals(workflowTask.getId())) - { - return false; - } - } - - if(query.getTaskName() != null) - { - if(!query.getTaskName().equals(workflowTask.getDefinition().getMetadata().getName())) - { - return false; - } - } - - if(query.getTaskState() != null) - { - if(!query.getTaskState().equals(workflowTask.getState())) - { - return false; - } - } - - // If we fall through, start task matches the query - return true; + + Boolean queryIsActive = query.isActive(); + if (queryIsActive != null) + { + if (queryIsActive != workflowTask.getPath().isActive()) + { + return false; + } + } + + String queryActorId = query.getActorId(); + if (queryActorId != null && !queryActorId.equals(workflowTask.getProperties().get(ContentModel.PROP_OWNER))) + { + return false; + } + + if (query.getProcessCustomProps() != null) + { + // Get properties for process instance, based on path of start task, + // which is process-instance + Map props = getPathProperties(workflowTask.getPath().getId()); + if (!checkPropertiesPresent(query.getProcessCustomProps(), props)) + { + return false; + } + } + + // Query by process name deprecated, but still implemented. + QName queryProcessName = query.getProcessName(); + if (queryProcessName != null) + { + String processName = factory.mapQNameToName(queryProcessName); + if (!processName.equals(workflowTask.getPath().getInstance().getDefinition().getName())) + { + return false; + } + } + + if (query.getWorkflowDefinitionName() != null) + { + if (!query.getWorkflowDefinitionName().equals( + workflowTask.getPath().getInstance().getDefinition().getName())) + { + return false; + } + } + + if (query.getTaskCustomProps() != null) + { + if (!checkPropertiesPresent(query.getTaskCustomProps(), workflowTask.getProperties())) + { + return false; + } + } + + if (query.getTaskId() != null) + { + if (!query.getTaskId().equals(workflowTask.getId())) + { + return false; + } + } + + if (query.getTaskName() != null) + { + if (!query.getTaskName().equals(workflowTask.getDefinition().getMetadata().getName())) + { + return false; + } + } + + if (query.getTaskState() != null) + { + if (!query.getTaskState().equals(workflowTask.getState())) + { + return false; + } + } + + // If we fall through, start task matches the query + return true; } - + private boolean checkPropertiesPresent(Map expectedProperties, Map props) { for(Map.Entry entry : expectedProperties.entrySet()) @@ -2038,24 +2112,34 @@ public class ActivitiWorkflowEngine extends BPMEngine implements WorkflowEngine LinkedList results = new LinkedList(); if(Boolean.FALSE.equals(isActive)==false) { - List activeInstances = runtimeService.createProcessInstanceQuery() - .processDefinitionId(processDefId) - .list(); + List activeInstances = getRuntimeProcessInstances(processDefId); List activeResults = typeConverter.convert(activeInstances); results.addAll(activeResults); } if(Boolean.TRUE.equals(isActive)==false) { - List completedInstances = historyService.createHistoricProcessInstanceQuery() - .processDefinitionId(processDefId) - .finished() - .list(); + List completedInstances = getHistoricProcessInstances(processDefId); List completedResults = typeConverter.convert(completedInstances); results.addAll(completedResults); } return results; } + private List getHistoricProcessInstances(String processDefId) + { + return historyService.createHistoricProcessInstanceQuery() + .processDefinitionId(processDefId) + .finished() + .list(); + } + + private List getRuntimeProcessInstances(String processDefId) + { + return runtimeService.createProcessInstanceQuery() + .processDefinitionId(processDefId) + .list(); + } + /** * @param nodeConverter the nodeConverter to set */ diff --git a/source/java/org/alfresco/repo/workflow/activiti/ActivitiWorkflowServiceIntegrationTest.java b/source/java/org/alfresco/repo/workflow/activiti/ActivitiWorkflowServiceIntegrationTest.java index 0b374b030b..a5dfc806de 100644 --- a/source/java/org/alfresco/repo/workflow/activiti/ActivitiWorkflowServiceIntegrationTest.java +++ b/source/java/org/alfresco/repo/workflow/activiti/ActivitiWorkflowServiceIntegrationTest.java @@ -21,6 +21,7 @@ package org.alfresco.repo.workflow.activiti; import java.io.Serializable; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -85,28 +86,27 @@ public class ActivitiWorkflowServiceIntegrationTest extends AbstractWorkflowServ @Override protected void checkTaskQueryStartTaskCompleted(String workflowInstanceId, WorkflowTask startTask) { - // In activiti, start-tasks only show up when the workflowInstanceId or taskId is passed + // In activiti, start-tasks only show up when the taskId or task name is passed in. List expectedTasks = Arrays.asList(startTask.getId()); - checkProcessIdQuery(workflowInstanceId, expectedTasks, WorkflowTaskState.COMPLETED); + List noTaskIds = Collections.emptyList(); + checkProcessIdQuery(workflowInstanceId, noTaskIds, WorkflowTaskState.COMPLETED); checkTaskIdQuery(startTask.getId(), WorkflowTaskState.COMPLETED); // Check additional filtering, when workflowInstanceId is passed QName startTaskName = QName.createQName(NamespaceService.WORKFLOW_MODEL_1_0_URI, "submitAdhocTask"); checkTaskNameQuery(startTaskName, expectedTasks, WorkflowTaskState.COMPLETED, workflowInstanceId); - checkActorIdQuery(USER1, expectedTasks, WorkflowTaskState.COMPLETED, workflowInstanceId); - checkIsActiveQuery(expectedTasks, WorkflowTaskState.COMPLETED, workflowInstanceId); - checkTaskPropsQuery(expectedTasks, WorkflowTaskState.COMPLETED, workflowInstanceId); + checkActorIdQuery(USER1, noTaskIds, WorkflowTaskState.COMPLETED, workflowInstanceId); + checkIsActiveQuery(noTaskIds, WorkflowTaskState.COMPLETED, workflowInstanceId); + checkTaskPropsQuery(noTaskIds, WorkflowTaskState.COMPLETED, workflowInstanceId); } @Override - protected void checkTaskQueryTaskCompleted(String workflowInstanceId, - WorkflowTask theTask, WorkflowTask startTask) + protected void checkTaskQueryTaskCompleted(String workflowInstanceId, WorkflowTask theTask, WorkflowTask startTask) { - List bothTasks = Arrays.asList(theTask.getId(), startTask.getId()); List withoutStartTask = Arrays.asList(theTask.getId()); - - checkProcessIdQuery(workflowInstanceId, bothTasks, WorkflowTaskState.COMPLETED); + + checkProcessIdQuery(workflowInstanceId, withoutStartTask, WorkflowTaskState.COMPLETED); // Adhoc task should only be returned QName taskName = QName.createQName(NamespaceService.WORKFLOW_MODEL_1_0_URI, "adhocTask"); @@ -117,7 +117,7 @@ public class ActivitiWorkflowServiceIntegrationTest extends AbstractWorkflowServ // Workflow is still active, but in activiti, active start-task is not returned when // no process-instance ID is provided - checkIsActiveQuery(withoutStartTask, WorkflowTaskState.COMPLETED, null); + checkIsActiveQuery(withoutStartTask, WorkflowTaskState.COMPLETED, workflowInstanceId); // Task has custom property set checkTaskPropsQuery(withoutStartTask, WorkflowTaskState.COMPLETED, null); @@ -130,6 +130,7 @@ public class ActivitiWorkflowServiceIntegrationTest extends AbstractWorkflowServ protected void checkQueryTasksInactiveWorkflow(String workflowInstanceId) { WorkflowTaskQuery taskQuery = createWorkflowTaskQuery(WorkflowTaskState.COMPLETED); taskQuery.setActive(false); + taskQuery.setProcessId(workflowInstanceId); List tasks = workflowService.queryTasks(taskQuery); assertNotNull(tasks); @@ -139,6 +140,7 @@ public class ActivitiWorkflowServiceIntegrationTest extends AbstractWorkflowServ taskQuery = createWorkflowTaskQuery(WorkflowTaskState.COMPLETED); taskQuery.setActive(true); + taskQuery.setProcessId(workflowInstanceId); checkNoTasksFoundUsingQuery(taskQuery); }