Month: August 2020

Integrating DMN and Business Process on Red Hat Process Automation Manager

DMN stands for Decision Model and Notation. According to Wikipedia it is a standard approach for describing and modeling repeatable decisions within organizations to ensure that decision models are interchangeable across organizations. It is another approach of creating a “decision” on RHPAM (Red Hat Process Automation Manager), other than Decision Table and DRL.

On RHPAM, DMN file can be deployed as a standalone dpeloyment, or as an embedded within a Business Process. On this writing, im trying to do both and we’ll see what are the benefit and weakness of each approach.

Lets try to create a simple DMN to calculate how much loan should one get based on his age and salary. Create “age” and “salary” as DMN Input Data, and two DMN Decisions. “Loan_limit” with Decision Table, and “result” with Context.

Save, Build and Deploy, and we can test it by using rest api. But first we need to check on DMN Namespace and Model Name which is highlighted on the first screenshot and then put is as json parameter.

curl -L -X POST 'http://localhost:8080/kie-server/services/rest/server/containers/loan_validation_1.0.0-SNAPSHOT/dmn' \
-H 'Authorization: Basic cGFtQWRtaW46cGFzc3dvcmQ=' \
-H 'Content-Type: application/json' \
--data-raw '{
  "model-namespace":"https://kiegroup.org/dmn/_43FF885A-C2FB-49A4-BFB4-0F007A2C1C4F",
  "model-name":"Validation",
  "dmn-context": {
    "age":50,
    "salary":1200
  }
}'

The next step is put this DMN into a workflow. We can start by crating a simple workflow, dont forget to add DMN Namespace and Model Name on Business Rule Task.

And run this curl ommand to create a new instance,

curl -L -X POST 'http://localhost:8080/kie-server/services/rest/server/containers/loan_validation_1.0.0-SNAPSHOT/processes/loan_workflow/instances/' \
-H 'Authorization: Basic cGFtQWRtaW46cGFzc3dvcmQ=' \
-H 'Content-Type: application/json' \
--data-raw '{
    "age":50,
    "salary":1200
}'

And we can see the result on log,

12:58:08,486 INFO  [stdout] (default task-17) ================
12:58:08,486 INFO  [stdout] (default task-17) you are eligible for 20000
12:58:08,486 INFO  [stdout] (default task-17) ================

Code sample can be downloaded on below github repository,

https://github.com/edwin/rhpam-loan-validation-sample-with-dmn

Securing Quarkus Metric API

Usually im creating a metrics API for displaying statistics and various metrics which are being use for measuring application healthiness. There are various tools that being use to capturing this statistics and displaying it, one example is using Prometheus and Grafana.

But on this example, we are not talking too much detail about Prometheus and Grafana, but more on how we providing those metrics on top of Quaskus while securing it so that no malicious user can access this metric API easily.

Lets start with a simple pom file,

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>QuarkusPrometheus</groupId>
    <artifactId>com.edw</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <quarkus.version>1.6.1.Final</quarkus.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <surefire-plugin.version>2.22.1</surefire-plugin.version>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>io.quarkus</groupId>
                <artifactId>quarkus-bom</artifactId>
                <version>${quarkus.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-resteasy</artifactId>
        </dependency>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-resteasy</artifactId>
        </dependency>

        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-smallrye-metrics</artifactId>
        </dependency>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-smallrye-health</artifactId>
        </dependency>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-elytron-security-properties-file</artifactId>
        </dependency>

        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-junit5</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>io.rest-assured</groupId>
            <artifactId>rest-assured</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>${surefire-plugin.version}</version>
                <configuration>
                    <systemProperties>
                        <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
                    </systemProperties>
                </configuration>
            </plugin>
            <plugin>
                <groupId>io.quarkus</groupId>
                <artifactId>quarkus-maven-plugin</artifactId>
                <version>${quarkus.version}</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>build</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

And a very simple application.properties for storing all my configurations, in here we can see that we are defining a specific role for accessing our metrics endpoint.

#port
quarkus.http.port=8082

#security
quarkus.security.users.embedded.enabled=true
quarkus.security.users.embedded.plain-text=true
quarkus.security.users.embedded.users.admin=password
quarkus.security.users.embedded.roles.admin=prom-role

quarkus.http.auth.policy.prom-policy.roles-allowed=prom-role

quarkus.http.auth.permission.prom-roles.policy=prom-policy
quarkus.http.auth.permission.prom-roles.paths=/metrics

run by using below command,

compile quarkus:dev

Try opening our metrics url directly,

We can try to login by using a specific username and password,

admin / password

If successfully login, we can see this view

One interesting thing is that we can use a different url for Kubernetes’s health and liveness probe check, without have to use any credential at all.

Sourcecode for this example can be downloaded on below url,

https://github.com/edwin/quarkus-secure-prometheus-api

Have fun with Quarkus 🙂

A Simple RHPAM-Application Integration with Multi User Approval Workflow

On this article, im trying to create a simple Leave Approval System which is deployed as microservices. So basically there are two different application, one Golang app as Frontend, and RHPAM (Red Hat Process Automation Manager) as Backend, and both are communicating by using a simple REST API.

Basically there are two users involved here, one is adminUser as requester, and spv02 as approver. As approver, spv02 can either accept or reject the requested leave. Easiest way to described the approval workflow is perhaps described in below image,

Lets start by creating two user on RHPAM,

adminUser / password
spv02 / password

Import project from github (code is at the end of this article), build and deployed it to KIE.

Now lets start with creating an entry form,

The touch-point between frontend and pam on this ui is RHPAM’s “process instances” API, and im adding a correlation-key which is a unique business primary key.

curl -L -X POST 'http://localhost:8080/kie-server/services/rest/server/containers/approval_system_1.0.1-SNAPSHOT/processes/approval/instances/correlation/TL-3422' \
-H 'Authorization: Basic YWRtaW5Vc2VyOnBhc3N3b3Jk' \
-H 'Content-Type: application/json' \
--data-raw '{
    "application": {
        "com.myspace.approval_system.Request": {
            "days": 9,
            "purpose":"Sick Leave"
        }
    }
}'

Next step is displaying all leave request that have been made by this corresponding user, we can capture this by using server queries API, given a specific username as initiator parameter,

curl -L -X GET 'http://localhost:8080/kie-server/services/rest/server/queries/processes/instances?initiator=adminUser&page=0&pageSize=10&sortOrder=true&status=1&status=2&status=3' \
-H 'Accept: application/json' \
-H 'Authorization: Basic YWRtaW5Vc2VyOnBhc3N3b3Jk'

Moving forward, now we are seeing from approval’s point of view, first we need to display what are the tasks which are assign to this user.

curl -L -X GET 'http://localhost:8080/kie-server/services/rest/server/queries/tasks/instances/owners?page=0&pageSize=10&sortOrder=true&sort=taskId' \
-H 'Accept: application/json' \
-H 'Authorization: Basic c3B2MDI6cGFzc3dvcmQ='

And the ability to Approve or Reject a specific request, there are two APIs which are involved here. That is one API for starting the task, and another one to complete it. Make sure you differentiate parameters on “approved” field, use “false” for Rejecting request, and “true” for Accepting request.

curl -L -X PUT 'http://localhost:8080/kie-server/services/rest/server/containers/approval_system_1.0.1-SNAPSHOT/tasks/6/states/started' \
-H 'Authorization: Basic c3B2MDI6cGFzc3dvcmQ='
curl -L -X PUT 'http://localhost:8080/kie-server/services/rest/server/containers/approval_system_1.0.1-SNAPSHOT/tasks/6/states/completed' \
-H 'Authorization: Basic c3B2MDI6cGFzc3dvcmQ=' \
-H 'Content-Type: application/json' \
--data-raw '{
    "approved": false
}'

And here are my repositories on Github,

frontend : 
https://github.com/edwin/frontend-for-approval-rhpam

backend :
https://github.com/edwin/rhpam-simple-approval-concept

Have fun playing with RHPAM 🙂