diff --git a/config/alfresco/activiti-context.xml b/config/alfresco/activiti-context.xml index 9d8566e264..337a606f4e 100644 --- a/config/alfresco/activiti-context.xml +++ b/config/alfresco/activiti-context.xml @@ -143,6 +143,11 @@ + + + jbpm alfresco/workflow/adhoc_processdefinition.xml text/xml - false + true diff --git a/source/java/org/alfresco/repo/workflow/AbstractWorkflowServiceIntegrationTest.java b/source/java/org/alfresco/repo/workflow/AbstractWorkflowServiceIntegrationTest.java index 309577873f..a8c3b0b40f 100644 --- a/source/java/org/alfresco/repo/workflow/AbstractWorkflowServiceIntegrationTest.java +++ b/source/java/org/alfresco/repo/workflow/AbstractWorkflowServiceIntegrationTest.java @@ -575,16 +575,16 @@ public abstract class AbstractWorkflowServiceIntegrationTest extends BaseSpringT // 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); + checkTaskNameQuery(taskName, Arrays.asList(theTask.getId()), WorkflowTaskState.COMPLETED, null); // Completed adhocTask is assigned to USER2 - checkActorIdQuery(USER2, Arrays.asList(theTask.getId()), WorkflowTaskState.COMPLETED); + checkActorIdQuery(USER2, Arrays.asList(theTask.getId()), WorkflowTaskState.COMPLETED, null); // Workflow is still active, both tasks will be returned - checkIsActiveQuery(expectedTasks, WorkflowTaskState.COMPLETED); + checkIsActiveQuery(expectedTasks, WorkflowTaskState.COMPLETED, null); // Both tasks have custom property set - checkTaskPropsQuery(expectedTasks, WorkflowTaskState.COMPLETED); + checkTaskPropsQuery(expectedTasks, WorkflowTaskState.COMPLETED, null); } protected void testTaskQueryInProgress(String workflowInstanceId, WorkflowTask expectedTask) @@ -595,10 +595,11 @@ public abstract class AbstractWorkflowServiceIntegrationTest extends BaseSpringT checkTaskIdQuery(expectedTask.getId(), WorkflowTaskState.IN_PROGRESS); QName taskName = QName.createQName(NamespaceService.WORKFLOW_MODEL_1_0_URI, "adhocTask"); - checkTaskNameQuery(taskName, expectedTasks, WorkflowTaskState.IN_PROGRESS); - checkActorIdQuery(USER2, expectedTasks, WorkflowTaskState.IN_PROGRESS); - checkIsActiveQuery(expectedTasks, WorkflowTaskState.IN_PROGRESS); - checkTaskPropsQuery(expectedTasks, WorkflowTaskState.IN_PROGRESS); + checkTaskNameQuery(taskName, expectedTasks, WorkflowTaskState.IN_PROGRESS, null); + checkActorIdQuery(USER2, expectedTasks, WorkflowTaskState.IN_PROGRESS, null); + checkIsActiveQuery(expectedTasks, WorkflowTaskState.IN_PROGRESS, null); + checkTaskPropsQuery(expectedTasks, WorkflowTaskState.IN_PROGRESS, null); + checkProcessPropsQuery(expectedTasks, WorkflowTaskState.IN_PROGRESS); } protected void testTaskQueryStartTaskCompleted(String workflowInstanceId, WorkflowTask startTask) { @@ -608,10 +609,10 @@ public abstract class AbstractWorkflowServiceIntegrationTest extends BaseSpringT checkTaskIdQuery(startTask.getId(), WorkflowTaskState.COMPLETED); QName startTaskName = QName.createQName(NamespaceService.WORKFLOW_MODEL_1_0_URI, "submitAdhocTask"); - checkTaskNameQuery(startTaskName, expectedTasks, WorkflowTaskState.COMPLETED); - checkActorIdQuery(USER1, expectedTasks, WorkflowTaskState.COMPLETED); - checkIsActiveQuery(expectedTasks, WorkflowTaskState.COMPLETED); - checkTaskPropsQuery(expectedTasks, WorkflowTaskState.COMPLETED); + checkTaskNameQuery(startTaskName, expectedTasks, WorkflowTaskState.COMPLETED, null); + checkActorIdQuery(USER1, expectedTasks, WorkflowTaskState.COMPLETED, null); + checkIsActiveQuery(expectedTasks, WorkflowTaskState.COMPLETED, null); + checkTaskPropsQuery(expectedTasks, WorkflowTaskState.COMPLETED, null); } public void testGetWorkflows() throws Exception @@ -767,14 +768,23 @@ public abstract class AbstractWorkflowServiceIntegrationTest extends BaseSpringT } } - protected void checkTaskNameQuery(QName taskName, List expectedTaskIds, WorkflowTaskState state) { + protected void checkTaskNameQuery(QName taskName, List expectedTaskIds, WorkflowTaskState state, + String optionalProcessId) { WorkflowTaskQuery taskQuery = createWorkflowTaskQuery(state); taskQuery.setTaskName(taskName); + if(optionalProcessId != null) + { + taskQuery.setProcessId(optionalProcessId); + } checkTasksFoundUsingQuery(expectedTaskIds, taskQuery); QName unexistingTaskName = QName.createQName(NamespaceService.WORKFLOW_MODEL_1_0_URI, "unexistingTask"); taskQuery = createWorkflowTaskQuery(state); taskQuery.setTaskName(unexistingTaskName); + if(optionalProcessId != null) + { + taskQuery.setProcessId(optionalProcessId); + } checkNoTasksFoundUsingQuery(taskQuery); } @@ -800,29 +810,48 @@ public abstract class AbstractWorkflowServiceIntegrationTest extends BaseSpringT checkNoTasksFoundUsingQuery(taskQuery); } - protected void checkIsActiveQuery(List expectedTaskIds, WorkflowTaskState state) + protected void checkIsActiveQuery(List expectedTaskIds, WorkflowTaskState state, + String optionalProcessId) { WorkflowTaskQuery taskQuery = createWorkflowTaskQuery(state); taskQuery.setActive(true); + if(optionalProcessId != null) + { + taskQuery.setProcessId(optionalProcessId); + } checkTasksFoundUsingQuery(expectedTaskIds, taskQuery); taskQuery = createWorkflowTaskQuery(state); taskQuery.setActive(false); + if(optionalProcessId != null) + { + taskQuery.setProcessId(optionalProcessId); + } checkNoTasksFoundUsingQuery(taskQuery); } - protected void checkActorIdQuery(String actorId, List expectedTaskIds, WorkflowTaskState state) + protected void checkActorIdQuery(String actorId, List expectedTaskIds, WorkflowTaskState state, + String optionalProcessId) { WorkflowTaskQuery taskQuery = createWorkflowTaskQuery(state); taskQuery.setActorId(actorId); + if(optionalProcessId != null) + { + taskQuery.setProcessId(optionalProcessId); + } checkTasksFoundUsingQuery(expectedTaskIds, taskQuery); taskQuery = createWorkflowTaskQuery(state); taskQuery.setActorId(USER3); + if(optionalProcessId != null) + { + taskQuery.setProcessId(optionalProcessId); + } checkNoTasksFoundUsingQuery(taskQuery); } - protected void checkTaskPropsQuery(List expectedTaskIds, WorkflowTaskState state) + protected void checkTaskPropsQuery(List expectedTaskIds, WorkflowTaskState state, + String optionalProcessId) { WorkflowTaskQuery taskQuery = createWorkflowTaskQuery(state); QName customStringProp = QName.createQName(NamespaceService.WORKFLOW_MODEL_1_0_URI, "customStringProp"); @@ -831,6 +860,10 @@ public abstract class AbstractWorkflowServiceIntegrationTest extends BaseSpringT taskProps.put(customStringProp, "stringValue"); taskQuery.setTaskCustomProps(taskProps); + if(optionalProcessId != null) + { + taskQuery.setProcessId(optionalProcessId); + } checkTasksFoundUsingQuery(expectedTaskIds, taskQuery); taskProps = new HashMap(); @@ -838,6 +871,10 @@ public abstract class AbstractWorkflowServiceIntegrationTest extends BaseSpringT taskQuery = createWorkflowTaskQuery(state); taskQuery.setTaskCustomProps(taskProps); + if(optionalProcessId != null) + { + taskQuery.setProcessId(optionalProcessId); + } checkNoTasksFoundUsingQuery(taskQuery); } diff --git a/source/java/org/alfresco/repo/workflow/activiti/ActivitiTaskComponentTest.java b/source/java/org/alfresco/repo/workflow/activiti/ActivitiTaskComponentTest.java index 0cc16c63cd..e9a674a3ea 100644 --- a/source/java/org/alfresco/repo/workflow/activiti/ActivitiTaskComponentTest.java +++ b/source/java/org/alfresco/repo/workflow/activiti/ActivitiTaskComponentTest.java @@ -240,8 +240,7 @@ public class ActivitiTaskComponentTest extends AbstractActivitiComponentTest WorkflowTask finishedTask = workflowEngine.getTaskById(finishedTaskId); assertNotNull(finishedTask); - // TODO: revive once http://jira.codehaus.org/browse/ACT-485 is fixed - // Assert.assertEquals("Task description", finishedTask.getDescription()); + Assert.assertEquals("Task description", finishedTask.getDescription()); Assert.assertEquals(finishedTaskId, finishedTask.getId()); Assert.assertEquals("bpm_foo_task", finishedTask.getName()); @@ -446,8 +445,31 @@ public class ActivitiTaskComponentTest extends AbstractActivitiComponentTest Assert.assertNotNull(tasks); Assert.assertEquals(0, tasks.size()); - // TODO: test using process-name, not yet implemented now - // TODO: test using task-name + // Test query by process-name + taskQuery = createWorkflowTaskQuery(WorkflowTaskState.IN_PROGRESS); + taskQuery.setProcessName(QName.createQName("testTask")); + tasks = workflowEngine.queryTasks(taskQuery); + + Assert.assertNotNull(tasks); + Assert.assertEquals(1, tasks.size()); + + taskQuery.setProcessName(QName.createQName("unexistingTaskName")); + tasks = workflowEngine.queryTasks(taskQuery); + Assert.assertNotNull(tasks); + Assert.assertEquals(0, tasks.size()); + + // Test query by task-name + taskQuery = createWorkflowTaskQuery(WorkflowTaskState.IN_PROGRESS); + taskQuery.setTaskName(QName.createQName("bpm_foo_task")); + tasks = workflowEngine.queryTasks(taskQuery); + + Assert.assertNotNull(tasks); + Assert.assertEquals(1, tasks.size()); + + taskQuery.setTaskName(QName.createQName("unexisting_task_name")); + tasks = workflowEngine.queryTasks(taskQuery); + Assert.assertNotNull(tasks); + Assert.assertEquals(0, tasks.size()); // Test querying task variables, using all possible (and allowed) types of variables Map variables = new HashMap(); @@ -499,29 +521,51 @@ public class ActivitiTaskComponentTest extends AbstractActivitiComponentTest ActivitiScriptNode otherNode = new ActivitiScriptNode(testUserNode, serviceRegistry); checkTaskVariableNoMatch(WorkflowTaskState.IN_PROGRESS, QName.createQName("scriptNodeVar"), otherNode); - // TODO: test using process variables + + // Query task based on process variable + runtime.setVariable(task.getExecutionId(), "processVar", "testing"); + taskQuery = createWorkflowTaskQuery(WorkflowTaskState.IN_PROGRESS); + Map props = new HashMap(); + props.put(QName.createQName("processVar"), "testing"); + taskQuery.setProcessCustomProps(props); + + tasks = workflowEngine.queryTasks(taskQuery); + assertNotNull(tasks); + assertEquals(1, tasks.size()); + + props.put(QName.createQName("processVar"), "notmatching"); + + tasks = workflowEngine.queryTasks(taskQuery); + assertNotNull(tasks); + assertEquals(0, tasks.size()); } @Test public void testQueryTasksCompleted() throws Exception { - // Testing all query functionality for WorkflowTaskState.IN_PROGRESS + // Testing all query functionality for WorkflowTaskState.COMPLETED WorkflowPath path = workflowEngine.startWorkflow(workflowDef.getId(), new HashMap()); Task task = taskService.createTaskQuery() .executionId(BPMEngineRegistry.getLocalId(path.getId())) .singleResult(); + + taskService.setVariableLocal(task.getId(), "taskVar", "theValue"); assertNotNull("Task should exist!", task); String globalTaskId = createGlobalId(task.getId()); // Set the actor taskService.setAssignee(task.getId(), TEST_USER); + // Set process prop + runtime.setVariable(task.getExecutionId(), "processVar", "testing"); + // End the task workflowEngine.endTask(globalTaskId, null); // Test query by taskId WorkflowTaskQuery taskQuery = createWorkflowTaskQuery(WorkflowTaskState.COMPLETED); + taskQuery.setActive(Boolean.FALSE); // Set to false, since workflow this task is in, has finished taskQuery.setTaskId(globalTaskId); List tasks = workflowEngine.queryTasks(taskQuery); @@ -540,6 +584,7 @@ public class ActivitiTaskComponentTest extends AbstractActivitiComponentTest // Test query by process ID, this should also return the start-task taskQuery = createWorkflowTaskQuery(WorkflowTaskState.COMPLETED); taskQuery.setProcessId(createGlobalId(task.getProcessInstanceId())); + taskQuery.setActive(Boolean.FALSE); tasks = workflowEngine.queryTasks(taskQuery); Assert.assertNotNull(tasks); @@ -572,6 +617,7 @@ public class ActivitiTaskComponentTest extends AbstractActivitiComponentTest // Test query by actor taskQuery = createWorkflowTaskQuery(WorkflowTaskState.COMPLETED); taskQuery.setActorId(TEST_USER); + taskQuery.setActive(Boolean.FALSE); tasks = workflowEngine.queryTasks(taskQuery); Assert.assertNotNull(tasks); @@ -585,11 +631,53 @@ public class ActivitiTaskComponentTest extends AbstractActivitiComponentTest Assert.assertNotNull(tasks); Assert.assertEquals(0, tasks.size()); - // TODO: test using process-name, not yet implemented now - // TODO: test using task-name + // Test query by process-name + taskQuery = createWorkflowTaskQuery(WorkflowTaskState.COMPLETED); + taskQuery.setProcessName(QName.createQName("testTask")); + taskQuery.setActive(Boolean.FALSE); + tasks = workflowEngine.queryTasks(taskQuery); - // TODO: test using task variables - // TODO: test using process variables + Assert.assertNotNull(tasks); + Assert.assertEquals(1, tasks.size()); + + taskQuery.setProcessName(QName.createQName("unexistingTaskName")); + tasks = workflowEngine.queryTasks(taskQuery); + Assert.assertNotNull(tasks); + Assert.assertEquals(0, tasks.size()); + + // Query task based on task variable + taskQuery = createWorkflowTaskQuery(WorkflowTaskState.COMPLETED); + Map props = new HashMap(); + props.put(QName.createQName("taskVar"), "theValue"); + taskQuery.setActive(false); + taskQuery.setTaskCustomProps(props); + + tasks = workflowEngine.queryTasks(taskQuery); + assertNotNull(tasks); + assertEquals(1, tasks.size()); + + props.put(QName.createQName("processVar"), "notmatching"); + + tasks = workflowEngine.queryTasks(taskQuery); + assertNotNull(tasks); + assertEquals(0, tasks.size()); + + // Query task based on process variable + taskQuery = createWorkflowTaskQuery(WorkflowTaskState.COMPLETED); + props = new HashMap(); + props.put(QName.createQName("processVar"), "testing"); + taskQuery.setActive(false); + taskQuery.setProcessCustomProps(props); + + tasks = workflowEngine.queryTasks(taskQuery); + assertNotNull(tasks); + assertEquals(1, tasks.size()); + + props.put(QName.createQName("processVar"), "notmatching"); + + tasks = workflowEngine.queryTasks(taskQuery); + assertNotNull(tasks); + assertEquals(0, tasks.size()); } diff --git a/source/java/org/alfresco/repo/workflow/activiti/ActivitiTaskTypeManager.java b/source/java/org/alfresco/repo/workflow/activiti/ActivitiTaskTypeManager.java index 03b4d89725..6792a45519 100644 --- a/source/java/org/alfresco/repo/workflow/activiti/ActivitiTaskTypeManager.java +++ b/source/java/org/alfresco/repo/workflow/activiti/ActivitiTaskTypeManager.java @@ -24,7 +24,7 @@ import org.activiti.engine.delegate.DelegateTask; import org.activiti.engine.form.FormData; import org.activiti.engine.form.TaskFormData; import org.activiti.engine.impl.form.TaskFormHandler; -import org.activiti.engine.impl.task.TaskEntity; +import org.activiti.engine.impl.persistence.entity.TaskEntity; import org.activiti.engine.task.Task; import org.alfresco.repo.workflow.WorkflowObjectFactory; import org.alfresco.service.cmr.dictionary.TypeDefinition; diff --git a/source/java/org/alfresco/repo/workflow/activiti/ActivitiTimerExecutionTest.java b/source/java/org/alfresco/repo/workflow/activiti/ActivitiTimerExecutionTest.java index 6cb3bd1576..5b87d6fcb6 100644 --- a/source/java/org/alfresco/repo/workflow/activiti/ActivitiTimerExecutionTest.java +++ b/source/java/org/alfresco/repo/workflow/activiti/ActivitiTimerExecutionTest.java @@ -26,7 +26,7 @@ import java.util.List; import java.util.Map; import org.activiti.engine.ProcessEngine; -import org.activiti.engine.impl.runtime.TimerEntity; +import org.activiti.engine.impl.persistence.entity.TimerEntity; import org.activiti.engine.repository.ProcessDefinition; import org.activiti.engine.runtime.Job; import org.alfresco.model.ContentModel; diff --git a/source/java/org/alfresco/repo/workflow/activiti/ActivitiUtil.java b/source/java/org/alfresco/repo/workflow/activiti/ActivitiUtil.java index 772acc1efe..993027c96a 100644 --- a/source/java/org/alfresco/repo/workflow/activiti/ActivitiUtil.java +++ b/source/java/org/alfresco/repo/workflow/activiti/ActivitiUtil.java @@ -32,8 +32,8 @@ import org.activiti.engine.form.StartFormData; import org.activiti.engine.history.HistoricProcessInstance; import org.activiti.engine.history.HistoricTaskInstance; import org.activiti.engine.impl.RepositoryServiceImpl; +import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity; import org.activiti.engine.impl.pvm.ReadOnlyProcessDefinition; -import org.activiti.engine.impl.repository.ProcessDefinitionEntity; import org.activiti.engine.repository.ProcessDefinition; import org.activiti.engine.runtime.Execution; import org.activiti.engine.runtime.ProcessInstance; diff --git a/source/java/org/alfresco/repo/workflow/activiti/ActivitiWorkflowEngine.java b/source/java/org/alfresco/repo/workflow/activiti/ActivitiWorkflowEngine.java index bbe87eb207..056fce192f 100644 --- a/source/java/org/alfresco/repo/workflow/activiti/ActivitiWorkflowEngine.java +++ b/source/java/org/alfresco/repo/workflow/activiti/ActivitiWorkflowEngine.java @@ -51,11 +51,11 @@ import org.activiti.engine.impl.bpmn.deployer.BpmnDeployer; import org.activiti.engine.impl.form.DefaultTaskFormHandler; import org.activiti.engine.impl.form.TaskFormHandler; import org.activiti.engine.impl.identity.Authentication; +import org.activiti.engine.impl.persistence.entity.TimerEntity; import org.activiti.engine.impl.pvm.PvmActivity; import org.activiti.engine.impl.pvm.PvmTransition; import org.activiti.engine.impl.pvm.ReadOnlyProcessDefinition; import org.activiti.engine.impl.pvm.process.ActivityImpl; -import org.activiti.engine.impl.runtime.TimerEntity; import org.activiti.engine.repository.Deployment; import org.activiti.engine.repository.ProcessDefinition; import org.activiti.engine.runtime.Execution; @@ -1369,7 +1369,6 @@ public class ActivitiWorkflowEngine extends BPMEngine implements WorkflowEngine @Override public List queryTasks(WorkflowTaskQuery query) { - // TODO: complete, only small part is implemented ArrayList result = new ArrayList(); WorkflowTaskState taskState = query.getTaskState(); if(WorkflowTaskState.COMPLETED.equals(taskState) == false) @@ -1407,9 +1406,8 @@ public class ActivitiWorkflowEngine extends BPMEngine implements WorkflowEngine if(query.getProcessName() != null) { - // String processName = getProcessNameMTSafe(query.getProcessName()); - // TODO: Method added in http://jira.codehaus.org/browse/ACT-459 - // taskQuery.processDefinitionName(processName); + String processName = getProcessNameMTSafe(query.getProcessName()); + taskQuery.processDefinitionKey(processName); } @@ -1447,7 +1445,11 @@ public class ActivitiWorkflowEngine extends BPMEngine implements WorkflowEngine private void addProcessPropertiesToQuery( Map processCustomProps, TaskQuery taskQuery) { - // TODO: implement + for(Entry customProperty : processCustomProps.entrySet()) + { + String name =factory.mapQNameToName(customProperty.getKey()); + taskQuery.processVariableValueEquals(name, customProperty.getValue()); + } } protected String getProcessNameMTSafe(QName processNameQName) @@ -1517,13 +1519,11 @@ public class ActivitiWorkflowEngine extends BPMEngine implements WorkflowEngine { if (orderByPart == WorkflowTaskQuery.OrderBy.TaskActor_Asc) { - // TODO: add in activiti - // taskQuery.orderByTaskAssignee().asc(); + taskQuery.orderByTaskAssignee().asc(); } else if (orderByPart == WorkflowTaskQuery.OrderBy.TaskActor_Desc) { - // TODO: add in activiti - // taskQuery.orderByTaskAssignee().desc(); + taskQuery.orderByTaskAssignee().desc(); } else if (orderByPart == WorkflowTaskQuery.OrderBy.TaskCreated_Asc) { @@ -1543,13 +1543,11 @@ public class ActivitiWorkflowEngine extends BPMEngine implements WorkflowEngine } else if (orderByPart == WorkflowTaskQuery.OrderBy.TaskId_Asc) { - // TODO: add in activiti - // taskQuery.orderByTaskId().asc(); + taskQuery.orderByTaskId().asc(); } else if (orderByPart == WorkflowTaskQuery.OrderBy.TaskId_Desc) { - // TODO: add in activiti - // taskQuery.orderByTaskId().desc(); + taskQuery.orderByTaskId().desc(); } else if (orderByPart == WorkflowTaskQuery.OrderBy.TaskName_Asc) { @@ -1581,7 +1579,6 @@ public class ActivitiWorkflowEngine extends BPMEngine implements WorkflowEngine private List queryHistoricTasks(WorkflowTaskQuery query) { - // TODO: Implement complete query HistoricTaskInstanceQuery historicQuery = historyService .createHistoricTaskInstanceQuery() .finished(); @@ -1609,12 +1606,30 @@ public class ActivitiWorkflowEngine extends BPMEngine implements WorkflowEngine if(query.getProcessName() != null) { - // String processName = getProcessNameMTSafe(query.getProcessName()); - // TODO: add to query + String processName = getProcessNameMTSafe(query.getProcessName()); + historicQuery.processDefinitionKey(processName); } - // TODO: task properties from history query - // TODO: process properties + if(query.getTaskCustomProps() != null) + { + addTaskPropertiesToQuery(query.getTaskCustomProps(), historicQuery); + } + + if(query.getProcessCustomProps() != null) + { + addProcessPropertiesToQuery(query.getProcessCustomProps(), historicQuery); + } + + if(query.isActive() != null) + { + if(query.isActive()) { + historicQuery.processUnfinished(); + } + else + { + historicQuery.processFinished(); + } + } // Order query if(query.getOrderBy() != null) @@ -1638,10 +1653,26 @@ public class ActivitiWorkflowEngine extends BPMEngine implements WorkflowEngine } + private void addTaskPropertiesToQuery(Map taskCustomProps, + HistoricTaskInstanceQuery taskQuery) { + for(Entry customProperty : taskCustomProps.entrySet()) + { + String name =factory.mapQNameToName(customProperty.getKey()); + taskQuery.taskVariableValueEquals(name, customProperty.getValue()); + } + } + + private void addProcessPropertiesToQuery(Map processCustomProps, + HistoricTaskInstanceQuery taskQuery) { + for(Entry customProperty : processCustomProps.entrySet()) + { + String name =factory.mapQNameToName(customProperty.getKey()); + taskQuery.processVariableValueEquals(name, customProperty.getValue()); + } + } + private List queryStartTasks(WorkflowTaskQuery query) { - - // TODO: implement further List startTasks = new ArrayList(); String processInstanceId = null; @@ -1683,6 +1714,18 @@ public class ActivitiWorkflowEngine extends BPMEngine implements WorkflowEngine 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; @@ -1755,7 +1798,7 @@ public class ActivitiWorkflowEngine extends BPMEngine implements WorkflowEngine { for(Map.Entry entry : expectedProperties.entrySet()) { - if(props.containsKey(entry.getValue())) + if(props.containsKey(entry.getKey())) { Object requiredValue = entry.getValue(); Object actualValue = props.get(entry.getKey()); @@ -1766,6 +1809,7 @@ public class ActivitiWorkflowEngine extends BPMEngine implements WorkflowEngine { return false; } + break; } else { @@ -1773,6 +1817,7 @@ public class ActivitiWorkflowEngine extends BPMEngine implements WorkflowEngine { return false; } + break; } } if(entry.getValue() != null) diff --git a/source/java/org/alfresco/repo/workflow/activiti/ActivitiWorkflowServiceIntegrationTest.java b/source/java/org/alfresco/repo/workflow/activiti/ActivitiWorkflowServiceIntegrationTest.java index 45de1b7cec..e06dd2fb9c 100644 --- a/source/java/org/alfresco/repo/workflow/activiti/ActivitiWorkflowServiceIntegrationTest.java +++ b/source/java/org/alfresco/repo/workflow/activiti/ActivitiWorkflowServiceIntegrationTest.java @@ -20,6 +20,7 @@ package org.alfresco.repo.workflow.activiti; import java.io.Serializable; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -30,6 +31,8 @@ import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.workflow.WorkflowDefinition; import org.alfresco.service.cmr.workflow.WorkflowPath; import org.alfresco.service.cmr.workflow.WorkflowTask; +import org.alfresco.service.cmr.workflow.WorkflowTaskQuery; +import org.alfresco.service.cmr.workflow.WorkflowTaskState; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; @@ -78,11 +81,63 @@ public class ActivitiWorkflowServiceIntegrationTest extends AbstractWorkflowServ Serializable outcome = result.getProperties().get(WorkflowModel.PROP_OUTCOME); assertEquals("Approve", outcome); } + + protected void testTaskQueryStartTaskCompleted(String workflowInstanceId, WorkflowTask startTask) + { + // In activiti, start-tasks only show up when the workflowInstanceId or taskId is passed + List expectedTasks = Arrays.asList(startTask.getId()); + + checkProcessIdQuery(workflowInstanceId, expectedTasks, 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); + } - @Override - public void testQueryTasks() { - // TODO: Revive test once all pieces of queryTasks() are finished on ActivitiWorkflowEngine - } + protected void testTaskQueryTaskCompleted(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); + + // Adhoc task should only be returned + QName taskName = QName.createQName(NamespaceService.WORKFLOW_MODEL_1_0_URI, "adhocTask"); + checkTaskNameQuery(taskName, withoutStartTask, WorkflowTaskState.COMPLETED, null); + + // Completed adhocTask is assigned to USER2 + checkActorIdQuery(USER2, withoutStartTask, WorkflowTaskState.COMPLETED, null); + + // 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); + + // Task has custom property set + checkTaskPropsQuery(withoutStartTask, WorkflowTaskState.COMPLETED, null); + + // Process properties + checkProcessPropsQuery(withoutStartTask, WorkflowTaskState.COMPLETED); + } + + protected void testQueryTasksInactiveWorkflow(String workflowInstanceId) { + WorkflowTaskQuery taskQuery = createWorkflowTaskQuery(WorkflowTaskState.COMPLETED); + taskQuery.setActive(false); + + List tasks = workflowService.queryTasks(taskQuery); + assertNotNull(tasks); + + // Activiti doesn't return start-task when no process/task id is set in query, so only 2 tasks will be returned + assertEquals(2, tasks.size()); + + taskQuery = createWorkflowTaskQuery(WorkflowTaskState.COMPLETED); + taskQuery.setActive(true); + checkNoTasksFoundUsingQuery(taskQuery); + } @Override protected String getEngine() diff --git a/source/java/org/alfresco/repo/workflow/activiti/AddTaskListenerParseListener.java b/source/java/org/alfresco/repo/workflow/activiti/AddTaskListenerParseListener.java index acc8b1ae7b..e835f7bf41 100644 --- a/source/java/org/alfresco/repo/workflow/activiti/AddTaskListenerParseListener.java +++ b/source/java/org/alfresco/repo/workflow/activiti/AddTaskListenerParseListener.java @@ -18,14 +18,14 @@ */ package org.alfresco.repo.workflow.activiti; +import org.activiti.engine.delegate.TaskListener; import org.activiti.engine.impl.bpmn.behavior.UserTaskActivityBehavior; import org.activiti.engine.impl.bpmn.parser.BpmnParseListener; +import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity; import org.activiti.engine.impl.pvm.delegate.ActivityBehavior; -import org.activiti.engine.impl.pvm.delegate.TaskListener; import org.activiti.engine.impl.pvm.process.ActivityImpl; import org.activiti.engine.impl.pvm.process.ScopeImpl; import org.activiti.engine.impl.pvm.process.TransitionImpl; -import org.activiti.engine.impl.repository.ProcessDefinitionEntity; import org.activiti.engine.impl.util.xml.Element; import org.activiti.engine.impl.variable.VariableDeclaration; diff --git a/source/java/org/alfresco/repo/workflow/activiti/AuthenticatedTimerJobHandler.java b/source/java/org/alfresco/repo/workflow/activiti/AuthenticatedTimerJobHandler.java index 8b022f98fa..f40767200e 100644 --- a/source/java/org/alfresco/repo/workflow/activiti/AuthenticatedTimerJobHandler.java +++ b/source/java/org/alfresco/repo/workflow/activiti/AuthenticatedTimerJobHandler.java @@ -22,8 +22,8 @@ package org.alfresco.repo.workflow.activiti; import org.activiti.engine.impl.TaskQueryImpl; import org.activiti.engine.impl.interceptor.CommandContext; import org.activiti.engine.impl.jobexecutor.JobHandler; +import org.activiti.engine.impl.persistence.entity.ExecutionEntity; import org.activiti.engine.impl.pvm.PvmActivity; -import org.activiti.engine.impl.runtime.ExecutionEntity; import org.activiti.engine.task.Task; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; diff --git a/source/java/org/alfresco/repo/workflow/activiti/listener/ScriptExecutionListener.java b/source/java/org/alfresco/repo/workflow/activiti/listener/ScriptExecutionListener.java index 68c67696b5..fa491e56b8 100644 --- a/source/java/org/alfresco/repo/workflow/activiti/listener/ScriptExecutionListener.java +++ b/source/java/org/alfresco/repo/workflow/activiti/listener/ScriptExecutionListener.java @@ -19,115 +19,55 @@ package org.alfresco.repo.workflow.activiti.listener; -import java.util.HashMap; import java.util.Map; -import java.util.Map.Entry; import org.activiti.engine.delegate.DelegateExecution; -import org.activiti.engine.impl.pvm.delegate.ExecutionListener; +import org.activiti.engine.delegate.ExecutionListener; import org.activiti.engine.impl.pvm.delegate.ExecutionListenerExecution; -import org.alfresco.model.ContentModel; -import org.alfresco.repo.security.authentication.AuthenticationUtil; -import org.alfresco.repo.workflow.WorkflowQNameConverter; import org.alfresco.repo.workflow.activiti.ActivitiConstants; -import org.alfresco.repo.workflow.activiti.ActivitiScriptNode; -import org.alfresco.repo.workflow.activiti.script.ActivitiScriptBase; -import org.alfresco.service.ServiceRegistry; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.repo.workflow.activiti.script.DelegateExecutionScriptBase; +import org.alfresco.service.cmr.repository.ScriptService; /** + * An {@link ExecutionListener} that runs a script against the {@link ScriptService}. + * + * The script that is executed can be set using field 'script'. A non-default + * script-processor can be set in the field 'scriptProcessor'. Optionally, you can run + * the script as a different user than the default by setting the field 'runAs'. + * By default, the user this script as the current logged-in user. If no user is + * currently logged in (eg. flow triggered by timer) the system user will be used instead. * * @author Nick Smith * @author Frederik Heremans * @since 3.4.e */ -public class ScriptExecutionListener extends ActivitiScriptBase implements ExecutionListener +public class ScriptExecutionListener extends DelegateExecutionScriptBase implements ExecutionListener { + private static final String DELETED_FLAG = "deleted"; private static final String CANCELLED_FLAG = "cancelled"; - + @Override - public void notify(ExecutionListenerExecution execution) throws Exception { - if(script != null) - { - String scriptString = getStringValue(script, execution); - String scriptProcessorName = getStringValue(scriptProcessor, execution); - String runAsUser = getStringValue(runAs, execution); - - // Make sure there is an authenticated user for the current thread, so when - // the script is executed using no 'runAs' from a job-executor thread, the workflow - // owner us used - boolean clearAuthenticationContext = checkFullyAuthenticatedUser(execution); - - // Get all activiti-defined objects - Map scriptModel = getInputMap(execution, runAsUser); - - // Add core alfresco objects to the input-map - getServiceRegistry().getScriptService().buildCoreModel(scriptModel); - - try - { - Object scriptOutput = executeScript(scriptString, scriptModel, scriptProcessorName, runAsUser); - - // TODO: What to do with the script-output? - if(scriptOutput != null) - { - // delegateTask.setVariableLocal("scriptOutput", scriptOutput); - } - } - finally - { - if(clearAuthenticationContext) - { - // If the current user has been set to the Task's assignee, we should clear it agian - AuthenticationUtil.clearCurrentSecurityContext(); - } - } - } - else - { - throw new IllegalArgumentException("The field 'script' should be set on the TaskListener"); - } + public void notify(DelegateExecution execution) throws Exception { + runScript(execution); } - protected Map getInputMap(ExecutionListenerExecution execution, String runAsUser) - { - HashMap scriptModel = new HashMap(1); - - // Add current logged-in user and it's user home - ActivitiScriptNode personNode = getPersonNode(runAsUser); - if(personNode != null) - { - ServiceRegistry registry = getServiceRegistry(); - scriptModel.put(PERSON_BINDING_NAME, personNode); - NodeRef userHomeNode = (NodeRef) registry.getNodeService().getProperty(personNode.getNodeRef(), ContentModel.PROP_HOMEFOLDER); - if (userHomeNode != null) - { - scriptModel.put(USERHOME_BINDING_NAME, new ActivitiScriptNode(userHomeNode, registry)); - } - } - - // Add activiti-specific objects - scriptModel.put(EXECUTION_BINDING_NAME, execution); - - // Add all workflow variables to model - Map variables = execution.getVariables(); - - for(Entry varEntry : variables.entrySet()) - { - scriptModel.put(varEntry.getKey(), varEntry.getValue()); - } - - // Add deleted/cancelled flags + @Override + protected Map getInputMap(DelegateExecution execution, + String runAsUser) { + Map scriptModel = super.getInputMap(execution, runAsUser); + + ExecutionListenerExecution listenerExecution = (ExecutionListenerExecution) execution; + + // Add deleted/cancelled flags boolean cancelled = false; boolean deleted = false; - if(ActivitiConstants.DELETE_REASON_DELETED.equals(execution.getDeleteReason())) + if(ActivitiConstants.DELETE_REASON_DELETED.equals(listenerExecution.getDeleteReason())) { deleted = true; } - else if(ActivitiConstants.DELETE_REASON_CANCELLED.equals(execution.getDeleteReason())) + else if(ActivitiConstants.DELETE_REASON_CANCELLED.equals(listenerExecution.getDeleteReason())) { cancelled = true; } @@ -136,28 +76,4 @@ public class ScriptExecutionListener extends ActivitiScriptBase implements Execu return scriptModel; } - - /** - * Checks a valid Fully Authenticated User is set. - * If none is set then attempts to set the workflow owner - * @param execution the execution - * @return true if the Fully Authenticated User was changed, otherwise false. - */ - private boolean checkFullyAuthenticatedUser(final DelegateExecution execution) { - if(AuthenticationUtil.getFullyAuthenticatedUser() == null) - { - NamespaceService namespaceService = getServiceRegistry().getNamespaceService(); - WorkflowQNameConverter qNameConverter = new WorkflowQNameConverter(namespaceService); - String ownerVariableName = qNameConverter.mapQNameToName(ContentModel.PROP_OWNER); - - String userName = (String) execution.getVariable(ownerVariableName); - if (userName != null) - { - AuthenticationUtil.setFullyAuthenticatedUser(userName); - return true; - } - } - return false; - } - } diff --git a/source/java/org/alfresco/repo/workflow/activiti/properties/ActivitiDueDatePropertyHandler.java b/source/java/org/alfresco/repo/workflow/activiti/properties/ActivitiDueDatePropertyHandler.java new file mode 100644 index 0000000000..735dfd15ac --- /dev/null +++ b/source/java/org/alfresco/repo/workflow/activiti/properties/ActivitiDueDatePropertyHandler.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2005-2011 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +package org.alfresco.repo.workflow.activiti.properties; + +import java.io.Serializable; +import java.util.Date; + +import org.activiti.engine.delegate.DelegateTask; +import org.activiti.engine.task.Task; +import org.alfresco.repo.workflow.WorkflowModel; +import org.alfresco.repo.workflow.activiti.ActivitiTaskPropertyHandler; +import org.alfresco.service.cmr.dictionary.TypeDefinition; +import org.alfresco.service.namespace.QName; + +/** + * @since 3.5 + * @author Frederik Heremans + * + */ +public class ActivitiDueDatePropertyHandler extends ActivitiTaskPropertyHandler +{ + + /** + * {@inheritDoc} + */ + + @Override + protected Object handleTaskProperty(Task task, TypeDefinition type, QName key, Serializable value) + { + checkType(key, value, Date.class); + task.setDueDate((Date) value); + return DO_NOT_ADD; + } + + /** + * {@inheritDoc} + */ + @Override + protected Object handleDelegateTaskProperty(DelegateTask task, TypeDefinition type, QName key, Serializable value) + { + checkType(key, value, Date.class); + task.setDueDate((Date) value); + return DO_NOT_ADD; + } + + /** + * {@inheritDoc} + */ + + @Override + protected QName getKey() + { + return WorkflowModel.PROP_DUE_DATE; + } + +} diff --git a/source/java/org/alfresco/repo/workflow/activiti/properties/ActivitiPooledActorsPropertyHandler.java b/source/java/org/alfresco/repo/workflow/activiti/properties/ActivitiPooledActorsPropertyHandler.java index cfe000bc7d..7f9a51c17c 100644 --- a/source/java/org/alfresco/repo/workflow/activiti/properties/ActivitiPooledActorsPropertyHandler.java +++ b/source/java/org/alfresco/repo/workflow/activiti/properties/ActivitiPooledActorsPropertyHandler.java @@ -28,8 +28,8 @@ import java.util.List; import org.activiti.engine.TaskService; import org.activiti.engine.delegate.DelegateTask; -import org.activiti.engine.impl.task.IdentityLinkEntity; -import org.activiti.engine.impl.task.TaskEntity; +import org.activiti.engine.impl.persistence.entity.IdentityLinkEntity; +import org.activiti.engine.impl.persistence.entity.TaskEntity; import org.activiti.engine.task.IdentityLink; import org.activiti.engine.task.IdentityLinkType; import org.activiti.engine.task.Task; diff --git a/source/java/org/alfresco/repo/workflow/activiti/properties/ActivitiPropertyConverter.java b/source/java/org/alfresco/repo/workflow/activiti/properties/ActivitiPropertyConverter.java index e43c428f41..4c60e684f8 100644 --- a/source/java/org/alfresco/repo/workflow/activiti/properties/ActivitiPropertyConverter.java +++ b/source/java/org/alfresco/repo/workflow/activiti/properties/ActivitiPropertyConverter.java @@ -38,8 +38,8 @@ import org.activiti.engine.history.HistoricDetailQuery; import org.activiti.engine.history.HistoricProcessInstance; import org.activiti.engine.history.HistoricTaskInstance; import org.activiti.engine.history.HistoricVariableUpdate; +import org.activiti.engine.impl.persistence.entity.TaskEntity; import org.activiti.engine.impl.pvm.ReadOnlyProcessDefinition; -import org.activiti.engine.impl.task.TaskEntity; import org.activiti.engine.repository.ProcessDefinition; import org.activiti.engine.task.IdentityLink; import org.activiti.engine.task.IdentityLinkType; @@ -148,8 +148,7 @@ public class ActivitiPropertyConverter properties.put(WorkflowModel.PROP_START_DATE, task.getCreateTime()); // Due date is present on the process instance - String dueDateKey = factory.mapQNameToName(WorkflowModel.PROP_DUE_DATE); - properties.put(WorkflowModel.PROP_DUE_DATE, (Serializable) variables.get(dueDateKey)); + properties.put(WorkflowModel.PROP_DUE_DATE, task.getDueDate()); // Since this is a runtime-task, it's not completed yet properties.put(WorkflowModel.PROP_COMPLETION_DATE, null); @@ -260,12 +259,8 @@ public class ActivitiPropertyConverter // Since the task is never started explicitally, we use the create time properties.put(WorkflowModel.PROP_START_DATE, task.getCreateTime()); - // Due date is present on the process instance - String dueDateKey = factory.mapQNameToName(WorkflowModel.PROP_DUE_DATE); - if(properties.containsKey(WorkflowModel.PROP_DUE_DATE)==false) - { - properties.put(WorkflowModel.PROP_DUE_DATE, (Serializable) variables.get(dueDateKey)); - } + // Due date + properties.put(WorkflowModel.PROP_DUE_DATE, task.getDueDate()); // Since this is a runtime-task, it's not completed yet properties.put(WorkflowModel.PROP_COMPLETION_DATE, null); @@ -302,12 +297,10 @@ public class ActivitiPropertyConverter // Since the task is never started explicitly, we use the create time properties.put(WorkflowModel.PROP_START_DATE, historicTask.getStartTime()); - Object dueDateKey = factory.mapQNameToName(WorkflowModel.PROP_DUE_DATE); - properties.put(WorkflowModel.PROP_DUE_DATE, (Serializable) variables.get(dueDateKey)); + properties.put(WorkflowModel.PROP_DUE_DATE, historicTask.getDueDate()); properties.put(WorkflowModel.PROP_COMPLETION_DATE, historicTask.getEndTime()); - // TODO: Put task priority in history - http://jira.codehaus.org/browse/ACT-484 - // properties.put(WorkflowModel.PROP_PRIORITY, historicTask.getPriority()); + properties.put(WorkflowModel.PROP_PRIORITY, historicTask.getPriority()); properties.put(ContentModel.PROP_CREATED, historicTask.getStartTime()); properties.put(ContentModel.PROP_OWNER, historicTask.getAssignee()); @@ -447,7 +440,6 @@ public class ActivitiPropertyConverter // Map activiti task instance fields to properties properties.put(WorkflowModel.PROP_TASK_ID, ActivitiConstants.START_TASK_PREFIX + historicProcessInstance.getId()); - // properties.put(WorkflowModel.PROP_DESCRIPTION, historicTask.getDescription()); properties.put(WorkflowModel.PROP_START_DATE, historicProcessInstance.getStartTime()); diff --git a/source/java/org/alfresco/repo/workflow/activiti/script/AlfrescoScriptDelegate.java b/source/java/org/alfresco/repo/workflow/activiti/script/AlfrescoScriptDelegate.java new file mode 100644 index 0000000000..5e75e47391 --- /dev/null +++ b/source/java/org/alfresco/repo/workflow/activiti/script/AlfrescoScriptDelegate.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2005-2011 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +package org.alfresco.repo.workflow.activiti.script; + +import org.activiti.engine.delegate.DelegateExecution; +import org.activiti.engine.delegate.JavaDelegate; +import org.alfresco.service.cmr.repository.ScriptService; + +/** + * A {@link JavaDelegate} that executes a script against the {@link ScriptService}. + * + * The script that is executed can be set using field 'script'. A non-default + * script-processor can be set in the field 'scriptProcessor'. Optionally, you can run + * the script as a different user than the default by setting the field 'runAs'. + * By default, the user this script as the current logged-in user. If no user is + * currently logged in (eg. flow triggered by timer) the system user will be used instead. + * + * @author Frederik Heremans + * @since 3.5 + */ +public class AlfrescoScriptDelegate extends DelegateExecutionScriptBase implements JavaDelegate { + + @Override + public void execute(DelegateExecution execution) throws Exception { + runScript(execution); + } +} diff --git a/source/java/org/alfresco/repo/workflow/activiti/script/DelegateExecutionScriptBase.java b/source/java/org/alfresco/repo/workflow/activiti/script/DelegateExecutionScriptBase.java new file mode 100644 index 0000000000..feaf198337 --- /dev/null +++ b/source/java/org/alfresco/repo/workflow/activiti/script/DelegateExecutionScriptBase.java @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2005-2011 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +package org.alfresco.repo.workflow.activiti.script; + +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + +import org.activiti.engine.delegate.DelegateExecution; +import org.alfresco.model.ContentModel; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.workflow.WorkflowQNameConverter; +import org.alfresco.repo.workflow.activiti.ActivitiScriptNode; +import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.ScriptService; +import org.alfresco.service.namespace.NamespaceService; + + +/** + * Base class for running scripts against the {@link ScriptService}, in activiti's + * {@link DelegateExecution} context. + * + * @author Frederik Heremans + * + */ +public class DelegateExecutionScriptBase extends ActivitiScriptBase { + + /** + * Run the script that is configured, using the given execution. + */ + protected void runScript(DelegateExecution execution) throws Exception { + if(script != null) + { + String scriptString = getStringValue(script, execution); + String scriptProcessorName = getStringValue(scriptProcessor, execution); + String runAsUser = getStringValue(runAs, execution); + + // Make sure there is an authenticated user for the current thread, so when + // the script is executed using no 'runAs' from a job-executor thread, the workflow + // owner us used + boolean clearAuthenticationContext = checkFullyAuthenticatedUser(execution); + + // Get all activiti-defined objects + Map scriptModel = getInputMap(execution, runAsUser); + + // Add core alfresco objects to the input-map + getServiceRegistry().getScriptService().buildCoreModel(scriptModel); + + try + { + Object scriptOutput = executeScript(scriptString, scriptModel, scriptProcessorName, runAsUser); + + // TODO: What to do with the script-output? + if(scriptOutput != null) + { + // delegateTask.setVariableLocal("scriptOutput", scriptOutput); + } + } + finally + { + if(clearAuthenticationContext) + { + // If the current user has been set to the Task's assignee, we should clear it agian + AuthenticationUtil.clearCurrentSecurityContext(); + } + } + } + else + { + throw new IllegalArgumentException("The field 'script' should be set on the TaskListener"); + } + } + + protected Map getInputMap(DelegateExecution execution, String runAsUser) + { + HashMap scriptModel = new HashMap(1); + + // Add current logged-in user and it's user home + ActivitiScriptNode personNode = getPersonNode(runAsUser); + if(personNode != null) + { + ServiceRegistry registry = getServiceRegistry(); + scriptModel.put(PERSON_BINDING_NAME, personNode); + NodeRef userHomeNode = (NodeRef) registry.getNodeService().getProperty(personNode.getNodeRef(), ContentModel.PROP_HOMEFOLDER); + if (userHomeNode != null) + { + scriptModel.put(USERHOME_BINDING_NAME, new ActivitiScriptNode(userHomeNode, registry)); + } + } + + // Add activiti-specific objects + scriptModel.put(EXECUTION_BINDING_NAME, execution); + + // Add all workflow variables to model + Map variables = execution.getVariables(); + + for(Entry varEntry : variables.entrySet()) + { + scriptModel.put(varEntry.getKey(), varEntry.getValue()); + } + + return scriptModel; + } + + /** + * Checks a valid Fully Authenticated User is set. + * If none is set then attempts to set the workflow owner + * @param execution the execution + * @return true if the Fully Authenticated User was changed, otherwise false. + */ + private boolean checkFullyAuthenticatedUser(final DelegateExecution execution) { + if(AuthenticationUtil.getFullyAuthenticatedUser() == null) + { + NamespaceService namespaceService = getServiceRegistry().getNamespaceService(); + WorkflowQNameConverter qNameConverter = new WorkflowQNameConverter(namespaceService); + String ownerVariableName = qNameConverter.mapQNameToName(ContentModel.PROP_OWNER); + + String userName = (String) execution.getVariable(ownerVariableName); + if (userName != null) + { + AuthenticationUtil.setFullyAuthenticatedUser(userName); + return true; + } + } + return false; + } + +} diff --git a/source/java/org/alfresco/repo/workflow/activiti/tasklistener/ScriptTaskListener.java b/source/java/org/alfresco/repo/workflow/activiti/tasklistener/ScriptTaskListener.java index 830b0d530c..ce33e19523 100644 --- a/source/java/org/alfresco/repo/workflow/activiti/tasklistener/ScriptTaskListener.java +++ b/source/java/org/alfresco/repo/workflow/activiti/tasklistener/ScriptTaskListener.java @@ -24,18 +24,25 @@ import java.util.Map; import java.util.Map.Entry; import org.activiti.engine.delegate.DelegateTask; -import org.activiti.engine.impl.pvm.delegate.TaskListener; +import org.activiti.engine.delegate.TaskListener; import org.alfresco.model.ContentModel; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.workflow.activiti.ActivitiScriptNode; import org.alfresco.repo.workflow.activiti.script.ActivitiScriptBase; import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.ScriptService; /** - * A {@link TaskListener} that runs the script in property 'script' - * using scripting-language specified by 'language' - * + * A {@link TaskListener} that runs the script against the {@link ScriptService}. + * + * The script that is executed can be set using field 'script'. A non-default + * script-processor can be set in the field 'scriptProcessor'. Optionally, you can run + * the script as a different user than the default by setting the field 'runAs'. + * By default, the user this script is executed with is the task's assignee. If no + * assignee is set, the current logged-in user is used. If no user is currently logged in + * (eg. flow triggered by timer) the system user will be used instead. + * * @author Frederik Heremans * @since 3.4.e */ diff --git a/source/java/org/alfresco/repo/workflow/activiti/tasklistener/TaskCompleteListener.java b/source/java/org/alfresco/repo/workflow/activiti/tasklistener/TaskCompleteListener.java index cb23755e52..2d6fec5cd5 100644 --- a/source/java/org/alfresco/repo/workflow/activiti/tasklistener/TaskCompleteListener.java +++ b/source/java/org/alfresco/repo/workflow/activiti/tasklistener/TaskCompleteListener.java @@ -25,9 +25,9 @@ import java.util.List; import java.util.Map; import org.activiti.engine.delegate.DelegateTask; -import org.activiti.engine.impl.pvm.delegate.TaskListener; -import org.activiti.engine.impl.task.IdentityLinkEntity; -import org.activiti.engine.impl.task.TaskEntity; +import org.activiti.engine.delegate.TaskListener; +import org.activiti.engine.impl.persistence.entity.IdentityLinkEntity; +import org.activiti.engine.impl.persistence.entity.TaskEntity; import org.activiti.engine.task.IdentityLink; import org.alfresco.repo.workflow.WorkflowModel; import org.alfresco.repo.workflow.WorkflowQNameConverter; diff --git a/source/java/org/alfresco/repo/workflow/activiti/tasklistener/TaskCreateListener.java b/source/java/org/alfresco/repo/workflow/activiti/tasklistener/TaskCreateListener.java index 766db7ecde..cdab33c3fb 100644 --- a/source/java/org/alfresco/repo/workflow/activiti/tasklistener/TaskCreateListener.java +++ b/source/java/org/alfresco/repo/workflow/activiti/tasklistener/TaskCreateListener.java @@ -20,10 +20,10 @@ package org.alfresco.repo.workflow.activiti.tasklistener; import org.activiti.engine.delegate.DelegateTask; +import org.activiti.engine.delegate.TaskListener; import org.activiti.engine.form.FormData; import org.activiti.engine.impl.form.TaskFormHandler; -import org.activiti.engine.impl.pvm.delegate.TaskListener; -import org.activiti.engine.impl.task.TaskEntity; +import org.activiti.engine.impl.persistence.entity.TaskEntity; import org.alfresco.repo.workflow.activiti.ActivitiConstants; import org.alfresco.repo.workflow.activiti.properties.ActivitiPropertyConverter;