Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Git Issue - 2749: Add decisionInstanceId to evaluate DMN decision api response #4197

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -111,4 +111,15 @@ public interface DmnDecisionResult extends List<DmnDecisionResultEntries>, Seria
*/
<T extends TypedValue> T getSingleEntryTyped();

/** Returns the value of decisionInstanceId that's part of DMN decision evaluation
* @return the decisionInstanceId generated
kmannuru marked this conversation as resolved.
Show resolved Hide resolved
* Returns null for a standalone dmn engine
*/
String getDmnDecisionInstanceId();

/** Set generated decisionInstanceId that's generated part of DMN evaluation
* @param dmnDecisionInstanceId
*/
void setDmnDecisionInstanceId(String dmnDecisionInstanceId);

}
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ public interface DmnEngine {
* @throws DmnEngineException
* if an error occurs during the evaluation
*
* @see #evaluateDecision(DmnDecision, VariableContext)
* @see #evaluateDecision(DmnDecision, VariableContext, String)
*/
DmnDecisionTableResult evaluateDecisionTable(DmnDecision decision, VariableContext variableContext);

Expand Down Expand Up @@ -262,6 +262,22 @@ public interface DmnEngine {
*/
DmnDecisionResult evaluateDecision(DmnDecision decision, VariableContext variableContext);

/**
* Evaluates a decision. The decision can be implemented as any kind of supported decision logic (e.g., decision table, literal expression).
*
* @param decision the {@link DmnDecision} to evaluate
* @param variableContext the variables context which is available during the evaluation
* of expressions in the table
* @param decisionInstanceId the variable that contains the decisionInstanceId for decision evaluation
* @return the {@link DmnDecisionResult} of this evaluation
*
* @throws DmnEngineException
* if the decision logic is not supported
* @throws DmnEngineException
* if an error occurs during the evaluation
*/
DmnDecisionResult evaluateDecision(DmnDecision decision, VariableContext variableContext, String decisionInstanceId);
kmannuru marked this conversation as resolved.
Show resolved Hide resolved

/**
* Evaluates the decision with the given key in a DMN decision model.
* The key is the {@code id} attribute of the decision in the DMN XML file.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,9 @@ public interface DmnDecisionEvaluationEvent {
* @return the number of executed decision elements during the evaluation
*/
long getExecutedDecisionElements();

/**
* @return the decisionInstanceId generated part of DMN evaluation
*/
String getDecisionInstanceId();
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ public class DefaultDmnDecisionContext {

public DefaultDmnDecisionContext(DefaultDmnEngineConfiguration configuration) {
evaluationListeners = configuration.getDecisionEvaluationListeners();

evaluationHandlers = new HashMap<Class<? extends DmnDecisionLogic>, DmnDecisionLogicEvaluationHandler>();
evaluationHandlers.put(DmnDecisionTableImpl.class, new DecisionTableEvaluationHandler(configuration));
evaluationHandlers.put(DmnDecisionLiteralExpressionImpl.class, new DecisionLiteralExpressionEvaluationHandler(configuration));
Expand All @@ -67,7 +66,7 @@ public DefaultDmnDecisionContext(DefaultDmnEngineConfiguration configuration) {
* @param variableContext the available variable context
* @return the result of the decision evaluation
*/
public DmnDecisionResult evaluateDecision(DmnDecision decision, VariableContext variableContext) {
public DmnDecisionResult evaluateDecision(DmnDecision decision, VariableContext variableContext, String decisionInstanceId) {

if(decision.getKey() == null) {
throw LOG.unableToFindAnyDecisionTable();
Expand All @@ -90,8 +89,11 @@ public DmnDecisionResult evaluateDecision(DmnDecision decision, VariableContext
addResultToVariableContext(evaluatedResult, variableMap, evaluateDecision);
}
}

generateDecisionEvaluationEvent(evaluatedEvents);
/**
* Setting generated decisionInstanceId to the events to persist the generated value as ID for ACT_HI_DECINST table
*/
generateDecisionEvaluationEvent(evaluatedEvents, decisionInstanceId);
evaluatedResult.setDmnDecisionInstanceId(decisionInstanceId);
return evaluatedResult;
}

Expand Down Expand Up @@ -162,7 +164,7 @@ protected boolean isDecisionTableWithCollectOrRuleOrderHitPolicy(DmnDecision eva
return isDecisionTableWithCollectHitPolicy;
}

protected void generateDecisionEvaluationEvent(List<DmnDecisionLogicEvaluationEvent> evaluatedEvents) {
protected void generateDecisionEvaluationEvent(List<DmnDecisionLogicEvaluationEvent> evaluatedEvents, String decisionInstanceId) {

DmnDecisionLogicEvaluationEvent rootEvaluatedEvent = null;
DmnDecisionEvaluationEventImpl decisionEvaluationEvent = new DmnDecisionEvaluationEventImpl();
Expand All @@ -176,6 +178,8 @@ protected void generateDecisionEvaluationEvent(List<DmnDecisionLogicEvaluationEv
decisionEvaluationEvent.setDecisionResult(rootEvaluatedEvent);
decisionEvaluationEvent.setExecutedDecisionInstances(evaluatedEvents.size());
decisionEvaluationEvent.setExecutedDecisionElements(executedDecisionElements);
//Setting decisionInstanceId to the event to persist the generated id for the history event
decisionEvaluationEvent.setDecisionInstanceId(decisionInstanceId);

evaluatedEvents.remove(rootEvaluatedEvent);
decisionEvaluationEvent.setRequiredDecisionResults(evaluatedEvents);
Expand Down
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔧 occurrences of evaluateDecision(decision, variableContext, null) can be replaced evaluateDecision(decision, variableContext) when you bring it back.

Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ public DmnDecisionTableResult evaluateDecisionTable(DmnDecision decision, Variab
if (decision instanceof DmnDecisionImpl && decision.isDecisionTable()) {
DefaultDmnDecisionContext decisionContext = new DefaultDmnDecisionContext(dmnEngineConfiguration);

DmnDecisionResult decisionResult = decisionContext.evaluateDecision(decision, variableContext);
DmnDecisionResult decisionResult = decisionContext.evaluateDecision(decision, variableContext, null);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@yanavasileva This will not change because we need to pass the decisionInsanceId to decisionContext.evaluateDecision(decision, variableContext, null);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When you are ready, please submit your changes, I will have a look then.

return DmnDecisionTableResultImpl.wrap(decisionResult);
}
else {
Expand Down Expand Up @@ -158,13 +158,26 @@ public DmnDecisionResult evaluateDecision(DmnDecision decision, Map<String, Obje
return evaluateDecision(decision, Variables.fromMap(variables).asVariableContext());
}

public DmnDecisionResult evaluateDecision(DmnDecision decision, VariableContext variableContext, String decisionInstanceId) {
ensureNotNull("decision", decision);
ensureNotNull("variableContext", variableContext);

if (decision instanceof DmnDecisionImpl) {
DefaultDmnDecisionContext decisionContext = new DefaultDmnDecisionContext(dmnEngineConfiguration);
return decisionContext.evaluateDecision(decision, variableContext, decisionInstanceId);
}
else {
throw LOG.decisionTypeNotSupported(decision);
}
}

public DmnDecisionResult evaluateDecision(DmnDecision decision, VariableContext variableContext) {
ensureNotNull("decision", decision);
ensureNotNull("variableContext", variableContext);

if (decision instanceof DmnDecisionImpl) {
DefaultDmnDecisionContext decisionContext = new DefaultDmnDecisionContext(dmnEngineConfiguration);
return decisionContext.evaluateDecision(decision, variableContext);
return decisionContext.evaluateDecision(decision, variableContext, null);
}
else {
throw LOG.decisionTypeNotSupported(decision);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ public class DmnDecisionResultImpl implements DmnDecisionResult {

protected final List<DmnDecisionResultEntries> ruleResults;

protected String dmnDecisionInstanceId;

public DmnDecisionResultImpl(List<DmnDecisionResultEntries> ruleResults) {
this.ruleResults = ruleResults;
}
Expand Down Expand Up @@ -224,6 +226,16 @@ public String toString() {
return ruleResults.toString();
}

@Override
public String getDmnDecisionInstanceId() {
return dmnDecisionInstanceId;
}

@Override
public void setDmnDecisionInstanceId(String dmnDecisionInstanceId) {
this.dmnDecisionInstanceId = dmnDecisionInstanceId;
}

protected List<DmnDecisionResultEntries> asUnmodifiableList() {
return Collections.unmodifiableList(ruleResults);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ public class DmnDecisionEvaluationEventImpl implements DmnDecisionEvaluationEven
protected long executedDecisionInstances;
protected long executedDecisionElements;

protected String decisionInstanceId;

@Override
public DmnDecisionLogicEvaluationEvent getDecisionResult() {
return decisionResult;
Expand Down Expand Up @@ -66,6 +68,15 @@ public void setExecutedDecisionElements(long executedDecisionElements) {
this.executedDecisionElements = executedDecisionElements;
}

@Override
public String getDecisionInstanceId() {
return decisionInstanceId;
}

public void setDecisionInstanceId(String decisionInstanceId) {
this.decisionInstanceId = decisionInstanceId;
}

@Override
public String toString() {
DmnDecision dmnDecision = decisionResult.getDecision();
Expand All @@ -76,6 +87,7 @@ public String toString() {
", requiredDecisionResults=" + requiredDecisionResults +
", executedDecisionInstances=" + executedDecisionInstances +
", executedDecisionElements=" + executedDecisionElements +
", dmnDecisionInstanceId=" + decisionInstanceId +
'}';
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

import java.io.InputStream;
import java.util.Map;
import java.util.UUID;

import org.camunda.bpm.dmn.engine.DmnDecision;
import org.camunda.bpm.dmn.engine.DmnDecisionLogic;
Expand Down Expand Up @@ -777,6 +778,20 @@ public void shouldEvaluateDecisionWithVariableContext() {
.isEqualTo(EXPECTED_OUTPUT_VALUE);
}

@Test
@DecisionResource(resource = ONE_RULE_DMN)
public void shouldEvaluateDecisionWithDecisionInstanceId() {
String decisionInstanceId = UUID.randomUUID().toString();
DmnDecisionResult results = dmnEngine.evaluateDecision(decision, createVariables().putValue("input", INPUT_VALUE).asVariableContext(), decisionInstanceId);

assertThat((String) results.getSingleEntry())
.isNotNull()
.isEqualTo(EXPECTED_OUTPUT_VALUE);
assertThat(results.getDmnDecisionInstanceId())
.isNotNull()
.isEqualTo(decisionInstanceId);
}

@Test
@DecisionResource(resource = DECISION_LITERAL_EXPRESSION_DMN)
public void shouldEvaluateDecisionLiteralExpression() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import java.util.UUID;
import org.camunda.bpm.dmn.engine.DmnDecisionResult;
import org.camunda.bpm.dmn.engine.DmnEngine;
import org.camunda.bpm.dmn.engine.DmnEngineConfiguration;
Expand Down Expand Up @@ -256,7 +256,7 @@ public void testJuelDoesNotShadowInnerProperty() {
inputs.putValue("a", mapVar);
inputs.putValue("b", "B_FROM_CONTEXT");

DmnDecisionResult result = dmnEngine.evaluateDecision(decision, inputs.asVariableContext());
DmnDecisionResult result = dmnEngine.evaluateDecision(decision, inputs.asVariableContext(), null);

assertThat((String) result.getSingleEntry()).isEqualTo("B_FROM_MAP");
}
Expand All @@ -270,10 +270,12 @@ public void testJuelResolvesListIndex() {
List<String> listVar = new ArrayList<>(1);
listVar.add("0_FROM_LIST");
inputs.putValue("a", listVar);
String decisionInstanceId = UUID.randomUUID().toString();

DmnDecisionResult result = dmnEngine.evaluateDecision(decision, inputs.asVariableContext());
DmnDecisionResult result = dmnEngine.evaluateDecision(decision, inputs.asVariableContext(), decisionInstanceId);

assertThat((String) result.getSingleEntry()).isEqualTo("0_FROM_LIST");
assertThat(result.getDmnDecisionInstanceId()).isEqualTo(decisionInstanceId);
}

protected DmnEngine createEngineWithDefaultExpressionLanguage(String expressionLanguage) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<#macro dto_macro docsUrl="">
<@lib.dto>
<@lib.property
name = "decisionInstanceId"
type = "string"
desc = "The form key." />

<@lib.property
name = "result"
type = "array"
last = true
dto = "DecisionResultDto" />
</@lib.dto>
</#macro>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<#macro dto_macro docsUrl="">
<@lib.dto>
<@lib.property
name = "result"
type = "object"
additionalProperties = true
last = true
dto = "VariableValueDto" />
</@lib.dto>
</#macro>
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<#macro endpoint_macro docsUrl="">
{
<@lib.endpointInfo
id = "evaluateDecisionByKeyWithDecisionInstanceId"
tag = "Decision Definition"
summary = "Evaluate By Key With Decision Instance Id"
desc = "Evaluates the latest version of the decision definition which belongs to no tenant.
The input values of the decision have to be supplied in the request body.
Returns decision instance id related to the evaluation" />

"parameters" : [

<@lib.parameter
name = "key"
location = "path"
type = "string"
required = true
last = true
desc = "The key of the decision definition (the latest version thereof) to be evaluated." />
],

<@lib.requestBody
mediaType = "application/json"
dto = "EvaluateDecisionDto"
examples = [ '"example-1": {
"summary": "POST /decision-definition/key/aKey/evaluate-with-id",
"value": {
"variables" : {
"amount" : { "value" : 600, "type" : "Double" },
"invoiceCategory" : { "value" : "Misc", "type" : "String" }
}
}
}'
] />

"responses" : {
<@lib.response
code = "200"
dto = "DecisionEvaluationDto"
additionalProperties = true
desc = "Request successful."
examples = ['"example-1": {
"summary": "Status 200 response",
"description": "Response for POST `/decision-definition/key/aKey/evaluate-with-id`",
"value": {
"decisionInstanceId": "aDecisionInstanceId",
"result": [{ "value" : "management", "type" : "String", "valueInfo" : null }]
}
}'] />

<@lib.response
code = "404"
dto = "ExceptionDto"
last = true
desc = "Decision definition with given key does not exist.
See the [Introduction](${docsUrl}/reference/rest/overview/#error-handling) for the error response format."/>
}
}
</#macro>
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package org.camunda.bpm.engine.rest.dto.repository;

import org.camunda.bpm.engine.rest.dto.VariableValueDto;

import java.util.List;
import java.util.Map;

public class DecisionEvaluationDto {
protected String decisionInstanceId;
protected List<Map<String, VariableValueDto>> result;

public String getDecisionInstanceId() {
return decisionInstanceId;
}

public void setDecisionInstanceId(String decisionInstanceId) {
this.decisionInstanceId = decisionInstanceId;
}

public List<Map<String, VariableValueDto>> getResult() {
return result;
}

public void setResult(List<Map<String, VariableValueDto>> result) {
this.result = result;
}
}
Loading