Skip to content

Commit

Permalink
[#634] Add signavio transformer to correct paths when a child decisio…
Browse files Browse the repository at this point in the history
…n is used as output
  • Loading branch information
opatrascoiu committed Feb 15, 2024
1 parent 02c9ccd commit 0d4d963
Show file tree
Hide file tree
Showing 3 changed files with 561 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
/*
* Copyright 2016 Goldman Sachs.
*
* 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 com.gs.dmn.signavio.transformation;

import com.gs.dmn.DMNModelRepository;
import com.gs.dmn.ast.*;
import com.gs.dmn.log.BuildLogger;
import com.gs.dmn.log.Slf4jBuildLogger;
import com.gs.dmn.runtime.DMNRuntimeException;
import com.gs.dmn.runtime.Pair;
import com.gs.dmn.signavio.testlab.TestLab;
import com.gs.dmn.signavio.transformation.config.Correction;
import com.gs.dmn.signavio.transformation.config.DecisionTableCorrection;
import com.gs.dmn.transformation.SimpleDMNTransformer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.stream.Collectors;

public class InOutCorrectPathsInDecisionsTransformer extends SimpleDMNTransformer<TestLab> {
protected static final Logger LOGGER = LoggerFactory.getLogger(InOutCorrectPathsInDecisionsTransformer.class);

protected final BuildLogger logger;
protected boolean transformRepository = true;

public InOutCorrectPathsInDecisionsTransformer() {
this(new Slf4jBuildLogger(LOGGER));
}

protected InOutCorrectPathsInDecisionsTransformer(BuildLogger logger) {
this.logger = logger;
}

@Override
public DMNModelRepository transform(DMNModelRepository repository) {
if (isEmpty(repository)) {
logger.warn("Repository is empty; transformer will not run");
return repository;
}

correctDecisions(repository);

this.transformRepository = false;
return repository;
}

@Override
public Pair<DMNModelRepository, List<TestLab>> transform(DMNModelRepository repository, List<TestLab> testCasesList) {
if (isEmpty(repository, testCasesList)) {
logger.warn("DMN repository or test list is empty; transformer will not run");
return new Pair<>(repository, testCasesList);
}

// Transform model
if (this.transformRepository) {
transform(repository);
}

return new Pair<>(repository, testCasesList);
}

private void correctDecisions(DMNModelRepository repository) {
for (TDefinitions definitions : repository.getAllDefinitions()) {
for (TDecision decision : repository.findDecisions(definitions)) {
TExpression expression = repository.expression(decision);
if (expression instanceof TDecisionTable) {
List<String> childNames = directChildDecisionNames(decision, repository);
correctDecision(decision, childNames, (TDecisionTable) expression);
}
}
}
}

private List<String> directChildDecisionNames(TDecision decision, DMNModelRepository repository) {
List<String> result = new ArrayList<>();
for (TInformationRequirement informationRequirement : decision.getInformationRequirement()) {
TDMNElementReference requiredDecision = informationRequirement.getRequiredDecision();
if (requiredDecision != null) {
String href = requiredDecision.getHref();
TDecision child = repository.findDecisionByRef(decision, href);
result.add(child.getName());
}
}

return result;
}

private void correctDecision(TDecision decision, List<String> childNames, TDecisionTable dte) {
if (childNames.isEmpty()) {
return;
}

for (String childName : childNames) {
String oldValue = String.format("%s.%s", childName, childName);
String newValue = childName;
// Correct rules
correctRules(decision, oldValue, newValue, dte);
}
}

private void correctRules(TDecision decision, String oldValue, String newValue, TDecisionTable dte) {
List<TDecisionRule> ruleList = dte.getRule();
for (int i=0; i<ruleList.size(); i++) {
TDecisionRule rule = ruleList.get(i);
for (TLiteralExpression outputEntry: rule.getOutputEntry()) {
updateLiteralExpression(outputEntry, oldValue, newValue, decision);
}
}
}

private void updateLiteralExpression(TLiteralExpression expression, String oldValue, String newValue, TDecision decision) {
String oldText = expression.getText();
String newText = oldText.replace(oldValue, newValue);

logger.info(String.format("Replacing expression '%s' with '%s' in decision '%s'", oldText, newText, decision.getName()));

expression.setText(newText);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
* Copyright 2016 Goldman Sachs.
*
* 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 com.gs.dmn.signavio.transformation;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.gs.dmn.DMNModelRepository;
import com.gs.dmn.ast.TDRGElement;
import com.gs.dmn.ast.TDecision;
import com.gs.dmn.ast.TDecisionTable;
import com.gs.dmn.ast.TExpression;
import com.gs.dmn.runtime.DMNRuntimeException;
import com.gs.dmn.runtime.Pair;
import com.gs.dmn.signavio.SignavioDMNModelRepository;
import com.gs.dmn.signavio.testlab.TestLab;
import com.gs.dmn.signavio.transformation.config.Correction;
import com.gs.dmn.signavio.transformation.config.DecisionTableCorrection;
import org.junit.Test;

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import static org.junit.Assert.*;

public class InOutCorrectPathsInDecisionsTransformerTest extends AbstractSignavioFileTransformerTest {
private static final ObjectMapper MAPPER = new ObjectMapper();

private final InOutCorrectPathsInDecisionsTransformer transformer = new InOutCorrectPathsInDecisionsTransformer();

@Test
public void testTransformationNormalFlow() throws Exception {
DMNModelRepository repository = executeTransformation(
signavioResource("dmn/complex/example-in-out-credit-decision-with-incorrect-paths.dmn")
);

// Check decision with no in-out pattern
TDRGElement firstDecision = repository.findDRGElementByName("processPriorIssues");
assertTrue(firstDecision instanceof TDecision);
TExpression firstExpression = repository.expression(firstDecision);
assertTrue(firstExpression instanceof TDecisionTable);
TDecisionTable firstDecisionTable = (TDecisionTable) firstExpression;
assertEquals("(count(applicant.priorIssues)*(-5))", firstDecisionTable.getRule().get(4).getOutputEntry().get(0).getText());

// Check decision with in-out pattern for inputs
TDRGElement secondDecision = repository.findDRGElementByName("compareAgainstLendingThreshold");
assertTrue(secondDecision instanceof TDecision);
TExpression secondExpression = repository.expression(secondDecision);
assertTrue(secondExpression instanceof TDecisionTable);
TDecisionTable secondDecisionTable = (TDecisionTable) secondExpression;
assertEquals("lendingThreshold.lendingThreshold", secondDecisionTable.getRule().get(1).getOutputEntry().get(0).getText());

// Check decision with in-out pattern for inputs
TDRGElement thirdDecision = repository.findDRGElementByName("incorrectDecision");
assertTrue(thirdDecision instanceof TDecision);
TExpression thirdExpression = repository.expression(thirdDecision);
assertTrue(thirdExpression instanceof TDecisionTable);
TDecisionTable thirdDecisionTable = (TDecisionTable) thirdExpression;
assertEquals("assessIssueRisk", thirdDecisionTable.getRule().get(1).getOutputEntry().get(0).getText());
}

@Test
public void testTransformationWhenEmptyRepo() {
DMNModelRepository repository = null;
transformer.transform(repository);
Pair<DMNModelRepository, List<TestLab>> res = transformer.transform(repository, null);
assertEquals(repository, res.getLeft());
}

@Test
public void testTransformationWhenEmptyConfig() {;
DMNModelRepository repository = new DMNModelRepository();
transformer.transform(repository);
Pair<DMNModelRepository, List<TestLab>> res = transformer.transform(repository, null);
assertEquals(repository, res.getLeft());
}

private DMNModelRepository executeTransformation(URI dmnFileURI) throws Exception {
File dmnFile = new File(dmnFileURI);
DMNModelRepository repository = new SignavioDMNModelRepository(this.dmnSerializer.readModel(dmnFile));

return transformer.transform(repository);
}
}
Loading

0 comments on commit 0d4d963

Please sign in to comment.