diff --git a/drools/drools-compiler/src/main/java/org/drools/compiler/rule/builder/PatternBuilder.java b/drools/drools-compiler/src/main/java/org/drools/compiler/rule/builder/PatternBuilder.java index b4312b0ac85..d3eed25a394 100755 --- a/drools/drools-compiler/src/main/java/org/drools/compiler/rule/builder/PatternBuilder.java +++ b/drools/drools-compiler/src/main/java/org/drools/compiler/rule/builder/PatternBuilder.java @@ -231,7 +231,8 @@ private void lookupObjectType(RuleBuildContext context, PatternDescr patternDesc firstXpathChunk.getConstraints() .forEach(s -> patternDescr.addConstraint(new ExprConstraintDescr(s))); if (!xpathAnalysis.isSinglePart()) { - patternDescr.addConstraint(new ExprConstraintDescr(patternDescr.getIdentifier() + " : " + expr.substring(xpathAnalysis.getPart(1).getStart()))); + String xpathExpr = (patternDescr.getIdentifier() == null ? "" : patternDescr.getIdentifier() + " : ") + expr.substring(xpathAnalysis.getPart(1).getStart()); + patternDescr.addConstraint(new ExprConstraintDescr(xpathExpr)); patternDescr.setIdentifier("$void$"); } } else { @@ -885,6 +886,7 @@ private Constraint buildXPathDescr(RuleBuildContext context, currentObjectType = getObjectType(context, patternDescr, patternClass.getName()); } + context.increaseXpathChuckNr(); pattern.setObjectType(currentObjectType); backReferenceClasses.add(0, patternClass); backRef.reset(); @@ -904,6 +906,7 @@ private Constraint buildXPathDescr(RuleBuildContext context, mvelCtx.setInXpath(false); pattern.setBackRefDeclarations(null); pattern.setObjectType(originalType); + context.resetXpathChuckNr(); } xpathConstraint.setXpathStartDeclaration(patternDescr.getXpathStartDeclaration()); @@ -1455,6 +1458,9 @@ protected void buildRuleBindings(RuleBuildContext context, } Declaration declr = pattern.addDeclaration(fieldBindingDescr.getVariable()); + if (context.isInXpath()) { + declr.setxPathOffset( context.getXpathChuckNr() ); + } final InternalReadAccessor extractor = getFieldReadAccessor(context, fieldBindingDescr, @@ -1471,7 +1477,7 @@ protected void buildRuleBindings(RuleBuildContext context, declr.setReadAccessor(extractor); - if (typeDeclaration != null && extractor instanceof ClassFieldReader) { + if (!declr.isFromXpathChunk() && typeDeclaration != null && extractor instanceof ClassFieldReader) { addFieldToPatternWatchlist(pattern, typeDeclaration, ((ClassFieldReader) extractor).getFieldName()); } } diff --git a/drools/drools-compiler/src/main/java/org/drools/compiler/rule/builder/RuleBuildContext.java b/drools/drools-compiler/src/main/java/org/drools/compiler/rule/builder/RuleBuildContext.java index 0416c8099cc..72e4498dee5 100755 --- a/drools/drools-compiler/src/main/java/org/drools/compiler/rule/builder/RuleBuildContext.java +++ b/drools/drools-compiler/src/main/java/org/drools/compiler/rule/builder/RuleBuildContext.java @@ -62,6 +62,8 @@ public class RuleBuildContext extends PackageBuildContext { private boolean inXpath; + private int xpathChuckNr = 0; + /** * Default constructor */ @@ -236,4 +238,16 @@ private String extractClassNameFromSourcePath() { return rule.getPackage() + "." + classNameBuilder.reverse().toString(); } + + public void increaseXpathChuckNr() { + xpathChuckNr++; + } + + public void resetXpathChuckNr() { + xpathChuckNr = 0; + } + + public int getXpathChuckNr() { + return xpathChuckNr; + } } diff --git a/drools/drools-core-reflective/src/main/java/org/drools/reflective/util/ClassUtils.java b/drools/drools-core-reflective/src/main/java/org/drools/reflective/util/ClassUtils.java index 020b754c6f4..1f5ebc281ac 100755 --- a/drools/drools-core-reflective/src/main/java/org/drools/reflective/util/ClassUtils.java +++ b/drools/drools-core-reflective/src/main/java/org/drools/reflective/util/ClassUtils.java @@ -651,6 +651,14 @@ public static String setter2property(String methodName) { return Character.toLowerCase(methodName.charAt(3)) + methodName.substring(4); } + public static boolean isGetter(String methodName) { + return (methodName.startsWith("get") && methodName.length() > 3) || (methodName.startsWith("is") && methodName.length() > 2); + } + + public static boolean isSetter(String methodName) { + return (methodName.startsWith("set") && methodName.length() > 3); + } + public static Class<?> convertFromPrimitiveType(Class<?> type) { if (!type.isPrimitive()) { return type; diff --git a/drools/drools-core/src/main/java/org/drools/core/QueryResultsRowImpl.java b/drools/drools-core/src/main/java/org/drools/core/QueryResultsRowImpl.java index e44ec127030..2805527cbaf 100755 --- a/drools/drools-core/src/main/java/org/drools/core/QueryResultsRowImpl.java +++ b/drools/drools-core/src/main/java/org/drools/core/QueryResultsRowImpl.java @@ -97,7 +97,7 @@ public FactHandle getFactHandle(String identifier) { } public FactHandle getFactHandle(Declaration declr) { - return this.row.getHandles()[ declr.getPattern().getOffset() ]; + return this.row.getHandles()[ declr.getOffset() ]; } public FactHandle getFactHandle(int i) { diff --git a/drools/drools-core/src/main/java/org/drools/core/base/mvel/MVELCompilationUnit.java b/drools/drools-core/src/main/java/org/drools/core/base/mvel/MVELCompilationUnit.java index e078dc0dad6..05c2cba33d1 100755 --- a/drools/drools-core/src/main/java/org/drools/core/base/mvel/MVELCompilationUnit.java +++ b/drools/drools-core/src/main/java/org/drools/core/base/mvel/MVELCompilationUnit.java @@ -390,7 +390,7 @@ private void updateFactory( Object knowledgeHelper, } for (Declaration decl : prevDecl) { - int offset = decl.getPattern().getOffset(); + int offset = decl.getOffset(); Object o = decl.getValue(workingMemory, objs != null ? objs[offset] : handles[offset].getObject()); factory.getIndexedVariableResolver(i++).setValue(o); } @@ -401,7 +401,7 @@ private void updateFactory( Object knowledgeHelper, for ( Declaration decl : this.localDeclarations ) { Object value; if( readLocalsFromTuple && tuple != null ) { - int offset = decl.getPattern().getOffset(); + int offset = decl.getOffset(); value = decl.getValue( workingMemory, objs != null ? objs[offset] : handles[offset].getObject() ); } else { @@ -439,7 +439,7 @@ private void updateFactory( Object knowledgeHelper, public static InternalFactHandle getFactHandle( Declaration declaration, InternalFactHandle[] handles ) { - return handles != null && handles.length > declaration.getPattern().getOffset() ? handles[declaration.getPattern().getOffset()] : null; + return handles != null && handles.length > declaration.getOffset() ? handles[declaration.getOffset()] : null; } private static Serializable compile( final String text, diff --git a/drools/drools-core/src/main/java/org/drools/core/event/rule/impl/SerializableActivation.java b/drools/drools-core/src/main/java/org/drools/core/event/rule/impl/SerializableActivation.java index a01b52b89e9..1f0056736fe 100755 --- a/drools/drools-core/src/main/java/org/drools/core/event/rule/impl/SerializableActivation.java +++ b/drools/drools-core/src/main/java/org/drools/core/event/rule/impl/SerializableActivation.java @@ -92,7 +92,7 @@ public List<Object> getObjects() { public Object getDeclarationValue(String variableName) { Declaration decl = ((RuleImpl)this.rule).getDeclaration( variableName ); - return decl.getValue( null, ((InternalFactHandle)factHandles.get(decl.getPattern().getOffset())).getObject() ); + return decl.getValue( null, ((InternalFactHandle)factHandles.get(decl.getOffset())).getObject() ); } public List<String> getDeclarationIds() { diff --git a/drools/drools-core/src/main/java/org/drools/core/factmodel/AccessibleFact.java b/drools/drools-core/src/main/java/org/drools/core/factmodel/AccessibleFact.java new file mode 100644 index 00000000000..da5d0074c18 --- /dev/null +++ b/drools/drools-core/src/main/java/org/drools/core/factmodel/AccessibleFact.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2020. Red Hat, Inc. and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * + * 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 org.drools.core.factmodel; + +public interface AccessibleFact { + Object getValue(String fieldName); + void setValue(String fieldName, Object value); +} diff --git a/drools/drools-core/src/main/java/org/drools/core/factmodel/ClassDefinition.java b/drools/drools-core/src/main/java/org/drools/core/factmodel/ClassDefinition.java index ac4eec2db2c..a9b5a390b02 100755 --- a/drools/drools-core/src/main/java/org/drools/core/factmodel/ClassDefinition.java +++ b/drools/drools-core/src/main/java/org/drools/core/factmodel/ClassDefinition.java @@ -31,7 +31,6 @@ import java.util.Map; import org.drools.core.phreak.Reactive; -import org.drools.core.util.ClassUtils; import org.kie.api.definition.type.Annotation; import org.kie.api.definition.type.FactField; import org.kie.api.definition.type.FactType; @@ -167,7 +166,7 @@ public final Collection<FieldDefinition> getFieldsDefinitions() { * @param fieldName * @return */ - public final FieldDefinition getField(final String fieldName) { + public FieldDefinition getField(final String fieldName) { return this.fields.get( fieldName ); } @@ -268,15 +267,6 @@ public Object get(Object bean, if (fieldDefinition != null) { return fieldDefinition.getFieldAccessor().getValue( bean ); } - java.lang.reflect.Field f = ClassUtils.getField( definedClass, field ); - if (f != null) { - f.setAccessible( true ); - try { - return f.get( bean ); - } catch (IllegalAccessException e) { - throw new RuntimeException( e ); - } - } return null; } @@ -286,16 +276,6 @@ public void set(Object bean, FieldDefinition fieldDefinition = getField( field ); if (fieldDefinition != null) { fieldDefinition.getFieldAccessor().setValue( bean, value ); - } else { - java.lang.reflect.Field f = ClassUtils.getField( definedClass, field ); - if (f != null) { - f.setAccessible( true ); - try { - f.set( bean, value ); - } catch (IllegalAccessException e) { - throw new RuntimeException( e ); - } - } } } diff --git a/drools/drools-core/src/main/java/org/drools/core/reteoo/BaseTuple.java b/drools/drools-core/src/main/java/org/drools/core/reteoo/BaseTuple.java index db50fb30ef7..8f9c94c389c 100755 --- a/drools/drools-core/src/main/java/org/drools/core/reteoo/BaseTuple.java +++ b/drools/drools-core/src/main/java/org/drools/core/reteoo/BaseTuple.java @@ -45,7 +45,7 @@ public abstract class BaseTuple implements Tuple { private boolean expired; public Object getObject(Declaration declaration) { - return getObject(declaration.getPattern().getOffset()); + return getObject(declaration.getOffset()); } public Object getContextObject() { @@ -128,7 +128,7 @@ public void clear() { @Override public InternalFactHandle get( Declaration declaration ) { - return get(declaration.getPattern().getOffset()); + return get(declaration.getOffset()); } @Override diff --git a/drools/drools-core/src/main/java/org/drools/core/rule/Declaration.java b/drools/drools-core/src/main/java/org/drools/core/rule/Declaration.java index 549658a9969..f73d5a33934 100755 --- a/drools/drools-core/src/main/java/org/drools/core/rule/Declaration.java +++ b/drools/drools-core/src/main/java/org/drools/core/rule/Declaration.java @@ -55,6 +55,8 @@ public class Declaration private transient Class<?> declarationClass; + private int xPathOffset = 0; + // ------------------------------------------------------------ // Constructors // ------------------------------------------------------------ @@ -188,6 +190,18 @@ public void setPattern(final Pattern pattern) { this.pattern = pattern; } + public int getOffset() { + return pattern.getOffset() + xPathOffset; + } + + public void setxPathOffset( int xPathOffset ) { + this.xPathOffset = xPathOffset; + } + + public boolean isFromXpathChunk() { + return xPathOffset >= 1; + } + /** * Returns true if this declaration is a pattern declaration */ diff --git a/drools/drools-core/src/main/java/org/drools/core/rule/EvalCondition.java b/drools/drools-core/src/main/java/org/drools/core/rule/EvalCondition.java index 3f7a8483014..0be98eb9bc8 100755 --- a/drools/drools-core/src/main/java/org/drools/core/rule/EvalCondition.java +++ b/drools/drools-core/src/main/java/org/drools/core/rule/EvalCondition.java @@ -169,7 +169,7 @@ public boolean equals(final Object object) { } for ( int i = 0, length = this.requiredDeclarations.length; i < length; i++ ) { - if ( this.requiredDeclarations[i].getPattern().getOffset() != other.requiredDeclarations[i].getPattern().getOffset() ) { + if ( this.requiredDeclarations[i].getOffset() != other.requiredDeclarations[i].getOffset() ) { return false; } diff --git a/drools/drools-core/src/main/java/org/drools/core/rule/PredicateConstraint.java b/drools/drools-core/src/main/java/org/drools/core/rule/PredicateConstraint.java index b92dce6199c..63e12175efc 100755 --- a/drools/drools-core/src/main/java/org/drools/core/rule/PredicateConstraint.java +++ b/drools/drools-core/src/main/java/org/drools/core/rule/PredicateConstraint.java @@ -210,7 +210,7 @@ public boolean equals(final Object object) { } for ( int i = 0, length = this.previousDeclarations.length; i < length; i++ ) { - if ( this.previousDeclarations[i].getPattern().getOffset() != other.previousDeclarations[i].getPattern().getOffset() ) { + if ( this.previousDeclarations[i].getOffset() != other.previousDeclarations[i].getOffset() ) { return false; } @@ -220,7 +220,7 @@ public boolean equals(final Object object) { } for ( int i = 0, length = this.localDeclarations.length; i < length; i++ ) { - if ( this.localDeclarations[i].getPattern().getOffset() != other.localDeclarations[i].getPattern().getOffset() ) { + if ( this.localDeclarations[i].getOffset() != other.localDeclarations[i].getOffset() ) { return false; } diff --git a/drools/drools-core/src/main/java/org/drools/core/rule/builder/dialect/asm/GeneratorHelper.java b/drools/drools-core/src/main/java/org/drools/core/rule/builder/dialect/asm/GeneratorHelper.java index 6279d6a4292..e1a5eec68c8 100755 --- a/drools/drools-core/src/main/java/org/drools/core/rule/builder/dialect/asm/GeneratorHelper.java +++ b/drools/drools-core/src/main/java/org/drools/core/rule/builder/dialect/asm/GeneratorHelper.java @@ -80,7 +80,7 @@ public static class DeclarationMatcher implements Comparable { public DeclarationMatcher(int originalIndex, Declaration declaration) { this.declaration = declaration; this.originalIndex = originalIndex; - this.rootDistance = declaration.getPattern().getOffset(); + this.rootDistance = declaration.getOffset(); } public int getOriginalIndex() { diff --git a/drools/drools-core/src/main/java/org/drools/core/rule/constraint/MvelConstraint.java b/drools/drools-core/src/main/java/org/drools/core/rule/constraint/MvelConstraint.java index 185d5102eb8..eac030fd9e3 100755 --- a/drools/drools-core/src/main/java/org/drools/core/rule/constraint/MvelConstraint.java +++ b/drools/drools-core/src/main/java/org/drools/core/rule/constraint/MvelConstraint.java @@ -369,7 +369,7 @@ public ContextEntry createContextEntry() { public FieldIndex getFieldIndex() { // declaration's offset can be modified by the reteoo's PatternBuilder so modify the indexingDeclaration accordingly - indexingDeclaration.getPattern().setOffset(declarations[0].getPattern().getOffset()); + indexingDeclaration.getPattern().setOffset(declarations[0].getOffset()); return new FieldIndex(extractor, indexingDeclaration, INDEX_EVALUATOR); } diff --git a/drools/drools-core/src/main/java/org/drools/core/rule/constraint/XpathConstraint.java b/drools/drools-core/src/main/java/org/drools/core/rule/constraint/XpathConstraint.java index 954ef2dc01f..08ca7423bd6 100755 --- a/drools/drools-core/src/main/java/org/drools/core/rule/constraint/XpathConstraint.java +++ b/drools/drools-core/src/main/java/org/drools/core/rule/constraint/XpathConstraint.java @@ -519,7 +519,7 @@ public Iterator getResults(Tuple leftTuple, InternalWorkingMemory wm, Propagatio Object obj = fh.getObject(); if (obj instanceof DroolsQuery) { - obj = ((DroolsQuery)obj).getElements()[declaration.getPattern().getOffset()]; + obj = ((DroolsQuery)obj).getElements()[declaration.getOffset()]; } return xpathEvaluator.evaluate(wm, leftTuple, obj).iterator(); diff --git a/drools/drools-core/src/main/java/org/drools/core/runtime/rule/impl/RowAdapter.java b/drools/drools-core/src/main/java/org/drools/core/runtime/rule/impl/RowAdapter.java index aa76e3f7b90..2076fd46b4c 100755 --- a/drools/drools-core/src/main/java/org/drools/core/runtime/rule/impl/RowAdapter.java +++ b/drools/drools-core/src/main/java/org/drools/core/runtime/rule/impl/RowAdapter.java @@ -36,7 +36,7 @@ public RowAdapter(final RuleImpl rule, } private InternalFactHandle getFactHandle(Declaration declr) { - return this.factHandles[ declr.getPattern().getOffset() ]; + return this.factHandles[ declr.getOffset() ]; } public Object get(String identifier) { diff --git a/drools/kogito-dmn/src/main/java/org/kie/kogito/dmn/DMNKogito.java b/drools/kogito-dmn/src/main/java/org/kie/kogito/dmn/DMNKogito.java index 074e28a43a0..8197e589fb7 100644 --- a/drools/kogito-dmn/src/main/java/org/kie/kogito/dmn/DMNKogito.java +++ b/drools/kogito-dmn/src/main/java/org/kie/kogito/dmn/DMNKogito.java @@ -16,34 +16,28 @@ package org.kie.kogito.dmn; -import org.drools.core.RuleBaseConfiguration; -import org.drools.core.definitions.InternalKnowledgePackage; -import org.drools.core.definitions.ResourceTypePackageRegistry; -import org.drools.core.definitions.impl.KnowledgePackageImpl; -import org.drools.core.impl.KnowledgeBaseImpl; -import org.drools.core.io.impl.FileSystemResource; -import org.kie.api.io.ResourceType; +import java.io.Reader; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.drools.core.io.impl.ReaderResource; +import org.kie.api.io.Resource; import org.kie.dmn.api.core.DMNModel; import org.kie.dmn.api.core.DMNRuntime; -import org.kie.dmn.core.compiler.DMNCompilerImpl; -import org.kie.dmn.core.impl.DMNPackageImpl; -import org.kie.dmn.core.impl.DMNRuntimeImpl; import org.kie.dmn.core.internal.utils.DMNEvaluationUtils; import org.kie.dmn.core.internal.utils.DMNEvaluationUtils.DMNEvaluationResult; +import org.kie.dmn.core.internal.utils.DMNRuntimeBuilder; +import org.kie.kogito.Application; import org.kie.kogito.dmn.rest.DMNResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.IOException; -import java.io.Reader; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; -import java.util.stream.Stream; - +/** + * Internal Utility class.<br/> + * Use {@link Application#decisionModels()} of Kogito API to programmatically access DMN assets and evaluate DMN decisions. + */ public class DMNKogito { private static final Logger LOG = LoggerFactory.getLogger(DMNKogito.class); @@ -52,44 +46,18 @@ private DMNKogito() { // intentionally private. } - public static DMNRuntime createGenericDMNRuntime(Reader... resources) { - KnowledgeBaseImpl knowledgeBase = new KnowledgeBaseImpl("", new RuleBaseConfiguration()); - Map<String, InternalKnowledgePackage> pkgs = knowledgeBase.getPackagesMap(); - DMNCompilerImpl compilerImpl = new DMNCompilerImpl(); - for (Reader dmnResource : resources) { - try { - DMNModel m = compilerImpl.compile(dmnResource); - InternalKnowledgePackage pkg = pkgs.computeIfAbsent(m.getNamespace(), KnowledgePackageImpl::new); - ResourceTypePackageRegistry rpkg = pkg.getResourceTypePackages(); - DMNPackageImpl dmnpkg = rpkg.computeIfAbsent(ResourceType.DMN, rtp -> new DMNPackageImpl(m.getNamespace())); - dmnpkg.addModel(m.getName(), m);// TODO add profiles? and check dups over namespace/name - } catch (Exception e) { - LOG.error("Failed on DMN resource", e); - } - } - return new DMNRuntimeImpl(knowledgeBase); - } - - public static DMNRuntime createGenericDMNRuntime() { - KnowledgeBaseImpl knowledgeBase = new KnowledgeBaseImpl("", new RuleBaseConfiguration()); - Map<String, InternalKnowledgePackage> pkgs = knowledgeBase.getPackagesMap(); - DMNCompilerImpl compilerImpl = new DMNCompilerImpl(); - try (Stream<Path> fileStream = Files.walk(Paths.get("."))) { - List<java.nio.file.Path> files = fileStream - .filter(path -> Files.isRegularFile(path) && path.toString().endsWith(".dmn")) - .peek(x -> LOG.debug("Adding DMN model {} to runtime", x)) - .collect(Collectors.toList()); - for (java.nio.file.Path file : files) { - DMNModel m = compilerImpl.compile(new FileSystemResource(file.toFile())); - InternalKnowledgePackage pkg = pkgs.computeIfAbsent(m.getNamespace(), KnowledgePackageImpl::new); - ResourceTypePackageRegistry rpkg = pkg.getResourceTypePackages(); - DMNPackageImpl dmnpkg = rpkg.computeIfAbsent(ResourceType.DMN, rtp -> new DMNPackageImpl(m.getNamespace())); - dmnpkg.addModel(m.getName(), m);// TODO add profiles? and check dups over namespace/name - } - } catch (IOException e) { - e.printStackTrace(); - } - return new DMNRuntimeImpl(knowledgeBase); + /** + * Internal Utility class.<br/> + * Use {@link Application#decisionModels()} of Kogito API to programmatically access DMN assets and evaluate DMN decisions. + */ + public static DMNRuntime createGenericDMNRuntime(Reader... readers) { + List<Resource> resources = Stream.of(readers).map(ReaderResource::new).collect(Collectors.toList()); + DMNRuntime dmnRuntime = DMNRuntimeBuilder.fromDefaults() + .setRootClassLoader(null) + .buildConfiguration() + .fromResources(resources) + .getOrElseThrow(e -> new RuntimeException("Error initalizing DMNRuntime", e)); + return dmnRuntime; } public static DMNModel modelByName(DMNRuntime dmnRuntime, String modelName) { diff --git a/drools/kogito-dmn/src/test/java/org/kie/kogito/dmn/DMNKogitoTest.java b/drools/kogito-dmn/src/test/java/org/kie/kogito/dmn/DMNKogitoTest.java index bde36e534bb..ee36015bfcb 100644 --- a/drools/kogito-dmn/src/test/java/org/kie/kogito/dmn/DMNKogitoTest.java +++ b/drools/kogito-dmn/src/test/java/org/kie/kogito/dmn/DMNKogitoTest.java @@ -15,26 +15,18 @@ package org.kie.kogito.dmn; +import java.io.InputStreamReader; + import org.junit.jupiter.api.Test; import org.kie.dmn.api.core.DMNRuntime; -import java.io.InputStreamReader; - import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; public class DMNKogitoTest { @Test public void testBasic() { DMNRuntime dmnRuntime = DMNKogito.createGenericDMNRuntime(new InputStreamReader(DMNKogitoTest.class.getResourceAsStream("TrafficViolation.dmn"))); - assertEquals(1, dmnRuntime.getModels().size()); - } - - @Test - public void testCreateGenericDMNRuntime() { - DMNRuntime dmnRuntime = DMNKogito.createGenericDMNRuntime(); - assertEquals(1, dmnRuntime.getModels().size()); - assertNotNull(dmnRuntime.getModels().get(0).getResource()); + assertEquals(dmnRuntime.getModels().size(), 1); } } diff --git a/drools/kogito-scenario-simulation/src/main/java/org/kogito/scenariosimulation/runner/KogitoDMNScenarioRunnerHelper.java b/drools/kogito-scenario-simulation/src/main/java/org/kogito/scenariosimulation/runner/KogitoDMNScenarioRunnerHelper.java index 34c1b1c159f..ab588a67106 100644 --- a/drools/kogito-scenario-simulation/src/main/java/org/kogito/scenariosimulation/runner/KogitoDMNScenarioRunnerHelper.java +++ b/drools/kogito-scenario-simulation/src/main/java/org/kogito/scenariosimulation/runner/KogitoDMNScenarioRunnerHelper.java @@ -15,6 +15,17 @@ */ package org.kogito.scenariosimulation.runner; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.drools.core.io.impl.FileSystemResource; import org.drools.scenariosimulation.api.model.ScenarioSimulationModel; import org.drools.scenariosimulation.api.model.ScesimModelDescriptor; import org.drools.scenariosimulation.api.model.Settings; @@ -24,23 +35,40 @@ import org.drools.scenariosimulation.backend.runner.model.InstanceGiven; import org.drools.scenariosimulation.backend.runner.model.ScenarioRunnerData; import org.drools.scenariosimulation.backend.util.DMNSimulationUtils; +import org.kie.api.io.Resource; import org.kie.api.runtime.KieContainer; import org.kie.dmn.api.core.DMNContext; import org.kie.dmn.api.core.DMNModel; import org.kie.dmn.api.core.DMNResult; import org.kie.dmn.api.core.DMNRuntime; -import org.kie.kogito.dmn.DMNKogito; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import org.kie.dmn.core.internal.utils.DMNRuntimeBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import static org.drools.scenariosimulation.backend.fluent.DMNScenarioExecutableBuilder.DMN_MODEL; import static org.drools.scenariosimulation.backend.fluent.DMNScenarioExecutableBuilder.DMN_RESULT; public class KogitoDMNScenarioRunnerHelper extends DMNScenarioRunnerHelper { - private DMNRuntime dmnRuntime = DMNKogito.createGenericDMNRuntime(); + private static final Logger LOG = LoggerFactory.getLogger(KogitoDMNScenarioRunnerHelper.class); + + private DMNRuntime dmnRuntime = null; + { + try (Stream<Path> fileStream = Files.walk(Paths.get("."))) { + List<Resource> resources = fileStream.filter(path -> Files.isRegularFile(path) && path.toString().endsWith(".dmn")) + .peek(x -> System.out.println(x)) + .map(Path::toFile) + .map(FileSystemResource::new) + .collect(Collectors.toList()); + dmnRuntime = DMNRuntimeBuilder.fromDefaults() + .setRootClassLoader(null) + .buildConfiguration() + .fromResources(resources) + .getOrElseThrow(e -> new RuntimeException("Error initalizing DMNRuntime", e)); + } catch (IOException e) { + throw new RuntimeException("Error initalizing KogitoDMNScenarioRunnerHelper", e); + } + } @Override protected Map<String, Object> executeScenario(KieContainer kieContainer, diff --git a/kogito-codegen/src/main/java/org/kie/kogito/codegen/decision/DMNRestResourceGenerator.java b/kogito-codegen/src/main/java/org/kie/kogito/codegen/decision/DMNRestResourceGenerator.java index a89bfc389d3..17b4240f8a3 100644 --- a/kogito-codegen/src/main/java/org/kie/kogito/codegen/decision/DMNRestResourceGenerator.java +++ b/kogito-codegen/src/main/java/org/kie/kogito/codegen/decision/DMNRestResourceGenerator.java @@ -32,10 +32,10 @@ import com.github.javaparser.ast.expr.StringLiteralExpr; import com.github.javaparser.ast.stmt.ReturnStmt; import org.drools.core.util.StringUtils; -import org.kie.kogito.codegen.BodyDeclarationComparator; +import org.kie.dmn.api.core.DMNModel; import org.kie.dmn.feel.codegen.feel11.CodegenStringUtil; import org.kie.dmn.model.api.DecisionService; -import org.kie.dmn.model.api.Definitions; +import org.kie.kogito.codegen.BodyDeclarationComparator; import org.kie.kogito.codegen.di.DependencyInjectionAnnotator; import org.kie.kogito.codegen.process.CodegenUtils; @@ -43,7 +43,7 @@ public class DMNRestResourceGenerator { - private final Definitions definitions; + private final DMNModel dmnModel; private final String decisionName; private final String nameURL; private final String packageName; @@ -54,12 +54,12 @@ public class DMNRestResourceGenerator { private DependencyInjectionAnnotator annotator; - public DMNRestResourceGenerator(Definitions definitions, String appCanonicalName) { - this.definitions = definitions; - this.packageName = CodegenStringUtil.escapeIdentifier(definitions.getNamespace()); - this.decisionId = definitions.getId(); - this.decisionName = CodegenStringUtil.escapeIdentifier(definitions.getName()); - this.nameURL = URLEncoder.encode(definitions.getName()).replaceAll("\\+", "%20"); + public DMNRestResourceGenerator(DMNModel model, String appCanonicalName) { + this.dmnModel = model; + this.packageName = CodegenStringUtil.escapeIdentifier(model.getNamespace()); + this.decisionId = model.getDefinitions().getId(); + this.decisionName = CodegenStringUtil.escapeIdentifier(model.getName()); + this.nameURL = URLEncoder.encode(model.getName()).replaceAll("\\+", "%20"); this.appCanonicalName = appCanonicalName; String classPrefix = StringUtils.capitalize(decisionName); this.resourceClazzName = classPrefix + "Resource"; @@ -97,7 +97,7 @@ public String generate() { } MethodDeclaration dmnMethod = template.findAll(MethodDeclaration.class, x -> x.getName().toString().equals("dmn")).get(0); - for (DecisionService ds : definitions.getDecisionService()) { + for (DecisionService ds : dmnModel.getDefinitions().getDecisionService()) { if (ds.getAdditionalAttributes().keySet().stream().anyMatch(qn -> qn.getLocalPart().equals("dynamicDecisionService"))) { continue; } @@ -130,8 +130,8 @@ private void interpolateStrings(StringLiteralExpr vv) { String interpolated = s.replace("$name$", decisionName) .replace("$nameURL$", nameURL) .replace("$id$", decisionId) - .replace("$modelName$", definitions.getName()) - .replace("$modelNamespace$", definitions.getNamespace()) + .replace("$modelName$", dmnModel.getName()) + .replace("$modelNamespace$", dmnModel.getNamespace()) .replace("$documentation$", documentation); vv.setString(interpolated); } diff --git a/kogito-codegen/src/main/java/org/kie/kogito/codegen/decision/DecisionCodegen.java b/kogito-codegen/src/main/java/org/kie/kogito/codegen/decision/DecisionCodegen.java index 6715b24b0bd..9b58e276ea9 100644 --- a/kogito-codegen/src/main/java/org/kie/kogito/codegen/decision/DecisionCodegen.java +++ b/kogito-codegen/src/main/java/org/kie/kogito/codegen/decision/DecisionCodegen.java @@ -33,16 +33,14 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipFile; -import javax.xml.namespace.QName; import org.drools.core.io.impl.ByteArrayResource; import org.drools.core.io.impl.FileSystemResource; import org.drools.core.io.internal.InternalResource; import org.kie.api.io.Resource; import org.kie.api.io.ResourceType; -import org.kie.dmn.backend.marshalling.v1x.DMNMarshallerFactory; -import org.kie.dmn.core.assembler.DMNResource; -import org.kie.dmn.model.api.Definitions; -import org.kie.internal.io.ResourceWithConfigurationImpl; +import org.kie.dmn.api.core.DMNModel; +import org.kie.dmn.api.core.DMNRuntime; +import org.kie.dmn.core.internal.utils.DMNRuntimeBuilder; import org.kie.kogito.codegen.AbstractGenerator; import org.kie.kogito.codegen.ApplicationGenerator; import org.kie.kogito.codegen.ApplicationSection; @@ -57,23 +55,23 @@ public class DecisionCodegen extends AbstractGenerator { public static DecisionCodegen ofJar(Path jarPath) throws IOException { - List<DMNResource> resources = new ArrayList<>(); + List<Resource> resources = new ArrayList<>(); try (ZipFile zipFile = new ZipFile( jarPath.toFile() )) { Enumeration< ? extends ZipEntry> entries = zipFile.entries(); while ( entries.hasMoreElements() ) { ZipEntry entry = entries.nextElement(); ResourceType resourceType = determineResourceType(entry.getName()); - if (entry.getName().endsWith(".dmn")) { + if (resourceType == ResourceType.DMN) { InternalResource resource = new ByteArrayResource( readBytesFromInputStream( zipFile.getInputStream( entry ) ) ); resource.setResourceType( resourceType ); resource.setSourcePath( entry.getName() ); - resources.add( toDmnResource( resource ) ); + resources.add(resource); } } } - return ofDecisions(jarPath, resources); + return ofDecisions(jarPath, parseDecisions(resources)); } public static DecisionCodegen ofPath(Path path) throws IOException { @@ -87,30 +85,21 @@ public static DecisionCodegen ofPath(Path path) throws IOException { } public static DecisionCodegen ofFiles(Path basePath, Collection<File> files) throws IOException { - List<DMNResource> result = parseDecisions(files); + List<DMNModel> result = parseDecisions(files.stream().map(FileSystemResource::new).collect(Collectors.toList())); return ofDecisions(basePath, result); } - private static DecisionCodegen ofDecisions(Path basePath, List<DMNResource> result) { + private static DecisionCodegen ofDecisions(Path basePath, List<DMNModel> result) { return new DecisionCodegen(basePath, result); } - private static List<DMNResource> parseDecisions(Collection<File> files) throws IOException { - List<DMNResource> result = new ArrayList<>(); - for (File dmnFile : files) { - FileSystemResource r = new FileSystemResource(dmnFile); - result.add(toDmnResource( r )); - } - return result; - } - - private static DMNResource toDmnResource( Resource r ) throws IOException { - Definitions defs = parseDecisionFile(r); - return new DMNResource(new QName(defs.getNamespace(), defs.getName()), new ResourceWithConfigurationImpl(r, null, null, null), defs); - } - - private static Definitions parseDecisionFile(Resource r) throws IOException { - return DMNMarshallerFactory.newDefaultMarshaller().unmarshal(r.getReader()); + private static List<DMNModel> parseDecisions(Collection<Resource> resources) throws IOException { + DMNRuntime dmnRuntime = DMNRuntimeBuilder.fromDefaults() + .setRootClassLoader(null) + .buildConfiguration() + .fromResources(resources) + .getOrElseThrow(e -> new RuntimeException("Error compiling DMN model(s)", e)); + return dmnRuntime.getModels(); } private String packageName; @@ -120,13 +109,13 @@ private static Definitions parseDecisionFile(Resource r) throws IOException { private DecisionContainerGenerator moduleGenerator; private Path basePath; - private final Map<String, DMNResource> models; + private final Map<String, DMNModel> models; private final List<GeneratedFile> generatedFiles = new ArrayList<>(); - public DecisionCodegen(Path basePath, Collection<? extends DMNResource> models) { + public DecisionCodegen(Path basePath, Collection<DMNModel> models) { this.basePath = basePath; this.models = new HashMap<>(); - for (DMNResource model : models) { + for (DMNModel model : models) { this.models.put(model.getDefinitions().getId(), model); } @@ -159,8 +148,8 @@ public List<GeneratedFile> generate() { List<DMNRestResourceGenerator> rgs = new ArrayList<>(); // REST resources - for (DMNResource dmnRes : models.values()) { - DMNRestResourceGenerator resourceGenerator = new DMNRestResourceGenerator(dmnRes.getDefinitions(), applicationCanonicalName).withDependencyInjection(annotator); + for (DMNModel model : models.values()) { + DMNRestResourceGenerator resourceGenerator = new DMNRestResourceGenerator(model, applicationCanonicalName).withDependencyInjection(annotator); rgs.add(resourceGenerator); } diff --git a/kogito-codegen/src/main/java/org/kie/kogito/codegen/decision/DecisionContainerGenerator.java b/kogito-codegen/src/main/java/org/kie/kogito/codegen/decision/DecisionContainerGenerator.java index 02d8bb62cad..10257af4337 100644 --- a/kogito-codegen/src/main/java/org/kie/kogito/codegen/decision/DecisionContainerGenerator.java +++ b/kogito-codegen/src/main/java/org/kie/kogito/codegen/decision/DecisionContainerGenerator.java @@ -30,7 +30,7 @@ import com.github.javaparser.ast.expr.ObjectCreationExpr; import com.github.javaparser.ast.expr.StringLiteralExpr; import com.github.javaparser.ast.type.ClassOrInterfaceType; -import org.kie.dmn.core.assembler.DMNResource; +import org.kie.dmn.api.core.DMNModel; import org.kie.kogito.codegen.AbstractApplicationSection; import org.kie.kogito.decision.DecisionModels; @@ -40,9 +40,9 @@ public class DecisionContainerGenerator extends AbstractApplicationSection { private String applicationCanonicalName; private final Path basePath; - private final Collection<? extends DMNResource> models; + private final Collection<DMNModel> models; - public DecisionContainerGenerator(String applicationCanonicalName, Path basePath, Collection<? extends DMNResource> models) { + public DecisionContainerGenerator(String applicationCanonicalName, Path basePath, Collection<DMNModel> models) { super("DecisionModels", "decisionModels", DecisionModels.class); this.applicationCanonicalName = applicationCanonicalName; this.basePath = basePath; @@ -69,8 +69,8 @@ public ClassOrInterfaceDeclaration classDeclaration() { ClassOrInterfaceDeclaration typeDeclaration = (ClassOrInterfaceDeclaration) clazz.getTypes().get(0); ClassOrInterfaceType applicationClass = StaticJavaParser.parseClassOrInterfaceType(applicationCanonicalName); ClassOrInterfaceType inputStreamReaderClass = StaticJavaParser.parseClassOrInterfaceType(java.io.InputStreamReader.class.getCanonicalName()); - for (DMNResource model : models) { - Path sourcePath = Paths.get(model.getResAndConfig().getResource().getSourcePath()); + for (DMNModel model : models) { + Path sourcePath = Paths.get(model.getResource().getSourcePath()); Path relativizedPath = basePath.relativize(sourcePath); String resourcePath = "/" + relativizedPath; MethodCallExpr getResAsStream = new MethodCallExpr(new FieldAccessExpr(applicationClass.getNameAsExpression(), "class"), "getResourceAsStream").addArgument(new StringLiteralExpr(resourcePath)); diff --git a/kogito-codegen/src/test/resources/org/kie/kogito/codegen/unit/RuleUnitDelete.drl b/kogito-codegen/src/test/resources/org/kie/kogito/codegen/unit/RuleUnitDelete.drl index 0ac499ec568..e72d7646955 100644 --- a/kogito-codegen/src/test/resources/org/kie/kogito/codegen/unit/RuleUnitDelete.drl +++ b/kogito-codegen/src/test/resources/org/kie/kogito/codegen/unit/RuleUnitDelete.drl @@ -13,7 +13,7 @@ then // but for now we don't want to enable an update of an object directly on the DataStore from a consequence // otherwise all the property reactivity information will be lost. The following modify will anyway have the // effect to propagate the update to the DataStore and then to all the rule units sharing it. - modify($p) { $p.setAdult(true) }; + modify($p) { setAdult(true) }; end rule RemoveNonAdult when diff --git a/kogito-codegen/src/test/resources/org/kie/kogito/codegen/unit/RuleUnitModify.drl b/kogito-codegen/src/test/resources/org/kie/kogito/codegen/unit/RuleUnitModify.drl index dc93db08383..f46d8a4d968 100644 --- a/kogito-codegen/src/test/resources/org/kie/kogito/codegen/unit/RuleUnitModify.drl +++ b/kogito-codegen/src/test/resources/org/kie/kogito/codegen/unit/RuleUnitModify.drl @@ -7,7 +7,7 @@ import org.kie.kogito.codegen.data.Results rule MakeAdult when $p: /persons[ age < 18 ] then - modify($p) { $p.setAge(22) }; + modify($p) { setAge(22) }; end rule IsAdult when diff --git a/kogito-codegen/src/test/resources/org/kie/kogito/codegen/unit/RuleUnitQuery.drl b/kogito-codegen/src/test/resources/org/kie/kogito/codegen/unit/RuleUnitQuery.drl index ad848527cfa..3378aa79a27 100644 --- a/kogito-codegen/src/test/resources/org/kie/kogito/codegen/unit/RuleUnitQuery.drl +++ b/kogito-codegen/src/test/resources/org/kie/kogito/codegen/unit/RuleUnitQuery.drl @@ -6,13 +6,13 @@ import org.kie.kogito.codegen.data.Person rule CheckAdult when $p: /persons[ age >= 18 ] then - modify($p) { $p.setAdult(true) }; + modify($p) { setAdult(true) }; end rule CheckNotAdult when $p: /persons[ age < 18 ] then - modify($p) { $p.setAdult(false) }; + modify($p) { setAdult(false) }; end query FindAdults diff --git a/kogito-quarkus-extension/integration-test/src/test/resources/adult.txt b/kogito-quarkus-extension/integration-test/src/test/resources/adult.txt index 4f6d709d54a..f47f11d9ae1 100644 --- a/kogito-quarkus-extension/integration-test/src/test/resources/adult.txt +++ b/kogito-quarkus-extension/integration-test/src/test/resources/adult.txt @@ -17,13 +17,13 @@ end rule CheckAdult when $p: /persons[ age >= 18 ] then - modify($p) { $p.setAdult(true) }; + modify($p) { setAdult(true) }; end rule CheckNotAdult when $p: /persons[ age < 18 ] then - modify($p) { $p.setAdult(false) }; + modify($p) { setAdult(false) }; end query FindAdultNames diff --git a/pom.xml b/pom.xml index 911bc79e91f..4e146db58bb 100644 --- a/pom.xml +++ b/pom.xml @@ -131,7 +131,7 @@ <version.org.keycloak.image>8.0.1</version.org.keycloak.image> <version.org.mockito>3.0.0</version.org.mockito> <version.org.mvel>2.4.4.Final</version.org.mvel> - <version.org.kie7>7.34.0.Final</version.org.kie7> + <version.org.kie7>7.36.0.Final</version.org.kie7> <version.org.reflections>0.9.11</version.org.reflections> <version.org.slf4j>1.7.25</version.org.slf4j> <version.testcontainers>1.12.4</version.testcontainers>