1111import org .kie .api .runtime .KieContainer ;
1212import org .kie .api .runtime .KieSession ;
1313import org .kie .dmn .api .core .*;
14+ import org .kie .dmn .api .core .ast .DecisionNode ;
15+
1416import java .io .*;
1517import java .util .*;
1618import org .drools .compiler .kie .builder .impl .InternalKieModule ;
1719
1820
21+ class DmnCompilationResult {
22+ public byte [] dmnBytes ;
23+ public List <String > errors ;
24+
25+ public DmnCompilationResult (byte [] dmnBytes , List <String > errors ) {
26+ this .dmnBytes = dmnBytes ;
27+ this .errors = errors ;
28+ }
29+ }
30+
1931@ ApplicationScoped
2032public class KieDmnService implements DmnService {
2133 @ Inject
@@ -31,7 +43,46 @@ private KieSession initializeKieSession(byte[] moduleBytes) throws IOException {
3143 return kieContainer .newKieSession ();
3244 }
3345
34- private byte [] compileDmnModel (String dmnXml , Map <String , String > dependenciesMap , String modelId ) throws IOException {
46+ // Validates that the DMN XML can compile and contains the required decision.
47+ // Returns a list of error messages if any issues are found.
48+ public List <String > validateDmnXml (
49+ String dmnXml , Map <String , String > dependenciesMap , String modelId , String requiredBooleanDecisionName
50+ ) throws Exception {
51+ DmnCompilationResult compilationResult = compileDmnModel (dmnXml , dependenciesMap , modelId );
52+ if (!compilationResult .errors .isEmpty ()) {
53+ return compilationResult .errors ;
54+ }
55+
56+ KieSession kieSession = initializeKieSession (compilationResult .dmnBytes );
57+ DMNRuntime dmnRuntime = kieSession .getKieRuntime (DMNRuntime .class );
58+
59+ List <DMNModel > dmnModels = dmnRuntime .getModels ();
60+ if (dmnModels .size () != 1 ) {
61+ return List .of ("Expected exactly one DMN model, found: " + dmnModels .size ());
62+ }
63+
64+ DMNModel dmnModel = dmnModels .get (0 );
65+ DecisionNode requiredBooleanDecision = dmnModel .getDecisions ().stream ()
66+ .filter (d -> d .getName ().equals (requiredBooleanDecisionName ))
67+ .findFirst ()
68+ .orElse (null );
69+ if (requiredBooleanDecision == null ) {
70+ List <String > decisionNames = dmnModel .getDecisions ().stream ()
71+ .map (DecisionNode ::getName )
72+ .toList ();
73+ return List .of (
74+ "Required Decision '" + requiredBooleanDecisionName + "' not found in DMN definition. " +
75+ "Decisions found: " + decisionNames
76+ );
77+ }
78+
79+ if (requiredBooleanDecision .getResultType ().getName () != "boolean" ) {
80+ return List .of ("The Result DataType of Decision '" + requiredBooleanDecisionName + "' must be of type 'boolean'." );
81+ }
82+ return new ArrayList <String >();
83+ }
84+
85+ private DmnCompilationResult compileDmnModel (String dmnXml , Map <String , String > dependenciesMap , String modelId ) {
3586 Log .info ("Compiling and saving DMN model: " + modelId );
3687
3788 KieServices kieServices = KieServices .Factory .get ();
@@ -69,18 +120,17 @@ private byte[] compileDmnModel(String dmnXml, Map<String, String> dependenciesMa
69120 Results results = kieBuilder .getResults ();
70121
71122 if (results .hasMessages (Message .Level .ERROR )) {
72- Log .error ("DMN Compilation errors for model " + modelId + ":" );
73- for (Message message : results .getMessages (Message .Level .ERROR )) {
74- Log .error (message .getText ());
75- }
76- throw new IllegalStateException ("DMN Model compilation failed for model: " + modelId );
123+ return new DmnCompilationResult (
124+ null ,
125+ results .getMessages (Message .Level .ERROR ).stream ().map (Message ::getText ).toList ()
126+ );
77127 }
78128
79129 InternalKieModule kieModule = (InternalKieModule ) kieBuilder .getKieModule ();
80130 byte [] kieModuleBytes = kieModule .getBytes ();
81131
82132 Log .info ("Serialized kieModule for model " + modelId );
83- return kieModuleBytes ;
133+ return new DmnCompilationResult ( kieModuleBytes , new ArrayList < String >()) ;
84134 }
85135
86136 public OptionalBoolean evaluateDmn (
@@ -95,12 +145,19 @@ public OptionalBoolean evaluateDmn(
95145 if (dmnXmlOpt .isEmpty ()) {
96146 throw new RuntimeException ("DMN file not found: " + dmnFilePath );
97147 }
98-
99148 String dmnXml = dmnXmlOpt .get ();
149+
100150 HashMap <String , String > dmnDependenciesMap = new HashMap <String , String >();
101- byte [] serializedModel = compileDmnModel (dmnXml , dmnDependenciesMap , dmnModelName );
151+ DmnCompilationResult compilationResult = compileDmnModel (dmnXml , dmnDependenciesMap , dmnModelName );
152+ if (!compilationResult .errors .isEmpty ()) {
153+ Log .error ("DMN Compilation errors for model " + dmnModelName + ":" );
154+ for (String error : compilationResult .errors ) {
155+ Log .error (error );
156+ }
157+ throw new IllegalStateException ("DMN Model compilation failed for model: " + dmnModelName );
158+ }
102159
103- KieSession kieSession = initializeKieSession (serializedModel );
160+ KieSession kieSession = initializeKieSession (compilationResult . dmnBytes );
104161 DMNRuntime dmnRuntime = kieSession .getKieRuntime (DMNRuntime .class );
105162
106163 List <DMNModel > dmnModels = dmnRuntime .getModels ();
0 commit comments