/** * Copyright (c) 2015 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * * 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 * * http://www.apache.org/licenses/LICENSE-2.0 * * 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.base; import org.activiti.engine.ActivitiIllegalArgumentException; import org.activiti.engine.ActivitiObjectNotFoundException; import org.activiti.engine.RuntimeService; import org.activiti.engine.impl.ProcessInstanceQueryProperty; import org.activiti.engine.query.QueryProperty; import org.activiti.engine.runtime.Execution; import org.activiti.engine.runtime.ProcessInstance; import org.activiti.engine.runtime.ProcessInstanceQuery; import org.activiti.engine.task.IdentityLink; import org.wso2.carbon.bpmn.rest.common.RestResponseFactory; import org.wso2.carbon.bpmn.rest.common.exception.BPMNConflictException; import org.wso2.carbon.bpmn.rest.common.utils.BPMNOSGIService; import org.wso2.carbon.bpmn.rest.engine.variable.QueryVariable; import org.wso2.carbon.bpmn.rest.model.common.DataResponse; import org.wso2.carbon.bpmn.rest.model.runtime.ProcessInstancePaginateList; import org.wso2.carbon.bpmn.rest.model.runtime.ProcessInstanceQueryRequest; import org.wso2.carbon.bpmn.rest.model.runtime.ProcessInstanceResponse; import javax.ws.rs.core.UriInfo; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class BaseProcessInstanceService { protected static final String DEFAULT_ENCODING = "UTF-8"; protected static final List<String> allPropertiesList = new ArrayList<>(); protected static Map<String, QueryProperty> allowedSortProperties = new HashMap<>(); static { allPropertiesList.add("id"); allPropertiesList.add("processDefinitionKey"); allPropertiesList.add("processDefinitionId"); allPropertiesList.add("businessKey"); allPropertiesList.add("involvedUser"); allPropertiesList.add("suspended"); allPropertiesList.add("superProcessInstanceId"); allPropertiesList.add("subProcessInstanceId"); allPropertiesList.add("excludeSubprocesses"); allPropertiesList.add("includeProcessVariables"); allPropertiesList.add("tenantId"); allPropertiesList.add("tenantIdLike"); allPropertiesList.add("withoutTenantId"); allPropertiesList.add("sort"); allPropertiesList.add("start"); allPropertiesList.add("size"); allPropertiesList.add("order"); } static { allowedSortProperties.put("processDefinitionId", ProcessInstanceQueryProperty.PROCESS_DEFINITION_ID); allowedSortProperties.put("processDefinitionKey", ProcessInstanceQueryProperty.PROCESS_DEFINITION_KEY); allowedSortProperties.put("id", ProcessInstanceQueryProperty.PROCESS_INSTANCE_ID); allowedSortProperties.put("tenantId", ProcessInstanceQueryProperty.TENANT_ID); } protected Map<String, String> allRequestParams(UriInfo uriInfo){ Map<String, String> allRequestParams = new HashMap<>(); for (String property:allPropertiesList){ String value= uriInfo.getQueryParameters().getFirst(property); if(value != null){ allRequestParams.put(property, value); } } return allRequestParams; } protected ProcessInstance getProcessInstanceFromRequest(String processInstanceId) { RuntimeService runtimeService = BPMNOSGIService.getRuntimeService(); ProcessInstance processInstance = runtimeService.createProcessInstanceQuery(). processInstanceId(processInstanceId).includeProcessVariables().singleResult(); if (processInstance == null) { throw new ActivitiObjectNotFoundException(" Could not find a process instance with id " + processInstanceId + "'.", ProcessInstance.class); } return processInstance; } protected Execution getExecutionInstanceFromRequest(String processInstanceId) { RuntimeService runtimeService = BPMNOSGIService.getRuntimeService(); Execution execution = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult(); if (execution == null) { throw new ActivitiObjectNotFoundException("Could not find a process instance with id '" + processInstanceId + "'.", ProcessInstance.class); } return execution; } protected ProcessInstanceResponse activateProcessInstance(ProcessInstance processInstance, UriInfo uriInfo) { if (!processInstance.isSuspended()) { throw new BPMNConflictException("Process instance with id '" + processInstance.getId() + "' is already active."); } RuntimeService runtimeService = BPMNOSGIService.getRuntimeService(); runtimeService.activateProcessInstanceById(processInstance.getId()); ProcessInstanceResponse response = new RestResponseFactory().createProcessInstanceResponse(processInstance, uriInfo.getBaseUri().toString()); // No need to re-fetch the instance, just alter the suspended state of the result-object response.setSuspended(false); return response; } protected ProcessInstanceResponse suspendProcessInstance(ProcessInstance processInstance, RestResponseFactory restResponseFactory, UriInfo uriInfo) { if (processInstance.isSuspended()) { throw new BPMNConflictException("Process instance with id '" + processInstance.getId() + "' is already suspended."); } RuntimeService runtimeService = BPMNOSGIService.getRuntimeService(); runtimeService.suspendProcessInstanceById(processInstance.getId()); ProcessInstanceResponse response = restResponseFactory.createProcessInstanceResponse(processInstance, uriInfo .getBaseUri().toString()); // No need to re-fetch the instance, just alter the suspended state of the result-object response.setSuspended(true); return response; } protected DataResponse getQueryResponse(ProcessInstanceQueryRequest queryRequest, Map<String, String> requestParams, UriInfo uriInfo) { RuntimeService runtimeService = BPMNOSGIService.getRuntimeService(); ProcessInstanceQuery query = runtimeService.createProcessInstanceQuery(); // Populate query based on request if (queryRequest.getProcessInstanceId() != null) { query.processInstanceId(queryRequest.getProcessInstanceId()); } if (queryRequest.getProcessDefinitionKey() != null) { query.processDefinitionKey(queryRequest.getProcessDefinitionKey()); } if (queryRequest.getProcessDefinitionId() != null) { query.processDefinitionId(queryRequest.getProcessDefinitionId()); } if (queryRequest.getProcessBusinessKey() != null) { query.processInstanceBusinessKey(queryRequest.getProcessBusinessKey()); } if (queryRequest.getInvolvedUser() != null) { query.involvedUser(queryRequest.getInvolvedUser()); } if (queryRequest.getSuspended() != null) { if (queryRequest.getSuspended()) { query.suspended(); } else { query.active(); } } if (queryRequest.getSubProcessInstanceId() != null) { query.subProcessInstanceId(queryRequest.getSubProcessInstanceId()); } if (queryRequest.getSuperProcessInstanceId() != null) { query.superProcessInstanceId(queryRequest.getSuperProcessInstanceId()); } if (queryRequest.getExcludeSubprocesses() != null) { query.excludeSubprocesses(queryRequest.getExcludeSubprocesses()); } if (queryRequest.getIncludeProcessVariables() != null) { if (queryRequest.getIncludeProcessVariables()) { query.includeProcessVariables(); } } if (queryRequest.getVariables() != null) { addVariables(query, queryRequest.getVariables()); } if(queryRequest.getTenantId() != null) { query.processInstanceTenantId(queryRequest.getTenantId()); } if(queryRequest.getTenantIdLike() != null) { query.processInstanceTenantIdLike(queryRequest.getTenantIdLike()); } if(Boolean.TRUE.equals(queryRequest.getWithoutTenantId())) { query.processInstanceWithoutTenantId(); } return new ProcessInstancePaginateList(new RestResponseFactory(), uriInfo) .paginateList(requestParams, queryRequest, query, "id", allowedSortProperties); } protected void addVariables(ProcessInstanceQuery processInstanceQuery, List<QueryVariable> variables) { RestResponseFactory restResponseFactory = new RestResponseFactory(); for (QueryVariable variable : variables) { if (variable.getVariableOperation() == null) { throw new ActivitiIllegalArgumentException("Variable operation is missing for variable: " + variable.getName()); } if (variable.getValue() == null) { throw new ActivitiIllegalArgumentException("Variable value is missing for variable: " + variable.getName()); } boolean nameLess = variable.getName() == null; Object actualValue = restResponseFactory.getVariableValue(variable); // A value-only query is only possible using equals-operator if (nameLess && variable.getVariableOperation() != QueryVariable.QueryVariableOperation.EQUALS) { throw new ActivitiIllegalArgumentException("Value-only query (without a variable-name) is only supported when using 'equals' operation."); } switch (variable.getVariableOperation()) { case EQUALS: if (nameLess) { processInstanceQuery.variableValueEquals(actualValue); } else { processInstanceQuery.variableValueEquals(variable.getName(), actualValue); } break; case EQUALS_IGNORE_CASE: if (actualValue instanceof String) { processInstanceQuery.variableValueEqualsIgnoreCase(variable.getName(), (String) actualValue); } else { throw new ActivitiIllegalArgumentException("Only string variable values are supported when ignoring casing, but was: " + actualValue.getClass().getName()); } break; case NOT_EQUALS: processInstanceQuery.variableValueNotEquals(variable.getName(), actualValue); break; case NOT_EQUALS_IGNORE_CASE: if (actualValue instanceof String) { processInstanceQuery.variableValueNotEqualsIgnoreCase(variable.getName(), (String) actualValue); } else { throw new ActivitiIllegalArgumentException("Only string variable values are supported when ignoring casing, but was: " + actualValue.getClass().getName()); } break; case LIKE: if (actualValue instanceof String) { processInstanceQuery.variableValueLike(variable.getName(), (String) actualValue); } else { throw new ActivitiIllegalArgumentException("Only string variable values are supported for like, but was: " + actualValue.getClass().getName()); } break; case GREATER_THAN: processInstanceQuery.variableValueGreaterThan(variable.getName(), actualValue); break; case GREATER_THAN_OR_EQUALS: processInstanceQuery.variableValueGreaterThanOrEqual(variable.getName(), actualValue); break; case LESS_THAN: processInstanceQuery.variableValueLessThan(variable.getName(), actualValue); break; case LESS_THAN_OR_EQUALS: processInstanceQuery.variableValueLessThanOrEqual(variable.getName(), actualValue); break; default: throw new ActivitiIllegalArgumentException("Unsupported variable query operation: " + variable.getVariableOperation()); } } } protected ProcessInstanceQueryRequest getQueryRequest(Map<String, String> allRequestParams){ // Populate query based on request ProcessInstanceQueryRequest queryRequest = new ProcessInstanceQueryRequest(); if (allRequestParams.containsKey("id")) { queryRequest.setProcessInstanceId(allRequestParams.get("id")); } if (allRequestParams.containsKey("processDefinitionKey")) { queryRequest.setProcessDefinitionKey(allRequestParams.get("processDefinitionKey")); } if (allRequestParams.containsKey("processDefinitionId")) { queryRequest.setProcessDefinitionId(allRequestParams.get("processDefinitionId")); } if (allRequestParams.containsKey("businessKey")) { queryRequest.setProcessBusinessKey(allRequestParams.get("businessKey")); } if (allRequestParams.containsKey("involvedUser")) { queryRequest.setInvolvedUser(allRequestParams.get("involvedUser")); } if (allRequestParams.containsKey("suspended")) { queryRequest.setSuspended(Boolean.valueOf(allRequestParams.get("suspended"))); } if (allRequestParams.containsKey("superProcessInstanceId")) { queryRequest.setSuperProcessInstanceId(allRequestParams.get("superProcessInstanceId")); } if (allRequestParams.containsKey("subProcessInstanceId")) { queryRequest.setSubProcessInstanceId(allRequestParams.get("subProcessInstanceId")); } if (allRequestParams.containsKey("excludeSubprocesses")) { queryRequest.setExcludeSubprocesses(Boolean.valueOf(allRequestParams.get("excludeSubprocesses"))); } if (allRequestParams.containsKey("includeProcessVariables")) { queryRequest.setIncludeProcessVariables(Boolean.valueOf(allRequestParams.get("includeProcessVariables"))); } if (allRequestParams.containsKey("tenantId")) { queryRequest.setTenantId(allRequestParams.get("tenantId")); } if (allRequestParams.containsKey("tenantIdLike")) { queryRequest.setTenantIdLike(allRequestParams.get("tenantIdLike")); } if (allRequestParams.containsKey("withoutTenantId")) { if (Boolean.valueOf(allRequestParams.get("withoutTenantId"))) { queryRequest.setWithoutTenantId(Boolean.TRUE); } } return queryRequest; } protected void validateIdentityLinkArguments(String identityId, String type) { if (identityId == null) { throw new ActivitiIllegalArgumentException("IdentityId is required."); } if (type == null) { throw new ActivitiIllegalArgumentException("Type is required."); } } protected IdentityLink getIdentityLink(String identityId, String type, String processInstanceId) { RuntimeService runtimeService = BPMNOSGIService.getRuntimeService(); // Perhaps it would be better to offer getting a single identity link from the API List<IdentityLink> allLinks = runtimeService.getIdentityLinksForProcessInstance(processInstanceId); for (IdentityLink link : allLinks) { if (identityId.equals(link.getUserId()) && link.getType().equals(type)) { return link; } } throw new ActivitiObjectNotFoundException("Could not find the requested identity link.", IdentityLink.class); } }