Skip to content

Commit 5233573

Browse files
committed
[#753] Add transformer to correct the variable names. Improve error handling in DMN environment factory.
1 parent 2a7419f commit 5233573

23 files changed

+291
-271
lines changed

dmn-core/src/main/java/com/gs/dmn/error/ErrorFactory.java

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,22 +31,22 @@ public class ErrorFactory {
3131
private ErrorFactory() {
3232
}
3333

34-
public static String makeDMNErrorMessage(TDefinitions definitions, TNamedElement element, String errorMessage) {
34+
public static String makeDMNErrorMessage(TDefinitions definitions, TDMNElement element, String errorMessage) {
3535
String location = makeLocation(definitions, element);
3636
return makeErrorMessage(location, errorMessage);
3737
}
3838

39-
public static String makeDMNExpressionErrorMessage(TDefinitions definitions, TNamedElement element, TExpression expression, String errorMessage) {
39+
public static String makeDMNExpressionErrorMessage(TDefinitions definitions, TDMNElement element, TExpression expression, String errorMessage) {
4040
String expressionText = expressionDescription(expression);
4141
return makeExpressionErrorMessage(definitions, element, expressionText, errorMessage);
4242
}
4343

44-
public static String makeELExpressionErrorMessage(TDefinitions definitions, TNamedElement element, Expression<Type> expression, String errorMessage) {
44+
public static String makeELExpressionErrorMessage(TDefinitions definitions, TDMNElement element, Expression<Type> expression, String errorMessage) {
4545
String expressionText = expressionDescription(expression);
4646
return makeExpressionErrorMessage(definitions, element, expressionText, errorMessage);
4747
}
4848

49-
private static String makeExpressionErrorMessage(TDefinitions definitions, TNamedElement element, String expressionText, String errorMessage) {
49+
private static String makeExpressionErrorMessage(TDefinitions definitions, TDMNElement element, String expressionText, String errorMessage) {
5050
String modelLocation = makeLocation(definitions, element);
5151

5252
// Make final error message
@@ -118,12 +118,9 @@ protected static void addElementCoordinates(TDMNElement element, List<String> lo
118118
}
119119
}
120120

121-
public static String makeIfErrorMessage(TNamedElement element, Type thenType, Type elseType) {
122-
if (element == null) {
123-
return String.format("Types of then and else branches are incompatible, found '%s' and '%s'", thenType, elseType);
124-
} else {
125-
return String.format("Types of then and else branches are incompatible, found '%s' and '%s' in element '%s'", thenType, elseType, element.getName());
126-
}
121+
public static String makeIfErrorMessage(TDMNElement element, Type thenType, Type elseType) {
122+
String errorMessage = String.format("Types of then and else branches are incompatible, found '%s' and '%s'", thenType, elseType);
123+
return makeDMNErrorMessage(null, element, errorMessage);
127124
}
128125

129126
public static String getDiagramId(TDMNElement element) {

dmn-core/src/main/java/com/gs/dmn/transformation/basic/StandardDMNEnvironmentFactory.java

Lines changed: 72 additions & 38 deletions
Large diffs are not rendered by default.

dmn-core/src/main/java/com/gs/dmn/validation/DefaultDMNValidator.java

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import com.gs.dmn.QualifiedName;
1717
import com.gs.dmn.ast.*;
1818
import com.gs.dmn.ast.visitor.TraversalVisitor;
19+
import com.gs.dmn.error.ErrorFactory;
1920
import com.gs.dmn.error.ErrorHandler;
2021
import com.gs.dmn.log.BuildLogger;
2122
import com.gs.dmn.log.Slf4jBuildLogger;
@@ -56,11 +57,11 @@ public void validateImport(TDefinitions definitions, TImport element, Validation
5657
validateNamedElement(definitions, element, context);
5758
if (StringUtils.isBlank(element.getImportType())) {
5859
String errorMessage = "Missing importType of import";
59-
context.addError(makeError(definitions, element, errorMessage));
60+
context.addError(ErrorFactory.makeDMNErrorMessage(definitions, element, errorMessage));
6061
}
6162
if (StringUtils.isBlank(element.getNamespace())) {
6263
String errorMessage = "Missing namespace of import";
63-
context.addError(makeError(definitions, element, errorMessage));
64+
context.addError(ErrorFactory.makeDMNErrorMessage(definitions, element, errorMessage));
6465
}
6566
}
6667

@@ -128,7 +129,7 @@ protected void validateUnique(TDefinitions definitions, List<? extends TDMNEleme
128129
// Report error
129130
if (!duplicates.isEmpty()) {
130131
String message = String.join(", ", duplicates);
131-
context.addError(makeError(definitions, null, String.format("%s Found duplicates for '%s'.", errorMessage, message)));
132+
context.addError(ErrorFactory.makeDMNErrorMessage(definitions, null, String.format("%s Found duplicates for '%s'.", errorMessage, message)));
132133
}
133134
}
134135

@@ -162,20 +163,20 @@ private void validateUniqueReferences(TDefinitions definitions, List<? extends T
162163
// Report error
163164
if (!duplicates.isEmpty()) {
164165
String message = String.join(", ", duplicates);
165-
context.addError(makeError(definitions, null, String.format("%s Found duplicates for '%s'.", errorMessage, message)));
166+
context.addError(ErrorFactory.makeDMNErrorMessage(definitions, null, String.format("%s Found duplicates for '%s'.", errorMessage, message)));
166167
}
167168
}
168169

169170
private void validateNamedElement(TDefinitions definitions, TNamedElement element, ValidationContext context) {
170171
// ID is mandatory for DRG elements, it is used in references
171172
if (StringUtils.isBlank(element.getId()) && element instanceof TDRGElement) {
172173
String errorMessage = String.format("Missing id for element %s", element.getClass().getSimpleName());
173-
context.addError(makeError(definitions, element, errorMessage));
174+
context.addError(ErrorFactory.makeDMNErrorMessage(definitions, element, errorMessage));
174175
}
175176
// Name is mandatory in XSD
176177
if (element.getName() == null) {
177178
String errorMessage = String.format("Missing name for element %s", element.getClass().getSimpleName());
178-
context.addError(makeError(definitions, element, errorMessage));
179+
context.addError(ErrorFactory.makeDMNErrorMessage(definitions, element, errorMessage));
179180
}
180181
}
181182

@@ -184,29 +185,29 @@ private void validateVariable(TDefinitions definitions, TNamedElement element, T
184185

185186
if (variable == null) {
186187
String errorMessage = "Missing variable";
187-
context.addError(makeError(definitions, element, errorMessage));
188+
context.addError(ErrorFactory.makeDMNErrorMessage(definitions, element, errorMessage));
188189
return;
189190
}
190191

191192
// validate element/variable/name
192193
if (variable.getName() == null) {
193194
String errorMessage = "Missing variable name";
194-
context.addError(makeError(definitions, element, errorMessage));
195+
context.addError(ErrorFactory.makeDMNErrorMessage(definitions, element, errorMessage));
195196
} else {
196197
// element/@name == element/variable/@name
197198
String variableName = variable.getName();
198199
String elementName = element.getName();
199200
if (!elementName.equals(variableName)) {
200201
String errorMessage = String.format("DRGElement name and variable name should be the same. Found '%s' and '%s'", elementName, variableName);
201-
context.addError(makeError(definitions, element, errorMessage));
202+
context.addError(ErrorFactory.makeDMNErrorMessage(definitions, element, errorMessage));
202203
}
203204
}
204205
// validate element/variable/@typeRef
205206
if (validateTypeRef) {
206207
QualifiedName typeRef = QualifiedName.toQualifiedName(definitions, variable.getTypeRef());
207208
if (repository.isNull(typeRef)) {
208209
String errorMessage = "Missing typRef of variable";
209-
context.addError(makeError(definitions, element, errorMessage));
210+
context.addError(ErrorFactory.makeDMNErrorMessage(definitions, element, errorMessage));
210211
}
211212
}
212213
}
@@ -237,7 +238,7 @@ private void validateReferences(TDefinitions definitions, TNamedElement element,
237238
private void validateExpression(TDefinitions definitions, TDRGElement element, TExpression expression, ValidationContext context) {
238239
if (expression == null) {
239240
String errorMessage = "Missing expression";
240-
context.addError(makeError(definitions, element, errorMessage));
241+
context.addError(ErrorFactory.makeDMNErrorMessage(definitions, element, errorMessage));
241242
} else {
242243
if (expression instanceof TList) {
243244
TList listExp = (TList) expression;
@@ -251,18 +252,18 @@ private void validateExpression(TDefinitions definitions, TDRGElement element, T
251252
TRelation relationExp = (TRelation) expression;
252253
if (((TRelation) expression).getColumn() == null && relationExp.getRow() == null) {
253254
String errorMessage = "Empty relation";
254-
context.addError(makeError(definitions, element, errorMessage));
255+
context.addError(ErrorFactory.makeDMNErrorMessage(definitions, element, errorMessage));
255256
}
256257
} else if (expression instanceof TUnaryTests) {
257258
TUnaryTests unaryTests = (TUnaryTests) expression;
258259
String expressionLanguage = unaryTests.getExpressionLanguage();
259260
if (!isSupported(expressionLanguage)) {
260261
String errorMessage = String.format("Not supported expression language '%s'", expressionLanguage);
261-
context.addError(makeError(definitions, element, errorMessage));
262+
context.addError(ErrorFactory.makeDMNErrorMessage(definitions, element, errorMessage));
262263
}
263264
if (StringUtils.isBlank(unaryTests.getText())) {
264265
String errorMessage = "Missing text of unary tests";
265-
context.addError(makeError(definitions, element, errorMessage));
266+
context.addError(ErrorFactory.makeDMNErrorMessage(definitions, element, errorMessage));
266267
}
267268
} else if (expression instanceof TConditional) {
268269
TConditional conditionalExp = (TConditional) expression;
@@ -291,11 +292,11 @@ private void validateExpression(TDefinitions definitions, TDRGElement element, T
291292
String expressionLanguage = ((TLiteralExpression) expression).getExpressionLanguage();
292293
if (!isSupported(expressionLanguage)) {
293294
String errorMessage = String.format("Not supported expression language '%s'", expressionLanguage);
294-
context.addError(makeError(definitions, element, errorMessage));
295+
context.addError(ErrorFactory.makeDMNErrorMessage(definitions, element, errorMessage));
295296
}
296297
if (StringUtils.isBlank(literalExpression.getText())) {
297298
String errorMessage = "Missing text of literal expression";
298-
context.addError(makeError(definitions, element, errorMessage));
299+
context.addError(ErrorFactory.makeDMNErrorMessage(definitions, element, errorMessage));
299300
}
300301
} else if (expression instanceof TFilter) {
301302
TFilter filterExp = (TFilter) expression;
@@ -306,7 +307,7 @@ private void validateExpression(TDefinitions definitions, TDRGElement element, T
306307
List<TContextEntry> contextEntryList = contextExp.getContextEntry();
307308
if (contextEntryList.isEmpty()) {
308309
String errorMessage = "Missing entries in context expression";
309-
context.addError(makeError(definitions, element, errorMessage));
310+
context.addError(ErrorFactory.makeDMNErrorMessage(definitions, element, errorMessage));
310311
}
311312
} else if (expression instanceof TInvocation) {
312313
TInvocation invocation = (TInvocation) expression;
@@ -319,18 +320,18 @@ private void validateDecisionTable(TDefinitions definitions, TDMNElement element
319320
List<TInputClause> input = decisionTable.getInput();
320321
if (input == null || input.isEmpty()) {
321322
String errorMessage = "Missing input clauses";
322-
context.addError(makeError(definitions, element, errorMessage));
323+
context.addError(ErrorFactory.makeDMNErrorMessage(definitions, element, errorMessage));
323324
}
324325
List<TOutputClause> output = decisionTable.getOutput();
325326
if (output == null || output.isEmpty()) {
326327
String errorMessage = "Missing output clauses";
327-
context.addError(makeError(definitions, element, errorMessage));
328+
context.addError(ErrorFactory.makeDMNErrorMessage(definitions, element, errorMessage));
328329
}
329330
validateHitPolicy(definitions, element, decisionTable, context);
330331
List<TDecisionRule> ruleList = decisionTable.getRule();
331332
if (ruleList == null || ruleList.isEmpty()) {
332333
String errorMessage = "Missing rules in decision table";
333-
context.addError(makeError(definitions, element, errorMessage));
334+
context.addError(ErrorFactory.makeDMNErrorMessage(definitions, element, errorMessage));
334335
} else {
335336
for (TDecisionRule rule : ruleList) {
336337
validateRule(definitions, element, rule, context);
@@ -344,13 +345,13 @@ private void validateHitPolicy(TDefinitions definitions, TDMNElement element, TD
344345
TBuiltinAggregator aggregation = decisionTable.getAggregation();
345346
if (hitPolicy != THitPolicy.COLLECT && aggregation != null) {
346347
String errorMessage = String.format("Aggregation '%s' not allowed for hit policy '%s'", aggregation, hitPolicy);
347-
context.addError(makeError(definitions, element, errorMessage));
348+
context.addError(ErrorFactory.makeDMNErrorMessage(definitions, element, errorMessage));
348349
}
349350
if (output != null && output.size() > 1
350351
&& hitPolicy == THitPolicy.COLLECT
351352
&& aggregation != null) {
352353
String errorMessage = String.format("Collect operator is not defined over multiple outputs for decision table '%s'", decisionTable.getId());
353-
context.addError(makeError(definitions, element, errorMessage));
354+
context.addError(ErrorFactory.makeDMNErrorMessage(definitions, element, errorMessage));
354355
}
355356
}
356357

@@ -362,19 +363,19 @@ private void validateRule(TDefinitions definitions, TDMNElement element, TDecisi
362363
List<TUnaryTests> inputEntry = rule.getInputEntry();
363364
if (inputEntry == null || inputEntry.isEmpty()) {
364365
String errorMessage = "No input entries for rule " + rule.getId();
365-
context.addError(makeError(definitions, element, errorMessage));
366+
context.addError(ErrorFactory.makeDMNErrorMessage(definitions, element, errorMessage));
366367
}
367368
List<TLiteralExpression> outputEntry = rule.getOutputEntry();
368369
if (outputEntry == null || outputEntry.isEmpty()) {
369370
String errorMessage = "No outputEntry entries for rule " + rule.getId();
370-
context.addError(makeError(definitions, element, errorMessage));
371+
context.addError(ErrorFactory.makeDMNErrorMessage(definitions, element, errorMessage));
371372
}
372373
}
373374

374375
private void checkChildExpression(TDefinitions definitions, TDRGElement element, TChildExpression childExpression, String parentName, String childName, ValidationContext context) {
375376
String errorMessage = String.format("Missing '%s' expression in '%s' boxed expression in element '%s'", childName, parentName, element.getName());
376377
if (childExpression == null || childExpression.getExpression() == null) {
377-
context.addError(makeError(definitions, element, errorMessage));
378+
context.addError(ErrorFactory.makeDMNErrorMessage(definitions, element, errorMessage));
378379
}
379380
}
380381

@@ -385,7 +386,7 @@ private void validateTypeRef(TDefinitions definitions, TInformationItem variable
385386
if (variableTypeRef != null && expressionTypeRef != null) {
386387
if (!Objects.equals(variableTypeRef, expressionTypeRef)) {
387388
String errorMessage = String.format("The variable type '%s' must be the same as the type of the contained expression '%s'", variableTypeRef, expressionTypeRef);
388-
context.addError(makeError(definitions, null, errorMessage));
389+
context.addError(ErrorFactory.makeDMNErrorMessage(definitions, null, errorMessage));
389390
}
390391
}
391392
}

dmn-core/src/main/java/com/gs/dmn/validation/SimpleDMNValidator.java

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,6 @@
1212
*/
1313
package com.gs.dmn.validation;
1414

15-
import com.gs.dmn.ast.TDMNElement;
16-
import com.gs.dmn.ast.TDefinitions;
17-
import com.gs.dmn.error.ErrorFactory;
1815
import com.gs.dmn.error.ErrorHandler;
1916
import com.gs.dmn.error.LogErrorHandler;
2017
import com.gs.dmn.log.BuildLogger;
@@ -25,15 +22,6 @@
2522
public abstract class SimpleDMNValidator implements DMNValidator {
2623
protected static final Logger LOGGER = LoggerFactory.getLogger(SimpleDMNValidator.class);
2724

28-
public static String makeError(TDefinitions definitions, TDMNElement element, String message) {
29-
String location = ErrorFactory.makeLocation(definitions, element);
30-
if (location == null) {
31-
return message;
32-
} else {
33-
return String.format("%s: error: %s", location, message);
34-
}
35-
}
36-
3725
protected final BuildLogger logger;
3826
protected final ErrorHandler errorHandler = new LogErrorHandler(LOGGER);
3927

dmn-core/src/main/java/com/gs/dmn/validation/SweepMissingIntervalValidator.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import com.gs.dmn.dialect.DMNDialectDefinition;
2121
import com.gs.dmn.el.analysis.semantics.type.Type;
2222
import com.gs.dmn.el.synthesis.ELTranslator;
23+
import com.gs.dmn.error.ErrorFactory;
2324
import com.gs.dmn.log.BuildLogger;
2425
import com.gs.dmn.log.Slf4jBuildLogger;
2526
import com.gs.dmn.validation.table.Bound;
@@ -84,7 +85,7 @@ private String makeError(TDRGElement element, int columnIndex, List<Interval> in
8485
} else {
8586
message = String.format("Intervals '%s' are not covered for column %d in '%s' table", intervalsString, columnIndex + 1, repository.displayName(element));
8687
}
87-
return makeError(model, element, message);
88+
return ErrorFactory.makeDMNErrorMessage(model, element, message);
8889
}
8990

9091
// Algorithm: findMissingRules.

dmn-core/src/main/java/com/gs/dmn/validation/SweepMissingRuleValidator.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import com.gs.dmn.dialect.DMNDialectDefinition;
2121
import com.gs.dmn.el.analysis.semantics.type.Type;
2222
import com.gs.dmn.el.synthesis.ELTranslator;
23+
import com.gs.dmn.error.ErrorFactory;
2324
import com.gs.dmn.log.BuildLogger;
2425
import com.gs.dmn.log.Slf4jBuildLogger;
2526
import com.gs.dmn.validation.table.*;
@@ -83,7 +84,7 @@ private String makeError(TDRGElement element, Rule rule, DMNModelRepository repo
8384
TDefinitions model = repository.getModel(element);
8485
String intervalsString = rule.getIntervals().stream().map(Interval::serialize).collect(Collectors.joining(", "));
8586
String message = String.format("Found missing rule '[%s]' in '%s' table", intervalsString, repository.displayName(element));
86-
return makeError(model, element, message);
87+
return ErrorFactory.makeDMNErrorMessage(model, element, message);
8788
}
8889

8990
// Algorithm: findMissingRules.

dmn-core/src/main/java/com/gs/dmn/validation/SweepRuleOverlapValidator.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import com.gs.dmn.dialect.DMNDialectDefinition;
2121
import com.gs.dmn.el.analysis.semantics.type.Type;
2222
import com.gs.dmn.el.synthesis.ELTranslator;
23+
import com.gs.dmn.error.ErrorFactory;
2324
import com.gs.dmn.log.BuildLogger;
2425
import com.gs.dmn.log.Slf4jBuildLogger;
2526
import com.gs.dmn.validation.table.Bound;
@@ -106,7 +107,7 @@ protected void validate(TDRGElement element, TDecisionTable decisionTable, Sweep
106107
private String makeError(TDRGElement element, RuleGroup group, DMNModelRepository repository) {
107108
TDefinitions model = repository.getModel(element);
108109
String message = String.format("Decision table rules '%s' overlap in decision '%s'", group.serialize(), repository.displayName(element));
109-
return makeError(model, element, message);
110+
return ErrorFactory.makeDMNErrorMessage(model, element, message);
110111
}
111112

112113
// From "Semantics and Analysis of DMN Decision Tables.pdf"

0 commit comments

Comments
 (0)