Skip to content

Commit

Permalink
[JBPM-9774] Incorrect object type returned in a DMN business-rule tas…
Browse files Browse the repository at this point in the history
…k of a BPMN
  • Loading branch information
elguardian committed Jun 7, 2021
1 parent 8d6dcee commit 49987ff
Show file tree
Hide file tree
Showing 6 changed files with 127 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@
import java.util.List;
import java.util.Map;

import org.jbpm.process.workitem.bpmn2.BusinessRuleTaskHandler;
import org.jbpm.test.JbpmTestCase;
import org.jbpm.test.listener.IterableProcessEventListener;
import org.junit.Test;
import org.kie.api.KieBase;
import org.kie.api.command.Command;
import org.kie.api.io.ResourceType;
import org.kie.api.runtime.KieSession;
Expand Down Expand Up @@ -59,6 +61,30 @@ public RuleTaskTest() {
super(false);
}

@Test
public void testBusinessRuleTaskProcess() throws Exception {
KieBase kbase = readKnowledgeBase();
KieSession ksession = createSession(kbase);

BusinessRuleTaskHandler handler = new BusinessRuleTaskHandler(GROUP_ID,
ARTIFACT_ID,
VERSION);
ksession.getWorkItemManager().registerWorkItemHandler("BusinessRuleTask",
handler);
Map<String, Object> params = new HashMap<String, Object>();
params.put("person",
new org.jbpm.process.workitem.bpmn2.objects.Person("john"));

WorkflowProcessInstance processInstance = (WorkflowProcessInstance) ksession.startProcess("evaluation.ruletask",
params);
org.jbpm.process.workitem.bpmn2.objects.Person variable = (org.jbpm.process.workitem.bpmn2.objects.Person) processInstance.getVariable("person");
assertEquals("john",
variable.getName());
assertEquals(35,
variable.getAge().intValue());
assertEquals(ProcessInstance.STATE_COMPLETED,
processInstance.getState());
}
@Test(timeout = 30000)
public void testRuleTask() {
Map<String, ResourceType> res = new HashMap<String, ResourceType>();
Expand Down
5 changes: 4 additions & 1 deletion jbpm-workitems/jbpm-workitems-bpmn2/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,10 @@
</exclusion>
</exclusions>
</dependency>

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>org.jbpm</groupId>
<artifactId>jbpm-workitems-core</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package org.jbpm.process.workitem.bpmn2;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
Expand All @@ -23,12 +24,10 @@
import java.util.stream.Collectors;

import org.jbpm.process.workitem.core.AbstractLogOrThrowWorkItemHandler;
import org.jbpm.process.workitem.core.util.Wid;
import org.jbpm.process.workitem.core.util.WidMavenDepends;
import org.jbpm.process.workitem.core.util.WidParameter;
import org.jbpm.process.workitem.core.util.service.WidAction;
import org.jbpm.process.workitem.core.util.service.WidAuth;
import org.jbpm.process.workitem.core.util.service.WidService;
import org.jbpm.workflow.core.node.DataAssociation;
import org.jbpm.workflow.core.node.WorkItemNode;
import org.jbpm.workflow.instance.WorkflowProcessInstance;
import org.jbpm.workflow.instance.node.WorkItemNodeInstance;
import org.kie.api.KieServices;
import org.kie.api.builder.KieScanner;
import org.kie.api.command.BatchExecutionCommand;
Expand All @@ -38,6 +37,8 @@
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.StatelessKieSession;
import org.kie.api.runtime.manager.RuntimeEngine;
import org.kie.api.runtime.manager.RuntimeManager;
import org.kie.api.runtime.process.WorkItem;
import org.kie.api.runtime.process.WorkItemManager;
import org.kie.api.runtime.rule.FactHandle;
Expand All @@ -47,9 +48,13 @@
import org.kie.dmn.api.core.DMNResult;
import org.kie.dmn.api.core.DMNRuntime;
import org.kie.internal.runtime.Cacheable;
import org.kie.internal.runtime.manager.RuntimeManagerRegistry;
import org.kie.internal.runtime.manager.context.ProcessInstanceIdContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.databind.ObjectMapper;

/**
* Additional BusinessRuleTask support that allows to decouple rules from processes - as default BusinessRuleTask
* uses exact same working memory (kie session) as process which essentially means same kbase.
Expand Down Expand Up @@ -90,6 +95,9 @@ public abstract class AbstractRuleTaskHandler extends AbstractLogOrThrowWorkItem
private KieContainer kieContainer;
private KieScanner kieScanner;

private ClassLoader classLoader;
private RuntimeManager runtimeManager;

public AbstractRuleTaskHandler(String groupId,
String artifactId,
String version) {
Expand All @@ -99,10 +107,18 @@ public AbstractRuleTaskHandler(String groupId,
-1);
}

public AbstractRuleTaskHandler(String groupId,
String artifactId,
String version,
long scannerInterval) {
this(groupId, artifactId, version, scannerInterval, null, null);
}
public AbstractRuleTaskHandler(String groupId,
String artifactId,
String version,
long scannerInterval) {
long scannerInterval,
ClassLoader classLoader,
RuntimeManager runtimeManager) {
logger.debug("About to create KieContainer for {}, {}, {} with scanner interval {}",
groupId,
artifactId,
Expand All @@ -111,7 +127,8 @@ public AbstractRuleTaskHandler(String groupId,
kieContainer = kieServices.newKieContainer(kieServices.newReleaseId(groupId,
artifactId,
version));

this.classLoader = classLoader;
this.runtimeManager = runtimeManager;
if (scannerInterval > 0) {
kieScanner = kieServices.newKieScanner(kieContainer);
kieScanner.start(scannerInterval);
Expand Down Expand Up @@ -154,7 +171,8 @@ public void executeWorkItem(WorkItem workItem,
results);
}
} else if (DMN_LANG.equalsIgnoreCase(language)) {
handleDMN(parameters,
handleDMN(workItem,
parameters,
results);
} else {
throw new IllegalArgumentException("Not supported language type " + language);
Expand Down Expand Up @@ -218,8 +236,7 @@ protected void handleStateless(WorkItem workItem,
String kieSessionName,
Map<String, Object> parameters,
Map<String, Object> results) {
logger.debug("Evaluating rules in stateless session with name {}",
kieSessionName);
logger.debug("Evaluating rules in stateless session with name {}", kieSessionName);
StatelessKieSession kieSession = kieContainer.newStatelessKieSession(kieSessionName);
List<Command<?>> commands = new ArrayList<Command<?>>();

Expand All @@ -246,7 +263,8 @@ protected void handleStateless(WorkItem workItem,
}
}

protected void handleDMN(Map<String, Object> parameters,
protected void handleDMN(WorkItem workItem,
Map<String, Object> parameters,
Map<String, Object> results) {
String namespace = (String) parameters.remove("Namespace");
String model = (String) parameters.remove("Model");
Expand Down Expand Up @@ -283,9 +301,54 @@ protected void handleDMN(Map<String, Object> parameters,
throw new RuntimeException("DMN result errors:: " + errors);
}

results.putAll(dmnResult.getContext().getAll());
// no class loader defined we don't even try to convert.
if(classLoader == null || runtimeManager == null) {
results.putAll(dmnResult.getContext().getAll());
return;
}

RuntimeEngine engine = runtimeManager.getRuntimeEngine(ProcessInstanceIdContext.get(workItem.getProcessInstanceId()));
try {
KieSession localksession = engine.getKieSession();
WorkflowProcessInstance processInstance = (WorkflowProcessInstance)
localksession.getProcessInstance(workItem.getProcessInstanceId());
WorkItemNodeInstance nodeInstance = findNodeInstance(workItem.getId(), processInstance);
WorkItemNode workItemNode = (WorkItemNode) nodeInstance.getNode();
// data outputs contains the structure refs for data association
Map<String, String> dataTypeOutputs = (Map<String, String>) workItemNode.getMetaData("DataOutputs");
Map<String, Object> data = dmnResult.getContext().getAll();
Map<String, Object> outcome = new HashMap<>();

if(!workItemNode.getOutAssociations().isEmpty()) {
// if there is one out association but the data is multiple we collapse to an object
if(workItemNode.getOutAssociations().size() == 1 && data.size() > 1) {
DataAssociation dataAssociation = workItemNode.getOutAssociations().get(0);
String type = dataTypeOutputs.get(dataAssociation.getTarget());
outcome.put(dataAssociation.getTarget(), transformResult(data, type));
} else {
// any other case we associated one by one
for(DataAssociation dataAssociation : workItemNode.getOutAssociations()) {
String type = dataTypeOutputs.get(dataAssociation.getTarget());
outcome.put(dataAssociation.getTarget(), transformResult(data.get(dataAssociation.getTarget()), type));
}
}
} else {
results.putAll(dmnResult.getContext().getAll());
}
} catch (IOException | ClassNotFoundException e) {
results.putAll(dmnResult.getContext().getAll());
} finally {
runtimeManager.disposeRuntimeEngine(engine);
}

}

private Object transformResult(Object toMarshal, String className) throws ClassNotFoundException, IOException {
ObjectMapper mapper = new ObjectMapper();
return mapper.convertValue(toMarshal, classLoader.loadClass(className));
}


public KieContainer getKieContainer() {
return this.kieContainer;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.jbpm.process.workitem.core.util.service.WidAction;
import org.jbpm.process.workitem.core.util.service.WidAuth;
import org.jbpm.process.workitem.core.util.service.WidService;
import org.kie.api.runtime.manager.RuntimeManager;

/**
* Additional BusinessRuleTask support that allows to decouple rules from processes - as default BusinessRuleTask
Expand Down Expand Up @@ -72,6 +73,15 @@ public BusinessRuleTaskHandler(String groupId,
super(groupId, artifactId, version, scannerInterval);
}

public BusinessRuleTaskHandler(String groupId,
String artifactId,
String version,
long scannerInterval,
ClassLoader classLoader,
RuntimeManager runtimeManager) {
super(groupId, artifactId, version, scannerInterval, classLoader, runtimeManager);
}

@Override
public String getRuleLanguage() {
return DRL_LANG;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import org.jbpm.process.workitem.core.util.service.WidAction;
import org.jbpm.process.workitem.core.util.service.WidAuth;
import org.jbpm.process.workitem.core.util.service.WidService;

import org.kie.api.runtime.manager.RuntimeManager;
/**
* Additional BusinessRuleTask support that allows to decouple rules from processes - as default BusinessRuleTask
* uses exact same working memory (kie session) as process which essentially means same kbase.
Expand Down Expand Up @@ -73,6 +73,15 @@ public DecisionTaskHandler(String groupId,
super(groupId, artifactId, version, scannerInterval);
}

public DecisionTaskHandler(String groupId,
String artifactId,
String version,
long scannerInterval,
ClassLoader classLoader,
RuntimeManager runtimeManager) {
super(groupId, artifactId, version, scannerInterval, classLoader, runtimeManager);
}

@Override
public String getRuleLanguage() {
return DMN_LANG;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ public void testDecisionTaskProcess() throws Exception {

BusinessRuleTaskHandler handler = new BusinessRuleTaskHandler(GROUP_ID,
ARTIFACT_ID,
VERSION);
VERSION,0);
ksession.getWorkItemManager().registerWorkItemHandler("DecisionTask",
handler);
Map<String, Object> params = new HashMap<String, Object>();
Expand Down

0 comments on commit 49987ff

Please sign in to comment.