/** * Copyright (c) 2014, 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.core.mgt.services; import org.activiti.engine.HistoryService; import org.activiti.engine.ProcessEngine; import org.activiti.engine.RepositoryService; import org.activiti.engine.RuntimeService; import org.activiti.engine.history.HistoricProcessInstance; import org.activiti.engine.history.HistoricProcessInstanceQuery; import org.activiti.engine.impl.RepositoryServiceImpl; import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity; import org.activiti.engine.repository.ProcessDefinition; import org.activiti.engine.runtime.ProcessInstance; import org.activiti.engine.runtime.ProcessInstanceQuery; import org.activiti.image.impl.DefaultProcessDiagramGenerator; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.wso2.carbon.bpmn.core.BPMNServerHolder; import org.wso2.carbon.bpmn.core.BPSFault; import org.wso2.carbon.bpmn.core.mgt.model.BPMNInstance; import org.wso2.carbon.bpmn.core.mgt.model.BPMNVariable; import org.wso2.carbon.context.CarbonContext; import sun.misc.BASE64Encoder; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Map; public class BPMNInstanceService { private static Log log = LogFactory.getLog(BPMNInstanceService.class); private int processInstanceCount = -1; private int historyInstanceCount = -1; /** * Start process by process ID * * @param processID * @throws BPSFault */ public void startProcess(String processID) throws BPSFault { ProcessEngine engine = BPMNServerHolder.getInstance().getEngine(); RuntimeService runtimeService = engine.getRuntimeService(); runtimeService.startProcessInstanceById(processID); } /** * Get All process instances * * @return list of BPMNInstances * @throws BPSFault */ public BPMNInstance[] getProcessInstances() throws BPSFault { Integer tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId(); ProcessEngine engine = BPMNServerHolder.getInstance().getEngine(); RuntimeService runtimeService = engine.getRuntimeService(); List<ProcessInstance> instances = runtimeService.createProcessInstanceQuery().processInstanceTenantId(tenantId.toString()).list(); BPMNInstance[] bpmnInstances = getTenantBPMNInstances(instances); return bpmnInstances; } /** * Returns Paginated Instances by passing filter parameters * * @param finished * @param instanceId * @param startAfter * @param startBefore * @param processId * @param isActive * @param variables * @param start * @param size * @return list of BPMNInstances for given filter parameters */ public BPMNInstance[] getPaginatedInstanceByFilter(boolean finished, String instanceId, Date startAfter, Date startBefore, String processId, boolean isActive, String variables, int start, int size) { List<BPMNInstance> bpmnInstanceList = new ArrayList<>(); Integer tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId(); ProcessEngine engine = BPMNServerHolder.getInstance().getEngine(); RuntimeService runtimeService = engine.getRuntimeService(); ProcessInstanceQuery query = runtimeService.createProcessInstanceQuery().processInstanceTenantId(tenantId.toString()); HistoricProcessInstanceQuery historicQuery = BPMNServerHolder.getInstance().getEngine().getHistoryService() .createHistoricProcessInstanceQuery().processInstanceTenantId(tenantId.toString()).includeProcessVariables(); query = query.includeProcessVariables(); if (finished) { historicQuery = historicQuery.finished(); if (instanceId != null && !instanceId.equals("")) { return getInstanceById(instanceId , finished); } if (processId != null && !processId.equals("")) { historicQuery = historicQuery.processDefinitionId(processId); } if (variables != null && !variables.trim().equals("")) { String variablePairs[] = variables.split(","); BPMNVariable[] bpmnVariables = new BPMNVariable[variablePairs.length]; for (int i = 0; i < variablePairs.length; i++) { String pair[] = variablePairs[i].split(":"); if (pair.length == 1) { bpmnVariables[i] = new BPMNVariable(pair[0], ""); } else { bpmnVariables[i] = new BPMNVariable(pair[0], pair[1]); } } if(variablePairs != null && variablePairs.length > 0){ for(BPMNVariable variable: bpmnVariables){ if (variable.getName() != null && !variable.getName().equals("")) { historicQuery = historicQuery .variableValueLike(variable.getName(), "%" + variable.getValue().toString() + "%"); } } } } if (startAfter != null) { historicQuery = historicQuery.startedAfter(startAfter); } if (startBefore != null) { historicQuery = historicQuery.startedBefore(startBefore); } processInstanceCount = (int) historicQuery.count(); List<HistoricProcessInstance> instances = historicQuery.listPage(start, size); for (HistoricProcessInstance instance: instances) { BPMNInstance bpmnInstance = new BPMNInstance(); bpmnInstance.setInstanceId(instance.getId()); bpmnInstance.setProcessId(instance.getProcessDefinitionId()); List<ProcessDefinition> processes = BPMNServerHolder.getInstance().getEngine().getRepositoryService() .createProcessDefinitionQuery().processDefinitionTenantId(tenantId.toString()) .processDefinitionId(instance.getProcessDefinitionId()).list(); String processName = instance.getProcessDefinitionId(); if (!processes.isEmpty()) { processName = processes.get(0).getName(); } bpmnInstance.setProcessName(processName); bpmnInstance.setStartTime(instance.getStartTime()); bpmnInstance.setEndTime(instance.getEndTime()); bpmnInstance.setVariables(formatVariables(instance.getProcessVariables())); bpmnInstanceList.add(bpmnInstance); } } else { historicQuery = historicQuery.unfinished(); if (instanceId != null && !instanceId.equals("")) { return getInstanceById(instanceId, finished); } if (processId != null && !processId.equals("")) { historicQuery = historicQuery.processDefinitionId(processId); } if (variables != null && !variables.trim().equals("")) { String variablePairs[] = variables.split(","); BPMNVariable[] bpmnVariables = new BPMNVariable[variablePairs.length]; for (int i = 0; i < variablePairs.length; i++) { String pair[] = variablePairs[i].split(":"); if (pair.length == 1) { bpmnVariables[i] = new BPMNVariable(pair[0], ""); } else { bpmnVariables[i] = new BPMNVariable(pair[0], pair[1]); } } if(variablePairs != null && variablePairs.length > 0){ for(BPMNVariable variable: bpmnVariables){ if (variable.getName() != null && !variable.getName().equals("")) { historicQuery = historicQuery .variableValueLike(variable.getName(), "%" + variable.getValue().toString() + "%"); } } } } if (startAfter != null) { historicQuery = historicQuery.startedAfter(startAfter); } if (startBefore != null) { historicQuery = historicQuery.startedBefore(startBefore); } processInstanceCount = (int) historicQuery.count(); List<HistoricProcessInstance> instances = historicQuery.listPage(start, size); for (HistoricProcessInstance instance: instances) { boolean isSuspended = query.processInstanceId(instance.getId()).list().get(0).isSuspended(); if( isSuspended == !isActive) { BPMNInstance bpmnInstance = new BPMNInstance(); bpmnInstance.setInstanceId(instance.getId()); bpmnInstance.setProcessId(instance.getProcessDefinitionId()); List<ProcessDefinition> processes = BPMNServerHolder.getInstance().getEngine().getRepositoryService() .createProcessDefinitionQuery().processDefinitionTenantId(tenantId.toString()) .processDefinitionId(instance.getProcessDefinitionId()).list(); String processName = instance.getProcessDefinitionId(); if (!processes.isEmpty()) { processName = processes.get(0).getName(); } bpmnInstance.setProcessName(processName); if (!query.processInstanceId(instance.getId()).list().isEmpty()) { bpmnInstance.setSuspended(isSuspended); } bpmnInstance.setStartTime(instance.getStartTime()); bpmnInstance.setEndTime(instance.getEndTime()); bpmnInstance.setVariables(formatVariables(instance.getProcessVariables())); bpmnInstanceList.add(bpmnInstance); } } } return bpmnInstanceList.toArray(new BPMNInstance[bpmnInstanceList.size()]); } /** * Get instances by instance Id and state * * @param instanceId * @param finished * @return list of BPMNInstances */ private BPMNInstance[] getInstanceById(String instanceId, boolean finished) { List<BPMNInstance> bpmnInstanceList = new ArrayList<>(); Integer tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId(); ProcessEngine engine = BPMNServerHolder.getInstance().getEngine(); RuntimeService runtimeService = engine.getRuntimeService(); ProcessInstanceQuery query = runtimeService.createProcessInstanceQuery().processInstanceTenantId(tenantId.toString()); HistoricProcessInstanceQuery historicQuery = BPMNServerHolder.getInstance().getEngine().getHistoryService() .createHistoricProcessInstanceQuery().processInstanceTenantId(tenantId.toString()).includeProcessVariables(); query = query.includeProcessVariables(); if (finished) { historicQuery.finished(); } else { historicQuery.unfinished(); } historicQuery = historicQuery.processInstanceId(instanceId); HistoricProcessInstance instance = historicQuery.singleResult(); if (instance != null) { processInstanceCount = 1; BPMNInstance bpmnInstance = new BPMNInstance(); bpmnInstance.setInstanceId(instance.getId()); bpmnInstance.setProcessId(instance.getProcessDefinitionId()); List<ProcessDefinition> processes = BPMNServerHolder.getInstance().getEngine().getRepositoryService() .createProcessDefinitionQuery().processDefinitionTenantId(tenantId.toString()) .processDefinitionId(instance.getProcessDefinitionId()).list(); String processName = instance.getProcessDefinitionId(); if (!processes.isEmpty()) { processName = processes.get(0).getName(); } bpmnInstance.setProcessName(processName); if (!query.processInstanceId(instance.getId()).list().isEmpty()) { bpmnInstance.setSuspended(query.processInstanceId(instance.getId()).list().get(0).isSuspended()); } bpmnInstance.setStartTime(instance.getStartTime()); bpmnInstance.setEndTime(instance.getEndTime()); bpmnInstance.setVariables(formatVariables(instance.getProcessVariables())); bpmnInstanceList.add(bpmnInstance); } else { processInstanceCount = 0; } return bpmnInstanceList.toArray(new BPMNInstance[bpmnInstanceList.size()]); } /** * Get paginated instances * * @param start * @param size * @return list of BPMNInstances * @throws BPSFault */ public BPMNInstance[] getPaginatedInstances(int start, int size) throws BPSFault { List<BPMNInstance> bpmnInstanceList = new ArrayList<>(); Integer tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId(); ProcessEngine engine = BPMNServerHolder.getInstance().getEngine(); RuntimeService runtimeService = engine.getRuntimeService(); ProcessInstanceQuery query = runtimeService.createProcessInstanceQuery().processInstanceTenantId(tenantId.toString()); HistoricProcessInstanceQuery historicQuery = BPMNServerHolder.getInstance().getEngine().getHistoryService() .createHistoricProcessInstanceQuery().processInstanceTenantId(tenantId.toString()); processInstanceCount = (int) query.count(); List<ProcessInstance> instances = query.includeProcessVariables().listPage(start, size); for (ProcessInstance instance: instances) { BPMNInstance bpmnInstance = new BPMNInstance(); bpmnInstance.setInstanceId(instance.getId()); bpmnInstance.setProcessId(instance.getProcessDefinitionId()); bpmnInstance.setSuspended(instance.isSuspended()); bpmnInstance.setStartTime(historicQuery.processInstanceId(instance.getId()).singleResult().getStartTime()); bpmnInstance.setVariables(formatVariables(instance.getProcessVariables())); bpmnInstanceList.add(bpmnInstance); } return bpmnInstanceList.toArray(new BPMNInstance[bpmnInstanceList.size()]); } /** * Get total instance count * * @return count int * @throws BPSFault */ public int getInstanceCount() throws BPSFault { if(processInstanceCount == -1) { Integer tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId(); ProcessEngine engine = BPMNServerHolder.getInstance().getEngine(); RuntimeService runtimeService = engine.getRuntimeService(); ProcessInstanceQuery query = runtimeService.createProcessInstanceQuery().processInstanceTenantId(tenantId.toString()); processInstanceCount = (int) query.includeProcessVariables().count(); } return processInstanceCount; } /** * Get paginated history instances * * @param start * @param size * @return list of BPMNInstances */ public BPMNInstance[] getPaginatedHistoryInstances(int start, int size){ BPMNInstance bpmnInstance; Integer tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId(); List<BPMNInstance> bpmnInstances = new ArrayList<>(); HistoryService historyService = BPMNServerHolder.getInstance().getEngine().getHistoryService(); HistoricProcessInstanceQuery query = historyService.createHistoricProcessInstanceQuery().processInstanceTenantId(tenantId.toString()) .finished().includeProcessVariables(); historyInstanceCount = (int) query.count(); List<HistoricProcessInstance> historicProcessInstances = query.listPage(start, size); for(HistoricProcessInstance instance: historicProcessInstances){ bpmnInstance = new BPMNInstance(); bpmnInstance.setInstanceId(instance.getId()); bpmnInstance.setProcessId(instance.getProcessDefinitionId()); bpmnInstance.setStartTime(instance.getStartTime()); bpmnInstance.setEndTime(instance.getEndTime()); bpmnInstance.setVariables(formatVariables(instance.getProcessVariables())); bpmnInstances.add(bpmnInstance); } return bpmnInstances.toArray(new BPMNInstance[bpmnInstances.size()]); } /** * Get total history instance count * * @return count int * @throws BPSFault */ public int getHistoryInstanceCount() throws BPSFault { if(historyInstanceCount == -1){ Integer tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId(); HistoryService historyService = BPMNServerHolder.getInstance().getEngine().getHistoryService(); HistoricProcessInstanceQuery query = historyService.createHistoricProcessInstanceQuery().processInstanceTenantId(tenantId.toString()).finished(); historyInstanceCount = (int) query.count(); } return historyInstanceCount; } /** * Delete history instance by instance ID * @param instanceId */ public void deleteHistoryInstance(String instanceId){ HistoryService historyService = BPMNServerHolder.getInstance().getEngine().getHistoryService(); historyService.deleteHistoricProcessInstance(instanceId); } /** * Delete all completed instances */ public void deleteAllCompletedInstances(){ Integer tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId(); HistoryService historyService = BPMNServerHolder.getInstance().getEngine().getHistoryService(); HistoricProcessInstanceQuery query = historyService.createHistoricProcessInstanceQuery().processInstanceTenantId(tenantId.toString()).finished(); for(HistoricProcessInstance instance: query.list()){ historyService.deleteHistoricProcessInstance(instance.getId()); } } /** * Get tenant history instances from a passed list * * @param instances * @return list of BPMNInstances */ private BPMNInstance[] getTenantBPMNHistoryInstances(List<ProcessInstance> instances) { BPMNInstance bpmnInstance; Integer tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId(); List<BPMNInstance> bpmnInstances = new ArrayList<BPMNInstance>(); RuntimeService runtimeService = BPMNServerHolder.getInstance().getEngine().getRuntimeService(); HistoricProcessInstanceQuery query = BPMNServerHolder.getInstance().getEngine().getHistoryService() .createHistoricProcessInstanceQuery().processInstanceTenantId(tenantId.toString()); for (ProcessInstance instance : instances) { bpmnInstance = new BPMNInstance(); bpmnInstance.setInstanceId(instance.getId()); bpmnInstance.setProcessId(instance.getProcessDefinitionId()); bpmnInstance.setSuspended(instance.isSuspended()); bpmnInstance.setStartTime(query.processInstanceId(instance.getId()).singleResult().getStartTime()); bpmnInstance.setVariables(formatVariables(runtimeService.getVariables(instance.getId()))); bpmnInstances.add(bpmnInstance); } return bpmnInstances.toArray(new BPMNInstance[bpmnInstances.size()]); } /** * Suspend process instance by instance ID * * @param instanceId * @throws BPSFault */ public void suspendProcessInstance(String instanceId) throws BPSFault { Integer tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId(); RuntimeService runtimeService = BPMNServerHolder.getInstance().getEngine().getRuntimeService(); List<ProcessInstance> processInstances = runtimeService.createProcessInstanceQuery().processInstanceTenantId(tenantId.toString()).processInstanceId(instanceId).list(); if (processInstances.isEmpty()) { String msg = "No process instances with the ID: " + instanceId; log.error(msg); throw new BPSFault(msg); } runtimeService.suspendProcessInstanceById(instanceId); } /** * Delete process instances by passing a list of IDs * * @param instanceIdSet * @throws BPSFault */ public void deleteProcessInstanceSet(String[] instanceIdSet) throws BPSFault { for (String instanceId : instanceIdSet) { deleteProcessInstance(instanceId); } } /** * Delete process instance by passing instance ID * * @param instanceId * @throws BPSFault */ public void deleteProcessInstance(String instanceId) throws BPSFault { Integer tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId(); RuntimeService runtimeService = BPMNServerHolder.getInstance().getEngine().getRuntimeService(); List<ProcessInstance> processInstances = runtimeService.createProcessInstanceQuery() .processInstanceTenantId(tenantId.toString()).processInstanceId(instanceId).list(); if (processInstances.isEmpty()) { HistoryService historyService = BPMNServerHolder.getInstance().getEngine().getHistoryService(); List<HistoricProcessInstance> historicProcessInstances = historyService.createHistoricProcessInstanceQuery() .processInstanceTenantId(tenantId.toString()).processInstanceId(instanceId).list(); if (historicProcessInstances.isEmpty()) { String msg = "No process instances with the ID: " + instanceId; log.error(msg); throw new BPSFault(msg); } historyService.deleteHistoricProcessInstance(instanceId); return; } runtimeService.deleteProcessInstance(instanceId, "Deleted by user: " + tenantId); } /** * Activate a process instance by passing the instance id * * @param instanceId * @throws BPSFault */ public void activateProcessInstance(String instanceId) throws BPSFault { Integer tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId(); RuntimeService runtimeService = BPMNServerHolder.getInstance().getEngine().getRuntimeService(); List<ProcessInstance> processInstances = runtimeService.createProcessInstanceQuery() .processInstanceTenantId(tenantId.toString()).processInstanceId(instanceId).list(); if (processInstances.isEmpty()) { String msg = "No process instances with the ID: " + instanceId; log.error(msg); throw new BPSFault(msg); } runtimeService.activateProcessInstanceById(instanceId); } /** * Get process instance diagram as a byte stream by passing the instance ID * * @param instanceId * @return Byte array String * @throws BPSFault */ public String getProcessInstanceDiagram(String instanceId) throws BPSFault { Integer tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId(); try { RuntimeService runtimeService = BPMNServerHolder.getInstance().getEngine().getRuntimeService(); RepositoryService repositoryService = BPMNServerHolder.getInstance().getEngine().getRepositoryService(); List<ProcessInstance> processInstances = runtimeService.createProcessInstanceQuery() .processInstanceTenantId(tenantId.toString()).processInstanceId(instanceId).list(); if (processInstances.isEmpty()) { String msg = "No process instance diagram for ID: " + instanceId; log.info(msg); return null; } ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService) .getDeployedProcessDefinition(processInstances.get(0).getProcessDefinitionId()); if(processDefinition != null && processDefinition.isGraphicalNotationDefined()){ InputStream diagramStream = new DefaultProcessDiagramGenerator().generateDiagram(repositoryService .getBpmnModel(processDefinition.getId()), "png", runtimeService.getActiveActivityIds(instanceId)); BufferedImage bufferedImage = ImageIO.read(diagramStream); return encodeToString(bufferedImage, "png"); }else { String msg = "Process definition graphical notations doesn't exists: " + instanceId; log.debug(msg); } } catch (IOException e) { String msg = "Failed to get the process instance."; log.error(msg, e); } return null; } /** * Internally used method to get all tenant BPMN instances from a passed instance list * * @param instances * @return list of BPMNInstances */ private BPMNInstance[] getTenantBPMNInstances(List<ProcessInstance> instances) { BPMNInstance bpmnInstance; Integer tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId(); List<BPMNInstance> bpmnInstances = new ArrayList<BPMNInstance>(); RuntimeService runtimeService = BPMNServerHolder.getInstance().getEngine().getRuntimeService(); HistoricProcessInstanceQuery query = BPMNServerHolder.getInstance().getEngine().getHistoryService() .createHistoricProcessInstanceQuery().processInstanceTenantId(tenantId.toString()); for (ProcessInstance instance : instances) { bpmnInstance = new BPMNInstance(); bpmnInstance.setInstanceId(instance.getId()); bpmnInstance.setProcessId(instance.getProcessDefinitionId()); bpmnInstance.setSuspended(instance.isSuspended()); bpmnInstance.setStartTime(query.processInstanceId(instance.getId()).singleResult().getStartTime()); bpmnInstance.setVariables(formatVariables(runtimeService.getVariables(instance.getId()))); bpmnInstances.add(bpmnInstance); } return bpmnInstances.toArray(new BPMNInstance[bpmnInstances.size()]); } /** * Internally used method to format variables * * @param processVariables * @return list of BPMNInstances */ private BPMNVariable[] formatVariables(Map<String, Object> processVariables) { BPMNVariable[] vars = new BPMNVariable[processVariables.size()]; int currentVar = 0; for (Map.Entry entry : processVariables.entrySet()) { Object value = processVariables.get(entry.getKey().toString()); if (value == null) { value = "null"; } else { value = String.valueOf(value); } vars[currentVar] = new BPMNVariable(entry.getKey().toString(), value.toString()); currentVar++; } return vars; } /** * Internally used method to encode a image to String * * @param image * @param type * @return encoded String */ private String encodeToString(BufferedImage image, String type) { String imageString = null; ByteArrayOutputStream bos = new ByteArrayOutputStream(); try { ImageIO.write(image, type, bos); byte[] imageBytes = bos.toByteArray(); BASE64Encoder encoder = new BASE64Encoder(); imageString = encoder.encode(imageBytes); } catch (IOException e) { log.error("Could not write image data", e); } finally { try { bos.close(); } catch (IOException e) { log.error("Could not close the byte stream", e); } } return imageString; } }