diff --git a/source/java/org/alfresco/rest/workflow/api/impl/ProcessDefinitionsImpl.java b/source/java/org/alfresco/rest/workflow/api/impl/ProcessDefinitionsImpl.java index 35a05f3ea3..081f66b00a 100644 --- a/source/java/org/alfresco/rest/workflow/api/impl/ProcessDefinitionsImpl.java +++ b/source/java/org/alfresco/rest/workflow/api/impl/ProcessDefinitionsImpl.java @@ -30,7 +30,6 @@ import java.util.Set; import java.util.UUID; import org.activiti.engine.form.StartFormData; -import org.activiti.engine.impl.form.StartFormHandler; import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity; import org.activiti.engine.repository.ProcessDefinitionQuery; import org.alfresco.repo.i18n.MessageService; @@ -385,31 +384,12 @@ public class ProcessDefinitionsImpl extends WorkflowRestImpl implements ProcessD { try { - StartFormData startFormData = null; - ProcessDefinitionEntity definitionEntity = getCachedProcessDefinition(processDefinition.getId()); - if (definitionEntity != null) - { - StartFormHandler startFormHandler = definitionEntity.getStartFormHandler(); - if (startFormHandler == null) { - throw new ApiException("No start form defined for " + processDefinition.getId()); - } - - startFormData = startFormHandler.createStartFormData(definitionEntity); - } - else - { - startFormData = activitiProcessEngine.getFormService().getStartFormData(processDefinition.getId()); - } - + StartFormData startFormData = activitiProcessEngine.getFormService().getStartFormData(processDefinition.getId()); if (startFormData != null) { processDefinitionRest.setStartFormResourceKey(startFormData.getFormKey()); } } - catch (ApiException e) - { - throw e; - } catch (Exception e) { throw new ApiException("Error while retrieving start form key"); diff --git a/source/java/org/alfresco/rest/workflow/api/impl/ProcessesImpl.java b/source/java/org/alfresco/rest/workflow/api/impl/ProcessesImpl.java index d0a652f0c3..c1b284b429 100644 --- a/source/java/org/alfresco/rest/workflow/api/impl/ProcessesImpl.java +++ b/source/java/org/alfresco/rest/workflow/api/impl/ProcessesImpl.java @@ -100,13 +100,14 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes protected static String PROCESS_STATUS_ANY = "any"; protected static String PROCESS_STATUS_ACTIVE = "active"; protected static String PROCESS_STATUS_COMPLETED = "completed"; + protected static String PROCESS_STATUS_DELETED = "deleted"; protected static final Set PROCESS_STATUS_LIST = new HashSet(Arrays.asList( - PROCESS_STATUS_ANY, PROCESS_STATUS_ACTIVE, PROCESS_STATUS_COMPLETED + PROCESS_STATUS_ANY, PROCESS_STATUS_ACTIVE, PROCESS_STATUS_COMPLETED, PROCESS_STATUS_DELETED )); protected static final Set PROCESS_COLLECTION_EQUALS_QUERY_PROPERTIES = new HashSet(Arrays.asList( - "processDefinitionId", "businessKey", "processDefinitionKey", "startUserId", "status" + "processDefinitionId", "businessKey", "processDefinitionKey", "startUserId", "status", "includeVariables" )); protected static final Set PROCESS_COLLECTION_GREATERTHAN_QUERY_PROPERTIES = new HashSet(Arrays.asList( @@ -289,6 +290,7 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes 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) { @@ -343,6 +345,15 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes 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 variableProperties = propertyWalker.getVariableProperties(); @@ -457,9 +468,31 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes int totalCount = (int) query.count(); List page = new ArrayList(processInstances.size()); + Map definitionTypeMap = new HashMap(); for (HistoricProcessInstance processInstance: processInstances) { - page.add(createProcessInfo(processInstance)); + 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(), workflowFactory.getTaskFullTypeDefinition(formKey, true)); + } + } + + if (definitionTypeMap.containsKey(processInfo.getProcessDefinitionId())) + { + // Convert raw variables to Variable objects + List resultingVariables = restVariableHelper.getVariables( + processInstance.getProcessVariables(), definitionTypeMap.get(processInfo.getProcessDefinitionId())); + processInfo.setProcessVariables(resultingVariables); + } + } + page.add(processInfo); } return CollectionWithPagingInfo.asPaged(paging, page, page.size() != totalCount, totalCount); @@ -732,6 +765,17 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes public void deleteProcess(String id) { validateIfUserAllowedToWorkWithProcess(id); + + ProcessInstance processInstance = activitiProcessEngine.getRuntimeService() + .createProcessInstanceQuery() + .processInstanceId(id) + .singleResult(); + + if (processInstance == null) + { + throw new EntityNotFoundException(id); + } + activitiProcessEngine.getRuntimeService().deleteProcessInstance(id, "deleted through REST API call"); } @@ -1056,11 +1100,8 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes protected ProcessInfo createProcessInfo(HistoricProcessInstance processInstance) { ProcessInfo processInfo = new ProcessInfo(processInstance); - ProcessDefinition definitionEntity = getCachedProcessDefinition(processInstance.getProcessDefinitionId()); - if (definitionEntity == null) - { - definitionEntity = activitiProcessEngine.getRepositoryService().getProcessDefinition(processInstance.getProcessDefinitionId()); - } + ProcessDefinition definitionEntity = activitiProcessEngine.getRepositoryService() + .getProcessDefinition(processInstance.getProcessDefinitionId()); processInfo.setProcessDefinitionKey(getLocalProcessDefinitionKey(definitionEntity.getKey())); return processInfo; } diff --git a/source/java/org/alfresco/rest/workflow/api/impl/RestVariableHelper.java b/source/java/org/alfresco/rest/workflow/api/impl/RestVariableHelper.java index efbf94f97f..3182f7dee6 100644 --- a/source/java/org/alfresco/rest/workflow/api/impl/RestVariableHelper.java +++ b/source/java/org/alfresco/rest/workflow/api/impl/RestVariableHelper.java @@ -80,18 +80,19 @@ public class RestVariableHelper * @param typeDefinition the typê definition for this task, used to extract types. * @return list of {@link TaskVariable}, representing the given raw variables */ - public List getTaskVariables(Map localVariables, Map globalVariables, TypeDefinition typeDefinition) + public List getTaskVariables(Map localVariables, Map globalVariables, + TypeDefinition startFormTypeDefinition, TypeDefinition taskTypeDefinition) { List result = new ArrayList(); - TypeDefinitionContext context = new TypeDefinitionContext(typeDefinition); - if (localVariables != null) { + TypeDefinitionContext context = new TypeDefinitionContext(taskTypeDefinition); addTaskVariables(result, localVariables, context, VariableScope.LOCAL); } if (globalVariables != null) { + TypeDefinitionContext context = new TypeDefinitionContext(startFormTypeDefinition); addTaskVariables(result, globalVariables, context, VariableScope.GLOBAL); } @@ -129,7 +130,7 @@ public class RestVariableHelper /** * Converts the raw variables to {@link TaskVariable}s and adds them to the given result-list. */ - protected void addTaskVariables(List result, Map variables, + public void addTaskVariables(List result, Map variables, TypeDefinitionContext context, VariableScope scope) { TaskVariable variable = null; diff --git a/source/java/org/alfresco/rest/workflow/api/impl/TasksImpl.java b/source/java/org/alfresco/rest/workflow/api/impl/TasksImpl.java index c925d13a05..443e80ebf7 100644 --- a/source/java/org/alfresco/rest/workflow/api/impl/TasksImpl.java +++ b/source/java/org/alfresco/rest/workflow/api/impl/TasksImpl.java @@ -28,11 +28,10 @@ import java.util.Map; import java.util.Set; import org.activiti.engine.ActivitiTaskAlreadyClaimedException; +import org.activiti.engine.form.StartFormData; import org.activiti.engine.history.HistoricTaskInstance; import org.activiti.engine.history.HistoricTaskInstanceQuery; import org.activiti.engine.history.HistoricVariableInstance; -import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity; -import org.activiti.engine.impl.task.TaskDefinition; import org.activiti.engine.task.DelegationState; import org.activiti.engine.task.IdentityLink; import org.activiti.engine.task.IdentityLinkType; @@ -88,7 +87,8 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks private static final Set TASK_COLLECTION_EQUALS_QUERY_PROPERTIES = new HashSet(Arrays.asList( "status", "assignee", "owner", "candidateUser", "candidateGroup", "name", "description", "priority", "processId", - "processBusinessKey", "activityDefinitionId", "processDefinitionId", "processDefinitionName", "startedAt", "endedAt", "dueAt" + "processBusinessKey", "activityDefinitionId", "processDefinitionId", "processDefinitionName", "startedAt", "endedAt", "dueAt", + "includeTaskVariables", "includeProcessVariables" )); private static final Set TASK_COLLECTION_MATCHES_QUERY_PROPERTIES = new HashSet(Arrays.asList( @@ -183,6 +183,8 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks Date dueAt = propertyWalker.getProperty("dueAt", WhereClauseParser.EQUALS, Date.class); Date dueAtGreaterThan = propertyWalker.getProperty("dueAt", WhereClauseParser.GREATERTHAN, Date.class); Date dueAtLessThan = propertyWalker.getProperty("dueAt", WhereClauseParser.LESSTHAN, Date.class); + Boolean includeProcessVariables = propertyWalker.getProperty("includeProcessVariables", WhereClauseParser.EQUALS, Boolean.class); + Boolean includeTaskVariables = propertyWalker.getProperty("includeTaskVariables", WhereClauseParser.EQUALS, Boolean.class); List sortList = parameters.getSorting(); SortColumn sortColumn = null; @@ -254,6 +256,14 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks if (startedAtGreaterThan != null) query.taskCreatedAfter(startedAtGreaterThan); if (startedAtLessThan != null) query.taskCreatedBefore(startedAtLessThan); + if (includeProcessVariables != null && includeProcessVariables) { + query.includeProcessVariables(); + } + + if (includeTaskVariables != null && includeTaskVariables) { + query.includeTaskLocalVariables(); + } + List variableProperties = propertyWalker.getVariableProperties(); if (variableProperties != null) { @@ -305,7 +315,7 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks } // Add involvment filtering if user is not admin - if(!authorityService.isAdminAuthority(AuthenticationUtil.getRunAsUser())) { + if(processInstanceId == null && !authorityService.isAdminAuthority(AuthenticationUtil.getRunAsUser())) { query.taskInvolvedUser(AuthenticationUtil.getRunAsUser()); } @@ -315,10 +325,16 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks totalCount = (int) query.count(); page = new ArrayList(tasks.size()); + Map definitionTypeMap = new HashMap(); for (org.activiti.engine.task.Task taskInstance: tasks) { Task task = new Task(taskInstance); task.setFormResourceKey(getFormResourceKey(taskInstance)); + if ((includeProcessVariables != null && includeProcessVariables) || (includeTaskVariables != null && includeTaskVariables)) + { + addVariables(task, includeProcessVariables, includeTaskVariables, taskInstance.getProcessVariables(), + taskInstance.getTaskLocalVariables(), definitionTypeMap); + } page.add(task); } } @@ -368,6 +384,14 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks if (endedAtGreaterThan != null) query.taskCompletedAfter(endedAtGreaterThan); if (endedAtLessThan != null) query.taskCompletedBefore(endedAtLessThan); + if (includeProcessVariables != null && includeProcessVariables) { + query.includeProcessVariables(); + } + + if (includeTaskVariables != null && includeTaskVariables) { + query.includeTaskLocalVariables(); + } + List variableProperties = propertyWalker.getVariableProperties(); if (variableProperties != null) { @@ -420,7 +444,7 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks } // Add involvment filtering if user is not admin - if(!authorityService.isAdminAuthority(AuthenticationUtil.getRunAsUser())) + if(processInstanceId == null && !authorityService.isAdminAuthority(AuthenticationUtil.getRunAsUser())) { query.taskInvolvedUser(AuthenticationUtil.getRunAsUser()); } @@ -431,9 +455,15 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks totalCount = (int) query.count(); page = new ArrayList(tasks.size()); + Map definitionTypeMap = new HashMap(); for (HistoricTaskInstance taskInstance: tasks) { Task task = new Task(taskInstance); + if ((includeProcessVariables != null && includeProcessVariables) || (includeTaskVariables != null && includeTaskVariables)) + { + addVariables(task, includeProcessVariables, includeTaskVariables, taskInstance.getProcessVariables(), + taskInstance.getTaskLocalVariables(), definitionTypeMap); + } page.add(task); } } @@ -445,6 +475,39 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks return CollectionWithPagingInfo.asPaged(paging, page, page.size() != totalCount, totalCount); } + protected void addVariables(Task task, Boolean includeProcessVariables, Boolean includeTaskVariables, + Map processVariables, Map taskVariables, Map definitionTypeMap) + { + TypeDefinition startFormTypeDefinition = null; + if (includeProcessVariables != null && includeProcessVariables) + { + if (definitionTypeMap.containsKey(task.getProcessDefinitionId()) == false) + { + StartFormData startFormData = activitiProcessEngine.getFormService().getStartFormData(task.getProcessDefinitionId()); + if (startFormData != null) + { + String formKey = startFormData.getFormKey(); + definitionTypeMap.put(task.getProcessDefinitionId(), workflowFactory.getTaskFullTypeDefinition(formKey, true)); + } + } + + if (definitionTypeMap.containsKey(task.getProcessDefinitionId())) + { + startFormTypeDefinition = definitionTypeMap.get(task.getProcessDefinitionId()); + } + } + + TypeDefinition taskTypeDefinition = null; + if (includeTaskVariables != null && includeTaskVariables) + { + taskTypeDefinition = getWorkflowFactory().getTaskFullTypeDefinition(task.getFormResourceKey(), false); + } + + List variables = restVariableHelper.getTaskVariables(taskVariables, processVariables, + startFormTypeDefinition, taskTypeDefinition); + task.setVariables(variables); + } + @Override public CollectionWithPagingInfo getTasks(String processId, Parameters parameters) { @@ -501,11 +564,6 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks query.processVariableValueEquals(ActivitiConstants.VAR_TENANT_DOMAIN, TenantUtil.getCurrentDomain()); } - // Add involvment filtering if user is not admin - if(!authorityService.isAdminAuthority(AuthenticationUtil.getRunAsUser())) { - query.taskInvolvedUser(AuthenticationUtil.getRunAsUser()); - } - setSorting(query, sortColumn); List tasks = query.listPage(paging.getSkipCount(), paging.getMaxItems()); @@ -642,8 +700,29 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks else { // Perform actions associated to state transition - if (taskAction != null) { - switch (taskAction) { + if (taskAction != null) + { + // look for variables submitted with task action + Map globalVariables = new HashMap(); + Map localVariables = new HashMap(); + if (selectedProperties.contains("variables") && task.getVariables() != null && task.getVariables().size() > 0) + { + for (TaskVariable taskVariable : task.getVariables()) + { + taskVariable = convertToTypedVariable(taskVariable, taskInstance); + if (taskVariable.getVariableScope() == VariableScope.GLOBAL) + { + globalVariables.put(taskVariable.getName(), taskVariable.getValue()); + } + else + { + localVariables.put(taskVariable.getName(), taskVariable.getValue()); + } + } + } + + switch (taskAction) + { case CLAIMED: try { @@ -655,7 +734,19 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks } break; case COMPLETED: - activitiProcessEngine.getTaskService().complete(taskId); + if (localVariables.size() > 0) + { + activitiProcessEngine.getTaskService().setVariablesLocal(taskId, localVariables); + } + if (globalVariables.size() > 0) + { + activitiProcessEngine.getTaskService().complete(taskId, globalVariables); + } + else + { + activitiProcessEngine.getTaskService().complete(taskId); + } + break; case DELEGATED: if(selectedProperties.contains("assignee") && task.getAssignee() != null) @@ -673,7 +764,18 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks } break; case RESOLVED: - activitiProcessEngine.getTaskService().resolveTask(taskId); + if (localVariables.size() > 0) + { + activitiProcessEngine.getTaskService().setVariablesLocal(taskId, localVariables); + } + if (globalVariables.size() > 0) + { + activitiProcessEngine.getTaskService().resolveTask(taskId, globalVariables); + } + else + { + activitiProcessEngine.getTaskService().resolveTask(taskId); + } break; case UNCLAIMED: @@ -771,7 +873,20 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks } // Convert raw variables to TaskVariables - List page = restVariableHelper.getTaskVariables(taskvariables, processVariables, getWorkflowFactory().getTaskFullTypeDefinition(formKey, false)); + TypeDefinition taskTypeDefinition = getWorkflowFactory().getTaskFullTypeDefinition(formKey, false); + TypeDefinition startFormTypeDefinition = null; + StartFormData startFormData = activitiProcessEngine.getFormService().getStartFormData(taskInstance.getProcessDefinitionId()); + if (startFormData != null) + { + startFormTypeDefinition = workflowFactory.getTaskFullTypeDefinition(startFormData.getFormKey(), true); + } + else + { + // fall back + startFormTypeDefinition = taskTypeDefinition; + } + List page = restVariableHelper.getTaskVariables(taskvariables, processVariables, + startFormTypeDefinition, taskTypeDefinition); return CollectionWithPagingInfo.asPaged(paging, page, false, page.size()); } @@ -779,7 +894,7 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks public TaskVariable updateTaskVariable(String taskId, TaskVariable taskVariable) { org.activiti.engine.task.Task taskInstance = getValidTask(taskId); - return updateVariableInTask(taskId, taskInstance, taskVariable); + return updateVariableInTask(taskInstance, taskVariable); } public List updateTaskVariables(String taskId, List variables) @@ -790,20 +905,44 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks { for (TaskVariable variable : variables) { - updatedVariables.add(updateVariableInTask(taskId, taskInstance, variable)); + updatedVariables.add(updateVariableInTask(taskInstance, variable)); } } return updatedVariables; } - protected TaskVariable updateVariableInTask(String taskId, org.activiti.engine.task.Task taskInstance, TaskVariable taskVariable) + protected TaskVariable updateVariableInTask(org.activiti.engine.task.Task taskInstance, TaskVariable taskVariable) + { + taskVariable = convertToTypedVariable(taskVariable, taskInstance); + + if (VariableScope.LOCAL.equals(taskVariable.getVariableScope())) + { + activitiProcessEngine.getTaskService().setVariableLocal(taskInstance.getId(), taskVariable.getName(), taskVariable.getValue()); + } + else if(VariableScope.GLOBAL.equals(taskVariable.getVariableScope())) + { + if(taskInstance.getExecutionId() != null) + { + activitiProcessEngine.getRuntimeService().setVariable(taskInstance.getExecutionId(), taskVariable.getName(), taskVariable.getValue()); + } + else + { + throw new InvalidArgumentException("Cannot set global variables on a task that is not part of a process."); + } + } + + return taskVariable; + } + + protected TaskVariable convertToTypedVariable(TaskVariable taskVariable, org.activiti.engine.task.Task taskInstance) { if (taskVariable.getName() == null) { throw new InvalidArgumentException("Variable name is required."); } - if (taskVariable.getVariableScope() == null || taskVariable.getVariableScope() == VariableScope.ANY) + if (taskVariable.getVariableScope() == null || (taskVariable.getVariableScope() != VariableScope.GLOBAL && + taskVariable.getVariableScope() != VariableScope.LOCAL)) { throw new InvalidArgumentException("Variable scope is required and can only be 'local' or 'global'."); } @@ -872,26 +1011,12 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks { actualValue = DefaultTypeConverter.INSTANCE.convert(dataTypeDefinition, taskVariable.getValue()); } - taskVariable.setValue(actualValue); - if (VariableScope.LOCAL.equals(taskVariable.getVariableScope())) - { - activitiProcessEngine.getTaskService().setVariableLocal(taskId, taskVariable.getName(), actualValue); - } - else if(VariableScope.GLOBAL.equals(taskVariable.getVariableScope())) - { - if(taskInstance.getExecutionId() != null) - { - activitiProcessEngine.getRuntimeService().setVariable(taskInstance.getExecutionId(), taskVariable.getName(), actualValue); - } - else - { - throw new InvalidArgumentException("Cannot set global variables on a task that is not part of a process."); - } - } + taskVariable.setValue(actualValue); // Set type so it's returned in case it was left empty taskVariable.setType(dataTypeDefinition.getName().toPrefixString(namespaceService)); + return taskVariable; } @@ -987,22 +1112,7 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks { if (task.getProcessDefinitionId() != null) { - ProcessDefinitionEntity definitionEntity = getCachedProcessDefinition(task.getProcessDefinitionId()); - - String formKey = null; - if (definitionEntity != null) - { - TaskDefinition taskDefinition = definitionEntity.getTaskDefinitions().get(task.getTaskDefinitionKey()); - if (taskDefinition != null) - { - formKey = taskDefinition.getTaskFormHandler().getFormKey().getExpressionText(); - } - } - else - { - formKey = activitiProcessEngine.getFormService().getTaskFormKey(task.getProcessDefinitionId(), task.getTaskDefinitionKey()); - } - + String formKey = activitiProcessEngine.getFormService().getTaskFormKey(task.getProcessDefinitionId(), task.getTaskDefinitionKey()); return formKey; } else diff --git a/source/java/org/alfresco/rest/workflow/api/impl/WorkflowRestImpl.java b/source/java/org/alfresco/rest/workflow/api/impl/WorkflowRestImpl.java index 620610a16b..1379f323fb 100644 --- a/source/java/org/alfresco/rest/workflow/api/impl/WorkflowRestImpl.java +++ b/source/java/org/alfresco/rest/workflow/api/impl/WorkflowRestImpl.java @@ -17,13 +17,6 @@ import org.activiti.engine.ProcessEngine; import org.activiti.engine.history.HistoricTaskInstance; import org.activiti.engine.history.HistoricTaskInstanceQuery; import org.activiti.engine.history.HistoricVariableInstance; -import org.activiti.engine.impl.ProcessEngineImpl; -import org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl; -import org.activiti.engine.impl.context.Context; -import org.activiti.engine.impl.interceptor.Command; -import org.activiti.engine.impl.interceptor.CommandContext; -import org.activiti.engine.impl.persistence.deploy.DeploymentCache; -import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity; import org.alfresco.model.ContentModel; import org.alfresco.repo.dictionary.constraint.ListOfValuesConstraint; import org.alfresco.repo.security.authentication.AuthenticationUtil; @@ -326,32 +319,6 @@ public class WorkflowRestImpl } } - /** - * Get the process definition from the cache if available - * - * @param processDefinitionId the unique id identifier of the process definition - */ - public ProcessDefinitionEntity getCachedProcessDefinition(final String processDefinitionId) - { - ProcessEngineConfigurationImpl processConfig = (ProcessEngineConfigurationImpl) ((ProcessEngineImpl) activitiProcessEngine).getProcessEngineConfiguration(); - ProcessDefinitionEntity definitionEntity = processConfig.getCommandExecutorTxRequired().execute(new Command() - { - - @Override - public ProcessDefinitionEntity execute(CommandContext commandContext) - { - DeploymentCache cache = Context - .getProcessEngineConfiguration() - .getDeploymentManager() - .getProcessDefinitionCache(); - - return cache.get(processDefinitionId); - } - - }); - return definitionEntity; - } - /** * Get the first parameter value, converted to the requested type. * @param parameters used to extract parameter value from diff --git a/source/java/org/alfresco/rest/workflow/api/model/ProcessInfo.java b/source/java/org/alfresco/rest/workflow/api/model/ProcessInfo.java index 6efcb2ca89..054976c0b7 100644 --- a/source/java/org/alfresco/rest/workflow/api/model/ProcessInfo.java +++ b/source/java/org/alfresco/rest/workflow/api/model/ProcessInfo.java @@ -19,6 +19,7 @@ package org.alfresco.rest.workflow.api.model; import java.util.Date; +import java.util.List; import java.util.Map; import java.util.Set; @@ -42,6 +43,7 @@ public class ProcessInfo boolean completed; Map variables; + List processVariables; Set items; public ProcessInfo() @@ -204,6 +206,16 @@ public class ProcessInfo this.variables = variables; } + public List getProcessVariables() + { + return processVariables; + } + + public void setProcessVariables(List processVariables) + { + this.processVariables = processVariables; + } + public Set getItems() { return items; diff --git a/source/java/org/alfresco/rest/workflow/api/model/Task.java b/source/java/org/alfresco/rest/workflow/api/model/Task.java index 4ba083ab10..7c045f0ae0 100644 --- a/source/java/org/alfresco/rest/workflow/api/model/Task.java +++ b/source/java/org/alfresco/rest/workflow/api/model/Task.java @@ -19,6 +19,7 @@ package org.alfresco.rest.workflow.api.model; import java.util.Date; +import java.util.List; import org.activiti.engine.history.HistoricTaskInstance; import org.activiti.engine.task.DelegationState; @@ -40,6 +41,7 @@ public class Task String assignee; String formResourceKey; String state; + List variables; public Task() { @@ -255,4 +257,14 @@ public class Task { this.state = state; } + + public List getVariables() + { + return variables; + } + + public void setVariables(List variables) + { + this.variables = variables; + } } \ No newline at end of file diff --git a/source/test-java/org/alfresco/rest/workflow/api/tests/ProcessWorkflowApiTest.java b/source/test-java/org/alfresco/rest/workflow/api/tests/ProcessWorkflowApiTest.java index f47cbb0f1c..9a6f0dd080 100644 --- a/source/test-java/org/alfresco/rest/workflow/api/tests/ProcessWorkflowApiTest.java +++ b/source/test-java/org/alfresco/rest/workflow/api/tests/ProcessWorkflowApiTest.java @@ -43,6 +43,7 @@ import org.alfresco.rest.api.tests.client.PublicApiException; import org.alfresco.rest.api.tests.client.RequestContext; import org.alfresco.rest.api.tests.client.data.Document; import org.alfresco.rest.workflow.api.model.ProcessInfo; +import org.alfresco.rest.workflow.api.model.Variable; import org.alfresco.rest.workflow.api.tests.WorkflowApiClient.ProcessesClient; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.NodeRef; @@ -539,6 +540,16 @@ public class ProcessWorkflowApiTest extends EnterpriseWorkflowTestApi assertNotNull(deletedInstance); assertNotNull(deletedInstance.getEndTime()); assertEquals("deleted through REST API call", deletedInstance.getDeleteReason()); + + try + { + processesClient.deleteProcessById(process.getId()); + fail("expected exeception"); + } + catch (PublicApiException e) + { + assertEquals(HttpStatus.NOT_FOUND.value(), e.getHttpResponse().getStatusCode()); + } } finally { @@ -632,6 +643,7 @@ public class ProcessWorkflowApiTest extends EnterpriseWorkflowTestApi processList = processesClient.getProcesses(paramMap); assertNotNull(processList); assertEquals(3, processList.getList().size()); + assertNull(processList.getList().get(0).getProcessVariables()); paramMap = new HashMap(); paramMap.put("where", "(processDefinitionKey = 'activitiAdhoc2')"); @@ -730,6 +742,85 @@ public class ProcessWorkflowApiTest extends EnterpriseWorkflowTestApi processList = processesClient.getProcesses(paramMap); assertNotNull(processList); assertEquals(1, processList.getList().size()); + + // include process variables as well + paramMap = new HashMap(); + paramMap.put("where", "(processDefinitionKey = 'activitiAdhoc' AND includeVariables = true)"); + paramMap.put("maxItems", "1"); + paramMap.put("skipCount", "0"); + processList = processesClient.getProcesses(paramMap); + assertNotNull(processList); + + assertEquals(1, processList.getList().size()); + + ProcessInfo processInfo = processList.getList().get(0); + assertNotNull(processInfo.getProcessVariables()); + + boolean foundDescription = false; + boolean foundAssignee = false; + for (Variable variable : processInfo.getProcessVariables()) + { + if ("bpm_description".equals(variable.getName())) + { + assertEquals("d:text", variable.getType()); + assertNull(variable.getValue()); + foundDescription = true; + } + else if ("bpm_assignee".equals(variable.getName())) + { + assertEquals("cm:person", variable.getType()); + assertEquals(requestContext.getRunAsUser(), variable.getValue()); + foundAssignee = true; + } + } + + assertTrue(foundDescription); + assertTrue(foundAssignee); + + // include process variables with paging + paramMap = new HashMap(); + paramMap.put("where", "(processDefinitionKey = 'activitiAdhoc' AND includeVariables = true)"); + paramMap.put("maxItems", "3"); + paramMap.put("skipCount", "1"); + processList = processesClient.getProcesses(paramMap); + assertNotNull(processList); + + assertEquals(2, processList.getList().size()); + + processInfo = processList.getList().get(0); + assertNotNull(processInfo.getProcessVariables()); + + foundDescription = false; + foundAssignee = false; + for (Variable variable : processInfo.getProcessVariables()) + { + if ("bpm_description".equals(variable.getName())) + { + assertEquals("d:text", variable.getType()); + assertNull(variable.getValue()); + foundDescription = true; + } + else if ("bpm_assignee".equals(variable.getName())) + { + assertEquals("cm:person", variable.getType()); + assertEquals(requestContext.getRunAsUser(), variable.getValue()); + foundAssignee = true; + } + } + + assertTrue(foundDescription); + assertTrue(foundAssignee); + + // include process variables with paging outside boundaries + paramMap = new HashMap(); + paramMap.put("where", "(processDefinitionKey = 'activitiAdhoc' AND includeVariables = true)"); + paramMap.put("maxItems", "4"); + paramMap.put("skipCount", "5"); + processList = processesClient.getProcesses(paramMap); + assertNotNull(processList); + + assertEquals(0, processList.getList().size()); + } finally { @@ -885,6 +976,9 @@ public class ProcessWorkflowApiTest extends EnterpriseWorkflowTestApi tenantAdmin = AuthenticationUtil.getAdminUserName() + "@" + anotherNetwork.getId(); final RequestContext otherContext = new RequestContext(anotherNetwork.getId(), tenantAdmin); + String otherPerson = getOtherPersonInNetwork(requestContext.getRunAsUser(), requestContext.getNetworkId()).getId(); + RequestContext otherPersonContext = new RequestContext(requestContext.getNetworkId(), otherPerson); + final ProcessInfo process1 = startAdhocProcess(requestContext, null); try @@ -954,6 +1048,64 @@ public class ProcessWorkflowApiTest extends EnterpriseWorkflowTestApi { assertEquals(HttpStatus.FORBIDDEN.value(), e.getHttpResponse().getStatusCode()); } + + // get task with other not-involved person + publicApiClient.setRequestContext(otherPersonContext); + paramMap = new HashMap(); + try + { + tasksJSON = processesClient.getTasks(process1.getId(), paramMap); + fail("forbidden expected"); + } + catch (PublicApiException e) + { + assertEquals(HttpStatus.FORBIDDEN.value(), e.getHttpResponse().getStatusCode()); + } + + // involve other person and get task + final Task task = activitiProcessEngine.getTaskService().createTaskQuery(). + processInstanceId(process1.getId()) + .singleResult(); + + activitiProcessEngine.getTaskService().addCandidateUser(task.getId(), otherPersonContext.getRunAsUser()); + + publicApiClient.setRequestContext(otherPersonContext); + paramMap = new HashMap(); + tasksJSON = processesClient.getTasks(process1.getId(), paramMap); + assertNotNull(tasksJSON); + entriesJSON = (JSONArray) tasksJSON.get("entries"); + assertNotNull(entriesJSON); + assertTrue(entriesJSON.size() == 1); + + // complete task and get tasks + TenantUtil.runAsUserTenant(new TenantRunAsWork() + { + @Override + public Void doWork() throws Exception + { + activitiProcessEngine.getTaskService().complete(task.getId()); + return null; + } + }, requestContext.getRunAsUser(), requestContext.getNetworkId()); + + publicApiClient.setRequestContext(requestContext); + paramMap = new HashMap(); + paramMap.put("status", "any"); + tasksJSON = processesClient.getTasks(process1.getId(), paramMap); + assertNotNull(tasksJSON); + entriesJSON = (JSONArray) tasksJSON.get("entries"); + assertNotNull(entriesJSON); + assertTrue(entriesJSON.size() == 2); + + publicApiClient.setRequestContext(otherPersonContext); + paramMap = new HashMap(); + paramMap.put("status", "any"); + tasksJSON = processesClient.getTasks(process1.getId(), paramMap); + assertNotNull(tasksJSON); + entriesJSON = (JSONArray) tasksJSON.get("entries"); + assertNotNull(entriesJSON); + assertTrue(entriesJSON.size() == 2); + } finally { diff --git a/source/test-java/org/alfresco/rest/workflow/api/tests/ProcessesParser.java b/source/test-java/org/alfresco/rest/workflow/api/tests/ProcessesParser.java index 8c02647a45..2c3322e203 100644 --- a/source/test-java/org/alfresco/rest/workflow/api/tests/ProcessesParser.java +++ b/source/test-java/org/alfresco/rest/workflow/api/tests/ProcessesParser.java @@ -18,10 +18,14 @@ */ package org.alfresco.rest.workflow.api.tests; +import java.util.ArrayList; +import java.util.List; import java.util.Map; import java.util.Set; import org.alfresco.rest.workflow.api.model.ProcessInfo; +import org.alfresco.rest.workflow.api.model.Variable; +import org.json.simple.JSONArray; import org.json.simple.JSONObject; public class ProcessesParser extends ListParser @@ -48,6 +52,22 @@ public class ProcessesParser extends ListParser processesRest.setCompleted((Boolean) entry.get("completed")); processesRest.setVariables((Map) entry.get("variables")); processesRest.setItems((Set) entry.get("item")); + + if (entry.get("processVariables") != null) { + List processVariables = new ArrayList(); + JSONArray variables = (JSONArray) entry.get("processVariables"); + for (int i = 0; i < variables.size(); i++) + { + JSONObject variableJSON = (JSONObject) variables.get(i); + Variable variable = new Variable(); + variable.setName((String) variableJSON.get("name")); + variable.setType((String) variableJSON.get("type")); + variable.setValue(variableJSON.get("value")); + processVariables.add(variable); + } + processesRest.setProcessVariables(processVariables); + } + return processesRest; } } diff --git a/source/test-java/org/alfresco/rest/workflow/api/tests/TaskWorkflowApiTest.java b/source/test-java/org/alfresco/rest/workflow/api/tests/TaskWorkflowApiTest.java index 99521091af..4a5dbe4394 100644 --- a/source/test-java/org/alfresco/rest/workflow/api/tests/TaskWorkflowApiTest.java +++ b/source/test-java/org/alfresco/rest/workflow/api/tests/TaskWorkflowApiTest.java @@ -36,6 +36,7 @@ import java.util.Map; import java.util.Set; import java.util.UUID; +import org.activiti.engine.history.HistoricTaskInstance; import org.activiti.engine.impl.util.ClockUtil; import org.activiti.engine.runtime.ProcessInstance; import org.activiti.engine.task.DelegationState; @@ -698,12 +699,14 @@ public class TaskWorkflowApiTest extends EnterpriseWorkflowTestApi ProcessInstance processCompleteAsOwner = startAdhocProcess(initiator, requestContext.getNetworkId(), null); ProcessInstance processCompleteAsInitiator = startAdhocProcess(initiator, requestContext.getNetworkId(), null); ProcessInstance processCompleteAsAdmin = startAdhocProcess(initiator, requestContext.getNetworkId(), null); + ProcessInstance processCompleteWithVariables = startAdhocProcess(initiator, requestContext.getNetworkId(), null); try { Task asAssigneeTask = activitiProcessEngine.getTaskService().createTaskQuery().processInstanceId(processCompleteAsAssignee.getId()).singleResult(); Task asOwnerTask = activitiProcessEngine.getTaskService().createTaskQuery().processInstanceId(processCompleteAsOwner.getId()).singleResult(); Task asInitiatorTask = activitiProcessEngine.getTaskService().createTaskQuery().processInstanceId(processCompleteAsInitiator.getId()).singleResult(); Task asAdminTask = activitiProcessEngine.getTaskService().createTaskQuery().processInstanceId(processCompleteAsAdmin.getId()).singleResult(); + Task withVariablesTask = activitiProcessEngine.getTaskService().createTaskQuery().processInstanceId(processCompleteWithVariables.getId()).singleResult(); TasksClient tasksClient = publicApiClient.tasksClient(); // Unclaiming the task when NOT assignee, owner, initiator or admin results in error @@ -755,10 +758,69 @@ public class TaskWorkflowApiTest extends EnterpriseWorkflowTestApi assertEquals("completed", result.get("state")); assertNotNull(result.get("endedAt")); assertNull(activitiProcessEngine.getTaskService().createTaskQuery().taskId(asAdminTask.getId()).singleResult()); + + // Complete with variables + requestContext.setRunAsUser(initiator); + activitiProcessEngine.getTaskService().setAssignee(withVariablesTask.getId(), null); + + JSONArray variablesArray = new JSONArray(); + JSONObject variableBody = new JSONObject(); + variableBody.put("name", "newGlobalVariable"); + variableBody.put("value", 1234); + variableBody.put("scope", "global"); + variablesArray.add(variableBody); + variableBody = new JSONObject(); + variableBody.put("name", "newLocalVariable"); + variableBody.put("value", 5678); + variableBody.put("scope", "local"); + variablesArray.add(variableBody); + + taskBody.put("variables", variablesArray); + selectedFields.add("variables"); + result = tasksClient.updateTask(withVariablesTask.getId(), taskBody, selectedFields); + assertEquals("completed", result.get("state")); + assertNotNull(result.get("endedAt")); + assertNull(activitiProcessEngine.getTaskService().createTaskQuery().taskId(withVariablesTask.getId()).singleResult()); + HistoricTaskInstance historyTask = activitiProcessEngine.getHistoryService().createHistoricTaskInstanceQuery() + .taskId(withVariablesTask.getId()) + .includeProcessVariables() + .includeTaskLocalVariables() + .singleResult(); + + assertEquals(1234, historyTask.getProcessVariables().get("newGlobalVariable")); + assertEquals(5678, historyTask.getTaskLocalVariables().get("newLocalVariable")); + + JSONObject variables = tasksClient.findTaskVariables(withVariablesTask.getId()); + assertNotNull(variables); + JSONObject list = (JSONObject) variables.get("list"); + assertNotNull(list); + JSONArray entries = (JSONArray) list.get("entries"); + assertNotNull(entries); + + boolean foundGlobal = false; + boolean foundLocal = false; + for (Object entry : entries) + { + JSONObject variableObject = (JSONObject) ((JSONObject) entry).get("entry"); + if ("newGlobalVariable".equals(variableObject.get("name"))) + { + assertEquals(1234L, variableObject.get("value")); + foundGlobal = true; + } + else if ("newLocalVariable".equals(variableObject.get("name"))) + { + assertEquals(5678L, variableObject.get("value")); + foundLocal = true; + } + } + + assertTrue(foundGlobal); + assertTrue(foundLocal); } finally { - cleanupProcessInstance(processCompleteAsAssignee, processCompleteAsAdmin, processCompleteAsInitiator, processCompleteAsOwner); + cleanupProcessInstance(processCompleteAsAssignee, processCompleteAsAdmin, processCompleteAsInitiator, + processCompleteAsOwner, processCompleteWithVariables); } } @@ -1540,7 +1602,7 @@ public class TaskWorkflowApiTest extends EnterpriseWorkflowTestApi // Test with existing processDefinitionId Map params = new HashMap(); - params.put("processDefinitionId", processDefinitionId); + params.put("where", "(processDefinitionId = '" + processDefinitionId + "' AND includeProcessVariables = true AND includeTaskVariables = true)"); JSONObject taskListJSONObject = tasksClient.findTasks(params); assertNotNull(taskListJSONObject); JSONObject paginationJSON = (JSONObject) taskListJSONObject.get("pagination"); @@ -1550,11 +1612,12 @@ public class TaskWorkflowApiTest extends EnterpriseWorkflowTestApi assertEquals(false, paginationJSON.get("hasMoreItems")); JSONArray jsonEntries = (JSONArray) taskListJSONObject.get("entries"); assertEquals(6, jsonEntries.size()); + validateVariables((JSONObject) jsonEntries.get(0), requestContext); // Test with existing processDefinitionId and max items params.clear(); params.put("maxItems", "3"); - params.put("processDefinitionId", processDefinitionId); + params.put("where", "(processDefinitionId = '" + processDefinitionId + "' AND includeProcessVariables = true AND includeTaskVariables = true)"); taskListJSONObject = tasksClient.findTasks(params); assertNotNull(taskListJSONObject); paginationJSON = (JSONObject) taskListJSONObject.get("pagination"); @@ -1564,11 +1627,12 @@ public class TaskWorkflowApiTest extends EnterpriseWorkflowTestApi assertEquals(true, paginationJSON.get("hasMoreItems")); jsonEntries = (JSONArray) taskListJSONObject.get("entries"); assertEquals(3, jsonEntries.size()); + validateVariables((JSONObject) jsonEntries.get(0), requestContext); // Test with existing processDefinitionId and skip count params.clear(); params.put("skipCount", "2"); - params.put("processDefinitionId", processDefinitionId); + params.put("where", "(processDefinitionId = '" + processDefinitionId + "' AND includeProcessVariables = true AND includeTaskVariables = true)"); taskListJSONObject = tasksClient.findTasks(params); assertNotNull(taskListJSONObject); paginationJSON = (JSONObject) taskListJSONObject.get("pagination"); @@ -1583,7 +1647,7 @@ public class TaskWorkflowApiTest extends EnterpriseWorkflowTestApi params.clear(); params.put("maxItems", "3"); params.put("skipCount", "2"); - params.put("processDefinitionId", processDefinitionId); + params.put("where", "(processDefinitionId = '" + processDefinitionId + "' AND includeProcessVariables = true AND includeTaskVariables = true)"); taskListJSONObject = tasksClient.findTasks(params); assertNotNull(taskListJSONObject); paginationJSON = (JSONObject) taskListJSONObject.get("pagination"); @@ -1598,7 +1662,7 @@ public class TaskWorkflowApiTest extends EnterpriseWorkflowTestApi params.clear(); params.put("maxItems", "3"); params.put("skipCount", "4"); - params.put("processDefinitionId", processDefinitionId); + params.put("where", "(processDefinitionId = '" + processDefinitionId + "' AND includeProcessVariables = true AND includeTaskVariables = true)"); taskListJSONObject = tasksClient.findTasks(params); assertNotNull(taskListJSONObject); paginationJSON = (JSONObject) taskListJSONObject.get("pagination"); @@ -1615,6 +1679,48 @@ public class TaskWorkflowApiTest extends EnterpriseWorkflowTestApi } } + protected void validateVariables(JSONObject entry, RequestContext requestContext) { + JSONObject taskObject = (JSONObject) entry.get("entry"); + JSONArray variables = (JSONArray) taskObject.get("variables"); + boolean foundInitiator = false; + boolean foundAssignee = false; + boolean foundPercentageComplete = false; + boolean foundReassignable = false; + for (int i = 0; i < variables.size(); i++) + { + JSONObject variableJSON = (JSONObject) variables.get(i); + if ("initiator".equals(variableJSON.get("name"))) + { + assertEquals("d:noderef", variableJSON.get("type")); + assertEquals(requestContext.getRunAsUser(), variableJSON.get("value")); + foundInitiator = true; + } + else if ("bpm_assignee".equals(variableJSON.get("name"))) + { + assertEquals("cm:person", variableJSON.get("type")); + assertEquals(requestContext.getRunAsUser(), variableJSON.get("value")); + foundAssignee = true; + } + else if ("bpm_percentComplete".equals(variableJSON.get("name"))) + { + assertEquals("d:int", variableJSON.get("type")); + assertEquals(0L, variableJSON.get("value")); + foundPercentageComplete = true; + } + else if ("bpm_reassignable".equals(variableJSON.get("name"))) + { + assertEquals("d:boolean", variableJSON.get("type")); + assertEquals(Boolean.TRUE, variableJSON.get("value")); + foundReassignable = true; + } + } + + assertTrue(foundInitiator); + assertTrue(foundAssignee); + assertTrue(foundPercentageComplete); + assertTrue(foundReassignable); + } + @Test public void testGetTasksWithSorting() throws Exception { @@ -1956,14 +2062,9 @@ public class TaskWorkflowApiTest extends EnterpriseWorkflowTestApi assertEquals("d:text", var.get("type")); assertEquals("Not Yet Started", var.get("value")); - var = entriesByName.get("bpm_status"); - assertNotNull(var); - assertEquals("d:text", var.get("type")); - assertEquals("Not Yet Started", var.get("value")); - var = entriesByName.get("bpm_assignee"); assertNotNull(var); - assertEquals("d:noderef", var.get("type")); + assertEquals("cm:person", var.get("type")); final String userName = requestContext.getRunAsUser(); assertEquals(userName, var.get("value"));