| /** |
| * |
| * Copyright (c) 2011, 2016 - Loetz GmbH&Co.KG (69115 Heidelberg, Germany) |
| * |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Christophe Loetz (Loetz GmbH&Co.KG) - initial implementation |
| * |
| */ |
| package org.eclipse.osbp.vaaclipse.addons.softwarefactory.bpmImpl; |
| |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import org.drools.definition.process.Connection; |
| import org.drools.definition.process.Node; |
| import org.drools.definition.process.Process; |
| import org.drools.process.core.datatype.DataType; |
| import org.drools.process.core.datatype.impl.type.ObjectDataType; |
| import org.drools.process.core.datatype.impl.type.StringDataType; |
| import org.drools.process.core.impl.WorkImpl; |
| import org.eclipse.osbp.bpm.api.AbstractBPMServiceTask; |
| import org.eclipse.osbp.bpm.api.BPMCallActivity; |
| import org.eclipse.osbp.bpm.api.BPMEndEvent; |
| import org.eclipse.osbp.bpm.api.BPMScriptTask; |
| import org.eclipse.osbp.bpm.api.BPMSplitGateway; |
| import org.eclipse.osbp.bpm.api.IBlipBPMConstants; |
| import org.eclipse.osbp.bpm.api.IBlipBPMItem; |
| import org.eclipse.osbp.bpm.api.IBlipBPMOutgoing; |
| import org.eclipse.osbp.bpm.api.IBlipBPMUserTask; |
| import org.eclipse.osbp.ui.api.useraccess.IBlipProcessPermissions; |
| import org.eclipse.osbp.xtext.blip.common.BlipBPMStartInfo; |
| import org.eclipse.osbp.xtext.blip.common.BlipHelper; |
| import org.jbpm.compiler.IProcessEnhancer; |
| import org.jbpm.process.core.context.variable.Variable; |
| import org.jbpm.ruleflow.core.RuleFlowProcess; |
| import org.jbpm.workflow.core.Constraint; |
| import org.jbpm.workflow.core.DroolsAction; |
| import org.jbpm.workflow.core.impl.ConstraintImpl; |
| import org.jbpm.workflow.core.impl.DroolsConsequenceAction; |
| import org.jbpm.workflow.core.impl.ExtendedNodeImpl; |
| import org.jbpm.workflow.core.node.ActionNode; |
| import org.jbpm.workflow.core.node.EndNode; |
| import org.jbpm.workflow.core.node.HumanTaskNode; |
| import org.jbpm.workflow.core.node.Join; |
| import org.jbpm.workflow.core.node.Split; |
| import org.jbpm.workflow.core.node.StartNode; |
| import org.jbpm.workflow.core.node.SubProcessNode; |
| import org.jbpm.workflow.core.node.WorkItemNode; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| import org.drools.process.core.ParameterDefinition; |
| import org.drools.process.core.impl.ParameterDefinitionImpl; |
| |
| public class BPMProcessEnhancer implements IProcessEnhancer { |
| |
| private static Logger log = LoggerFactory.getLogger(BPMProcessEnhancer.class); |
| |
| private final BlipBPMStartInfo startInfo; |
| private final IBlipProcessPermissions blipProcessPermissions; |
| |
| private ObjectDataType protocolDataType; |
| private StringDataType stringDataType; |
| private ObjectDataType workloadDtoDataType; |
| |
| public BPMProcessEnhancer(BlipBPMStartInfo startInfo, IBlipProcessPermissions blipProcessPermissions) { |
| this.startInfo = startInfo; |
| if (blipProcessPermissions == null) { |
| this.blipProcessPermissions = DefaultBlipProcessPermissions.INSTANCE; |
| } |
| else { |
| this.blipProcessPermissions = blipProcessPermissions; |
| } |
| } |
| |
| @Override |
| public void enhanceProcess(Process basicProcess) { |
| if (basicProcess instanceof RuleFlowProcess) { |
| RuleFlowProcess process = (RuleFlowProcess) basicProcess; |
| String workloadDtoFqn = startInfo.getWorkloadDtoFqn(); |
| String functionGroupFqn = startInfo.getFunctionGroupFqn(); |
| if (functionGroupFqn == null) { |
| functionGroupFqn = ""; |
| } |
| String[] tokens = functionGroupFqn.split("\\."); |
| String functionGroupCls = tokens[tokens.length-1]; |
| enhanceProcessImports(process, workloadDtoFqn, functionGroupFqn); |
| enhanceProcessFunctionImports(process, functionGroupFqn); |
| enhanceProcessVariables(process, workloadDtoFqn); |
| // enhance nodes |
| for (Node node : process.getNodes()) { |
| if (node instanceof HumanTaskNode) { |
| enhanceHumanTaskNode(process, (HumanTaskNode) node, functionGroupCls); |
| } |
| else if (node instanceof ActionNode) { |
| enhanceActionNode(process, (ActionNode) node, functionGroupCls); |
| } |
| else if (node instanceof Split) { |
| enhanceSplitGateway(process, functionGroupCls, (Split) node); |
| } |
| else if (node instanceof Join) { |
| log.warn("Node "+node.getName()+" "+node.getClass().getCanonicalName()+" does not be enhanced RIGHT NOW! Maybe later on?"); |
| } |
| else if (node instanceof SubProcessNode) { |
| enhanceSubProcessNode(process, functionGroupCls, (SubProcessNode) node); |
| } |
| else if (node instanceof StartNode) { |
| log.debug("Node "+node.getName()+" "+node.getClass().getCanonicalName()+" does not need to be enhanced"); |
| } |
| else if (node instanceof EndNode) { |
| enhanceEndNode(process, (EndNode) node); |
| } |
| else if (node instanceof WorkItemNode) { |
| enhanceWorkItemNode(process, (WorkItemNode) node, functionGroupCls); |
| } |
| else { |
| log.warn("Node "+node.getName()+" "+node.getClass().getCanonicalName()+" will not be enhanced! IS ITR NECESSARY?"); |
| } |
| } |
| } |
| } |
| |
| private void enhanceSplitGateway(RuleFlowProcess process, String functionGroupCls, Split split) { |
| String name = BlipHelper.getBpmItemRecommendedName(split.getName()); |
| IBlipBPMItem bpmItem = startInfo.getBpmItemForBpmId(name); |
| if (bpmItem instanceof BPMSplitGateway) { |
| for (IBlipBPMOutgoing outgoing : ((BPMSplitGateway) bpmItem).getOutgoings()) { |
| List<Connection> connections = split.getOutgoingConnections(org.jbpm.workflow.core.Node.CONNECTION_DEFAULT_TYPE); |
| for (Connection connection : connections) { |
| if (connection.getMetaData("UniqueId").equals(outgoing.getBpmId())) { |
| // enhance sequence flow constraints |
| boolean modify = true; |
| Constraint constraint = split.getConstraint(connection); |
| if (constraint == null) { |
| constraint = new ConstraintImpl(); |
| modify = false; |
| } |
| constraint.setName(outgoing.getBlipId()); |
| constraint.setType("code"); |
| constraint.setDialect("mvel"); |
| constraint.setDefault(false); |
| constraint.setPriority(outgoing.getPriority()); |
| constraint.setConstraint("return "+functionGroupCls+"."+outgoing.getTestFunction()+"(kcontext);"); |
| if (modify) { |
| log.debug(process.getId()+" "+constraint.getName()+": modify constraint "+constraint.getPriority()+" "+constraint.getDialect()+" "+constraint.getConstraint()); |
| } |
| else { |
| split.setConstraint(connection, constraint); |
| log.debug(process.getId()+" "+constraint.getName()+": add constraint "+constraint.getPriority()+" "+constraint.getDialect()+" "+constraint.getConstraint()); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| private void enhanceProcessImports(RuleFlowProcess process, String workloadDtoFqn, String functionGroupFqn) { |
| boolean modified = false; |
| List<String> imports = process.getImports(); |
| if (imports == null) { |
| imports = new ArrayList<String>(); |
| } |
| modified |= addItem(process, "imports", imports, workloadDtoFqn, ""); |
| modified |= addItem(process, "imports", imports, functionGroupFqn, ""); |
| if (modified) { |
| process.setImports(imports); |
| } |
| } |
| |
| private void enhanceProcessFunctionImports(RuleFlowProcess process, String functionGroupFqn) { |
| boolean modified; |
| modified = false; |
| List<String> functions = process.getFunctionImports(); |
| if (functions == null) { |
| functions = new ArrayList<String>(); |
| } |
| modified |= addItem(process, "function imports", functions, functionGroupFqn, ".*"); |
| if (modified) { |
| process.setFunctionImports(functions); |
| } |
| } |
| |
| private void enhanceProcessVariables(RuleFlowProcess process, String workloadDtoFqn) { |
| boolean modified; |
| protocolDataType = new ObjectDataType(org.eclipse.osbp.bpm.api.IBlipBPMProcessProtocol.class.getCanonicalName()); |
| stringDataType = new StringDataType(); |
| workloadDtoDataType = null; |
| if ((workloadDtoFqn != null) && !workloadDtoFqn.isEmpty()) { |
| workloadDtoDataType = new ObjectDataType(workloadDtoFqn); |
| } |
| // ObjectDataType functionGroupDataType = new ObjectDataType(functionGroupFqn); |
| modified = false; |
| List<Variable> variables = process.getVariableScope().getVariables(); |
| modified |= addVariable (process, variables, IBlipBPMConstants.VARIABLE_PROCESS_PROTOCOL, protocolDataType); |
| if (workloadDtoFqn != null) { |
| modified |= addVariable (process, variables, IBlipBPMConstants.VARIABLE_PROCESS_WORKLOAD_DTO_FQN, stringDataType); |
| modified |= addVariable (process, variables, IBlipBPMConstants.VARIABLE_PROCESS_WORKLOAD_DTO, workloadDtoDataType); |
| } |
| if (modified) { |
| process.getVariableScope().setVariables(variables); |
| } |
| } |
| |
| private static final String[] inOutMappings = new String[] { |
| IBlipBPMConstants.VARIABLE_PROCESS_PROTOCOL, |
| IBlipBPMConstants.VARIABLE_PROCESS_WORKLOAD_DTO_FQN, |
| IBlipBPMConstants.VARIABLE_PROCESS_WORKLOAD_DTO, |
| }; |
| |
| private void enhanceHumanTaskNode(RuleFlowProcess process, HumanTaskNode humantask, String functionGroupCls) { |
| String processName = BlipHelper.getBpmItemRecommendedName(process.getId()); |
| String humanTaskName = BlipHelper.getBpmItemRecommendedName(humantask.getName()); |
| IBlipBPMUserTask bpmUserTask = startInfo.getBpmHumanTaskForBpmId(humanTaskName); |
| // enhance authorization roles and locale |
| List<String> roles = blipProcessPermissions.getHumanTaskExecutableRoles(processName, humanTaskName); |
| modifyWorkParameter(process, humantask, "GroupId", String.join(",", roles)); |
| modifyWorkParameter(process, humantask, "Locale", "en-US"); |
| // enhance in-/out-mapping of process local variables |
| for (String variable : inOutMappings) { |
| if (!humantask.getInMappings().containsKey(variable)) { |
| humantask.addInMapping(variable, variable); |
| log.debug(process.getId()+" "+humantask.getName()+": add in-mapping "+variable); |
| } |
| if (!humantask.getOutMappings().containsKey(variable)) { |
| humantask.addOutMapping(variable, variable); |
| log.debug(process.getId()+" "+humantask.getName()+": add out-mapping "+variable); |
| } |
| } |
| if (bpmUserTask != null) { |
| String function; |
| List<DroolsAction> actions; |
| // enhance on entry |
| function = bpmUserTask.getOnEntryFunction(); |
| if (function != null) { |
| function = functionGroupCls+"."+function+"(kcontext);"; |
| actions = humantask.getActions(ExtendedNodeImpl.EVENT_NODE_ENTER); |
| if (actions == null) { |
| actions = new ArrayList<DroolsAction>(); |
| } |
| else { |
| actions.clear(); |
| } |
| actions.add(new DroolsConsequenceAction("java", function)); |
| } |
| else { |
| actions = null; |
| } |
| humantask.setActions(ExtendedNodeImpl.EVENT_NODE_ENTER, actions); |
| log.debug(process.getId()+" "+humantask.getName()+": modify on entry "+function); |
| // enhance on exit |
| function = bpmUserTask.getOnExitFunction(); |
| if (function != null) { |
| function = functionGroupCls+"."+function+"(kcontext);"; |
| actions = humantask.getActions(ExtendedNodeImpl.EVENT_NODE_EXIT); |
| if (actions == null) { |
| actions = new ArrayList<DroolsAction>(); |
| } |
| else { |
| actions.clear(); |
| } |
| actions.add(new DroolsConsequenceAction("java", function)); |
| } |
| else { |
| actions = null; |
| } |
| humantask.setActions(ExtendedNodeImpl.EVENT_NODE_EXIT, actions); |
| log.debug(process.getId()+" "+humantask.getName()+": modify on exit "+function); |
| } |
| } |
| |
| private void enhanceSubProcessNode(RuleFlowProcess process, String functionGroupCls, SubProcessNode subProcess) { |
| String processName = BlipHelper.getBpmItemRecommendedName(process.getId()); |
| String subProcessName = BlipHelper.getBpmItemRecommendedName(subProcess.getName()); |
| IBlipBPMItem bpmItem = startInfo.getBpmItemForBpmId(subProcessName); |
| BPMCallActivity bpmCallActivity = (bpmItem instanceof BPMCallActivity) ? (BPMCallActivity)bpmItem : null; |
| // enhance authorization roles and locale |
| // List<String> roles = blipProcessPermissions.getHumanTaskExecutableRoles(processName, humanTaskName); |
| // modifyWorkParameter(process, humantask, "GroupId", String.join(",", roles)); |
| // modifyWorkParameter(process, humantask, "Locale", "en-US"); |
| // enhance in-/out-mapping of process local variables |
| for (String variable : inOutMappings) { |
| if (!subProcess.getInMappings().containsKey(variable)) { |
| subProcess.addInMapping(variable, variable); |
| log.debug(process.getId()+" "+subProcess.getName()+": add in-mapping "+variable); |
| } |
| if (!subProcess.getOutMappings().containsKey(variable)) { |
| subProcess.addOutMapping(variable, variable); |
| log.debug(process.getId()+" "+subProcess.getName()+": add out-mapping "+variable); |
| } |
| } |
| if (bpmCallActivity != null) { |
| String function; |
| List<DroolsAction> actions; |
| // enhance on entry |
| function = bpmCallActivity.getOnEntryFunction(); |
| if (function != null) { |
| function = functionGroupCls+"."+function+"(kcontext);"; |
| actions = subProcess.getActions(ExtendedNodeImpl.EVENT_NODE_ENTER); |
| if (actions == null) { |
| actions = new ArrayList<DroolsAction>(); |
| } |
| else { |
| actions.clear(); |
| } |
| actions.add(new DroolsConsequenceAction("java", function)); |
| } |
| else { |
| actions = null; |
| } |
| subProcess.setActions(ExtendedNodeImpl.EVENT_NODE_ENTER, actions); |
| log.debug(process.getId()+" "+subProcess.getName()+": modify on entry "+function); |
| // enhance on exit |
| function = bpmCallActivity.getOnExitFunction(); |
| if (function != null) { |
| function = functionGroupCls+"."+function+"(kcontext);"; |
| actions = subProcess.getActions(ExtendedNodeImpl.EVENT_NODE_EXIT); |
| if (actions == null) { |
| actions = new ArrayList<DroolsAction>(); |
| } |
| else { |
| actions.clear(); |
| } |
| actions.add(new DroolsConsequenceAction("java", function)); |
| } |
| else { |
| actions = null; |
| } |
| subProcess.setActions(ExtendedNodeImpl.EVENT_NODE_EXIT, actions); |
| log.debug(process.getId()+" "+subProcess.getName()+": modify on exit "+function); |
| } |
| } |
| |
| private void enhanceWorkItemNode(RuleFlowProcess process, WorkItemNode workItem, String functionGroupCls) { |
| String processName = BlipHelper.getBpmItemRecommendedName(process.getId()); |
| String workItemName = BlipHelper.getBpmItemRecommendedName(workItem.getName()); |
| IBlipBPMItem bpmWorkItem = startInfo.getBpmItemForBpmId(workItemName); |
| // enhance authorization roles and locale |
| // enhance in-/out-mapping of process local variables |
| for (String variable : inOutMappings) { |
| if (!workItem.getInMappings().containsKey(variable)) { |
| workItem.addInMapping(variable, variable); |
| log.debug(process.getId()+" "+workItem.getName()+": add in-mapping "+variable); |
| } |
| if (!workItem.getOutMappings().containsKey(variable)) { |
| workItem.addOutMapping(variable, variable); |
| log.debug(process.getId()+" "+workItem.getName()+": add out-mapping "+variable); |
| } |
| } |
| Set<ParameterDefinition> parameterDefinitions = new HashSet<>(); |
| Map<String, Object> parameters = new HashMap<>(); |
| parameterDefinitions.add(new ParameterDefinitionImpl(IBlipBPMConstants.VARIABLE_PROCESS_PROTOCOL, protocolDataType)); |
| parameters.put(IBlipBPMConstants.VARIABLE_PROCESS_PROTOCOL, null); |
| parameterDefinitions.add(new ParameterDefinitionImpl(IBlipBPMConstants.VARIABLE_PROCESS_WORKLOAD_DTO_FQN, stringDataType)); |
| parameters.put(IBlipBPMConstants.VARIABLE_PROCESS_WORKLOAD_DTO_FQN, null); |
| if (workloadDtoDataType != null) { |
| parameterDefinitions.add(new ParameterDefinitionImpl(IBlipBPMConstants.VARIABLE_PROCESS_WORKLOAD_DTO, workloadDtoDataType)); |
| parameters.put(IBlipBPMConstants.VARIABLE_PROCESS_WORKLOAD_DTO, null); |
| } |
| workItem.getWork().setParameterDefinitions(parameterDefinitions); |
| workItem.getWork().setParameters(parameters); |
| if (bpmWorkItem instanceof AbstractBPMServiceTask) { |
| String function; |
| List<DroolsAction> actions; |
| // enhance on entry |
| function = ((AbstractBPMServiceTask)bpmWorkItem).getOnEntryFunction(); |
| if (function != null) { |
| function = functionGroupCls+"."+function+"(kcontext);"; |
| actions = workItem.getActions(ExtendedNodeImpl.EVENT_NODE_ENTER); |
| if (actions == null) { |
| actions = new ArrayList<DroolsAction>(); |
| } |
| else { |
| actions.clear(); |
| } |
| actions.add(new DroolsConsequenceAction("java", function)); |
| } |
| else { |
| actions = null; |
| } |
| workItem.setActions(ExtendedNodeImpl.EVENT_NODE_ENTER, actions); |
| log.debug(process.getId()+" "+workItem.getName()+": modify on entry "+function); |
| // enhance on exit |
| function = ((AbstractBPMServiceTask)bpmWorkItem).getOnExitFunction(); |
| if (function != null) { |
| function = functionGroupCls+"."+function+"(kcontext);"; |
| actions = workItem.getActions(ExtendedNodeImpl.EVENT_NODE_EXIT); |
| if (actions == null) { |
| actions = new ArrayList<DroolsAction>(); |
| } |
| else { |
| actions.clear(); |
| } |
| actions.add(new DroolsConsequenceAction("java", function)); |
| } |
| else { |
| actions = null; |
| } |
| workItem.setActions(ExtendedNodeImpl.EVENT_NODE_EXIT, actions); |
| log.debug(process.getId()+" "+workItem.getName()+": modify on exit "+function); |
| } |
| } |
| |
| private void enhanceActionNode(RuleFlowProcess process, ActionNode action, String functionGroupCls) { |
| String name = BlipHelper.getBpmItemRecommendedName(action.getName()); |
| IBlipBPMItem bpmItem = startInfo.getBpmItemForBpmId(name); |
| if (bpmItem instanceof BPMScriptTask) { |
| BPMScriptTask script = (BPMScriptTask) bpmItem; |
| String function = script.getFunction(); |
| if (function == null) { |
| function = ""; |
| } |
| action.setAction(new DroolsConsequenceAction("java", |
| functionGroupCls+"."+function+"(kcontext);" |
| )); |
| log.debug(process.getId()+" "+action.getName()+": modify action "+function); |
| } |
| } |
| |
| private void enhanceEndNode(RuleFlowProcess process, EndNode endNode) { |
| String name = BlipHelper.getBpmItemRecommendedName(endNode.getName()); |
| IBlipBPMItem bpmItem = startInfo.getBpmItemForBpmId(name); |
| if (bpmItem instanceof BPMEndEvent) { |
| boolean terminateProcess = ((BPMEndEvent)bpmItem).isTerminatesProcess(); |
| endNode.setTerminate(terminateProcess); |
| log.debug(process.getId()+" "+endNode.getName()+": modify terminate process="+terminateProcess); |
| } |
| } |
| |
| private void modifyWorkParameter(RuleFlowProcess process, HumanTaskNode humantask, String parameter, String value) { |
| WorkImpl work = (WorkImpl) humantask.getWork(); |
| if (!value.equals(work.getParameter(parameter))) { |
| work.setParameter(parameter, value); |
| log.debug(process.getId()+" "+humantask.getName()+": set "+parameter+"="+value); |
| } |
| } |
| |
| private Variable findVariable(List<Variable> variables, String name) { |
| for (Variable variable : variables) { |
| if (variable.getName().equals(name)) { |
| return variable; |
| } |
| } |
| return null; |
| } |
| |
| private boolean addVariable(RuleFlowProcess process, List<Variable> variables, String name, DataType dataType) { |
| if ((dataType != null) && (findVariable(variables, name) == null)) { |
| Variable variable = new Variable(); |
| variable.setName(name); |
| variable.setType(dataType); |
| variables.add(variable); |
| log.debug(process.getId()+" variables: add "+name); |
| return true; |
| } |
| return false; |
| } |
| |
| private boolean addItem(RuleFlowProcess process, String listname, List<String> items, String item, String postfix) { |
| if ((item != null) && !item.isEmpty() && !items.contains(item)) { |
| items.add(item+postfix); |
| log.debug(process.getId()+" "+listname+": add "+item+postfix); |
| return true; |
| } |
| return false; |
| } |
| } |