DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Custom Functions in Power Flows DMN

Learn more about decision engines, particularly Power Flows DMN.

Mariusz Kumor user avatar by
Mariusz Kumor
·
Apr. 04, 19 · Tutorial
Like (2)
Save
Tweet
Share
10.35K Views

Join the DZone community and get the full member experience.

Join For Free

This article will be dedicated to modern and interesting decision engines, and to be precise, I will focus on one in particular — Power Flows DMN. This project is a library written in Java with open-source code and is available on GitHub. There are many standards and notations for decision engines. One of the most popular is OMG DMN 1.1, and the following project was based on such.

The basic idea of the decision engine is to evaluate rules and return the result. Different engines support different languages to create dynamically calculated expressions. Thanks to this approach, the rules are more generic and re-usable. They often allow us to describe rules that are simply not possible statically. 

But a good decision engine should be able to call functions within dynamic expressions. And it would be best if you could define your own ones. By browsing the DMN Power Flows source code, we can see that this functionality has been added. Let's look at the possibilities offered by the tool.

The engine itself supports the evaluation in the following languages:
a) FEEL
b) Juel
c) Groovy
d) MVEL
e) JavaScript

But can we write our own functions for each language and use it in the expression? It turns out — yes!

Let's say our example expression will look like:

testMethod(x, 1) == "I'm no. 1 test static method"


In addition, we assume that the above expression is written in JavaScript. In this example, we wanted to have the ability to use the testMethod function in expressions so that the user configuring the business rules does not have to duplicate the complex functionality calculating the result, but instead, they used a concise expression consisting only of calling the function.

Let's move to the code. The method to the name used in the expression can be bound with its implementation in Java. Yes, we can make it available to any language used in expressions, but it must be implemented in Java. As for the implementation methods, two are supported:

a) Static methods
b) Instance methods

The first one can be used in any of the supported programming languages. Instance methods work for JavaScript and Groovy.

Static Methods

Let's start with the configuration. First, we need a class defining the methods. For example, check out the following listing:

public class MySampleClass {

    private final String value;

    public MySampleClass(final String value) {
        this.value = value;
    }

    public String mySampleInstanceMethod(final int firstParam, final String secondParam) {
        return value + "I'm no. " + firstParam + " " + secondParam + " instance method;
    }

    public static String mySampleStaticMethod(final String firstParam, final int secondParam) {
       return "I'm no. " + secondParam + " " + firstParam + " static method;
    }
}


Methods in the class must be public. The above class defines two methods. One of them is static; the other is not. The instance method will be used by calling it on an instance of the  MySampleClass class. We have to configure the above methods so that they will be visible to the decision engine.

Method method = MethodSource.class.getMethod("mySampleStaticMethod", String.class, Integer.TYPE);
List<MethodBinding> methodBindings = new ArrayList<>();
methodBindings.add(new StaticMethodBinding("testMethod", method));


First of all, we need to get the method object from the given class. Next, we create a  StaticMethodBinding class (a type of MethodBinding) object and add it to the collection. The collection can contain many objects of the mentioned class. The first argument of  StaticMethodBinding constructor is the name available in expression. In our example, it's the testMethod:

DecisionEngineConfiguration decisionEngineConfiguration = new DefaultDecisionEngineConfiguration().methodBindings(methodBindings);


For a prepared collection, we set to the decision engine configuration:

DecisionEngine decisionEngine = decisionEngineConfiguration.configure();


And from the configuration, we can get the DecisionEngine instance. At the end, we can evaluate the decision. It's important to construct decision variables. Since our example expression contains variable x, there is a need to set the variable:

Map<String, Serializable> vars = new HashMap<>();
vars.put("x", "text");
DecisionVariables decisionVariables = new DecisionVariables(vars);

Decision decision = //your decision object containing expression with custom function in rules

DecisionResult decisionResult = decisionEngine.evaluate(decision, decisionVariables);


Instance Methods

In case we want to use an instance method, the configuration approach is very similar. The only difference is how we get the method from the class. We can perform it as follows:

MethodSource theInstance = new MethodSource("Hello! ");
Method method = MethodSource.class.getMethod("mySampleInstanceMethod", Integer.TYPE, String.class);
List<MethodBinding> methodBindings = new ArrayList<>();
methodBindings.add(new InstanceMethodBinding("testMethod", method, () -> theInstance));


Having prepared the methodBindings collection, we are able to configure and get DecisionEngine instance like in the static method example.

Of course, we can mix MethodBinding types in methodBindings collection and the decision engine accepts both typesStaticMethodBinding and InstanceMethodBinding together for one configuration.

Flow (web browser) Engine

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • What Was the Question Again, ChatGPT?
  • A Brief Overview of the Spring Cloud Framework
  • API Design Patterns Review
  • Microservices Discovery With Eureka

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: