/** * Copyright (c) 2015 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * <p/> * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * <p/> * http://www.apache.org/licenses/LICENSE-2.0 * <p/> * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.wso2.carbon.bpmn.rest.service.runtime; import com.fasterxml.jackson.databind.ObjectMapper; import org.activiti.engine.*; import org.activiti.engine.history.HistoricTaskInstance; import org.activiti.engine.impl.persistence.entity.TaskEntity; import org.activiti.engine.impl.persistence.entity.VariableInstanceEntity; import org.activiti.engine.task.*; import org.apache.commons.io.IOUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.cxf.jaxrs.ext.multipart.MultipartBody; import org.wso2.carbon.bpmn.rest.common.RequestUtil; import org.wso2.carbon.bpmn.rest.common.RestResponseFactory; import org.wso2.carbon.bpmn.rest.common.RestUrls; import org.wso2.carbon.bpmn.rest.common.exception.BPMNConflictException; import org.wso2.carbon.bpmn.rest.common.exception.BPMNForbiddenException; import org.wso2.carbon.bpmn.rest.common.utils.BPMNOSGIService; import org.wso2.carbon.bpmn.rest.common.utils.Utils; import org.wso2.carbon.bpmn.rest.engine.variable.RestVariable; import org.wso2.carbon.bpmn.rest.model.common.DataResponse; import org.wso2.carbon.bpmn.rest.model.common.RestIdentityLink; import org.wso2.carbon.bpmn.rest.model.runtime.*; import org.wso2.carbon.bpmn.rest.service.base.BaseTaskService; import javax.activation.DataHandler; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.ws.rs.*; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Unmarshaller; import java.io.*; import java.util.*; @Path("/tasks") public class WorkflowTaskService extends BaseTaskService { private static final Log log = LogFactory.getLog(WorkflowTaskService.class); @Context UriInfo uriInfo; @GET @Path("/") @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Response getTasks() { // Create a Task query request TaskQueryRequest request = new TaskQueryRequest(); Map<String, String> requestParams = new HashMap<>(); for (String property : allPropertiesList) { String value = uriInfo.getQueryParameters().getFirst(property); if (value != null) { requestParams.put(property, value); } } // Populate filter-parameters if (requestParams.containsKey("name")) { request.setName(requestParams.get("name")); } if (requestParams.containsKey("nameLike")) { request.setNameLike(requestParams.get("nameLike")); } if (requestParams.containsKey("description")) { request.setDescription(requestParams.get("description")); } if (requestParams.containsKey("descriptionLike")) { request.setDescriptionLike(requestParams.get("descriptionLike")); } if (requestParams.containsKey("priority")) { request.setPriority(Integer.valueOf(requestParams.get("priority"))); } if (requestParams.containsKey("minimumPriority")) { request.setMinimumPriority(Integer.valueOf(requestParams.get("minimumPriority"))); } if (requestParams.containsKey("maximumPriority")) { request.setMaximumPriority(Integer.valueOf(requestParams.get("maximumPriority"))); } if (requestParams.containsKey("assignee")) { request.setAssignee(requestParams.get("assignee")); } if (requestParams.containsKey("owner")) { request.setOwner(requestParams.get("owner")); } if (requestParams.containsKey("unassigned")) { request.setUnassigned(Boolean.valueOf(requestParams.get("unassigned"))); } if (requestParams.containsKey("delegationState")) { request.setDelegationState(requestParams.get("delegationState")); } if (requestParams.containsKey("candidateUser")) { request.setCandidateUser(requestParams.get("candidateUser")); } if (requestParams.containsKey("involvedUser")) { request.setInvolvedUser(requestParams.get("involvedUser")); } if (requestParams.containsKey("candidateGroup")) { request.setCandidateGroup(requestParams.get("candidateGroup")); } if (requestParams.containsKey("candidateGroups")) { String[] candidateGroups = requestParams.get("candidateGroups").split(","); List<String> groups = new ArrayList<String>(candidateGroups.length); for (String candidateGroup : candidateGroups) { groups.add(candidateGroup); } request.setCandidateGroupIn(groups); } if (requestParams.containsKey("processDefinitionKey")) { request.setProcessDefinitionKey(requestParams.get("processDefinitionKey")); } if (requestParams.containsKey("processDefinitionKeyLike")) { request.setProcessDefinitionKeyLike(requestParams.get("processDefinitionKeyLike")); } if (requestParams.containsKey("processDefinitionName")) { request.setProcessDefinitionName(requestParams.get("processDefinitionName")); } if (requestParams.containsKey("processDefinitionNameLike")) { request.setProcessDefinitionNameLike(requestParams.get("processDefinitionNameLike")); } if (requestParams.containsKey("processInstanceId")) { request.setProcessInstanceId(requestParams.get("processInstanceId")); } if (requestParams.containsKey("processInstanceBusinessKey")) { request.setProcessInstanceBusinessKey(requestParams.get("processInstanceBusinessKey")); } if (requestParams.containsKey("executionId")) { request.setExecutionId(requestParams.get("executionId")); } if (requestParams.containsKey("createdOn")) { request.setCreatedOn(RequestUtil.getDate(requestParams, "createdOn")); } if (requestParams.containsKey("createdBefore")) { request.setCreatedBefore(RequestUtil.getDate(requestParams, "createdBefore")); } if (requestParams.containsKey("createdAfter")) { request.setCreatedAfter(RequestUtil.getDate(requestParams, "createdAfter")); } if (requestParams.containsKey("excludeSubTasks")) { request.setExcludeSubTasks(Boolean.valueOf(requestParams.get("excludeSubTasks"))); } if (requestParams.containsKey("taskDefinitionKey")) { request.setTaskDefinitionKey(requestParams.get("taskDefinitionKey")); } if (requestParams.containsKey("taskDefinitionKeyLike")) { request.setTaskDefinitionKeyLike(requestParams.get("taskDefinitionKeyLike")); } if (requestParams.containsKey("dueDate")) { request.setDueDate(RequestUtil.getDate(requestParams, "dueDate")); } if (requestParams.containsKey("dueBefore")) { request.setDueBefore(RequestUtil.getDate(requestParams, "dueBefore")); } if (requestParams.containsKey("dueAfter")) { request.setDueAfter(RequestUtil.getDate(requestParams, "dueAfter")); } if (requestParams.containsKey("active")) { request.setActive(Boolean.valueOf(requestParams.get("active"))); } if (requestParams.containsKey("includeTaskLocalVariables")) { request.setIncludeTaskLocalVariables(Boolean.valueOf(requestParams.get("includeTaskLocalVariables"))); } if (requestParams.containsKey("includeProcessVariables")) { request.setIncludeProcessVariables(Boolean.valueOf(requestParams.get("includeProcessVariables"))); } if (requestParams.containsKey("tenantId")) { request.setTenantId(requestParams.get("tenantId")); } if (requestParams.containsKey("tenantIdLike")) { request.setTenantIdLike(requestParams.get("tenantIdLike")); } if (requestParams.containsKey("withoutTenantId") && Boolean.valueOf(requestParams.get("withoutTenantId"))) { request.setWithoutTenantId(Boolean.TRUE); } if (requestParams.containsKey("candidateOrAssigned")) { request.setCandidateOrAssigned(requestParams.get("candidateOrAssigned")); } DataResponse dataResponse = getTasksFromQueryRequest(request, uriInfo, requestParams); return Response.ok().entity(dataResponse).build(); //return getTasksFromQueryRequest(request, requestParams); } /** * Create a new task instance for a process instance. * @param taskRequest * @return */ @POST @Path("/") @Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Response createTask(TaskRequest taskRequest) { TaskService taskService = BPMNOSGIService.getTaskService(); Task task = taskService.newTask(); // Populate the task properties based on the request populateTaskFromRequest(task, taskRequest); if (taskRequest.isTenantIdSet()) { ((TaskEntity) task).setTenantId(taskRequest.getTenantId()); } taskService.saveTask(task); return Response.ok().entity(new RestResponseFactory().createTaskResponse(task, uriInfo.getBaseUri().toString())).build(); } @GET @Path("/{taskId}") @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Response getTask(@PathParam("taskId") String taskId) { TaskResponse taskResponse = new RestResponseFactory().createTaskResponse(getTaskFromRequest(taskId), uriInfo .getBaseUri() .toString()); return Response.ok().entity(taskResponse).build(); } @PUT @Path("/{taskId}") @Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Response updateTask(@PathParam("taskId") String taskId, TaskRequest taskRequest) { if (taskRequest == null) { throw new ActivitiException("A request body was expected when updating the task."); } Task task = getTaskFromRequest(taskId); // Populate the task properties based on the request populateTaskFromRequest(task, taskRequest); TaskService taskService = BPMNOSGIService.getTaskService(); // Save the task and fetch agian, it's possible that an assignment-listener has updated // fields after it was saved so we can't use the in-memory task taskService.saveTask(task); task = taskService.createTaskQuery().taskId(task.getId()).singleResult(); return Response.ok().entity(new RestResponseFactory().createTaskResponse(task, uriInfo.getBaseUri().toString())).build(); } @POST @Path("/{taskId}") @Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Response executeTaskAction(@PathParam("taskId") String taskId, TaskActionRequest actionRequest) { if (actionRequest == null) { throw new ActivitiException("A request body was expected when executing a task action."); } Task task = getTaskFromRequest(taskId); TaskService taskService = BPMNOSGIService.getTaskService(); if (TaskActionRequest.ACTION_COMPLETE.equals(actionRequest.getAction())) { completeTask(task, actionRequest, taskService); } else if (TaskActionRequest.ACTION_CLAIM.equals(actionRequest.getAction())) { claimTask(task, actionRequest, taskService); } else if (TaskActionRequest.ACTION_DELEGATE.equals(actionRequest.getAction())) { delegateTask(task, actionRequest, taskService); } else if (TaskActionRequest.ACTION_RESOLVE.equals(actionRequest.getAction())) { resolveTask(task, taskService); } else { throw new ActivitiIllegalArgumentException("Invalid action: '" + actionRequest.getAction() + "'."); } return Response.ok().status(Response.Status.OK).build(); } @DELETE @Path("/{taskId}") public Response deleteTask(@PathParam("taskId") String taskId) { Boolean cascadeHistory = false; if (uriInfo.getQueryParameters().getFirst("cascadeHistory") != null) { cascadeHistory = Boolean.valueOf(uriInfo.getQueryParameters().getFirst("cascadeHistory")); } String deleteReason = uriInfo.getQueryParameters().getFirst("deleteReason"); Task taskToDelete = getTaskFromRequest(taskId); if (taskToDelete.getExecutionId() != null) { // Can't delete a task that is part of a process instance throw new BPMNForbiddenException("Cannot delete a task that is part of a process-instance."); } TaskService taskService = BPMNOSGIService.getTaskService(); if (cascadeHistory != null) { // Ignore delete-reason since the task-history (where the reason is recorded) will be deleted anyway taskService.deleteTask(taskToDelete.getId(), cascadeHistory); } else { // Delete with delete-reason taskService.deleteTask(taskToDelete.getId(), deleteReason); } return Response.ok().status(Response.Status.NO_CONTENT).build(); } @GET @Path("/{taskId}/variables") @Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Response getVariables(@PathParam("taskId") String taskId) { String scope = uriInfo.getQueryParameters().getFirst("scope"); List<RestVariable> result = new ArrayList<>(); Map<String, RestVariable> variableMap = new HashMap<String, RestVariable>(); // Check if it's a valid task to get the variables for Task task = getTaskFromRequest(taskId); RestVariable.RestVariableScope variableScope = RestVariable.getScopeFromString(scope); if (variableScope == null) { // Use both local and global variables addLocalVariables(task, variableMap, uriInfo.getBaseUri().toString()); addGlobalVariables(task, variableMap, uriInfo.getBaseUri().toString()); } else if (variableScope == RestVariable.RestVariableScope.GLOBAL) { addGlobalVariables(task, variableMap, uriInfo.getBaseUri().toString()); } else if (variableScope == RestVariable.RestVariableScope.LOCAL) { addLocalVariables(task, variableMap, uriInfo.getBaseUri().toString()); } // Get unique variables from map result.addAll(variableMap.values()); RestVariableCollection restVariableCollection = new RestVariableCollection(); restVariableCollection.setRestVariables(result); return Response.ok().entity(restVariableCollection).build(); } @GET @Path("/{taskId}/variables/{variableName}") @Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public RestVariable getVariable(@PathParam("taskId") String taskId, @PathParam("variableName") String variableName) { String scope = uriInfo.getQueryParameters().getFirst("scope"); return getVariableFromRequest(taskId, variableName, scope, false, uriInfo.getBaseUri().toString()); } @GET @Path("/{taskId}/variables/{variableName}/data") @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Response getVariableData(@PathParam("taskId") String taskId, @PathParam("variableName") String variableName) { String scope = uriInfo.getQueryParameters().getFirst("scope"); Response.ResponseBuilder responseBuilder = Response.ok(); try { byte[] result = null; RestVariable variable = getVariableFromRequest(taskId, variableName, scope, true, uriInfo.getBaseUri().toString()); if (RestResponseFactory.BYTE_ARRAY_VARIABLE_TYPE.equals(variable.getType())) { result = (byte[]) variable.getValue(); responseBuilder.type(MediaType.APPLICATION_OCTET_STREAM); } else if (RestResponseFactory.SERIALIZABLE_VARIABLE_TYPE.equals(variable.getType())) { ByteArrayOutputStream buffer = new ByteArrayOutputStream(); ObjectOutputStream outputStream = new ObjectOutputStream(buffer); outputStream.writeObject(variable.getValue()); outputStream.close(); result = buffer.toByteArray(); responseBuilder.type("application/x-java-serialized-object"); } else { throw new ActivitiObjectNotFoundException("The variable does not have a binary data stream.", null); } return responseBuilder.entity(result).build(); } catch (IOException ioe) { // Re-throw IOException throw new ActivitiException("Unexpected error getting variable data", ioe); } } @POST @Path("/{taskId}/variables") @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) @Consumes(MediaType.MULTIPART_FORM_DATA) public Response createBinaryTaskVariable(@PathParam("taskId") String taskId, MultipartBody multipartBody) { Task task = getTaskFromRequest(taskId); Object result = null; try { result = setBinaryVariable(multipartBody, task, true, uriInfo); } catch (IOException e) { throw new ActivitiIllegalArgumentException("Error Reading variable attachment", e); } if (result != null) { return Response.ok().status(Response.Status.CREATED).build(); } else { throw new ActivitiIllegalArgumentException("Binary Task variable creation failed"); } } @POST @Path("/{taskId}/variables") @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) @Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Response createTaskVariable(@PathParam("taskId") String taskId, @Context HttpServletRequest httpServletRequest) { Task task = getTaskFromRequest(taskId); List<RestVariable> inputVariables = new ArrayList<>(); List<RestVariable> resultVariables = new ArrayList<>(); Response.ResponseBuilder responseBuilder = Response.ok(); try { if (Utils.isApplicationJsonRequest(httpServletRequest)) { try { @SuppressWarnings("unchecked") List<Object> variableObjects = (List<Object>) new ObjectMapper().readValue(httpServletRequest.getInputStream(), List.class); for (Object restObject : variableObjects) { RestVariable restVariable = new ObjectMapper().convertValue(restObject, RestVariable.class); inputVariables.add(restVariable); } } catch (IOException e) { throw new ActivitiIllegalArgumentException("request body could not be transformed to a RestVariable " + "instance.", e); } } else if (Utils.isApplicationXmlRequest(httpServletRequest)) { JAXBContext jaxbContext = null; try { jaxbContext = JAXBContext.newInstance(RestVariableCollection.class); Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller(); RestVariableCollection restVariableCollection = (RestVariableCollection) jaxbUnmarshaller. unmarshal(httpServletRequest.getInputStream()); if (restVariableCollection == null) { throw new ActivitiIllegalArgumentException("xml request body could not be transformed to a " + "RestVariable Collection instance."); } List<RestVariable> restVariableList = restVariableCollection.getRestVariables(); if (restVariableList.size() == 0) { throw new ActivitiIllegalArgumentException("xml request body could not identify any rest " + "variables to be updated"); } for (RestVariable restVariable : restVariableList) { inputVariables.add(restVariable); } } catch (JAXBException | IOException e) { throw new ActivitiIllegalArgumentException("xml request body could not be transformed to a " + "RestVariable instance.", e); } } } catch (Exception e) { throw new ActivitiIllegalArgumentException("Failed to serialize to a RestVariable instance", e); } if (inputVariables.size() == 0) { throw new ActivitiIllegalArgumentException("Request didn't contain a list of variables to create."); } RestVariable.RestVariableScope sharedScope = null; RestVariable.RestVariableScope varScope = null; Map<String, Object> variablesToSet = new HashMap<>(); RestResponseFactory restResponseFactory = new RestResponseFactory(); for (RestVariable var : inputVariables) { // Validate if scopes match varScope = var.getVariableScope(); if (var.getName() == null) { throw new ActivitiIllegalArgumentException("Variable name is required"); } if (varScope == null) { varScope = RestVariable.RestVariableScope.LOCAL; } if (sharedScope == null) { sharedScope = varScope; } if (varScope != sharedScope) { throw new ActivitiIllegalArgumentException("Only allowed to update multiple variables in the same scope."); } if (hasVariableOnScope(task, var.getName(), varScope)) { throw new BPMNConflictException("Variable '" + var.getName() + "' is already present on task '" + task.getId() + "'."); } Object actualVariableValue = restResponseFactory.getVariableValue(var); variablesToSet.put(var.getName(), actualVariableValue); resultVariables.add(restResponseFactory.createRestVariable(var.getName(), actualVariableValue, varScope, task.getId(), RestResponseFactory.VARIABLE_TASK, false, uriInfo.getBaseUri().toString())); } RuntimeService runtimeService = BPMNOSGIService.getRuntimeService(); TaskService taskService = BPMNOSGIService.getTaskService(); if (!variablesToSet.isEmpty()) { if (sharedScope == RestVariable.RestVariableScope.LOCAL) { taskService.setVariablesLocal(task.getId(), variablesToSet); } else { if (task.getExecutionId() != null) { // Explicitly set on execution, setting non-local variables on task will override local-variables if exists runtimeService.setVariables(task.getExecutionId(), variablesToSet); } else { // Standalone task, no global variables possible throw new ActivitiIllegalArgumentException("Cannot set global variables on task '" + task.getId() + "', task is not part of process."); } } } RestVariableCollection restVariableCollection = new RestVariableCollection(); restVariableCollection.setRestVariables(resultVariables); responseBuilder.entity(restVariableCollection); return responseBuilder.status(Response.Status.CREATED).build(); } @PUT @Path("/{taskId}/variables/{variableName}") @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) @Consumes(MediaType.MULTIPART_FORM_DATA) public Response updateBinaryTaskVariable(@PathParam("taskId") String taskId, @PathParam("variableName") String variableName, MultipartBody multipartBody) { Task task = getTaskFromRequest(taskId); RestVariable result = null; try { result = setBinaryVariable(multipartBody, task, false, uriInfo); } catch (IOException e) { throw new ActivitiIllegalArgumentException("Error Reading variable attachment", e); } if (result != null) { if (!result.getName().equals(variableName)) { throw new ActivitiIllegalArgumentException("Variable name in the body should be equal to the name used in the requested URL."); } } return Response.ok().entity(result).build(); } @PUT @Path("/{taskId}/variables/{variableName}") @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) @Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Response updateTaskVariable(@PathParam("taskId") String taskId, @PathParam("variableName") String variableName, @Context HttpServletRequest httpServletRequest) { Task task = getTaskFromRequest(taskId); RestVariable restVariable = null; if (Utils.isApplicationJsonRequest(httpServletRequest)) { try { restVariable = new ObjectMapper().readValue(httpServletRequest.getInputStream(), RestVariable.class); } catch (Exception e) { throw new ActivitiIllegalArgumentException("Error converting request body to RestVariable instance", e); } } else if (Utils.isApplicationXmlRequest(httpServletRequest)) { JAXBContext jaxbContext = null; try { jaxbContext = JAXBContext.newInstance(RestVariable.class); Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller(); restVariable = (RestVariable) jaxbUnmarshaller. unmarshal(httpServletRequest.getInputStream()); } catch (JAXBException | IOException e) { throw new ActivitiIllegalArgumentException("xml request body could not be transformed to a " + "Rest Variable instance.", e); } } if (restVariable == null) { throw new ActivitiException("Invalid body was supplied"); } if (!restVariable.getName().equals(variableName)) { throw new ActivitiIllegalArgumentException("Variable name in the body should be equal to the name used in the requested URL."); } RestVariable result = setSimpleVariable(restVariable, task, false); return Response.ok().entity(result).build(); } @DELETE @Path("/{taskId}/variables/{variableName}") @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Response deleteVariable(@PathParam("taskId") String taskId, @PathParam("variableName") String variableName) { String scopeString = uriInfo.getQueryParameters().getFirst("scope"); Task task = getTaskFromRequest(taskId); // Determine scope RestVariable.RestVariableScope scope = RestVariable.RestVariableScope.LOCAL; if (scopeString != null) { scope = RestVariable.getScopeFromString(scopeString); } if (!hasVariableOnScope(task, variableName, scope)) { throw new ActivitiObjectNotFoundException("Task '" + task.getId() + "' doesn't have a variable '" + variableName + "' in scope " + scope.name().toLowerCase(), VariableInstanceEntity.class); } RuntimeService runtimeService = BPMNOSGIService.getRuntimeService(); TaskService taskService = BPMNOSGIService.getTaskService(); if (scope == RestVariable.RestVariableScope.LOCAL) { taskService.removeVariableLocal(task.getId(), variableName); } else { // Safe to use executionId, as the hasVariableOnScope whould have stopped a global-var update on standalone task runtimeService.removeVariable(task.getExecutionId(), variableName); } return Response.ok().status(Response.Status.NO_CONTENT).build(); } @DELETE @Path("/{taskId}/variables") @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Response deleteAllLocalTaskVariables(@PathParam("taskId") String taskId) { TaskService taskService = BPMNOSGIService.getTaskService(); Task task = getTaskFromRequest(taskId); Collection<String> currentVariables = taskService.getVariablesLocal(task.getId()).keySet(); taskService.removeVariablesLocal(task.getId(), currentVariables); return Response.ok().status(Response.Status.NO_CONTENT).build(); } @GET @Path("/{taskId}/identitylinks") @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Response getIdentityLinks(@PathParam("taskId") String taskId) { Task task = getTaskFromRequest(taskId); TaskService taskService = BPMNOSGIService.getTaskService(); List<RestIdentityLink> restIdentityLinks = new RestResponseFactory().createRestIdentityLinks(taskService.getIdentityLinksForTask(task.getId()), uriInfo.getBaseUri().toString()); RestIdentityLinkCollection restIdentityLinkCollection = new RestIdentityLinkCollection(); restIdentityLinkCollection.setRestIdentityLinks(restIdentityLinks); return Response.ok().entity(restIdentityLinkCollection).build(); } @GET @Path("/{taskId}/identitylinks/{family}") @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Response getIdentityLinksForFamily(@PathParam("taskId") String taskId, @PathParam("family") String family) { Task task = getTaskFromRequest(taskId); TaskService taskService = BPMNOSGIService.getTaskService(); if (family == null || (!RestUrls.SEGMENT_IDENTITYLINKS_FAMILY_GROUPS.equals(family) && !RestUrls.SEGMENT_IDENTITYLINKS_FAMILY_USERS.equals(family))) { throw new ActivitiIllegalArgumentException("Identity link family should be 'users' or 'groups'."); } boolean isUser = family.equals(RestUrls.SEGMENT_IDENTITYLINKS_FAMILY_USERS); List<RestIdentityLink> results = new ArrayList<RestIdentityLink>(); List<IdentityLink> allLinks = taskService.getIdentityLinksForTask(task.getId()); for (IdentityLink link : allLinks) { boolean match = false; if (isUser) { match = link.getUserId() != null; } else { match = link.getGroupId() != null; } if (match) { results.add(new RestResponseFactory().createRestIdentityLink(link, uriInfo.getBaseUri().toString())); } } RestIdentityLinkCollection restIdentityLinkCollection = new RestIdentityLinkCollection(); restIdentityLinkCollection.setRestIdentityLinks(results); return Response.ok().entity(restIdentityLinkCollection).build(); } @GET @Path("/{taskId}/identitylinks/{family}/{identityId}/{type}") @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Response getIdentityLink(@PathParam("taskId") String taskId, @PathParam("family") String family, @PathParam("identityId") String identityId, @PathParam("type") String type, @Context HttpServletRequest httpServletRequest) { Task task = getTaskFromRequest(taskId); validateIdentityLinkArguments(family, identityId, type); IdentityLink link = getIdentityLink(family, identityId, type, task.getId()); return Response.ok().entity(new RestResponseFactory().createRestIdentityLink(link, uriInfo.getBaseUri().toString())) .build(); } @DELETE @Path("/{taskId}/identitylinks/{family}/{identityId}/{type}") public Response deleteIdentityLink(@PathParam("taskId") String taskId, @PathParam("family") String family, @PathParam("identityId") String identityId, @PathParam("type") String type) { Task task = getTaskFromRequest(taskId); validateIdentityLinkArguments(family, identityId, type); // Check if identitylink to delete exists getIdentityLink(family, identityId, type, task.getId()); TaskService taskService = BPMNOSGIService.getTaskService(); if (RestUrls.SEGMENT_IDENTITYLINKS_FAMILY_USERS.equals(family)) { taskService.deleteUserIdentityLink(task.getId(), identityId, type); } else { taskService.deleteGroupIdentityLink(task.getId(), identityId, type); } return Response.ok().status(Response.Status.NO_CONTENT).build(); } @POST @Path("/{taskId}/identitylinks") @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Response createIdentityLink(@PathParam("taskId") String taskId, RestIdentityLink identityLink) { Task task = getTaskFromRequest(taskId); if (identityLink.getGroup() == null && identityLink.getUser() == null) { throw new ActivitiIllegalArgumentException("A group or a user is required to create an identity link."); } if (identityLink.getGroup() != null && identityLink.getUser() != null) { throw new ActivitiIllegalArgumentException("Only one of user or group can be used to create an identity link."); } if (identityLink.getType() == null) { throw new ActivitiIllegalArgumentException("The identity link type is required."); } TaskService taskService = BPMNOSGIService.getTaskService(); if (identityLink.getGroup() != null) { taskService.addGroupIdentityLink(task.getId(), identityLink.getGroup(), identityLink.getType()); } else { taskService.addUserIdentityLink(task.getId(), identityLink.getUser(), identityLink.getType()); } RestIdentityLink restIdentityLink = new RestResponseFactory().createRestIdentityLink(identityLink.getType(), identityLink.getUser(), identityLink.getGroup(), task.getId(), null, null, uriInfo.getBaseUri().toString()); return Response.ok().status(Response.Status.CREATED).entity(restIdentityLink).build(); } @POST @Path("/{taskId}/attachments") @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) @Consumes(MediaType.MULTIPART_FORM_DATA) public Response createAttachmentForBinary(@PathParam("taskId") String taskId, MultipartBody multipartBody, @Context HttpServletRequest httpServletRequest) { boolean debugEnabled = log.isDebugEnabled(); List<org.apache.cxf.jaxrs.ext.multipart.Attachment> attachments = multipartBody.getAllAttachments(); int attachmentSize = attachments.size(); if (attachmentSize <= 0) { throw new ActivitiIllegalArgumentException("No Attachments found with the request body"); } AttachmentDataHolder attachmentDataHolder = new AttachmentDataHolder(); for (int i = 0; i < attachmentSize; i++) { org.apache.cxf.jaxrs.ext.multipart.Attachment attachment = attachments.get(i); String contentDispositionHeaderValue = attachment.getHeader("Content-Disposition"); String contentType = attachment.getHeader("Content-Type"); if (debugEnabled) { log.debug("Going to iterate:" + i); log.debug("contentDisposition:" + contentDispositionHeaderValue); } if (contentDispositionHeaderValue != null) { contentDispositionHeaderValue = contentDispositionHeaderValue.trim(); Map<String, String> contentDispositionHeaderValueMap = Utils.processContentDispositionHeader (contentDispositionHeaderValue); String dispositionName = contentDispositionHeaderValueMap.get("name"); DataHandler dataHandler = attachment.getDataHandler(); OutputStream outputStream = null; if ("name".equals(dispositionName)) { try { outputStream = Utils.getAttachmentStream(dataHandler.getInputStream()); } catch (IOException e) { throw new ActivitiIllegalArgumentException("Attachment Name Reading error occured", e); } if (outputStream != null) { String fileName = outputStream.toString(); attachmentDataHolder.setName(fileName); } } else if ("type".equals(dispositionName)) { try { outputStream = Utils.getAttachmentStream(dataHandler.getInputStream()); } catch (IOException e) { throw new ActivitiIllegalArgumentException("Attachment Type Reading error occured", e); } if (outputStream != null) { String typeName = outputStream.toString(); attachmentDataHolder.setType(typeName); } } else if ("description".equals(dispositionName)) { try { outputStream = Utils.getAttachmentStream(dataHandler.getInputStream()); } catch (IOException e) { throw new ActivitiIllegalArgumentException("Attachment Description Reading error occured", e); } if (outputStream != null) { String description = outputStream.toString(); attachmentDataHolder.setDescription(description); } } if (contentType != null) { if ("file".equals(dispositionName)) { InputStream inputStream = null; try { inputStream = dataHandler.getInputStream(); } catch (IOException e) { throw new ActivitiIllegalArgumentException("Error Occured During processing empty body.", e); } if (inputStream != null) { attachmentDataHolder.setContentType(contentType); byte[] attachmentArray = new byte[0]; try { attachmentArray = IOUtils.toByteArray(inputStream); } catch (IOException e) { throw new ActivitiIllegalArgumentException("Processing Attachment Body Failed.", e); } attachmentDataHolder.setAttachmentArray(attachmentArray); } } } } } attachmentDataHolder.printDebug(); if (attachmentDataHolder.getName() == null) { throw new ActivitiIllegalArgumentException("Attachment name is required."); } if (attachmentDataHolder.getAttachmentArray() == null) { throw new ActivitiIllegalArgumentException("Empty attachment body was found in request body after " + "decoding the request" + "."); } TaskService taskService = BPMNOSGIService.getTaskService(); Task task = getTaskFromRequest(taskId); Response.ResponseBuilder responseBuilder = Response.ok(); AttachmentResponse result = null; try { InputStream inputStream = new ByteArrayInputStream(attachmentDataHolder.getAttachmentArray()); Attachment createdAttachment = taskService.createAttachment(attachmentDataHolder.getContentType(), task.getId(), task .getProcessInstanceId(), attachmentDataHolder.getName(), attachmentDataHolder .getDescription(), inputStream); responseBuilder.status(Response.Status.CREATED); result = new RestResponseFactory().createAttachmentResponse(createdAttachment, uriInfo.getBaseUri() .toString ()); } catch (Exception e) { throw new ActivitiException("Error creating attachment response", e); } return responseBuilder.status(Response.Status.CREATED).entity(result).build(); } @POST @Path("/{taskId}/attachments") @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) @Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Response createAttachmentForNonBinary(@PathParam("taskId") String taskId, @Context HttpServletRequest httpServletRequest, AttachmentRequest attachmentRequest) { AttachmentResponse result = null; Task task = getTaskFromRequest(taskId); Response.ResponseBuilder responseBuilder = Response.ok(); if (attachmentRequest == null) { throw new ActivitiIllegalArgumentException("AttachmentRequest properties not found in request"); } result = createSimpleAttachment(attachmentRequest, task); return responseBuilder.status(Response.Status.CREATED).entity(result).build(); } @GET @Path("/{taskId}/attachments") @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Response getAttachments(@PathParam("taskId") String taskId) { List<AttachmentResponse> result = new ArrayList<AttachmentResponse>(); HistoricTaskInstance task = getHistoricTaskFromRequest(taskId); TaskService taskService = BPMNOSGIService.getTaskService(); RestResponseFactory restResponseFactory = new RestResponseFactory(); String baseUri = uriInfo.getBaseUri().toString(); for (Attachment attachment : taskService.getProcessInstanceAttachments(task.getProcessInstanceId())) { result.add(restResponseFactory.createAttachmentResponse(attachment, baseUri)); } AttachmentResponseCollection attachmentResponseCollection = new AttachmentResponseCollection(); attachmentResponseCollection.setAttachmentResponseList(result); return Response.ok().entity(attachmentResponseCollection).build(); } @GET @Path("/{taskId}/attachments/{attachmentId}") @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Response getAttachment(@PathParam("taskId") String taskId, @PathParam("attachmentId") String attachmentId) { HistoricTaskInstance task = getHistoricTaskFromRequest(taskId); TaskService taskService = BPMNOSGIService.getTaskService(); Attachment attachment = taskService.getAttachment(attachmentId); if (attachment == null) { throw new ActivitiObjectNotFoundException("Task '" + task.getId() + "' doesn't have an attachment with id '" + attachmentId + "'.", Comment.class); } return Response.ok().entity(new RestResponseFactory().createAttachmentResponse(attachment, uriInfo.getBaseUri ().toString())).build(); } @DELETE @Path("/{taskId}/attachments/{attachmentId}") public Response deleteAttachment(@PathParam("taskId") String taskId, @PathParam("attachmentId") String attachmentId) { Task task = getTaskFromRequest(taskId); TaskService taskService = BPMNOSGIService.getTaskService(); Attachment attachment = taskService.getAttachment(attachmentId); if (attachment == null) { throw new ActivitiObjectNotFoundException("Task '" + task.getId() + "' doesn't have an attachment with id '" + attachmentId + "'.", Comment.class); } taskService.deleteAttachment(attachmentId); return Response.ok().status(Response.Status.NO_CONTENT).build(); } @GET @Path("/{taskId}/attachments/{attachmentId}/content") public Response getAttachmentContent(@PathParam("taskId") String taskId, @PathParam("attachmentId") String attachmentId) { TaskService taskService = BPMNOSGIService.getTaskService(); HistoricTaskInstance task = getHistoricTaskFromRequest(taskId); Attachment attachment = taskService.getAttachment(attachmentId); if (attachment == null) { throw new ActivitiObjectNotFoundException("Task '" + task.getId() + "' doesn't have an attachment with id '" + attachmentId + "'.", Attachment.class); } InputStream attachmentStream = taskService.getAttachmentContent(attachmentId); if (attachmentStream == null) { throw new ActivitiObjectNotFoundException("Attachment with id '" + attachmentId + "' doesn't have content associated with it.", Attachment.class); } Response.ResponseBuilder responseBuilder = Response.ok(); String type = attachment.getType(); MediaType mediaType = MediaType.valueOf(type); if (mediaType != null) { responseBuilder.type(mediaType); } else { responseBuilder.type("application/octet-stream"); } byte[] attachmentArray; try { attachmentArray = IOUtils.toByteArray(attachmentStream); } catch (IOException e) { throw new ActivitiException("Error creating attachment data", e); } String dispositionValue = "inline; filename=\"" + attachment.getName() + "\""; responseBuilder.header("Content-Disposition", dispositionValue); return responseBuilder.entity(attachmentArray).build(); } @GET @Path("/{taskId}/comments") @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Response getComments(@PathParam("taskId") String taskId) { HistoricTaskInstance task = getHistoricTaskFromRequest(taskId); TaskService taskService = BPMNOSGIService.getTaskService(); List<CommentResponse> commentResponseList = new RestResponseFactory().createRestCommentList(taskService .getTaskComments(task.getId()), uriInfo.getBaseUri().toString()); CommentResponseCollection commentResponseCollection = new CommentResponseCollection(); commentResponseCollection.setCommentResponseList(commentResponseList); return Response.ok().entity(commentResponseCollection).build(); } @POST @Path("/{taskId}/comments") @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) @Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Response createComment(@PathParam("taskId") String taskId, CommentRequest comment) { Task task = getTaskFromRequest(taskId); if (comment.getMessage() == null) { throw new ActivitiIllegalArgumentException("Comment text is required."); } String processInstanceId = null; TaskService taskService = BPMNOSGIService.getTaskService(); if (comment.isSaveProcessInstanceId()) { Task taskEntity = taskService.createTaskQuery().taskId(task.getId()).singleResult(); processInstanceId = taskEntity.getProcessInstanceId(); } Comment createdComment = taskService.addComment(task.getId(), processInstanceId, comment.getMessage()); CommentResponse commentResponse = new RestResponseFactory().createRestComment(createdComment, uriInfo .getBaseUri().toString()); return Response.ok().status(Response.Status.CREATED).entity(commentResponse).build(); } @GET @Path("/{taskId}/comments/{commentId}") @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Response getComment(@PathParam("taskId") String taskId, @PathParam("commentId") String commentId) { HistoricTaskInstance task = getHistoricTaskFromRequest(taskId); TaskService taskService = BPMNOSGIService.getTaskService(); Comment comment = taskService.getComment(commentId); if (comment == null || !task.getId().equals(comment.getTaskId())) { throw new ActivitiObjectNotFoundException("Task '" + task.getId() + "' doesn't have a comment with id '" + commentId + "'.", Comment.class); } return Response.ok().entity(new RestResponseFactory().createRestComment(comment, uriInfo.getBaseUri() .toString())).build(); } @DELETE @Path("/{taskId}/comments/{commentId}") @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Response deleteComment(@PathParam("taskId") String taskId, @PathParam("commentId") String commentId) { // Check if task exists Task task = getTaskFromRequest(taskId); TaskService taskService = BPMNOSGIService.getTaskService(); Comment comment = taskService.getComment(commentId); if (comment == null || comment.getTaskId() == null || !comment.getTaskId().equals(task.getId())) { throw new ActivitiObjectNotFoundException("Task '" + task.getId() + "' doesn't have a comment with id '" + commentId + "'.", Comment.class); } taskService.deleteComment(commentId); return Response.ok().status(Response.Status.NO_CONTENT).build(); } @GET @Path("/{taskId}/events") @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Response getEvents(@PathParam("taskId") String taskId) { HistoricTaskInstance task = getHistoricTaskFromRequest(taskId); TaskService taskService = BPMNOSGIService.getTaskService(); List<EventResponse> eventResponseList = new RestResponseFactory().createEventResponseList(taskService .getTaskEvents(task.getId()), uriInfo.getBaseUri().toString()); EventResponseCollection eventResponseCollection = new EventResponseCollection(); eventResponseCollection.setEventResponseList(eventResponseList); return Response.ok().entity(eventResponseCollection).build(); } @GET @Path("/{taskId}/events/{eventId}") @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Response getEvent(@PathParam("taskId") String taskId, @PathParam("eventId") String eventId) { HistoricTaskInstance task = getHistoricTaskFromRequest(taskId); TaskService taskService = BPMNOSGIService.getTaskService(); Event event = taskService.getEvent(eventId); if (event == null || !task.getId().equals(event.getTaskId())) { throw new ActivitiObjectNotFoundException("Task '" + task.getId() + "' doesn't have an event with id '" + eventId + "'.", Event.class); } EventResponse eventResponse = new RestResponseFactory().createEventResponse(event, uriInfo.getBaseUri() .toString()); return Response.ok().entity(eventResponse).build(); } @DELETE @Path("/{taskd}/events/{eventId}") public Response deleteEvent(@PathParam("taskId") String taskId, @PathParam("eventId") String eventId) { // Check if task exists Task task = getTaskFromRequest(taskId); TaskService taskService = BPMNOSGIService.getTaskService(); Event event = taskService.getEvent(eventId); if (event == null || event.getTaskId() == null || !event.getTaskId().equals(task.getId())) { throw new ActivitiObjectNotFoundException("Task '" + task.getId() + "' doesn't have an event with id '" + event + "'.", Event.class); } taskService.deleteComment(eventId); return Response.ok().status(Response.Status.NO_CONTENT).build(); } protected HistoricTaskInstance getHistoricTaskFromRequest(String taskId) { HistoryService historyService = BPMNOSGIService.getHistoryService(); HistoricTaskInstance task = historyService.createHistoricTaskInstanceQuery().taskId(taskId).singleResult(); if (task == null) { throw new ActivitiObjectNotFoundException("Could not find a task with id '" + taskId + "'.", Task.class); } return task; } protected AttachmentResponse createSimpleAttachment(AttachmentRequest attachmentRequest, Task task) { if (attachmentRequest.getName() == null) { throw new ActivitiIllegalArgumentException("Attachment name is required."); } TaskService taskService = BPMNOSGIService.getTaskService(); Attachment createdAttachment = taskService.createAttachment(attachmentRequest.getType(), task.getId(), task.getProcessInstanceId(), attachmentRequest.getName(), attachmentRequest.getDescription(), attachmentRequest.getExternalUrl()); return new RestResponseFactory().createAttachmentResponse(createdAttachment, uriInfo.getBaseUri().toString()); } /* protected AttachmentResponse createBinaryAttachment(HttpServletRequest httpServletRequest, Task task, Response.ResponseBuilder responseBuilder) throws IOException { String name = uriInfo.getQueryParameters().getFirst("name"); String description = uriInfo.getQueryParameters().getFirst("description"); String type = uriInfo.getQueryParameters().getFirst("type"); byte[] byteArray = Utils.processMultiPartFile(httpServletRequest, "Attachment content"); if (byteArray == null) { throw new ActivitiIllegalArgumentException("Empty attachment body was found in request body after " + "decoding the request" + "."); } if (name == null) { throw new ActivitiIllegalArgumentException("Attachment name is required."); } TaskService taskService = BPMNOSGIService.getTaskService(); try { InputStream inputStream = new ByteArrayInputStream(byteArray); Attachment createdAttachment = taskService.createAttachment(type, task.getId(), task.getProcessInstanceId(), name, description, inputStream); responseBuilder.status(Response.Status.CREATED); return new RestResponseFactory().createAttachmentResponse(createdAttachment, uriInfo.getBaseUri().toString()); } catch (Exception e) { throw new ActivitiException("Error creating attachment response", e); } }*/ protected IdentityLink getIdentityLink(String family, String identityId, String type, String taskId) { boolean isUser = family.equals(RestUrls.SEGMENT_IDENTITYLINKS_FAMILY_USERS); TaskService taskService = BPMNOSGIService.getTaskService(); // Perhaps it would be better to offer getting a single identitylink from the API List<IdentityLink> allLinks = taskService.getIdentityLinksForTask(taskId); for (IdentityLink link : allLinks) { boolean rightIdentity = false; if (isUser) { rightIdentity = identityId.equals(link.getUserId()); } else { rightIdentity = identityId.equals(link.getGroupId()); } if (rightIdentity && link.getType().equals(type)) { return link; } } throw new ActivitiObjectNotFoundException("Could not find the requested identity link.", IdentityLink.class); } protected void validateIdentityLinkArguments(String family, String identityId, String type) { if (family == null || (!RestUrls.SEGMENT_IDENTITYLINKS_FAMILY_GROUPS.equals(family) && !RestUrls.SEGMENT_IDENTITYLINKS_FAMILY_USERS.equals(family))) { throw new ActivitiIllegalArgumentException("Identity link family should be 'users' or 'groups'."); } if (identityId == null) { throw new ActivitiIllegalArgumentException("IdentityId is required."); } if (type == null) { throw new ActivitiIllegalArgumentException("Type is required."); } } protected RestVariable setSimpleVariable(RestVariable restVariable, Task task, boolean isNew) { if (restVariable.getName() == null) { throw new ActivitiIllegalArgumentException("Variable name is required"); } // Figure out scope, revert to local is omitted RestVariable.RestVariableScope scope = restVariable.getVariableScope(); if (scope == null) { scope = RestVariable.RestVariableScope.LOCAL; } RestResponseFactory restResponseFactory = new RestResponseFactory(); Object actualVariableValue = restResponseFactory.getVariableValue(restVariable); setVariable(task, restVariable.getName(), actualVariableValue, scope, isNew); return restResponseFactory.createRestVariable(restVariable.getName(), actualVariableValue, scope, task.getId(), RestResponseFactory.VARIABLE_TASK, false, uriInfo.getBaseUri().toString()); } protected void completeTask(Task task, TaskActionRequest actionRequest, TaskService taskService) { if (actionRequest.getVariables() != null) { Map<String, Object> variablesToSet = new HashMap<String, Object>(); RestResponseFactory restResponseFactory = new RestResponseFactory(); for (RestVariable var : actionRequest.getVariables()) { if (var.getName() == null) { throw new ActivitiIllegalArgumentException("Variable name is required"); } Object actualVariableValue = restResponseFactory.getVariableValue(var); variablesToSet.put(var.getName(), actualVariableValue); } taskService.complete(task.getId(), variablesToSet); } else { taskService.complete(task.getId()); } } protected void claimTask(Task task, TaskActionRequest actionRequest, TaskService taskService) { // In case the task is already claimed, a ActivitiTaskAlreadyClaimedException is thrown and converted to // a CONFLICT response by the ExceptionHandlerAdvice List list = taskService.createTaskQuery().taskId(task.getId()).taskCandidateUser(actionRequest.getAssignee()).list(); if (list == null || list.isEmpty()) {//user is not a candidate throw new BPMNForbiddenException("The user:" + actionRequest.getAssignee() + " is not a candidate user of this task"); } else { taskService.claim(task.getId(), actionRequest.getAssignee()); } } protected void delegateTask(Task task, TaskActionRequest actionRequest, TaskService taskService) { if (actionRequest.getAssignee() == null) { throw new ActivitiIllegalArgumentException("An assignee is required when delegating a task."); } taskService.delegateTask(task.getId(), actionRequest.getAssignee()); } protected void resolveTask(Task task, TaskService taskService) { taskService.resolveTask(task.getId()); } protected void populateTaskFromRequest(Task task, TaskRequest taskRequest) { if (taskRequest.isNameSet()) { task.setName(taskRequest.getName()); } if (taskRequest.isAssigneeSet()) { task.setAssignee(taskRequest.getAssignee()); } if (taskRequest.isDescriptionSet()) { task.setDescription(taskRequest.getDescription()); } if (taskRequest.isDuedateSet()) { task.setDueDate(taskRequest.getDueDate()); } if (taskRequest.isOwnerSet()) { task.setOwner(taskRequest.getOwner()); } if (taskRequest.isParentTaskIdSet()) { task.setParentTaskId(taskRequest.getParentTaskId()); } if (taskRequest.isPrioritySet()) { task.setPriority(taskRequest.getPriority()); } if (taskRequest.isCategorySet()) { task.setCategory(taskRequest.getCategory()); } if (taskRequest.isTenantIdSet()) { task.setTenantId(taskRequest.getTenantId()); } if (taskRequest.isFormKeySet()) { task.setFormKey(taskRequest.getFormKey()); } if (taskRequest.isDelegationStateSet()) { DelegationState delegationState = getDelegationState(taskRequest.getDelegationState()); task.setDelegationState(delegationState); } } }