/*
* Copyright 2015 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*
* 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.jbpm.kie.services.impl.xml;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.jbpm.bpmn2.core.ItemDefinition;
import org.jbpm.compiler.xml.ProcessDataEventListener;
import org.jbpm.kie.services.impl.bpmn2.ProcessDescriptor;
import org.jbpm.kie.services.impl.bpmn2.UserTaskDefinitionImpl;
import org.jbpm.kie.services.impl.model.ProcessAssetDesc;
import org.jbpm.process.core.context.variable.Variable;
import org.jbpm.process.core.impl.ProcessImpl;
import org.jbpm.ruleflow.core.RuleFlowProcess;
import org.jbpm.workflow.core.Node;
import org.jbpm.workflow.core.WorkflowProcess;
import org.jbpm.workflow.core.node.HumanTaskNode;
import org.jbpm.workflow.core.node.RuleSetNode;
import org.jbpm.workflow.core.node.SubProcessNode;
import org.jbpm.workflow.core.node.WorkItemNode;
import org.kie.api.definition.process.Process;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ServicesProcessDataEventListener implements ProcessDataEventListener {
private static final Logger logger = LoggerFactory.getLogger(ServicesProcessDataEventListener.class);
private ProcessDescriptor processDescriptor = new ProcessDescriptor();
private Map<String, ItemDefinition> itemDefinitions;
private Set<String> signals;
private List<Variable> variables = new ArrayList<Variable>();
@SuppressWarnings("unchecked")
@Override
public void onNodeAdded(Node node) {
logger.debug("Added node " + node);
if (node instanceof HumanTaskNode) {
HumanTaskNode humanTaskNode = (HumanTaskNode) node;
String name = humanTaskNode.getName();
UserTaskDefinitionImpl task = (UserTaskDefinitionImpl)processDescriptor.getTasks().get(name);
if (task == null) {
task = new UserTaskDefinitionImpl();
task.setName(name);
processDescriptor.getTasks().put(task.getName(), task);
}
Map<String, Object> parameters = humanTaskNode.getWork().getParameters();
Collection<String> currentAssignment = processDescriptor.getTaskAssignments().get(humanTaskNode.getName());
for(String parameter : parameters.keySet()){
if(parameter.equals("GroupId") || parameter.equals("ActorId")){
if(currentAssignment == null){
currentAssignment = new ArrayList<String>();
processDescriptor.getTaskAssignments().put(humanTaskNode.getName(), currentAssignment);
}
currentAssignment.add(humanTaskNode.getWork().getParameter(parameter).toString());
}
}
((UserTaskDefinitionImpl)processDescriptor.getTasks().get(humanTaskNode.getName())).setAssociatedEntities(currentAssignment);
Map<String, String> inputParams = new HashMap<String, String>();
for (Map.Entry<String, String> in : ((Map<String, String>) humanTaskNode.getMetaData("DataInputs")).entrySet()) {
inputParams.put(in.getKey(), in.getValue());
}
Map<String, String> outputParams = new HashMap<String, String>();
for (Map.Entry<String, String> out : ((Map<String, String>) humanTaskNode.getMetaData("DataOutputs")).entrySet()) {
outputParams.put(out.getKey(), out.getValue());
}
task.setTaskInputMappings(inputParams);
task.setTaskOutputMappings(outputParams);
task.setComment(asString(humanTaskNode.getWork().getParameter("Comment")));
task.setCreatedBy(asString(humanTaskNode.getWork().getParameter("CreatedBy")));
task.setPriority(asInt(humanTaskNode.getWork().getParameter("Priority")));
task.setSkippable(asBoolean(humanTaskNode.getWork().getParameter("Skippable")));
processDescriptor.getTaskInputMappings().put(task.getName(), inputParams);
processDescriptor.getTaskOutputMappings().put(task.getName(), outputParams);
} else if (node instanceof RuleSetNode) {
RuleSetNode ruleSetNode = (RuleSetNode) node;
String ruleFlowGroup = ruleSetNode.getRuleFlowGroup();
if( ruleFlowGroup != null ) {
processDescriptor.getReferencedRules().add(ruleFlowGroup);
}
} else if (node instanceof WorkItemNode) {
processDescriptor.getServiceTasks().put(node.getName(), ((WorkItemNode) node).getWork().getName());
} else if (node instanceof SubProcessNode) {
SubProcessNode subProcess = (SubProcessNode) node;
String processId = subProcess.getProcessId();
if (subProcess.getProcessName() != null) {
processDescriptor.addReusableSubProcessName(subProcess.getProcessName());
} else {
processDescriptor.getReusableSubProcesses().add(processId);
}
}
}
@Override
public void onProcessAdded(Process process) {
logger.debug("Added process with id {} and name {}", process.getId(), process.getName());
ProcessAssetDesc processDesc = new ProcessAssetDesc(process.getId(), process.getName(), process.getVersion()
, process.getPackageName(), process.getType(), process.getKnowledgeType().name(), process.getNamespace(), "", ((WorkflowProcess)process).isDynamic());
processDescriptor.setProcess(processDesc);
//add process descriptor as process meta data
process.getMetaData().put("ProcessDescriptor", processDescriptor);
}
@SuppressWarnings("unchecked")
@Override
public void onMetaDataAdded(String name, Object data) {
if (name.equals("Variable")) {
variables.add((Variable) data);
} else if ("ItemDefinitions".equals(name)) {
itemDefinitions = (Map<String, ItemDefinition>) data;
} else if ("signalNames".equals(name)) {
signals = (Set<String>) data;
}
}
@Override
public void onComplete(Process process) {
// process item definitions
if (itemDefinitions != null) {
for (ItemDefinition item : itemDefinitions.values()) {
String id = item.getId();
String structureRef = item.getStructureRef();
// NPE!
String itemDefinitionId = processDescriptor.getGlobalItemDefinitions().get(id);
if(itemDefinitionId == null) {
processDescriptor.getGlobalItemDefinitions().put(id, structureRef);
if( structureRef.contains(".") ) {
processDescriptor.getReferencedClasses().add(structureRef);
} else {
processDescriptor.getUnqualifiedClasses().add(structureRef);
}
}
}
}
// process globals
Map<String, String> globals = ((RuleFlowProcess)process).getGlobals();
if (globals != null) {
Set<String> globalNames = new HashSet<>();
for (Entry<String, String> globalEntry : globals.entrySet() ) {
globalNames.add(globalEntry.getKey());
String type = globalEntry.getValue();
if( type.contains(".") ) {
processDescriptor.getReferencedClasses().add(type);
} else {
processDescriptor.getUnqualifiedClasses().add(type);
}
}
processDescriptor.setGlobals(globalNames);
}
// process imports
Set<String> imports = ((RuleFlowProcess)process).getImports();
if (imports != null) {
for (String type : imports) {
if( type.contains(".") ) {
processDescriptor.getReferencedClasses().add(type);
} else {
processDescriptor.getUnqualifiedClasses().add(type);
}
}
}
}
// helper methods
private Integer getInteger(String value) {
int priority = 0;
if (value != null) {
try {
priority = new Integer(value);
} catch (NumberFormatException e) {
// do nothing
}
}
return priority;
}
protected void resolveUnqualifiedClasses() {
Set<String> qualifiedClassSimpleNames = new HashSet<String>();
for( String className : processDescriptor.getReferencedClasses() ) {
qualifiedClassSimpleNames.add(className.substring(className.lastIndexOf('.') + 1));
}
for( Iterator<String> iter = processDescriptor.getUnqualifiedClasses().iterator(); iter.hasNext(); ) {
if( qualifiedClassSimpleNames.contains(iter.next()) ) {
iter.remove();
}
}
for( Iterator<String> iter = processDescriptor.getUnqualifiedClasses().iterator(); iter.hasNext(); ) {
String name = iter.next();
if( "Object".equals(name) || "String".equals(name)
|| "Float".equals(name) || "Integer".equals(name)
|| "Boolean".equals(name) ) {
processDescriptor.getReferencedClasses().add("java.lang." + name );
iter.remove();
}
}
for( String className : processDescriptor.getUnqualifiedClasses() ) {
logger.warn("Unable to resolve unqualified class name, adding to list of classes: '{}'", className );
processDescriptor.getReferencedClasses().add(className);
}
}
@SuppressWarnings("unchecked")
@Override
public void onBuildComplete(Process process) {
// process java dialect types
Set<String> referencedTypes = (Set<String>) process.getMetaData().get("JavaDialectReferencedTypes");
if (referencedTypes != null && !referencedTypes.isEmpty()) {
processDescriptor.getReferencedClasses().addAll(referencedTypes);
}
Set<String> unqualifiedClasses = (Set<String>) process.getMetaData().get("JavaDialectUnqualifiedTypes");
if (unqualifiedClasses != null && !unqualifiedClasses.isEmpty()) {
processDescriptor.getUnqualifiedClasses().addAll(unqualifiedClasses);
}
// process java return value types
referencedTypes = (Set<String>) process.getMetaData().get("JavaReturnValueReferencedTypes");
if (referencedTypes != null && !referencedTypes.isEmpty()) {
processDescriptor.getReferencedClasses().addAll(referencedTypes);
}
unqualifiedClasses = (Set<String>) process.getMetaData().get("JavaReturnValueUnqualifiedTypes");
if (unqualifiedClasses != null && !unqualifiedClasses.isEmpty()) {
processDescriptor.getUnqualifiedClasses().addAll(unqualifiedClasses);
}
// process mvel dialect types
referencedTypes = (Set<String>) process.getMetaData().get("MVELDialectReferencedTypes");
if (referencedTypes != null && !referencedTypes.isEmpty()) {
processDescriptor.getReferencedClasses().addAll(referencedTypes);
}
// process mvel return value types
referencedTypes = (Set<String>) process.getMetaData().get("MVELReturnValueReferencedTypes");
if (referencedTypes != null && !referencedTypes.isEmpty()) {
processDescriptor.getReferencedClasses().addAll(referencedTypes);
}
// process unqualified classes
resolveUnqualifiedClasses();
// process variables
if (variables != null) {
for (Variable data : variables) {
String type = data.getType().getStringType();
String itemSubjectRef = (String) data.getMetaData("ItemSubjectRef");
if (itemSubjectRef != null && itemDefinitions != null) {
ItemDefinition itemDef = itemDefinitions.get(itemSubjectRef);
type = itemDef.getStructureRef();
}
processDescriptor.getInputs().put(data.getName(), type);
}
}
// process signals
if( signals != null ) {
processDescriptor.setSignals(signals);
}
}
protected Integer asInt(Object value) {
if (value == null) {
return 0;
}
try {
return Integer.parseInt(value.toString());
} catch (NumberFormatException e) {
return 0;
}
}
protected Boolean asBoolean(Object value) {
if (value == null) {
return true;
}
return Boolean.valueOf(value.toString());
}
protected String asString(Object value) {
if (value == null) {
return "";
}
return value.toString();
}
}