Skip to content
This repository has been archived by the owner on Sep 13, 2022. It is now read-only.

Commit

Permalink
JBPM-5681 - DMN support for BusinessRuleTask (#548)
Browse files Browse the repository at this point in the history
  • Loading branch information
mswiderski committed Feb 15, 2017
1 parent db80708 commit 6a94b07
Show file tree
Hide file tree
Showing 13 changed files with 639 additions and 12 deletions.
Expand Up @@ -26,6 +26,9 @@
*
*/
public interface BpmnMarshallerHelper {

public static final String RULE_LANG_DRL = "DRL";
public static final String RULE_LANG_DMN = "DMN";

/**
* Applies the set of properties from the json model to the BPMN 2 element.
Expand Down
Expand Up @@ -26,7 +26,9 @@
import bpsim.impl.BpsimPackageImpl;
import org.eclipse.emf.common.util.EList;
import org.jboss.drools.*;
import org.jbpm.designer.bpmn2.BpmnMarshallerHelper;
import org.jbpm.designer.util.Utils;
import org.jbpm.workflow.core.node.RuleSetNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.codehaus.jackson.JsonEncoding;
Expand Down Expand Up @@ -1124,6 +1126,14 @@ protected void marshallTask(Task task, BPMNPlane plane, JsonGenerator generator,
properties.put("ruleflowgroup", entry.getValue());
}
}
String ruleLanguage = ((BusinessRuleTask) task).getImplementation();
if (RuleSetNode.DMN_LANG.equals(ruleLanguage)) {
ruleLanguage = BpmnMarshallerHelper.RULE_LANG_DMN;
} else {
ruleLanguage = BpmnMarshallerHelper.RULE_LANG_DRL;
}
properties.put("rulelanguage", ruleLanguage);

} else if (task instanceof ScriptTask) {
ScriptTask scriptTask = (ScriptTask) task;
properties.put("script", scriptTask.getScript() != null ? scriptTask.getScript().replace("\\", "\\\\").replace("\n", "\\n") : "");
Expand Down
Expand Up @@ -74,6 +74,7 @@
import org.jbpm.designer.bpmn2.resource.JBPMBpmn2ResourceFactoryImpl;
import org.jbpm.designer.bpmn2.util.DIZorderComparator;
import org.jbpm.designer.util.Utils;
import org.jbpm.workflow.core.node.RuleSetNode;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleReference;
import org.osgi.framework.InvalidSyntaxException;
Expand Down Expand Up @@ -4787,6 +4788,17 @@ protected void applyBusinessRuleTaskProperties(BusinessRuleTask task, Map<String
scriptLanguage);
task.getAnyAttribute().add(extensionEntry);
}

if(properties.get("rulelanguage") != null && properties.get("rulelanguage").length() > 0) {
String ruleLanguage = properties.get("rulelanguage");
if (BpmnMarshallerHelper.RULE_LANG_DMN.equals(ruleLanguage)) {
task.setImplementation(RuleSetNode.DMN_LANG);
} else {
task.setImplementation(RuleSetNode.DRL_LANG);
}
} else {
task.setImplementation(RuleSetNode.DRL_LANG);
}
}

protected void applyScriptTaskProperties(ScriptTask scriptTask, Map<String, String> properties) {
Expand Down
Expand Up @@ -35,9 +35,11 @@
import org.jbpm.bpmn2.xml.BPMNDISemanticModule;
import org.jbpm.bpmn2.xml.BPMNSemanticModule;
import org.jbpm.compiler.xml.XmlProcessReader;
import org.jbpm.designer.bpmn2.BpmnMarshallerHelper;
import org.jbpm.designer.web.profile.IDiagramProfile;
import org.jbpm.process.core.validation.ProcessValidationError;
import org.jbpm.ruleflow.core.validation.RuleFlowProcessValidator;
import org.jbpm.workflow.core.node.RuleSetNode;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
Expand Down Expand Up @@ -322,20 +324,52 @@ private void checkFlowNode(FlowNode flowNode, FlowElementsContainer container, P
}

private void checkBusinessRuleTask(BusinessRuleTask businessRuleTask) {
Iterator<FeatureMap.Entry> biter = businessRuleTask.getAnyAttribute().iterator();
boolean foundRuleflowGroup = false;
while(biter.hasNext()) {
FeatureMap.Entry entry = biter.next();
if(entry.getEStructuralFeature().getName().equals("ruleFlowGroup")) {
foundRuleflowGroup = true;
String ruleflowGroup = (String) entry.getValue();
if(isEmpty(ruleflowGroup)) {
addError(businessRuleTask, new ValidationSyntaxError(businessRuleTask, BPMN2_TYPE, SyntaxCheckerErrors.BUSINESS_RULE_TASK_NO_RULEFLOW_GROUP));
String ruleLanguage = businessRuleTask.getImplementation();
if (RuleSetNode.DMN_LANG.equals(ruleLanguage)) {
ruleLanguage = BpmnMarshallerHelper.RULE_LANG_DMN;
} else {
ruleLanguage = BpmnMarshallerHelper.RULE_LANG_DRL;
}
if (ruleLanguage.equals(BpmnMarshallerHelper.RULE_LANG_DRL)) {
Iterator<FeatureMap.Entry> biter = businessRuleTask.getAnyAttribute().iterator();
boolean foundRuleflowGroup = false;
while (biter.hasNext()) {
FeatureMap.Entry entry = biter.next();
if (entry.getEStructuralFeature().getName().equals("ruleFlowGroup")) {
foundRuleflowGroup = true;
String ruleflowGroup = (String) entry.getValue();
if (isEmpty(ruleflowGroup)) {
addError(businessRuleTask, new ValidationSyntaxError(businessRuleTask, BPMN2_TYPE, SyntaxCheckerErrors.BUSINESS_RULE_TASK_NO_RULEFLOW_GROUP));
}
}
}
}
if(!foundRuleflowGroup) {
addError(businessRuleTask, new ValidationSyntaxError(businessRuleTask, BPMN2_TYPE, SyntaxCheckerErrors.BUSINESS_RULE_TASK_NO_RULEFLOW_GROUP));
if (!foundRuleflowGroup) {
addError(businessRuleTask, new ValidationSyntaxError(businessRuleTask, BPMN2_TYPE, SyntaxCheckerErrors.BUSINESS_RULE_TASK_NO_RULEFLOW_GROUP));
}
} else if (ruleLanguage.equals(BpmnMarshallerHelper.RULE_LANG_DMN)) {
boolean missingNamespace = true;
boolean missingModel = true;
if (businessRuleTask.getIoSpecification() != null) {
List<DataInput> dataInputs = businessRuleTask.getIoSpecification().getDataInputs();

if (dataInputs != null) {
for (DataInput di : dataInputs) {
if ("namespace".equals(di.getName())) {
missingNamespace = false;
} else if ("model".equals(di.getName())) {
missingModel = false;
}

}
}
}
if (missingNamespace) {
addError(businessRuleTask, new ValidationSyntaxError(businessRuleTask, BPMN2_TYPE, SyntaxCheckerErrors.DMN_BUSINESS_RULE_TASK_NO_NAMESPACE));
}
if (missingModel) {
addError(businessRuleTask, new ValidationSyntaxError(businessRuleTask, BPMN2_TYPE, SyntaxCheckerErrors.DMN_BUSINESS_RULE_TASK_NO_MODEL));
}

}
}

Expand Down
Expand Up @@ -3,6 +3,8 @@
public class SyntaxCheckerErrors {
public static final String AT_LEAST_ONE_OUTGOING_PROBABILITY_VALUE_100 = "At least one outgoing connection should have probability equal to 100.";
public static final String BUSINESS_RULE_TASK_NO_RULEFLOW_GROUP = "Business Rule Task has no ruleflow-group.";
public static final String DMN_BUSINESS_RULE_TASK_NO_NAMESPACE = "DMN Business Rule Task has no namespace set.";
public static final String DMN_BUSINESS_RULE_TASK_NO_MODEL = "DMN Business Rule Task has no model set.";
public static final String COST_PER_TIME_UNIT_MUST_BE_POSITIVE = "Cost per Time Unit value must be positive.";
public static final String END_NODE_NO_INCOMING_CONNECTIONS = "End node has no incoming connections";
public static final String EVENT_HAS_NO_ERROR_REF = " Event has no errorref.";
Expand Down
Expand Up @@ -3,6 +3,7 @@
import java.util.ArrayList;
import java.util.List;

import org.jbpm.designer.bpmn2.BpmnMarshallerHelper;
import org.jbpm.designer.bpmn2.impl.helpers.SimpleEdge;
import org.jbpm.designer.bpmn2.utils.Bpmn2Loader;
import org.jbpm.designer.bpmn2.validation.BPMN2SyntaxCheckerTest;
Expand Down Expand Up @@ -446,6 +447,7 @@ public void testBusinessRuleTask() throws Exception {
JSONObject properties = ruleTask.getJSONObject("properties");
assertEquals("simpleGroup", properties.getString("ruleflowgroup"));
assertEquals(true, properties.getBoolean("isasync"));
assertEquals(BpmnMarshallerHelper.RULE_LANG_DRL, properties.getString("rulelanguage"));
}

@Test
Expand Down Expand Up @@ -566,4 +568,12 @@ public void testAdHocSubprocessDroolsCompletionCondition() throws Exception {
assertEquals("drools", scriptLanguage);
}

@Test
public void testDMNBusinessRuleTask() throws Exception {
JSONObject process = loader.loadProcessFromXml("dmnBusinessRule.bpmn2");
JSONObject ruleTask = getChildByName(process, "test");
JSONObject properties = ruleTask.getJSONObject("properties");
assertEquals(BpmnMarshallerHelper.RULE_LANG_DMN, properties.getString("rulelanguage"));
}

}
Expand Up @@ -35,6 +35,7 @@
import org.jboss.drools.impl.MetaDataTypeImpl;
import org.jbpm.designer.bpmn2.impl.helpers.SimpleEdge;
import org.jbpm.designer.bpmn2.utils.Bpmn2Loader;
import org.jbpm.workflow.core.node.RuleSetNode;
import org.junit.Test;

import static org.jbpm.designer.bpmn2.impl.helpers.SimpleEdge.*;
Expand Down Expand Up @@ -205,6 +206,7 @@ public void testBusinessRuleTask() throws Exception {
BusinessRuleTask ruleTask = (BusinessRuleTask) task;
verifyAttribute(ruleTask, "ruleFlowGroup", "simpleGroup");
assertEquals("<![CDATA[true]]>", getMetaDataValue(task.getExtensionValues(), "customAsync"));
assertEquals(RuleSetNode.DRL_LANG, ruleTask.getImplementation());
}

@Test
Expand Down Expand Up @@ -1692,6 +1694,16 @@ public void testAdHocSubprocessDroolsCompletionCondition() throws Exception {
assertEquals("http://www.jboss.org/drools/rule", expression.getLanguage());
}

@Test
public void testDMNBusinessRuleTask() throws Exception {
Definitions definitions = loader.loadProcessFromJson("dmnBusinessRule.json");
Process process = getRootProcess(definitions);
FlowElement task = getFlowElement(process.getFlowElements(), "test");
assertTrue(task instanceof BusinessRuleTask);
BusinessRuleTask ruleTask = (BusinessRuleTask) task;
assertEquals(RuleSetNode.DMN_LANG, ruleTask.getImplementation());
}

public void testInputOutputSetsOfIoSpecification() throws Exception {
Definitions definitions = loader.loadProcessFromJson("taskIoSpecification.json");
Process process = getRootProcess(definitions);
Expand Down
Expand Up @@ -306,6 +306,23 @@ public void testMultipleSubprocessStartEvents() throws Exception {
verifyErrorsOfElement(syntaxChecker, subProcess, Arrays.asList(SyntaxCheckerErrors.MULTIPLE_START_EVENTS));
}

@Test
public void testEmptyDMNBusinessRule() throws Exception {
JSONObject process = loader.loadProcessFromXml("emptyDmnBusinessRule.bpmn2", BPMN2SyntaxCheckerTest.class);
JSONObject ruleTask = loader.getChildByName(process, "test");
String processJson = loader.getProcessJson();
BPMN2SyntaxChecker syntaxChecker = new BPMN2SyntaxChecker(processJson, "", loader.getProfile());
verifyErrorsOfElement(syntaxChecker, ruleTask, Arrays.asList(SyntaxCheckerErrors.DMN_BUSINESS_RULE_TASK_NO_NAMESPACE, SyntaxCheckerErrors.DMN_BUSINESS_RULE_TASK_NO_MODEL));
}

@Test
public void testDMNBusinessRule() throws Exception {
loader.loadProcessFromXml("dmnBusinessRule.bpmn2");
String processJson = loader.getProcessJson();
BPMN2SyntaxChecker syntaxChecker = new BPMN2SyntaxChecker(processJson, "", loader.getProfile());
verifyNoErrors(syntaxChecker);
}

private void verifyNoErrors(SyntaxChecker syntaxChecker) throws Exception {
syntaxChecker.checkSyntax();
assertFalse(syntaxChecker.errorsFound());
Expand Down
@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="UTF-8"?>
<bpmn2:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.omg.org/bpmn20" xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:bpsim="http://www.bpsim.org/schemas/1.0" xmlns:color="http://www.omg.org/spec/BPMN/non-normative/color" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:drools="http://www.jboss.org/drools" id="_-1Ao0PINEealZIUu-TmO8g" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd http://www.jboss.org/drools drools.xsd http://www.bpsim.org/schemas/1.0 bpsim.xsd" exporter="jBPM Designer" exporterVersion="6.2.0" expressionLanguage="http://www.mvel.org/2.0" targetNamespace="http://www.omg.org/bpmn20" typeLanguage="http://www.java.com/javaTypes">
<bpmn2:itemDefinition id="__17AA6636-67D4-4AB8-B995-54C8E5997061_namespaceInputXItem" structureRef="String"/>
<bpmn2:itemDefinition id="__17AA6636-67D4-4AB8-B995-54C8E5997061_modelInputXItem" structureRef="String"/>
<bpmn2:process id="evaluation.ruletest" drools:packageName="org.jbpm" drools:version="1.0" name="ruletest" isExecutable="true">
<bpmn2:startEvent id="processStartEvent" drools:selectable="true" color:background-color="#9acd32" color:border-color="#000000" color:color="#000000" name="">
<bpmn2:extensionElements>
<drools:metaData name="elementname">
<drools:metaValue><![CDATA[]]></drools:metaValue>
</drools:metaData>
</bpmn2:extensionElements>
<bpmn2:outgoing>_D5C0FB17-AC8C-4BCF-BD69-9F973B581836</bpmn2:outgoing>
</bpmn2:startEvent>
<bpmn2:businessRuleTask id="_17AA6636-67D4-4AB8-B995-54C8E5997061" drools:selectable="true" drools:scriptFormat="http://www.java.com/java" color:background-color="#fafad2" color:border-color="#000000" color:color="#000000" name="test" implementation="http://www.jboss.org/drools/dmn">
<bpmn2:extensionElements>
<drools:metaData name="elementname">
<drools:metaValue><![CDATA[test]]></drools:metaValue>
</drools:metaData>
</bpmn2:extensionElements>
<bpmn2:incoming>_D5C0FB17-AC8C-4BCF-BD69-9F973B581836</bpmn2:incoming>
<bpmn2:outgoing>_F083F326-63AB-49F5-BC23-C412BA817441</bpmn2:outgoing>
<bpmn2:ioSpecification id="_-1Ao0fINEealZIUu-TmO8g">
<bpmn2:dataInput id="_17AA6636-67D4-4AB8-B995-54C8E5997061_namespaceInputX" drools:dtype="String" itemSubjectRef="__17AA6636-67D4-4AB8-B995-54C8E5997061_namespaceInputXItem" name="namespace"/>
<bpmn2:dataInput id="_17AA6636-67D4-4AB8-B995-54C8E5997061_modelInputX" drools:dtype="String" itemSubjectRef="__17AA6636-67D4-4AB8-B995-54C8E5997061_modelInputXItem" name="model"/>
<bpmn2:inputSet id="_-1Ao0vINEealZIUu-TmO8g">
<bpmn2:dataInputRefs>_17AA6636-67D4-4AB8-B995-54C8E5997061_namespaceInputX</bpmn2:dataInputRefs>
<bpmn2:dataInputRefs>_17AA6636-67D4-4AB8-B995-54C8E5997061_modelInputX</bpmn2:dataInputRefs>
</bpmn2:inputSet>
<bpmn2:outputSet id="_-1Ao0_INEealZIUu-TmO8g"/>
</bpmn2:ioSpecification>
<bpmn2:dataInputAssociation id="_-1Ao1PINEealZIUu-TmO8g">
<bpmn2:targetRef>_17AA6636-67D4-4AB8-B995-54C8E5997061_namespaceInputX</bpmn2:targetRef>
<bpmn2:assignment id="_-1Ao1fINEealZIUu-TmO8g">
<bpmn2:from xsi:type="bpmn2:tFormalExpression" id="_-1Ao1vINEealZIUu-TmO8g">dmn-namespace</bpmn2:from>
<bpmn2:to xsi:type="bpmn2:tFormalExpression" id="_-1Ao1_INEealZIUu-TmO8g">_17AA6636-67D4-4AB8-B995-54C8E5997061_namespaceInputX</bpmn2:to>
</bpmn2:assignment>
</bpmn2:dataInputAssociation>
<bpmn2:dataInputAssociation id="_-1Ao2PINEealZIUu-TmO8g">
<bpmn2:targetRef>_17AA6636-67D4-4AB8-B995-54C8E5997061_modelInputX</bpmn2:targetRef>
<bpmn2:assignment id="_-1Ao2fINEealZIUu-TmO8g">
<bpmn2:from xsi:type="bpmn2:tFormalExpression" id="_-1Ao2vINEealZIUu-TmO8g">mymodel</bpmn2:from>
<bpmn2:to xsi:type="bpmn2:tFormalExpression" id="_-1Ao2_INEealZIUu-TmO8g">_17AA6636-67D4-4AB8-B995-54C8E5997061_modelInputX</bpmn2:to>
</bpmn2:assignment>
</bpmn2:dataInputAssociation>
</bpmn2:businessRuleTask>
<bpmn2:sequenceFlow id="_D5C0FB17-AC8C-4BCF-BD69-9F973B581836" drools:selectable="true" color:background-color="#000000" color:border-color="#000000" color:color="#000000" sourceRef="processStartEvent" targetRef="_17AA6636-67D4-4AB8-B995-54C8E5997061"/>
<bpmn2:endEvent id="_BABAFC71-44A6-4480-9143-7DA25C4C17CF" drools:selectable="true" color:background-color="#ff6347" color:border-color="#000000" color:color="#000000" name="">
<bpmn2:extensionElements>
<drools:metaData name="elementname">
<drools:metaValue><![CDATA[]]></drools:metaValue>
</drools:metaData>
</bpmn2:extensionElements>
<bpmn2:incoming>_F083F326-63AB-49F5-BC23-C412BA817441</bpmn2:incoming>
</bpmn2:endEvent>
<bpmn2:sequenceFlow id="_F083F326-63AB-49F5-BC23-C412BA817441" drools:selectable="true" color:background-color="#000000" color:border-color="#000000" color:color="#000000" sourceRef="_17AA6636-67D4-4AB8-B995-54C8E5997061" targetRef="_BABAFC71-44A6-4480-9143-7DA25C4C17CF"/>
</bpmn2:process>
<bpmndi:BPMNDiagram id="_-1Ao3PINEealZIUu-TmO8g">
<bpmndi:BPMNPlane id="_-1Ao3fINEealZIUu-TmO8g" bpmnElement="evaluation.ruletest">
<bpmndi:BPMNShape id="_-1Ao3vINEealZIUu-TmO8g" bpmnElement="processStartEvent">
<dc:Bounds height="30.0" width="30.0" x="120.0" y="165.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_-1BP4PINEealZIUu-TmO8g" bpmnElement="_17AA6636-67D4-4AB8-B995-54C8E5997061">
<dc:Bounds height="80.0" width="100.0" x="195.0" y="140.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_-1BP4fINEealZIUu-TmO8g" bpmnElement="_BABAFC71-44A6-4480-9143-7DA25C4C17CF">
<dc:Bounds height="28.0" width="28.0" x="345.0" y="166.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="_-1BP4vINEealZIUu-TmO8g" bpmnElement="_D5C0FB17-AC8C-4BCF-BD69-9F973B581836" sourceElement="_-1Ao3vINEealZIUu-TmO8g" targetElement="_-1BP4PINEealZIUu-TmO8g">
<di:waypoint xsi:type="dc:Point" x="135.0" y="180.0"/>
<di:waypoint xsi:type="dc:Point" x="245.0" y="180.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="_-1BP4_INEealZIUu-TmO8g" bpmnElement="_F083F326-63AB-49F5-BC23-C412BA817441" sourceElement="_-1BP4PINEealZIUu-TmO8g" targetElement="_-1BP4fINEealZIUu-TmO8g">
<di:waypoint xsi:type="dc:Point" x="245.0" y="180.0"/>
<di:waypoint xsi:type="dc:Point" x="359.0" y="180.0"/>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn2:definitions>

0 comments on commit 6a94b07

Please sign in to comment.