Coder Social home page Coder Social logo

dmn-scala's Introduction

DMN Scala

An engine to execute decisions according to the DMN specification.

The engine uses the Camunda DMN model api for parsing DMN files and the FEEL-Scala engine to evaluate FEEL expressions.

Features:

  • support for the latest version of DMN (Compliance Level 3)¹
    • Decision Table
    • Business Knowledge Model
    • Context
    • Literal Expression
    • List
    • Relation
    • Function Definition
    • Invocation
  • evaluation of parsed DMN models
  • extensible by own functions and types

¹ the DMN coverage is measured by the DMN TCK

How to use it?

Add the DMN engine to your project by copying the jar file (dmn-engine-${version}.jar) or adding the project as dependency.

<dependency>
  <groupId>org.camunda.bpm.extension.dmn.scala</groupId>
  <artifactId>dmn-engine</artifactId>
  <version>${version}</version>
</dependency>

Create a new instance of the class 'DmnEngine'. Use this instance to parse and evaluate a DMN decision.

object MyProgram {
  
  val engine = new DmnEngine
  
  def evaluate(stream: InputStream, decisionId: String, context: Map[String, Any]) {
    
  val result = 
    engine
      .parse(stream)
      .flatMap(dmn => engine.eval(dmn, decisionId, context))
        
    result match {
      case Left(failure)    => // ...
      case Right(NilResult) => // ...
      case Right(r)         => // ...
    }
  }  
}

Provide Custom Functions

The engine comes with a bunch of built-in functions which are defined by the DMN specification. And it allows you to define own functions as FEEL expressions (using the keyword function) or as context entry element.

However, the engine provides also a SPI to add custom functions which are written in Scala / Java. The classes are loaded via Java's service loader mechanism. Please have a look at the documentation to see how to implement the SPI.

Transform Custom Types

The engine has a transformer (aka ValueMapper) to transform the incoming variables into FEEL types and to transform the decision result back into regular Scala types.

If you need to transform custom types or change the result types then you can implement a SPI. The implementation is loaded via Java's service loader mechanism. Please have a look at the documentation to see how to implement the SPI.

Contribution

Found a bug? Please report it using Github Issues.

Want to extend, improve or fix a bug? Pull Requests are very welcome.

Want to discuss something? The Camunda Forum might be the best place for it.

License

Apache License, Version 2.0

dmn-scala's People

Contributors

actions-user avatar andreagiardini avatar barmac avatar chaima-mnsr avatar dependabot[bot] avatar falko avatar jphillips-bp3 avatar koevskinikola avatar korthout avatar lwille avatar mboskamp avatar menski avatar pihme avatar pme123 avatar remcowesterhoud avatar saig0 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

dmn-scala's Issues

Names are escaped with the wrong character

In the DMN engine, I can enable an option to escape names that contain whitespaces or dashes. This allows to parse the FEEL expressions with the FEEL-Scala engine.

But it is using the escape character ' instead of `.

DMN-Engine version: 1.6.2

I can track the evaluation

AT:

  • I can track how the decision is evaluated (e.g. which decision is evaluated, which rules are matched, etc.)
  • based on this it should be able to build a kind of history / audit log

I can read the index of a rule from the parsed decision table

Is your feature request related to a problem? Please describe.
As a user, I want to see which rule of the decision table matched. For example, the 1st and 3rd rule matched.

When I evaluate a decision table then I get the audit log that contains the matched rules. Each rule has an id, input entries, and output entries.

But the rule doesn't contain the index of it in the decision table.

Describe the solution you'd like
Extend the rule by its index in the decision table.

Related issues

camunda/camunda#8112

How does one pass a date type as an input?

Hello,

I've succesfully tested passing strings or numbers as an input to decision tables but I can't figure out how date types.

No error is thrown when using "date" or "date and time" input types though result returns null.

Any change you could give a working example ?

Here is the outcome in the online Camunda simulator:
Screenshot 2020-12-15 at 20 31 06

Set up a documentation page

Description

Currently, the project doesn't have proper documentation. There is only the README with some basic information. Since the project will be used by two other Camunda projects, we should provide documentation that covers relevant parts, like bootstrapping or internals about the usage.

First, we need to set up a documentation page. We should use Docusaurus like the FEEL-Scala project and Camunda Cloud.

Create a new benchmark for the DMN engine

Description

Create a new benchmark and cover some basic functions. It should be a starting point to compare the DMN engines and give an idea of the performance. We can extend the benchmark over time.

The goal is to

  • execute the benchmark manually
  • allow triggering it from the build pipeline

A model containing an empty businessKnowledgeModel element will throw a NullPointerException when parsing

A model containing an empty "businessKnowledgeModel" element (as generated by camunda modeler) will fail to parse with the following exception, seen in dmn-engine 1.3.1:

Exception in thread "main" java.lang.NullPointerException at org.camunda.dmn.parser.DmnParser.parseBusinessKnowledgeModel(DmnParser.scala:158) at org.camunda.dmn.parser.DmnParser.$anonfun$parseDecision$7(DmnParser.scala:116) at scala.collection.mutable.HashMap.getOrElseUpdate(HashMap.scala:86) at org.camunda.dmn.parser.DmnParser.$anonfun$parseDecision$6(DmnParser.scala:116) at scala.collection.TraversableLike.$anonfun$map$1(TraversableLike.scala:237) at scala.collection.immutable.List.foreach(List.scala:392) at scala.collection.TraversableLike.map(TraversableLike.scala:237) at scala.collection.TraversableLike.map$(TraversableLike.scala:230) at scala.collection.immutable.List.map(List.scala:298) at org.camunda.dmn.parser.DmnParser.parseDecision(DmnParser.scala:115) at org.camunda.dmn.parser.DmnParser.$anonfun$parseModel$3(DmnParser.scala:91) at scala.collection.mutable.HashMap.getOrElseUpdate(HashMap.scala:86) at org.camunda.dmn.parser.DmnParser.$anonfun$parseModel$2(DmnParser.scala:91) at scala.collection.TraversableLike.$anonfun$map$1(TraversableLike.scala:237) at scala.collection.immutable.List.foreach(List.scala:392) at scala.collection.TraversableLike.map(TraversableLike.scala:237) at scala.collection.TraversableLike.map$(TraversableLike.scala:230) at scala.collection.immutable.List.map(List.scala:298) at org.camunda.dmn.parser.DmnParser.parseModel(DmnParser.scala:89) at org.camunda.dmn.parser.DmnParser.parse(DmnParser.scala:74) at org.camunda.dmn.DmnEngine.parse(DmnEngine.scala:134) at model.dmn.ModelEvaluatorDmnScala$.getDecisionFunctions(ModelEvaluatorDmnScala.scala:79) at decisionservice.CmdLineClient$.$anonfun$loadScoreFunctions$4(CmdLineClient.scala:179) at scala.collection.TraversableLike.$anonfun$flatMap$1(TraversableLike.scala:244) at scala.collection.mutable.ArraySeq.foreach(ArraySeq.scala:75) at scala.collection.TraversableLike.flatMap(TraversableLike.scala:244) at scala.collection.TraversableLike.flatMap$(TraversableLike.scala:241) at scala.collection.AbstractTraversable.flatMap(Traversable.scala:108) at decisionservice.CmdLineClient$.loadScoreFunctions(CmdLineClient.scala:179) at decisionservice.CmdLineClient$.setup(CmdLineClient.scala:61) at decisionservice.CmdLineClient$.main(CmdLineClient.scala:30) at decisionservice.CmdLineClient.main(CmdLineClient.scala)

Here's an example dmn model that will cause this, as generated by camunda modeler (I included some comments)

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/DMN/20151101/dmn.xsd" xmlns:biodi="http://bpmn.io/schema/dmn/biodi/1.0" id="Definitions_0cum8ey" name="DRD" namespace="http://camunda.org/schema/1.0/dmn" exporter="Camunda Modeler" exporterVersion="3.1.2">
  <decision id="decision_bkm_parse_test" name="expression test">
    <extensionElements>
      <biodi:bounds x="521" y="81" width="180" height="80" />
      <biodi:edge source="BusinessKnowledgeModel_1en940y">
        <biodi:waypoints x="291" y="118" />
        <biodi:waypoints x="521" y="120" />
      </biodi:edge>
    </extensionElements>
    <variable id="InformationItem_1mbj8gg" name="expressionOutput" typeRef="string" />
    <knowledgeRequirement>
      <requiredKnowledge href="#BusinessKnowledgeModel_1en940y" />
    </knowledgeRequirement>
    <literalExpression id="LiteralExpression_0ycsm8o" expressionLanguage="feel">
      <text>"parsed correctly"</text>
    </literalExpression>
  </decision>
  <businessKnowledgeModel id="BusinessKnowledgeModel_1en940y" name="my buisness model">
    <extensionElements>
      <biodi:bounds x="156" y="94" width="135" height="46" />
    </extensionElements>

    <!--not having this breaks it-->
    <!--<encapsulatedLogic>-->
    <!--</encapsulatedLogic>-->

    <!--can even do this-->
    <!--<nothing/>-->
  </businessKnowledgeModel>
</definitions>

It's expecting an "encapsulatedLogic" element within the "businessKnowledgeModel" element. Including that will fix the problem. Actually including any nonsense element will allow the model to parse. Having or not having an "extensionElements" element has no effect.

Obviously camunda modeler doesn't allow any functionality within BKM's but would be nice to include in diagrams as a placeholder.

I'm not sure if this incompatibility should be fixed on dmn-scala end or modeler end. In this case seems that dmn-scala should at least be able to parse and give a reasonable error rather than NullPointerException

Fetch the variables lazy from a given context

Description

Currently, we need to pass the variables for the evaluation as a map. The FEEL engine exposes an API to pass a context instead. The context allows fetching the variables lazily when they are used by the engine.

We should expose a similar API to allow lazy fetching of variables. We could also try to use the same classes to simplify the integration.

NoClassDefFoundError after

Hello,

I get this error after installing the dmn-scala\zeebe-worker :

`❯ java -jar .\target\dmn-engine-zeebe-worker-1.6.1-SNAPSHOT-full.jar

Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/logging/log4j/util/StackLocator$FqcnCallerLocator
at org.apache.logging.log4j.util.StackLocator.(StackLocator.java:37)
at org.apache.logging.log4j.util.StackLocatorUtil.(StackLocatorUtil.java:33)
at org.apache.logging.slf4j.Log4jLoggerFactory.getContext(Log4jLoggerFactory.java:44)
at org.apache.logging.log4j.spi.AbstractLoggerAdapter.getLogger(AbstractLoggerAdapter.java:48)
at org.apache.logging.slf4j.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:30)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:358)
at org.camunda.dmn.package$.(package.scala:7)
at org.camunda.dmn.zeebe.ZeebeDmnWorkerApplication.start(ZeebeDmnWorkerApplication.scala:52)
at org.camunda.dmn.zeebe.ZeebeDmnWorkerApplication$.main(ZeebeDmnWorkerApplication.scala:27)
at org.camunda.dmn.zeebe.ZeebeDmnWorkerApplication.main(ZeebeDmnWorkerApplication.scala)
Caused by: java.lang.ClassNotFoundException: org.apache.logging.log4j.util.StackLocator$FqcnCallerLocator
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:606)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:168)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
... 10 more
Exception in thread "shutdownHook1" java.lang.NoClassDefFoundError: Could not initialize class org.camunda.dmn.package$
at org.camunda.dmn.zeebe.ZeebeDmnWorkerApplication.stop(ZeebeDmnWorkerApplication.scala:73)
at org.camunda.dmn.zeebe.ZeebeDmnWorkerApplication$.$anonfun$main$3(ZeebeDmnWorkerApplication.scala:25)
at scala.sys.ShutdownHookThread$.$anonfun$apply$1(ShutdownHookThread.scala:35)
at java.base/java.lang.Thread.run(Thread.java:832)`

I also get the same error when I run java -jar .\dmn-engine-zeebe-worker-1.6.0-full.jar.

Is this repo being maintained or is it obsolete ?

Environment :

  • Windows 10
  • Java version :
    ❯ java -version java version "15.0.2" 2021-01-19 Java(TM) SE Runtime Environment (build 15.0.2+7-27) Java HotSpot(TM) 64-Bit Server VM (build 15.0.2+7-27, mixed mode, sharing)

Upgrade to Camunda 7.13 and Scala 2.13

I would like to create a semi-automatic DMN Tester. As a Scala-Developer I would like to use this library and try out Scala 3 - hence I need at least Scala 2.13.

@saig0 In the Forum you mentioned:

However, I will schedule a new release to update the dependencies :slight_smile:

(see https://forum.camunda.org/t/dmn-scala-plugin-support/19761/6)

I tried it to upgrade it myself - but could not get the tests to work.

Running the existing code did not work at all:

[info] Set current project to root (in build file:/Users/mpa/dev/Github/experiments/dmn-scala/)
[error] Modules were resolved with conflicting cross-version suffixes in ProjectRef(uri("file:/Users/mpa/dev/Github/experiments/dmn-scala/"), "zeebeWorker"):
[error]    org.scala-lang.modules:scala-parser-combinators _2.12, _2.13
[error] java.lang.RuntimeException: Conflicting cross-version suffixes in: org.scala-lang.modules:scala-parser-combinators
[error] 	at scala.sys.package$.error(package.scala:27)
[error] 	at sbt.librarymanagement.ConflictWarning$.processCrossVersioned(ConflictWarning.scala:39)
[error] 	at sbt.librarymanagement.ConflictWarning$.apply(ConflictWarning.scala:19)

Can you indicate - if and when you can provide such a release?

FEEL 1.3 namespace is not supported

If I parse a DMN contains an expression with the FEEL 1.3 namespace https://www.omg.org/spec/dmn/20191111/feel/ then it fails.

Failure message:

Expression language 'https://www.omg.org/spec/dmn/20191111/feel/' is not supported

It seems that the FEEL namespace of version 1.3 (and 1.2) is not supported.

DMN engine version 1.6.2

Output of decision tables generated by Camunda modeler not usable as variables in dmn-scala

Decision tables generated in Camunda modeler do not behave as I would expect when evaluated with dmn-scala. The output of a decision table is not usable by any DRD elements within the same model that use it as a required decision. Outputs of a decision table are not written to variables in the FEEL engine.

The reason for this is decision table elements generated by Camunda modeler do not include a variable element defining any variables named as outputs of the table.

An example model created with Camunda modeler 3.1.2 and evaluated with dmn-engine 1.3.1:

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/DMN/20151101/dmn.xsd" xmlns:biodi="http://bpmn.io/schema/dmn/biodi/1.0" id="Definitions_0cum8ey" name="DRD" namespace="http://camunda.org/schema/1.0/dmn" exporter="Camunda Modeler" exporterVersion="3.1.2">
  <decision id="decision_dt_output_test" name="decision table test">
    <extensionElements>
      <biodi:bounds x="161" y="266" width="180" height="80" />
    </extensionElements>
    <decisionTable id="decisionTable_1">
      <input id="input_1">
        <inputExpression id="inputExpression_1" typeRef="string">
          <text>true</text>
        </inputExpression>
      </input>
      <output id="output_1" label="My Output Variable" name="myOutputVariable" typeRef="string" />
      <rule id="DecisionRule_0zhf2yo">
        <inputEntry id="UnaryTests_0q0fp8n">
          <text>true</text>
        </inputEntry>
        <outputEntry id="LiteralExpression_0bdx038">
          <text>"my output value"</text>
        </outputEntry>
      </rule>
    </decisionTable>
  </decision>
  <decision id="decision_dt_chaining_test" name="expression test">
    <extensionElements>
      <biodi:bounds x="156" y="80" width="180" height="80" />
      <biodi:edge source="decision_dt_output_test">
        <biodi:waypoints x="254" y="266" />
        <biodi:waypoints x="254" y="160" />
      </biodi:edge>
    </extensionElements>
    <variable id="InformationItem_1mbj8gg" name="expressionOutput" typeRef="string" />
    <informationRequirement>
      <requiredDecision href="#decision_dt_output_test" />
    </informationRequirement>
    <literalExpression id="LiteralExpression_0ycsm8o" expressionLanguage="feel">
      <text>"output variable equals: " + myOutputVariable</text>
    </literalExpression>
  </decision>
</definitions>

evaluating that for "decision_dt_chaining_test" will give a warn:
553 [main] WARN org.camunda.feel.FeelEngine - Suppressed failure: no variable found for name 'myOutputVariable'

and output of
NilResult

I think this is more on the modeler end as it seems decision tables, same as literal expressions (which Camunda modeler does do), should define output variables with the variable element. Can open an issue over there if preferred. Here's a reference table from https://github.com/dmn-tck/tck/blob/master/TestCases/compliance-level-3/0017-tableTests/0017-tableTests.dmn which uses the variable element.

Although presumably these models do behave as expected using the Camunda dmn java engine? I haven't tested it. The incompatibility between the modeler and dmn-scala is why I'm submitting this here.

Decision table output names should not be null

Describe the bug
When creating a decision table adding an output name is optional. This works fine when there is a single output. It causes problems in Zeebe when there are multiple outputs. If we have the following decision:

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="https://www.omg.org/spec/DMN/20191111/MODEL/" xmlns:dmndi="https://www.omg.org/spec/DMN/20191111/DMNDI/" xmlns:dc="http://www.omg.org/spec/DMN/20180521/DC/" xmlns:modeler="http://camunda.org/schema/modeler/1.0" id="Definitions_0dxhm7g" name="DRD" namespace="http://camunda.org/schema/1.0/dmn" exporter="Camunda Modeler" exporterVersion="5.0.0" modeler:executionPlatform="Camunda Cloud" modeler:executionPlatformVersion="8.0.0">
  <decision id="decision" name="Decision 1">
    <decisionTable id="DecisionTable_11j2yhz" hitPolicy="RULE ORDER">
      <input id="Input_1">
        <inputExpression id="InputExpression_1" typeRef="string">
          <text>x</text>
        </inputExpression>
        <inputValues id="UnaryTests_1mi91l8">
          <text>"test"</text>
        </inputValues>
      </input>
      <output id="Output_1" label="y" typeRef="boolean" />
      <output id="OutputClause_0w2nbsl" label="z" name="z" typeRef="string" />
      <rule id="DecisionRule_0z6705j">
        <inputEntry id="UnaryTests_07m9i6y">
          <text>"x"</text>
        </inputEntry>
        <outputEntry id="LiteralExpression_0wdqh88">
          <text>false</text>
        </outputEntry>
        <outputEntry id="LiteralExpression_1tgk1ca">
          <text>"z"</text>
        </outputEntry>
      </rule>
    </decisionTable>
  </decision>
  <dmndi:DMNDI>
    <dmndi:DMNDiagram>
      <dmndi:DMNShape dmnElementRef="decision">
        <dc:Bounds height="80" width="180" x="160" y="100" />
      </dmndi:DMNShape>
    </dmndi:DMNDiagram>
  </dmndi:DMNDI>
</definitions>

Note the <output id="Output_1" label="y" typeRef="boolean" /> without a name attribute. Zeebe will try to map the output of this decision to a json object:

{
    null: false,
    "z": "z"
}

Because the name of y has not been defined it will be null. This is not valid.

To Reproduce
Steps to reproduce the behavior:

  1. Create a decision table with multiple outputs
  2. Make sure one of the outputs does not have an output name

Expected behavior
A validation fails when validating a decision table containing an output without an output name.

Environment

  • DMN engine version: 1.7.1
  • Integration:
    • Camunda Cloud/Zeebe: 8.0.1+

Related Zeebe issue: camunda/camunda#9269

Align the public Java API with the Scala API

Description

Since the DMN engine will be integrated into Java projects, it should expose the same APIs for Scala and Java. The (major) public classes should be used smoothly with Java (e.g. avoid exposing unhandy Scala classes).

This includes the following parts:

  • parse DMN
  • ParsedDmn
  • DecisionResult
  • EvalResult
  • EvalFailure
  • AuditLog

Detect cyclic dependencies in kowledge during parsing

Is your feature request related to a problem? Please describe.
Knowledge requests can depend on each other. This can create cyclic dependencies. These cannot be evaluated properly at runtime.

Describe the solution you'd like
When parsing a DMN file, detect cyclic dependencies in knowledge requirements. If any such cycles are found, return an error.

Related issues

Lazy evaluation - parse/evaluate only the required decisions

Currently, the DMN engine parses the whole DMN before it evaluates a decision. In general, this behavior is fine because it detects possible failures early on parsing instead of throwing failures later when evaluating a decision.

However, in some cases, it can be handy to parse/evaluate only the decisions that are required to evaluate a given decision (i.e. lazy evaluation). The other decision logic is ignored and doesn't cause a failure. As a result, it should be possible to evaluate a decision, even if another decision (logic) is not parsable/executable.

This could be used for running the DMN TCK. It would allow a more fine granular detection of failing test cases.

Error in case of a number with null value

Hi @saig0 ,

In the following model, Decision_testNumberNull has three rules, transforming a number into a boolean:

  1. >=1 ---> true
  2. <1 ---> false
  3. null ---> null

I would expect the third rule to be hit in case "number": null.
Instead I get

{
    "message": "failed to evaluate expression '>=1':\nexpected Number, Date, Time or Duration but found 'ValNull'"
}

The DMN1.1 specification mentions:

There is no value for notANumber, positiveInfinity, or negativeInfinity. Use null instead.

This is the model:

<?xml version="1.0" encoding="UTF-8"?> <definitions xmlns="http://www.omg.org/spec/DMN/20151101/dmn.xsd" xmlns:biodi="http://bpmn.io/schema/dmn/biodi/1.0" id="Definitions_0yik8kn" name="DRD" namespace="http://camunda.org/schema/1.0/dmn"> <decision id="Decision_testNumberNull" name="Decision_testNumberNull"> <extensionElements> <biodi:bounds x="493" y="154" width="180" height="80" /> </extensionElements> <decisionTable id="decisionTable_1"> <input id="input_1"> <inputExpression id="inputExpression_1" typeRef="number"> <text>number</text> </inputExpression> </input> <output id="output_1" name="result" typeRef="boolean" /> <rule id="DecisionRule_0yq3enu"> <inputEntry id="UnaryTests_0mpzyq6"> <text>&gt;=1</text> </inputEntry> <outputEntry id="LiteralExpression_1pscgba"> <text>true</text> </outputEntry> </rule> <rule id="DecisionRule_184h1dc"> <inputEntry id="UnaryTests_19ptzym"> <text>&lt;1</text> </inputEntry> <outputEntry id="LiteralExpression_1o1euap"> <text>false</text> </outputEntry> </rule> <rule id="DecisionRule_1dbfjb8"> <inputEntry id="UnaryTests_1ufzcbx"> <text>null</text> </inputEntry> <outputEntry id="LiteralExpression_1ytapo9"> <text>null</text> </outputEntry> </rule> </decisionTable> </decision> </definitions>

append() and concatenate() results in elements with added variableName

Describe the bug
append(["a","b","c"],"d") or concatenate(["a","b","c"],"d"), results in variableName=[{variableName=a},{variableName=b},{variableName=c},{variableName=d}], instead of ["a","b","c","d"]

in case the arguments were passed through as variables, only the appended or concatenated element is affected

Example1
decision simpleAppendedList with expression append(["a","b","c"],"d") results in
simpleAppendedList => ObjectValue [value=[{simpleAppendedList=a}, {simpleAppendedList=b}, {simpleAppendedList=c}, {simpleAppendedList=d}], isDeserialized=true, serializationDataFormat=application/x-java-serialized-object, objectTypeName=java.util.ArrayList, serializedValue=352 chars, isTransient=false]

Example2
with input variables

  • initList => ObjectValue [value=[{property2=property2_value1, property1=property1_value1, property3=property3_value1}, {property2=property2_value2, property1=property1_value2, property3=property3_value2}, {property2=property2_value3, property1=property1_value3, property3=property3_value3}], isDeserialized=true, serializationDataFormat=application/x-java-serialized-object, objectTypeName=java.util.ArrayList, serializedValue=564 chars, isTransient=false]

  • newItem => Value '{"property1" : "property1_value4", "property2" : "property2_value4", "property3" : "property3_value4"}' of type 'PrimitiveValueType[string]', isTransient=false

decision appendedList with expression append(initList,newItem) results in
appendedList => ObjectValue [value=[{property2=property2_value1, property1=property1_value1, property3=property3_value1}, {property2=property2_value2, property1=property1_value2, property3=property3_value2}, {property2=property2_value3, property1=property1_value3, property3=property3_value3}, {appendedList={"property1" : "property1_value4", "property2" : "property2_value4", "property3" : "property3_value4"}}], isDeserialized=true, serializationDataFormat=application/x-java-serialized-object, objectTypeName=java.util.ArrayList, serializedValue=760 chars, isTransient=false]

Environment
As Camunda BPM process engine plugin?
version: 1.3.1

Zeebe Worker doesn't complete the job with a list or a context result

If a decision has a list or a context/map result then the worker doesn't serialize the result correctly.
It passes the plain result to the Zeebe client. But the client can not handle Scala objects. As a result, the job is not completed with the actual decision result.

Environment: Zeebe worker
Version: 1.6.1

Invoke a function defined in a required BKM

I can invoke a function that is defined in a required BKM. The function can be defined

  • as a function definition (as decision logic)
  • as a literal in a literal expression
  • inside a context

requires camunda/feel-scala/issues/335


Edit: currently, it is possible to invoke the function if it is defined in a required decision but not a BKM.

Evaluation result contains the audit log (aka. decision tree)

Is your feature request related to a problem? Please describe.
A commonly requested feature in DMN is the decision tree. That means that the evaluation of a decision should return the result but also all intermediate results (e.g. from required decisions).

Currently, the DMN engine allows registering listeners that receive the audit log of an evaluation. The audit log contains all intermediate results and data about the evaluation.

Describe the solution you'd like
Return the audit log as part of the evaluation result.

The caller of the API receives the decision result and the audit log. The audit log can be used for history or as a decision tree. Or, it can be ignored.

Related issues

Split public API from implementation packages

Description

We should split the packages to make it clear which parts belongs to the public API. For the public API, we need to guarantee backward compatibility.

  • create a new package org.camunda.dmn.api for the public API
  • create a new package org.camunda.dmn.impl for the internal parts
  • extract the public API from the DmnEngine and move it in the package
    • split Scala and Java API
    • engine builder
    • the decision result
    • audit log
    • parsed decisions
  • ensure the public API will not break the backward compatibility
    • use either Clirr (like in FEEL) or Revapi (like in Zeebe)
  • document the restrictions in the contributing guide, similar to FEEL-Scala: https://github.com/camunda/feel-scala/blob/master/CONTRIBUTING.md#public-api-and-backwards-compatibility

I can set the value mapper and function provider in the builder

Description

The DMN engine uses a value mapper and a function provider to build the internal FEEL engine. Currently, the value mapper and the function provider are loaded via Java's SPI.

We should extend the builder to pass the value mapper and the function provider directly (without using Java's SPI mechanism).

Remove all modules except the DMN engine

Description

Currently, the project contains the following modules:

  • dmn-engine
  • engine-benchmark
  • camunda-plugin
  • zeebe-worker
  • standalone-engine
  • engine-rest

We will support only the DMN engine officially. We should remove the other modules because:

  • the Camunda Platform 7 integration will be implemented in their main project eventually
  • the Zeebe worker is obsolete after we integrated the DMN engine in Zeebe
  • the REST API and standalone utilities could be extracted as a community project (if there is an interest)
  • the benchmark is an interesting idea but currently it includes only one case and it is set up for SBT - let's create a new project/module

DMN literal expression : handling regular expressions

Hello,

I'm trying to process some text using regular expressions, so I handled it like this :

image

However, when I deploy the DMN file, this is the log I get :

06:51:51.053 [main] WARN org.camunda.dmn.DmnEngine - Failure(Fail to parse file 'test_js.dmn': Failure(Expression language 'javascript' is not supported))

It seems that the DMN Engine worker does not support JS.

Am I missing some setup ? Is there a better way to do this ?

Thank you for your help,

Critical Vulnerability

Describe the bug
Apache Commons Text performs variable interpolation, allowing properties to be dynamically evaluated and expanded. The standard format for interpolation is "${prefix:name}", where "prefix" is used to locate an instance of org.apache.commons.text.lookup.StringLookup that performs the interpolation. Starting with version 1.5 and continuing through 1.9, the set of default Lookup instances included interpolators that could result in arbitrary code execution or contact with remote servers. These lookups are: - "script" - execute expressions using the JVM script execution engine (javax.script) - "dns" - resolve dns records - "url" - load values from urls, including from remote servers Applications using the interpolation defaults in the affected versions may be vulnerable to remote code execution or unintentional contact with remote servers if untrusted configuration values are used. Users are recommended to upgrade to Apache Commons Text 1.10.0, which disables the problematic interpolators by default.

To Reproduce
Steps to reproduce the behavior:

  1. Run OWASP Dependency-Checker

Expected behavior
A vulnerability report with no critical vulnerabilities

Environment

  • DMN engine version: 1.7.3
  • Integration:
    • Camunda BPM: 7.x.y
    • Camunda Cloud/Zeebe: 1.x.y
    • Standalone with REST API
    • Embedded as library in custom application

eval with unknown decision id leads to NoSuchElementException

Describe the bug
When I try to eval using a ParsedDmn, but with a decisionId that does not occur in the provided ParsedDmn, then the following exception is thrown:

java.util.NoSuchElementException: last of empty list

	at scala.collection.immutable.Nil$.last(List.scala:665)
	at scala.collection.immutable.Nil$.last(List.scala:661)
	at org.camunda.dmn.Audit$AuditLog.<init>(Audit.scala:17)
	at org.camunda.dmn.DmnEngine.$anonfun$eval$4(DmnEngine.scala:188)
	at scala.Option.getOrElse(Option.scala:201)
	at org.camunda.dmn.DmnEngine.eval(DmnEngine.scala:185)
	at org.camunda.dmn.DmnEngine.eval(DmnEngine.scala:220)

To Reproduce
Steps to reproduce the behavior:

  • parse a simple dmn
  • call eval(dmn: ParsedDmn, decisionId: String, variables: java.util.Map[String, Object]): DecisionResult with the parsed dmn, a decisionId that does not occur in the provided dmn, and an empty Map as variables.
  • the exception is thrown

Expected behavior
A Failure result: Failure(s"no decision found with id '$decisionId'")

Environment

  • DMN engine version: 1.7.1
  • Integration:
    • Camunda Cloud/Zeebe: personal development branch

Write a user guide

Description

Write a guide for users to cover:

  • which DMN elements are supported
  • which parts of each DMN element are supported
  • how to use required decisions
  • how to use required BKM
  • how to invoke functions

blocked by #112

FEEL expression fails to parse when referencing an itemComponent with a space in the name

Describe the bug
DMN models that contain itemDefinitions with itemComponents that include spaces in their name, throw a "failed to parse expression" error. An example from the included VacationDayCalculator.dmn model is: FEEL expression: failed to parse expression 'Years of Service(employee.start Date, calculation date)': Expected (!"(" | "." | parameters | StringIn("<=", ">=", "<", ">", "!=", "=") | "between" | "in" | "and" | "or" | end-of-input):1:19, found "(employee."

In this example, employee is of type Employee which is an itemDefinition containing an itemComponent "start Date". Note that 'calculation date' also contains a space, but it is a variable with a typeRef="date". We are not experiencing the same parse error with 'calculation date'.

To Reproduce
Steps to reproduce the behavior:

  1. Create a DMN model with an ItemDefinition that has an itemComponent, whose name contains a space.
  2. Create a valid FEEL expression that references the itemComponent that contains the space.

Expected behavior
The FEEL expression should successfully parse.

Environment

  • DMN engine version: 1.7.1
  • Integration:
    • Embedded as library in custom application

Note that when we create the DmnEngine object using the DmnEngine.Builder we are setting the following builder properties:

  • escapeNamesWithSpaces(true)
  • escapeNamesWithDashes(true)

Here is a sample DMN model that demonstrates the problem.
VacationDayCalculator.dmn.zip

Type conversion of singleton lists

A singleton list (i.e. a list with one item) can be converted into a value and visa-verse.

For example, if the variable of a decision is of type list<string> and the decision logic evaluates to string then the value is converted into list<string>.


image

image

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.