From 7eddedb6fcff628c271ba6db10e11b8935c64e37 Mon Sep 17 00:00:00 2001 From: egonzale Date: Mon, 7 Jun 2021 09:34:37 +0200 Subject: [PATCH] [JBPM-9774] Incorrect object type returned in a DMN business-rule task of a BPMN --- .../test/java/org/jbpm/test/JbpmTestCase.java | 40 +++++ .../functional/task/BusinessRuleTaskTest.java | 111 ++++++++++++++ .../task/buildPersonCollectionDecision.dmn | 46 ++++++ .../functional/task/buildPersonDecision.dmn | 46 ++++++ .../businessRuleCollectionTaskProcess.bpmn2 | 143 ++++++++++++++++++ .../task/businessRuleTaskProcess.bpmn2 | 143 ++++++++++++++++++ jbpm-workitems/jbpm-workitems-bpmn2/pom.xml | 5 +- .../bpmn2/AbstractRuleTaskHandler.java | 87 +++++++++-- .../bpmn2/BusinessRuleTaskHandler.java | 10 ++ .../workitem/bpmn2/DecisionTaskHandler.java | 11 +- .../workitem/bpmn2/TypeTransformer.java | 72 +++++++++ .../workitem/bpmn2/BusinessRuleTaskTest.java | 2 +- .../workitem/bpmn2/TypeTransformerTest.java | 51 +++++++ .../workitem/bpmn2/objects/Person.java | 4 + 14 files changed, 756 insertions(+), 15 deletions(-) create mode 100644 jbpm-test-coverage/src/test/java/org/jbpm/test/functional/task/BusinessRuleTaskTest.java create mode 100644 jbpm-test-coverage/src/test/resources/org/jbpm/test/functional/task/buildPersonCollectionDecision.dmn create mode 100644 jbpm-test-coverage/src/test/resources/org/jbpm/test/functional/task/buildPersonDecision.dmn create mode 100644 jbpm-test-coverage/src/test/resources/org/jbpm/test/functional/task/businessRuleCollectionTaskProcess.bpmn2 create mode 100644 jbpm-test-coverage/src/test/resources/org/jbpm/test/functional/task/businessRuleTaskProcess.bpmn2 create mode 100644 jbpm-workitems/jbpm-workitems-bpmn2/src/main/java/org/jbpm/process/workitem/bpmn2/TypeTransformer.java create mode 100644 jbpm-workitems/jbpm-workitems-bpmn2/src/test/java/org/jbpm/process/workitem/bpmn2/TypeTransformerTest.java diff --git a/jbpm-test-coverage/src/test/java/org/jbpm/test/JbpmTestCase.java b/jbpm-test-coverage/src/test/java/org/jbpm/test/JbpmTestCase.java index fbb596f2fe..38fe485e1b 100644 --- a/jbpm-test-coverage/src/test/java/org/jbpm/test/JbpmTestCase.java +++ b/jbpm-test-coverage/src/test/java/org/jbpm/test/JbpmTestCase.java @@ -16,19 +16,32 @@ package org.jbpm.test; +import java.io.File; +import java.nio.file.Files; import java.util.Map; import java.util.Properties; +import java.util.UUID; +import org.apache.commons.io.IOUtils; import org.assertj.core.api.Assertions; +import org.drools.compiler.kie.builder.impl.InternalKieModule; import org.jbpm.test.persistence.util.PersistenceUtil; import org.junit.Rule; import org.junit.rules.TestRule; import org.junit.rules.TestWatcher; import org.junit.runner.Description; import org.kie.api.KieServices; +import org.kie.api.builder.KieBuilder; +import org.kie.api.builder.KieFileSystem; +import org.kie.api.builder.Message; +import org.kie.api.builder.ReleaseId; +import org.kie.api.builder.Results; import org.kie.api.command.KieCommands; +import org.kie.api.io.Resource; import org.kie.api.io.ResourceType; import org.kie.api.runtime.KieSession; +import org.kie.internal.builder.InternalKieBuilder; +import org.kie.scanner.KieMavenRepository; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -104,5 +117,32 @@ protected static KieCommands getCommands() { return getServices().getCommands(); } + protected byte[] createAndDeployJar(KieServices ks, ReleaseId releaseId, Resource... resources) throws Exception { + KieFileSystem kfs = ks.newKieFileSystem().generateAndWritePomXML(releaseId); + for (int i = 0; i < resources.length; i++) { + if (resources[i] != null) { + kfs.write(resources[i]); + } + } + KieBuilder kieBuilder = ks.newKieBuilder(kfs); + ((InternalKieBuilder) kieBuilder).buildAll(o -> true); + Results results = kieBuilder.getResults(); + if (results.hasMessages(Message.Level.ERROR)) { + throw new IllegalStateException(results.getMessages(Message.Level.ERROR).toString()); + } + InternalKieModule kieModule = (InternalKieModule) ks.getRepository().getKieModule(releaseId); + byte[] pomXmlContent = IOUtils.toByteArray(kieModule.getPomAsStream()); + File pom = new File("target", + UUID.randomUUID().toString()); + Files.write(pom.toPath(), + pomXmlContent); + KieMavenRepository.getKieMavenRepository().installArtifact(releaseId, + kieModule, + pom); + + byte[] jar = kieModule.getBytes(); + return jar; + } + } diff --git a/jbpm-test-coverage/src/test/java/org/jbpm/test/functional/task/BusinessRuleTaskTest.java b/jbpm-test-coverage/src/test/java/org/jbpm/test/functional/task/BusinessRuleTaskTest.java new file mode 100644 index 0000000000..c56198313d --- /dev/null +++ b/jbpm-test-coverage/src/test/java/org/jbpm/test/functional/task/BusinessRuleTaskTest.java @@ -0,0 +1,111 @@ +/* + * Copyright 2017 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. + * 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.jbpm.test.functional.task; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import org.jbpm.process.workitem.bpmn2.BusinessRuleTaskHandler; +import org.jbpm.test.JbpmTestCase; +import org.jbpm.test.domain.Person; +import org.jbpm.workflow.instance.impl.WorkflowProcessInstanceImpl; +import org.junit.Assert; +import org.junit.Test; +import org.kie.api.KieServices; +import org.kie.api.io.ResourceType; +import org.kie.api.runtime.KieSession; +import org.kie.api.runtime.process.ProcessInstance; + +/** + * Business rules task test. testing execution of rules with specified rule-flow group. + */ +public class BusinessRuleTaskTest extends JbpmTestCase { + + private static final String RULE_TASK = "org/jbpm/test/functional/task/businessRuleTaskProcess.bpmn2"; + private static final String RULE_TASK_ID = "org.jbpm.test.functional.task.businessRuleTask"; + + private static final String RULE_TASK_COLLECTION = "org/jbpm/test/functional/task/businessRuleCollectionTaskProcess.bpmn2"; + private static final String RULE_TASK_COLLECTION_ID = "org.jbpm.test.functional.task.businessRuleTask"; + + private static final String GROUP_ID = "org.jbpm"; + private static final String ARTIFACT_ID = "test-kjar"; + private static final String VERSION = "1.0"; + + private KieServices ks = KieServices.Factory.get(); + + public BusinessRuleTaskTest() { + super(false); + } + + @Test + public void testRuleTask() throws Exception { + // deploy external kjar + createAndDeployJar(ks, + ks.newReleaseId(GROUP_ID, + ARTIFACT_ID, + VERSION), + ks.getResources().newClassPathResource("org/jbpm/test/functional/task/buildPersonDecision.dmn"), + ks.getResources().newFileSystemResource("src/main/java/org/jbpm/test/domain/Person.java")); + + // create the brt + BusinessRuleTaskHandler handler = new BusinessRuleTaskHandler(GROUP_ID, + ARTIFACT_ID, + VERSION,0, this.getClass().getClassLoader(), this.manager); + addWorkItemHandler("BusinessRuleTask", handler); + + KieSession kieSession = createKSession(RULE_TASK); + handler.setRuntimeManager(manager); + + WorkflowProcessInstanceImpl pi = (WorkflowProcessInstanceImpl) kieSession.startProcess(RULE_TASK_ID); + Assert.assertTrue(pi.getVariable("person") instanceof Person); + + } + + @Test + public void testRuleTaskCollection() throws Exception { + // deploy external kjar + createAndDeployJar(ks, + ks.newReleaseId(GROUP_ID, + ARTIFACT_ID, + VERSION), + ks.getResources().newClassPathResource("org/jbpm/test/functional/task/buildPersonCollectionDecision.dmn"), + ks.getResources().newFileSystemResource("src/main/java/org/jbpm/test/domain/Person.java")); + + // create the brt + BusinessRuleTaskHandler handler = new BusinessRuleTaskHandler(GROUP_ID, + ARTIFACT_ID, + VERSION,0, this.getClass().getClassLoader(), this.manager); + addWorkItemHandler("BusinessRuleTask", handler); + + KieSession kieSession = createKSession(RULE_TASK_COLLECTION); + handler.setRuntimeManager(manager); + + WorkflowProcessInstanceImpl pi = (WorkflowProcessInstanceImpl) kieSession.startProcess(RULE_TASK_COLLECTION_ID); + Assert.assertTrue(pi.getVariable("person") instanceof List); + Assert.assertTrue(((List) pi.getVariable("person")).get(0) instanceof Person); + + } + + public KieSession createKSession(Map res) { + createRuntimeManager(res); + return getRuntimeEngine().getKieSession(); + } + + + +} \ No newline at end of file diff --git a/jbpm-test-coverage/src/test/resources/org/jbpm/test/functional/task/buildPersonCollectionDecision.dmn b/jbpm-test-coverage/src/test/resources/org/jbpm/test/functional/task/buildPersonCollectionDecision.dmn new file mode 100644 index 0000000000..06b9df6fd5 --- /dev/null +++ b/jbpm-test-coverage/src/test/resources/org/jbpm/test/functional/task/buildPersonCollectionDecision.dmn @@ -0,0 +1,46 @@ + + + + + + number + + + string + + + + + + + [ { "name" : "john dow", age: 12 } ] + + + + + + + + 300 + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/jbpm-test-coverage/src/test/resources/org/jbpm/test/functional/task/buildPersonDecision.dmn b/jbpm-test-coverage/src/test/resources/org/jbpm/test/functional/task/buildPersonDecision.dmn new file mode 100644 index 0000000000..e86eb29b22 --- /dev/null +++ b/jbpm-test-coverage/src/test/resources/org/jbpm/test/functional/task/buildPersonDecision.dmn @@ -0,0 +1,46 @@ + + + + + + number + + + string + + + + + + + { "name" : "john dow", age: 12 } + + + + + + + + 300 + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/jbpm-test-coverage/src/test/resources/org/jbpm/test/functional/task/businessRuleCollectionTaskProcess.bpmn2 b/jbpm-test-coverage/src/test/resources/org/jbpm/test/functional/task/businessRuleCollectionTaskProcess.bpmn2 new file mode 100644 index 0000000000..825b95f551 --- /dev/null +++ b/jbpm-test-coverage/src/test/resources/org/jbpm/test/functional/task/businessRuleCollectionTaskProcess.bpmn2 @@ -0,0 +1,143 @@ + + + + + + + + + + + + + + + + + + + + + _3BC25712-7B84-401D-B679-2A6F32F2562E + + + + + + + + _3BC25712-7B84-401D-B679-2A6F32F2562E + _7E6A1B8E-9C93-4A27-B9E3-A4F2CC334307 + + + + + + + + + + + + _1A84CCFE-AABC-4C31-A88D-FD534C5BA734_LanguageInputX + _1A84CCFE-AABC-4C31-A88D-FD534C5BA734_ModelInputX + _1A84CCFE-AABC-4C31-A88D-FD534C5BA734_NamespaceInputX + _1A84CCFE-AABC-4C31-A88D-FD534C5BA734_DecisionInputX + _1A84CCFE-AABC-4C31-A88D-FD534C5BA734_personInputX + _1A84CCFE-AABC-4C31-A88D-FD534C5BA734_TaskNameInputX + + + _1A84CCFE-AABC-4C31-A88D-FD534C5BA734_personOutputX + + + + _1A84CCFE-AABC-4C31-A88D-FD534C5BA734_LanguageInputX + + + _1A84CCFE-AABC-4C31-A88D-FD534C5BA734_LanguageInputX + + + + _1A84CCFE-AABC-4C31-A88D-FD534C5BA734_ModelInputX + + + _1A84CCFE-AABC-4C31-A88D-FD534C5BA734_ModelInputX + + + + _1A84CCFE-AABC-4C31-A88D-FD534C5BA734_NamespaceInputX + + + _1A84CCFE-AABC-4C31-A88D-FD534C5BA734_NamespaceInputX + + + + _1A84CCFE-AABC-4C31-A88D-FD534C5BA734_DecisionInputX + + + _1A84CCFE-AABC-4C31-A88D-FD534C5BA734_DecisionInputX + + + + _1A84CCFE-AABC-4C31-A88D-FD534C5BA734_TaskNameInputX + + + _1A84CCFE-AABC-4C31-A88D-FD534C5BA734_TaskNameInputX + + + + personBRL + person + + + + + + + + + _7E6A1B8E-9C93-4A27-B9E3-A4F2CC334307 + _8E0320B7-E7B8-4D28-B560-146657A4B78E + + + + + + + + + + _8E0320B7-E7B8-4D28-B560-146657A4B78E + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/jbpm-test-coverage/src/test/resources/org/jbpm/test/functional/task/businessRuleTaskProcess.bpmn2 b/jbpm-test-coverage/src/test/resources/org/jbpm/test/functional/task/businessRuleTaskProcess.bpmn2 new file mode 100644 index 0000000000..69dfc45588 --- /dev/null +++ b/jbpm-test-coverage/src/test/resources/org/jbpm/test/functional/task/businessRuleTaskProcess.bpmn2 @@ -0,0 +1,143 @@ + + + + + + + + + + + + + + + + + + + + + _3BC25712-7B84-401D-B679-2A6F32F2562E + + + + + + + + _3BC25712-7B84-401D-B679-2A6F32F2562E + _7E6A1B8E-9C93-4A27-B9E3-A4F2CC334307 + + + + + + + + + + + + _1A84CCFE-AABC-4C31-A88D-FD534C5BA734_LanguageInputX + _1A84CCFE-AABC-4C31-A88D-FD534C5BA734_ModelInputX + _1A84CCFE-AABC-4C31-A88D-FD534C5BA734_NamespaceInputX + _1A84CCFE-AABC-4C31-A88D-FD534C5BA734_DecisionInputX + _1A84CCFE-AABC-4C31-A88D-FD534C5BA734_personInputX + _1A84CCFE-AABC-4C31-A88D-FD534C5BA734_TaskNameInputX + + + _1A84CCFE-AABC-4C31-A88D-FD534C5BA734_personOutputX + + + + _1A84CCFE-AABC-4C31-A88D-FD534C5BA734_LanguageInputX + + + _1A84CCFE-AABC-4C31-A88D-FD534C5BA734_LanguageInputX + + + + _1A84CCFE-AABC-4C31-A88D-FD534C5BA734_ModelInputX + + + _1A84CCFE-AABC-4C31-A88D-FD534C5BA734_ModelInputX + + + + _1A84CCFE-AABC-4C31-A88D-FD534C5BA734_NamespaceInputX + + + _1A84CCFE-AABC-4C31-A88D-FD534C5BA734_NamespaceInputX + + + + _1A84CCFE-AABC-4C31-A88D-FD534C5BA734_DecisionInputX + + + _1A84CCFE-AABC-4C31-A88D-FD534C5BA734_DecisionInputX + + + + _1A84CCFE-AABC-4C31-A88D-FD534C5BA734_TaskNameInputX + + + _1A84CCFE-AABC-4C31-A88D-FD534C5BA734_TaskNameInputX + + + + personBRL + person + + + + + + + + + _7E6A1B8E-9C93-4A27-B9E3-A4F2CC334307 + _8E0320B7-E7B8-4D28-B560-146657A4B78E + + + + + + + + + + _8E0320B7-E7B8-4D28-B560-146657A4B78E + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/jbpm-workitems/jbpm-workitems-bpmn2/pom.xml b/jbpm-workitems/jbpm-workitems-bpmn2/pom.xml index 4441a0e343..3d6387c69e 100644 --- a/jbpm-workitems/jbpm-workitems-bpmn2/pom.xml +++ b/jbpm-workitems/jbpm-workitems-bpmn2/pom.xml @@ -117,7 +117,10 @@ - + + com.fasterxml.jackson.core + jackson-databind + org.jbpm jbpm-workitems-core diff --git a/jbpm-workitems/jbpm-workitems-bpmn2/src/main/java/org/jbpm/process/workitem/bpmn2/AbstractRuleTaskHandler.java b/jbpm-workitems/jbpm-workitems-bpmn2/src/main/java/org/jbpm/process/workitem/bpmn2/AbstractRuleTaskHandler.java index d1031b93b2..67f87f1652 100644 --- a/jbpm-workitems/jbpm-workitems-bpmn2/src/main/java/org/jbpm/process/workitem/bpmn2/AbstractRuleTaskHandler.java +++ b/jbpm-workitems/jbpm-workitems-bpmn2/src/main/java/org/jbpm/process/workitem/bpmn2/AbstractRuleTaskHandler.java @@ -15,7 +15,9 @@ */ package org.jbpm.process.workitem.bpmn2; +import java.io.IOException; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -23,12 +25,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; @@ -38,6 +38,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; @@ -47,9 +49,15 @@ 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; +import com.github.javaparser.JavaParser; +import com.github.javaparser.JavaParserBuild; + /** * 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. @@ -90,6 +98,10 @@ public abstract class AbstractRuleTaskHandler extends AbstractLogOrThrowWorkItem private KieContainer kieContainer; private KieScanner kieScanner; + private ClassLoader classLoader; + private RuntimeManager runtimeManager; + private TypeTransformer typeTransformer; + public AbstractRuleTaskHandler(String groupId, String artifactId, String version) { @@ -99,10 +111,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, @@ -111,6 +131,9 @@ public AbstractRuleTaskHandler(String groupId, kieContainer = kieServices.newKieContainer(kieServices.newReleaseId(groupId, artifactId, version)); + this.classLoader = classLoader; + this.runtimeManager = runtimeManager; + this.typeTransformer = new TypeTransformer(classLoader); if (scannerInterval > 0) { kieScanner = kieServices.newKieScanner(kieContainer); @@ -154,7 +177,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); @@ -174,6 +198,10 @@ public void abortWorkItem(WorkItem workItem, // no-op } + public void setRuntimeManager(RuntimeManager runtimeManager) { + this.runtimeManager = runtimeManager; + } + @Override public void close() { if (kieScanner != null) { @@ -218,8 +246,7 @@ protected void handleStateless(WorkItem workItem, String kieSessionName, Map parameters, Map 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> commands = new ArrayList>(); @@ -246,7 +273,8 @@ protected void handleStateless(WorkItem workItem, } } - protected void handleDMN(Map parameters, + protected void handleDMN(WorkItem workItem, + Map parameters, Map results) { String namespace = (String) parameters.remove("Namespace"); String model = (String) parameters.remove("Model"); @@ -283,9 +311,44 @@ protected void handleDMN(Map 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 dataTypeOutputs = (Map) workItemNode.getMetaData("DataOutputs"); + Map decisionOutputData = dmnResult.getContext().getAll(); + Map outcome = new HashMap<>(); + + if(!workItemNode.getOutAssociations().isEmpty()) { + // if there is one out association but the data is multiple we collapse to an object + for(DataAssociation dataAssociation : workItemNode.getOutAssociations()) { + String targetOutputTask = dataAssociation.getSources().get(0); + String targetTypeOutputTask = dataTypeOutputs.get(targetOutputTask); + outcome.put(targetOutputTask, typeTransformer.transform(decisionOutputData.get(targetOutputTask), targetTypeOutputTask)); + } + results.putAll(outcome); + } else { + results.putAll(dmnResult.getContext().getAll()); + } + } catch (IOException | ClassNotFoundException e) { + results.putAll(dmnResult.getContext().getAll()); + } finally { + runtimeManager.disposeRuntimeEngine(engine); + } + } + public KieContainer getKieContainer() { return this.kieContainer; } diff --git a/jbpm-workitems/jbpm-workitems-bpmn2/src/main/java/org/jbpm/process/workitem/bpmn2/BusinessRuleTaskHandler.java b/jbpm-workitems/jbpm-workitems-bpmn2/src/main/java/org/jbpm/process/workitem/bpmn2/BusinessRuleTaskHandler.java index 2f1529e154..22315e0b4a 100644 --- a/jbpm-workitems/jbpm-workitems-bpmn2/src/main/java/org/jbpm/process/workitem/bpmn2/BusinessRuleTaskHandler.java +++ b/jbpm-workitems/jbpm-workitems-bpmn2/src/main/java/org/jbpm/process/workitem/bpmn2/BusinessRuleTaskHandler.java @@ -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 @@ -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; diff --git a/jbpm-workitems/jbpm-workitems-bpmn2/src/main/java/org/jbpm/process/workitem/bpmn2/DecisionTaskHandler.java b/jbpm-workitems/jbpm-workitems-bpmn2/src/main/java/org/jbpm/process/workitem/bpmn2/DecisionTaskHandler.java index 3bd820be9b..d052f51065 100644 --- a/jbpm-workitems/jbpm-workitems-bpmn2/src/main/java/org/jbpm/process/workitem/bpmn2/DecisionTaskHandler.java +++ b/jbpm-workitems/jbpm-workitems-bpmn2/src/main/java/org/jbpm/process/workitem/bpmn2/DecisionTaskHandler.java @@ -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. @@ -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; diff --git a/jbpm-workitems/jbpm-workitems-bpmn2/src/main/java/org/jbpm/process/workitem/bpmn2/TypeTransformer.java b/jbpm-workitems/jbpm-workitems-bpmn2/src/main/java/org/jbpm/process/workitem/bpmn2/TypeTransformer.java new file mode 100644 index 0000000000..09b2e384df --- /dev/null +++ b/jbpm-workitems/jbpm-workitems-bpmn2/src/main/java/org/jbpm/process/workitem/bpmn2/TypeTransformer.java @@ -0,0 +1,72 @@ +/* + * Copyright 2021 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. + * 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.jbpm.process.workitem.bpmn2; + +import java.io.IOException; +import java.io.StringReader; +import java.util.Collection; +import java.util.List; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.JavaType; +import com.github.javaparser.JavaParser; +import com.github.javaparser.ParseResult; +import com.github.javaparser.ast.type.ClassOrInterfaceType; +import com.github.javaparser.ast.type.Type; +import com.github.javaparser.ast.type.ClassOrInterfaceType; + + +public class TypeTransformer { + + private ObjectMapper mapper; + private ClassLoader classLoader; + + public TypeTransformer() { + this(TypeTransformer.class.getClassLoader()); + } + public TypeTransformer(ClassLoader classLoader) { + this.mapper = new ObjectMapper(); + this.classLoader = classLoader; + } + + public Object transform(Object toMarshal, String className) throws ClassNotFoundException, IOException { + JavaParser parser = new JavaParser(); + ParseResult unit = parser.parseType(className); + if(!unit.isSuccessful()) { + return toMarshal; + } + ClassOrInterfaceType type = (ClassOrInterfaceType) unit.getResult().get(); + Class targetClazz = classLoader.loadClass(toString(type)); + if(Collection.class.isAssignableFrom(targetClazz) && type.getTypeArguments().isPresent()) { + // it is a generic so we try to read it. + ClassOrInterfaceType argument = (ClassOrInterfaceType) type.getTypeArguments().get().get(0); + Class genericType = classLoader.loadClass(toString(argument)); + JavaType targetGenericType = mapper.getTypeFactory().constructCollectionType(List.class, genericType); + return mapper.convertValue(toMarshal, targetGenericType); + } + + return mapper.convertValue(toMarshal, targetClazz); + + } + + private String toString(ClassOrInterfaceType type) { + StringBuilder str = new StringBuilder(); + type.getScope().ifPresent(s -> str.append(s.asString()).append(".")); + str.append(type.getNameAsString()); + return str.toString(); + } +} diff --git a/jbpm-workitems/jbpm-workitems-bpmn2/src/test/java/org/jbpm/process/workitem/bpmn2/BusinessRuleTaskTest.java b/jbpm-workitems/jbpm-workitems-bpmn2/src/test/java/org/jbpm/process/workitem/bpmn2/BusinessRuleTaskTest.java index 85535df99b..bf2e9ec446 100644 --- a/jbpm-workitems/jbpm-workitems-bpmn2/src/test/java/org/jbpm/process/workitem/bpmn2/BusinessRuleTaskTest.java +++ b/jbpm-workitems/jbpm-workitems-bpmn2/src/test/java/org/jbpm/process/workitem/bpmn2/BusinessRuleTaskTest.java @@ -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 params = new HashMap(); diff --git a/jbpm-workitems/jbpm-workitems-bpmn2/src/test/java/org/jbpm/process/workitem/bpmn2/TypeTransformerTest.java b/jbpm-workitems/jbpm-workitems-bpmn2/src/test/java/org/jbpm/process/workitem/bpmn2/TypeTransformerTest.java new file mode 100644 index 0000000000..c3013668bc --- /dev/null +++ b/jbpm-workitems/jbpm-workitems-bpmn2/src/test/java/org/jbpm/process/workitem/bpmn2/TypeTransformerTest.java @@ -0,0 +1,51 @@ +/* + * Copyright 2021 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. + * 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.jbpm.process.workitem.bpmn2; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import org.jbpm.process.workitem.bpmn2.objects.Person; +import org.junit.Assert; +import org.junit.Test; + +public class TypeTransformerTest { + + @Test + public void pojoTest() throws Exception { + TypeTransformer typeTransformer = new TypeTransformer(); + Map data= new LinkedHashMap<>(); + data.put("age", 12); + Object person = typeTransformer.transform(data, Person.class.getCanonicalName()); + Assert.assertTrue(person instanceof Person); + } + + @Test + public void colletionTest() throws Exception { + TypeTransformer typeTransformer = new TypeTransformer(); + List> data = new ArrayList<>(); + Map p1 = new LinkedHashMap<>(); + p1.put("age", 12); + data.add(p1); + Object outcome = typeTransformer.transform(data, "java.util.List"); + Assert.assertTrue(outcome instanceof java.util.List); + List persons = (List) outcome; + Assert.assertTrue(persons.get(0) instanceof Person); + } +} diff --git a/jbpm-workitems/jbpm-workitems-bpmn2/src/test/java/org/jbpm/process/workitem/bpmn2/objects/Person.java b/jbpm-workitems/jbpm-workitems-bpmn2/src/test/java/org/jbpm/process/workitem/bpmn2/objects/Person.java index 78724db891..df17108339 100644 --- a/jbpm-workitems/jbpm-workitems-bpmn2/src/test/java/org/jbpm/process/workitem/bpmn2/objects/Person.java +++ b/jbpm-workitems/jbpm-workitems-bpmn2/src/test/java/org/jbpm/process/workitem/bpmn2/objects/Person.java @@ -21,6 +21,10 @@ public class Person { private String name; private Integer age; + public Person() { + // do nothing + } + public Person(String name) { this.name = name; }