From be2acca4ac24f4ed270ecf435a97782ac4c627ae Mon Sep 17 00:00:00 2001 From: tarilabs Date: Fri, 8 Sep 2017 11:01:28 +0200 Subject: [PATCH] Fixing the remainder of the code and providing test case. --- .../java/org/kie/dmn/core/DMNRuntimeTest.java | 62 ++++++++++++- .../org/kie/dmn/core/util/DMNRuntimeUtil.java | 19 ++++ .../resources/org/kie/dmn/core/Caller.dmn | 86 +++++++++++++++++++ .../resources/org/kie/dmn/core/Calling.dmn | 62 +++++++++++++ .../runtime/functions/BuiltInFunctions.java | 7 +- .../functions/CallDecisionFunction.java | 23 ++++- 6 files changed, 252 insertions(+), 7 deletions(-) create mode 100644 kie-dmn/kie-dmn-core/src/test/resources/org/kie/dmn/core/Caller.dmn create mode 100644 kie-dmn/kie-dmn-core/src/test/resources/org/kie/dmn/core/Calling.dmn diff --git a/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/DMNRuntimeTest.java b/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/DMNRuntimeTest.java index 754aaa892d6..5da45a2ec51 100644 --- a/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/DMNRuntimeTest.java +++ b/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/DMNRuntimeTest.java @@ -25,7 +25,9 @@ import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.hasEntry; import static org.hamcrest.Matchers.hasSize; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; import static org.kie.dmn.core.util.DynamicTypeUtils.entry; import static org.kie.dmn.core.util.DynamicTypeUtils.prototype; import static org.mockito.Matchers.any; @@ -48,6 +50,7 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; + import org.junit.Ignore; import org.junit.Test; import org.kie.dmn.api.core.DMNContext; @@ -1322,5 +1325,62 @@ public void testArtificialAttributes() { assertThat( result.get( "Greeting Message" ), is( "Hello John Doe" ) ); } + + @Test + public void testCallDecisionFunction() { + DMNRuntime runtime = DMNRuntimeUtil.createRuntimeWithAdditionalResources( "Caller.dmn", this.getClass(), "Calling.dmn" ); + DMNModel dmnModel = runtime.getModel( "http://www.trisotech.com/definitions/_b0a696d6-3d57-4e97-b5d4-b44a63909d67", "Caller" ); + assertThat( dmnModel, notNullValue() ); + + DMNContext context = DMNFactory.newContext(); + context.set( "My Name", "John Doe" ); + context.set( "My Number", 3 ); + context.set( "Call ns", "http://www.trisotech.com/definitions/_88156d21-3acc-43b6-8b81-385caf0bb6ca" ); + context.set( "Call name", "Calling" ); + context.set( "Call decision", "Final Result" ); + + // Good case. + { + DMNResult dmnResult = runtime.evaluateAll( dmnModel, context ); + assertThat( DMNRuntimeUtil.formatMessages( dmnResult.getMessages() ), dmnResult.hasErrors(), is( false ) ); + + DMNContext result = dmnResult.getContext(); + assertThat( result.get( "Final decision" ), is( "The final decision is: Hello, John Doe your number once double is equal to: 6" ) ); + } + + // Error if wrong namespace/name + { + DMNContext wrongNsContext = context.clone(); + wrongNsContext.set("Call ns", "http://www.acme.com/a-wrong-namespace"); + + DMNResult wrongNsResult = runtime.evaluateAll( dmnModel, wrongNsContext ); + assertThat( DMNRuntimeUtil.formatMessages( wrongNsResult.getMessages() ), wrongNsResult.hasErrors(), is( true ) ); + // total of: 2. x1 error in calling external decision, and x1 error in making final decision as it depends on the former. + assertThat( wrongNsResult.getMessages().size(), is( 2 ) ); + } + + // Error if wrong decision name in model + { + DMNContext wrongDecisionContext = context.clone(); + wrongDecisionContext.set("Call decision", ""); + + DMNResult wrongDecisionResult = runtime.evaluateAll( dmnModel, wrongDecisionContext ); + assertThat( DMNRuntimeUtil.formatMessages( wrongDecisionResult.getMessages() ), wrongDecisionResult.hasErrors(), is( true ) ); + // total of: 2. x1 error in calling external decision, and x1 error in making final decision as it depends on the former. + assertThat( wrongDecisionResult.getMessages().size(), is( 2 ) ); + } + + // Error if model and decision is found, but problem in external invocation. + { + DMNContext wrongContext = context.clone(); + wrongContext.set("My Number", ""); + + DMNResult wrongResult = runtime.evaluateAll( dmnModel, wrongContext ); + assertThat( DMNRuntimeUtil.formatMessages( wrongResult.getMessages() ), wrongResult.hasErrors(), is( true ) ); + // total of: 2. x1 error in calling external decision, and x1 error in making final decision as it depends on the former. + // please notice it will print 4 lines in the log, 2x are the "external invocation" and then 2x are the one by the caller, checked herebelow: + assertThat( wrongResult.getMessages().size(), is( 2 ) ); + } + } } diff --git a/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/util/DMNRuntimeUtil.java b/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/util/DMNRuntimeUtil.java index 80d2a681ed3..d81a60ecacb 100644 --- a/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/util/DMNRuntimeUtil.java +++ b/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/util/DMNRuntimeUtil.java @@ -16,12 +16,14 @@ package org.kie.dmn.core.util; +import java.util.ArrayList; import java.util.List; import java.util.UUID; import java.util.stream.Collectors; import org.junit.Assert; import org.kie.api.KieServices; +import org.kie.api.io.Resource; import org.kie.api.runtime.KieContainer; import org.kie.dmn.api.core.DMNMessage; import org.kie.dmn.api.core.DMNRuntime; @@ -48,6 +50,23 @@ public static DMNRuntime createRuntime(final String resourceName, final Class te Assert.assertNotNull(runtime); return runtime; } + + public static DMNRuntime createRuntimeWithAdditionalResources(final String resourceName, final Class testClass, final String... additionalResources) { + final KieServices ks = KieServices.Factory.get(); + Resource mainResource = ks.getResources().newClassPathResource(resourceName, testClass); + List totalResources = new ArrayList<>(); + totalResources.add(mainResource); + for ( String add : additionalResources ) { + totalResources.add( ks.getResources().newClassPathResource(add, testClass) ); + } + final KieContainer kieContainer = KieHelper.getKieContainer( + ks.newReleaseId("org.kie", "dmn-test-"+UUID.randomUUID(), "1.0"), + totalResources.toArray(new Resource[] {})); + + final DMNRuntime runtime = kieContainer.newKieSession().getKieRuntime(DMNRuntime.class); + Assert.assertNotNull(runtime); + return runtime; + } public static DMNRuntimeEventListener createListener() { return new DefaultDMNRuntimeEventListener() { diff --git a/kie-dmn/kie-dmn-core/src/test/resources/org/kie/dmn/core/Caller.dmn b/kie-dmn/kie-dmn-core/src/test/resources/org/kie/dmn/core/Caller.dmn new file mode 100644 index 00000000000..6a4bc23cf47 --- /dev/null +++ b/kie-dmn/kie-dmn-core/src/test/resources/org/kie/dmn/core/Caller.dmn @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + call decision + + + + + Call ns + + + + + + Call name + + + + + + Call decision + + + + + + + + + My Name + + + + + + My Number + + + + + + + + + + + + + + + + + + + "The final decision is: " + Calling outside + + + + + + + + + + + + diff --git a/kie-dmn/kie-dmn-core/src/test/resources/org/kie/dmn/core/Calling.dmn b/kie-dmn/kie-dmn-core/src/test/resources/org/kie/dmn/core/Calling.dmn new file mode 100644 index 00000000000..473cc793728 --- /dev/null +++ b/kie-dmn/kie-dmn-core/src/test/resources/org/kie/dmn/core/Calling.dmn @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + "Hello, " + Caller name + + + + + + + + + + + + A number + + + + + + A number + + + + + + left + right + + + + + sum left and right + + + + + + + + + + + + + + Greet caller + " your number once double is equal to: " + string(Duoble the number) + + + diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/BuiltInFunctions.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/BuiltInFunctions.java index e3a0a46fd7c..e50776c4f8a 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/BuiltInFunctions.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/BuiltInFunctions.java @@ -16,10 +16,10 @@ package org.kie.dmn.feel.runtime.functions; -import org.kie.dmn.feel.runtime.FEELFunction; - import java.util.stream.Stream; +import org.kie.dmn.feel.runtime.FEELFunction; + public class BuiltInFunctions { protected final static FEELFunction[] FUNCTIONS = new FEELFunction[]{ @@ -69,7 +69,8 @@ public class BuiltInFunctions { // additional functions not part of the spec version 1.1 new NowFunction(), new TodayFunction(), - new CodeFunction() + new CodeFunction(), + new CallDecisionFunction() }; public static FEELFunction[] getFunctions() { diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/CallDecisionFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/CallDecisionFunction.java index 64c64d59ce2..68d2e991f89 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/CallDecisionFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/CallDecisionFunction.java @@ -16,6 +16,8 @@ package org.kie.dmn.feel.runtime.functions; +import java.util.Map; + import org.kie.dmn.api.core.DMNContext; import org.kie.dmn.api.core.DMNModel; import org.kie.dmn.api.core.DMNResult; @@ -25,8 +27,6 @@ import org.kie.dmn.feel.runtime.events.FEELEventBase; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; -import java.util.Map; - public class CallDecisionFunction extends BaseFEELFunction { public CallDecisionFunction() { @@ -38,6 +38,7 @@ public FEELFnResult invoke(@ParameterName("ctx") EvaluationContext ctx, @ParameterName("decision name") String decisionName, @ParameterName("invocation context") Map invocationContext) { DMNRuntime dmnRuntime = ctx.getDMNRuntime(); + if(namespace == null) { return FEELFnResult.ofError(new InvalidParametersEvent(FEELEvent.Severity.ERROR, "namespace", "cannot be null")); } @@ -53,15 +54,32 @@ public FEELFnResult invoke(@ParameterName("ctx") EvaluationContext ctx, if(invocationContext == null) { return FEELFnResult.ofError(new InvalidParametersEvent(FEELEvent.Severity.ERROR, "invocation context", "cannot be null")); } + FEELEvent capturedException = null; try { ctx.enterFrame(); DMNModel dmnModel = dmnRuntime.getModel(namespace, modelName); + if (dmnModel == null) { + return FEELFnResult.ofError( + new FEELEventBase(FEELEvent.Severity.ERROR, "Cannot find model '"+modelName+"' in namespace "+namespace, null) + ); + } + if (dmnModel.getDecisionByName(decisionName) == null) { + return FEELFnResult.ofError( + new FEELEventBase(FEELEvent.Severity.ERROR, "Cannot find decision '"+decisionName+"' in the model", null) + ); + } DMNContext dmnContext = dmnRuntime.newContext(); dmnContext.getAll().putAll(invocationContext); DMNResult requiredDecisionResult = dmnRuntime.evaluateDecisionByName(dmnModel, decisionName, dmnContext); + if (requiredDecisionResult.hasErrors()) { + return FEELFnResult.ofError( + new FEELEventBase(FEELEvent.Severity.ERROR, "Errors occurred while invoking the external decision: " + requiredDecisionResult.getMessages(), null) + ); + } + return FEELFnResult.ofResult(requiredDecisionResult.getContext().get(decisionName)); } catch(Exception e) { capturedException = new FEELEventBase(FEELEvent.Severity.ERROR, "Error invoking function", new RuntimeException("Error invoking function " + getName() + ".", e)); @@ -71,5 +89,4 @@ public FEELFnResult invoke(@ParameterName("ctx") EvaluationContext ctx, return FEELFnResult.ofError(capturedException); } - }