As a follow up of part 1 of the Automatiko IoT and MQTT I'd like to take you further in exploration around workflows and IoT with MQTT.
This time we look at the details of how to take advantage of some MQTT features (e.g. wildcard topics), collect sensor data into a bucket (or to make this simple - a list) and then assign user tasks based on amount of data collected instead of for every event.
In addition to that, we look into Automatiko features that makes using workflows for IoT way easier...
Wildcard topics
Let's start with MQTT feature for subscribers - this is actually what workflow in our sample is - a MQTT topic subscriber. So let's first look like how does it work under the hood in Automatiko.
Automatiko uses message events (start or intermediate) of BPMN to integrate with message broker - in this case MQTT. Message events are referencing message which describes the way how it can connect to the broker
by default uses name as the topic name
data type of the message defines what type will be used to unmarshall incoming event into
supports custom attributes to alter defaults
In this article we are going to use custom attributes to define both topic that will use wildcard and the correlation expression to extract information out of the topic instead of the message (as we did in part 1).
In the screenshot above you can see two custom attributes
topic
correlationExpression
Topic is used to define the actual topic in MQTT that the workflow definition will be connected to and listening to incoming events.
Correlation expression on the other side defines an expression that will be used for each incoming event to extract a key to be used for both identification and correlation.
Correlation expression uses special function "topic" that accepts following parameters
message - references the incoming message
index - an index that will reference different parts of the topic - it starts with 0
So for this example topic(message, 1) and the topic home/kitchen/temp the extracted correlation key will be kitchen. This in turn will be used as identifier of the workflow instance and thus you can use it in the service api calls.
You can read up more on the messaging support in automatiko in documentation.
Data bucket to collect sensor data
Next topic for today is the collection of sensor data. In part one we simply assign it to a data object of the same type. This time we expand and make sure we can accumulate the data.
So with that said there are few things that must be done
data object must be of type list
data object of type list needs to be initialized so it can easily get new items
message events received from MQTT need to be added to the list instead of assigned to data object (which would mean overridden)
Changing type is rather simple but ensuring it is initialized might be a bit more complex... but not with automatiko :) It is as simple as adding a tag on data object - auto-initialized
Configuring the message event to append to a list instead of assigning to the data object is also rather simple with automatiko, it is to use expression instead of direct mapping on the message event.
And that's it - we have now ready to use data bucket for our sensor data.
Decide when to include human actors
In this simple example we are going to receive events from MQTT and collect them into a bucket. But we don't want to involve human actors on each event. So here we can use gateways - a construct that allows us to have different paths in the workflow.
We only create a user task when the bucket has more than 5 events collected. Otherwise it simply end the path. But to prevent the workflow instance from finishing we make the workflow to be ad hoc - that allows it to stay active even though there are no active nodes in it. Marking workflow as ad hoc is done in the Properties -> Process panel.
See it in action
Have a look at this 10 min video showing all this in action. Note that this is live coding so you will see the errors as they might show up and you can imagine that this is not a scripted video where everything works from the start :)
Code can be found in github where each part of the series is a separate tag and main branch is pointing to latest version of the code base.
Conclusions
This part focused on bringing more advanced features of MQTT into the workflows to show the integration and how powerful these two can be. Using topic information as correlation, locating right workflow instances for incoming events and accumulating data is one of the most common use cases for IoT so workflows should make it simple to realize that.
Around a month ago there was the first release of Automatiko project. It aims at providing an easy to use yet powerful toolkit to build services and functions based on workflows and decision. You can read up more information about the Automatiko project at the website or blog.
This blog post is very basic introduction that attempts to address the first level of entry when starting with Automatiko.
Before you start...
So first things first... to get you up and running you need few things on your local computer
Java 11 +
Maven 3.6 +
Eclipse IDE and Automatiko plugin
Optionally docker or podman to run services as containers
The use case of this introductory sample is very simple - to connect to MQTT to receive data from the sensors that are being published there. It mainly focuses on the steps to get this working and further articles will provide more advanced features in action.
Let's get started
To get started you need to create a project, a maven project to be precise. Luckily Automatiko comes with bunch of maven archetypes that makes this task way faster. One of the is `automatiko-iot-archetype` and this is the one we are going to use today.
Archetype can be used from IDE or command line so whatever you prefer can be used and result will be exactly the same.
Once the project is there, you need to define your data model that will be used by the workflow - as data objects. In this example you can create simple POJO like class names `Temperature` that will have two fields
value - of type double that will contain the temperature value from the sensor
room - the location where the temperature was measured
Next step is to create a workflow definition that will be responsible for connection to MQTT broker. This is realised by message start event that allows not only to be the entry point for new instances but also allows to define some characteristics of the connectivity and processing.
All that is needed to talk to the MQTT broker is defined directly in the workflow definition. In our sample case, the topic in MQTT broker is simple taken from the message defined on the start event.
At the same time, data that is received from the MQTT topic is automatically converted to the data model - represented as 'Temperature` class and mapped to a `temp` data object inside the workflow instance.
Lastly, user task is also added to the workflow definition that introduces a human actor into the flow. That is mainly for demonstration purpose to show we receive data from MQTT that is properly converted into a Temperature class instance and set within the workflow instance data objects (aka variables).
A bit of advance...
As you will see when running this sample, ID of the workflow instance is auto generated (in UUID format). But that can be changed and take advantage of either data or the MQTT topic itself. By setting correlation or correlation expression on the message (via its custom attributes) you can set the id to be more domain specific.
In this case, we take the room from the message and use it as correlation. Correlation upon start of the workflow instance becomes its id - aka business key and by that it can be used in exchange with the generated ID. With that said you can use this when interacting with service API.
You can look at the introduction video that covers the content of this article.
Let's get this running...
To get this running we need a MQTT broker. Personally I find Mosquitto to be excellent choice but any MQTT compliant broker would work.
You can get Mosqiutto running with just a simple command (docker required)
docker run -it -p 1883:1883 -p 9001:9001 eclipse-mosquitto
There are other ways to run mosquitto so visit website if docker is not an option.
Run the Automatiko service
Since Automatiko generates fully functional service there is no much to do to see it in action. It is based on maven and leverages Quarkus as runtime so most Quarkus features are also available out of the box e.g. dev mode, Dev UI etc.
mvn clean quarkus:dev
and then wait a bit for maven to download all the bits....
Once it's started you should see similar log entries
You can head directly to http://localhost:8080/swagger-ui and you will be presented with nicely document API of your service
So it is now fully functional service connected to your local MQTT broker. With this you can start publishing sensor data to it and see how quickly they are consumed by Automatiko service.
You can use mosquitto client command to publish messages from command line
mosquitto_pub -t temperature -m '{"room":"livingroom", "value" : 25.0}'
use Swagger UI to see created instances based on incoming messages from MQTT.
Running as container
In case you would like to get this running as container then it is again dead simple, just run maven command with `container` profile enabled
mvn clean package -Pcontainer
And that's it. As soon as build is over you will have the container image in your local registry.
Conclusion
That's it for the first introduction - I hope it will get you interested and you will look forward for the next articles. They will come ever other week... at least that's the plan. Please share your feedback either here or via mailing list and twitter.
If you have any ideas for the use cases to cover with Automatiko don't hesitate to let us know about them as we are here to help and explore.
jBPM6 introduces new module - jbpm-runtime-manager - that aims at significantly simplify management of:
KnowledgeBase (KieBase)
KnowledgeSession (KieSession)
Moreover it allows to use predefined strategies for handling knowledge sessions and its relation to process instance. By default jBPM6 comes with three strategies:
Singleton - single knowledge session that will execute all process instances
Per Request - every request (which is in fact call to getRuntimeEngine) will get new knowledge session
Per Process Instance - every process instance will have its dedicated knowledge session for the entire life time
To make use of the strategy it's enough to create proper type of RuntimeManager. jBPM6 allows to obtain instance of the RuntimeManager in various ways, this article will provide hands on information on how it can be achieved.
With jBPM6 a whole new way of building application has been provided - Context and Dependency Injection is now available for users to build application and bring the power of jBPM to next level. Obviously CDI is not the only way to make use of jBPM - the regular API based approach is still available and fully functional.
CDI integration
jBPM6 tooling (like jbpm console or kie-wb) is built on CDI and thanks to that set of services has been provided to ease the development for custom applications that are based on CDI. These services are bundled as part of jbpm-kie-services and provides compact solution to most of the required operations to put BPM into your application:
deployment service - deploys and undeploys units (kjars) into the process engine
runtime service - gives access to state of the process engine, like retrieve process definitions, process instances, history log, etc
bpmn2 data service - gives access to details of the process definition taken from BPMN2 xml
form provider service - gives access to forms for processes and tasks
So whenever custom application is built with CDI these services are recommended way to go to get most of the power of CDI and jBPM. Moreover it's the safest way too as it is used in jBPM tooling so it got fair amount of testing to secure it does what is expected.
Using jbpm-kie-services is not a mandatory to be able to use jBPM6 in CDI environment but it does have some advantages:
- allow to maintain multiple RuntimeManagers within single execution environment
- allow independent deploy and undeploy of units (kjar) without server/application restart
- allow to select different strategies for different units
while these are all appealing add-ons they are not always needed, especially if application requires only single RuntimeManager instance to be included in the application. If that's the case we can let CDI container to create the RuntimeManager instance for us. That is considered second approach to CDI integration where only single instance of RuntimeManager is active and it's managed completely by the CDI container. Application needs to provide environment that RuntimeManager will be based on.
Last but not least is the regular API based approach to jBPM6 and RuntimeManager. It expects to be built by the application and in fact provides all configuration options. Moreover this is the simplest way to extend the functionality of RuntimeManager that comes out of the box.
This article is just an introduction to the way jBPM6 and RuntimeManager can be used. More detailed articles will follow to provide in-depth information on every option given here (cdi with services, pure cdi, api).
If you have any aspects that you would like to see in next articles (regarding runtime manager and CDI) just drop a comment here and I'll do by best to include them.
For those that keep an eye on jBPM user forum it won't be any surprise as it was already announced and sometime ago even request for comments was posted. So, I would like to emphasise once again - a brand new book for developers about jBPM5 and Drools by Mauricio Salatino a.k.a. Salaboy is coming.
I had a pleasure to slightly help with this book by reviewing it. I admit this is an excellent reading for those that are new to jBPM5 (and Drools) world as well as to those that are already familiar with it and are planning to put it into mission critical systems. Mauricio provides not only guidelines about the engine but goes beyond that by elaborating about different approaches on how to best utilize these frameworks.
It is much more than title would suggest, it is not only about jBPM5 (but main focus is on the business processes) but it covers topics like:
BPMN2 specification
Human tasks and WS-HT specification
Rule engine (Drools Expert)
Complex Event Processing (Drools Fusion)
Tooling (jBPM Web Designer, eclipse modeller, etc)
Centrailzed repository (Drools Guvnor)
Book is equipped with number of real life examples including source code that allows reader to follow all the content put in every chapter.
In conclusion, this is a book that everyone who wants to use jBPM5 to its full extend should get. I definitely recommend it for everyone who is interested in jBPM and Drools projects as it provides excellent introduction and much more than that.
Book is scheduled to be available in December 2012 so stay tuned.
JUDCon 2012 in Boston was a great place to meet with fellow developers and discuss about future of jBPM. I had a pleasure to give a talk about experimental project that I have been working on for quite some time, but unfortunately not enough time was spent on it. Anyway, I gave a introduction to the project that I use to call jbpm enterprise.
The goal of this project is to provide comprehensive BPM platform on top of jBPM and Drools projects to leverage the most of them in the enterprise (Java EE) environment. So what it does?
First of all it bundles jbpm and drools (together with all dependencies) into JBoss Module.
Next it provides very tiny layer that abstracts knowledge api and provides simplified interfaces to interact with execution engine (execution engine is knowledge base with sessions enclosed by an component with additional characteristics - more in presentation)
exposes some services via OSGi service repository
provides maven archetypes to build your components that utilize the platform over OSGi service registry
bundle archetype that is dedicated to put you process/rules/events logic in
web application archetype that makes use of the platform (starts, signal processes, etc)
More details can be found in the presentation from the JUDCon2012 conference.
As a continuation of the first post, let's try to make use of LDAP configuration to make actors aware of the tasks awaiting their attention.
Human task service is capable of reacting on certain events such as task was not started or task was not completed in time. Currently there are two options a process designer can choose from:
remind the user about the task
reassign the task to another actor/group
Depending on the needs either one of them or both can be configured on a user task activity, moreover designers are not limited to single instances of those events, for instance user task can be modelled as follows:
as soon as task is created send notification to the actor assigned to it
if there is no action within a day, send a reminder to the actor
if there is no action within two days, reassign the task to another actor
if the task is not completed within a week send notification to a manager
This is illustrated on following screen cast, starting at designing a process with user task, configuring deadlines (reassignment and notifications), building and running the process.
1. first let's design the process and define deadlines
2. now it is time to build the package and execute process
Task service supports four types of events:
reassign if not started
reassign if not completed
notify if not started
notify if not completed
To give some flexibility, expression that reference process and task variables are supported, for instance when modelling notification, users and/or groups can point to a process variables to get a list of users/groups that should be notified. In addition, notification subject and body can reference both process and task variables and provides additional variables that could be useful when referring to a task:
processInstanceId
processSessionId
workItemId
taskId
owners
and all task variables are available as Map in
doc
Process variables are accessed with #{variable} and task variables are accessed with ${variable}, simple notification could look like this:
Hello,
A task with id ${taskId} was assigned to you. You can access it in your personal <a href="http://localhost:8080/jbpm-console/app.html#errai_ToolSet_Tasks;Group_Tasks.3">inbox</a>.
Regards
jBPM
Although HTML notifications are supported it is recommended to make use of process variables and some services to provide email templates instead of putting them inline within process definition, the bpmn2 file. Both subject and body of the notification can be declared as process variable.
but how to configure it?
Note: This guide assumes that human task service is deployed as web application, if that is not the case please refer to online documentation.
There are two elements that needs to be provided to make human task capable of performing deadline actions:
configure user info component that delivers information required by notification mechanism
configure email service
And of course declare deadline requirements on the user task in your process.
Previous post showed how to configure LDAP user info component to utilize external service as user information provider (Quick recap - it simple requires to put the right class name in web.xml
init param section - user.info.class and LDAP configuration property
file). As this is rather common to use LDAP in such cases there is a way to add custom implementations as well so you are not limited to that.
Configuring email service is done by providing drools.email.conf property file that contains smtp configuration and place it inside META-INF directory of jbpm-human-task-war/WEB-INF/classes.
NOTE: there could be a need of prefixing file name with additional drools. to be found properly due to bug. So file name should be drools.drools.email.conf; this will be fixed in 5.4.
With this, many uses cases can be covered as shown in the example but most likely not all, so if there are any scenarios you find yourself in and think it might be useful to others please let us know about it:)
jBPM engine itself does not require to have knowledge about users and groups but to build more complete platform based on it sooner or later users and their memberships will be needed. Prior to version 5.3, jBPM relied on basic (and demo only) setup based on some property files. With 5.3 you can make use of integration that allow to employ existing LDAP server.
So, let's start digging into it :)
User and group information are relevant to two components:
jbpm console
human task server
jbpm console need to know about users and their roles to properly authenticate and grant them with correct access in the console.
Human task server has bit more to do with users and groups. First of all it requires it when assigning task to entities (either user or group). Next, in case notification mechanism is configured it requires to fetch more information about the entity (such as email address, etc.)
Bit of heads up is always welcome, but how this can be configured and used? Firstly, we need to have a LDAP server that could be used as user repository. If you have already one this step can be omitted.
Install and configure LDAP server
Install and configure LDAP server of your choice, I personally use OpenLDAP that can be downloaded and used freely for evaluation purpose. Regardless of your choice most likely the best guide on installation and configuration is to be found on the server home page.
Note: make sure that when configuring your LDAP server inetOrgPerson schema is included otherwise import of example ldif will fail.
Once the server is up and running it's time to load it with some information that will be used later on by jBPM. Following is a sample setup of users and groups that matches the one used in previous versions of jBPM5 (Example ldif file expect that there is already domain configured (dc=jbpm,dc=org)):
Rest of the post assumes that LDAP server is installed on the same machine as application server that hosts jbpm (but it is not limited to that).
Configure JBoss AS7 security domain to use LDAP
Next step is to configure application server that host jbpm console to authenticate users using LDAP instead of the default property file based security domain. In fact there are no changes needed to jbpm console itself but only to JBoss AS7 configuration.
To use LDAP, jbpm-console security domain inside standalone.xml file should be replaced with: <security-domain name="jbpm-console"> <authentication> <login-module code="org.jboss.security.auth.spi.LdapExtLoginModule" flag="required"> <module-option name="baseCtxDN" value="ou=People,dc=jbpm,dc=org"/> <module-option name="baseFilter" value="(uid={0})"/> <module-option name="rolesCtxDN" value="ou=Roles,dc=jbpm,dc=org"/> <module-option name="roleFilter" value="(member=uid={0},ou=People,dc=jbpm,dc=org)"/> <module-option name="roleAttributeID" value="cn"/> <module-option name="allowEmptyPasswords" value="true"/> </login-module> </authentication> </security-domain>
This is pure JBoss configuration so in case of more advanced setup is required please visit JBoss AS7 documentation.
Note that from jBPM 5.3 jbpm console is capable of using any security domain that JBoss AS supports with just configuring it properly on application server so it is not limited to LDAP.
Configure Human task server to use LDAP
Finally it is time to look into the details of human task server configuration to make it use of LDAP as user repository. Those that are following jBPM development are already familiar with UserGroupCallback interface that is responsible for providing user and group/role information to the task server. So naturally LDAP integration is done through implementation of that interface.
Similar to configuring application server, ldap callback needs to be configured (with property file for instance). Here is a sample file that corresponds to the configuration used throughout the post:
As from 5.3 by default human task server is deployed as web application on Jboss AS7. With this, user can simply adjust configuration of the human task server by editing its web.xml file. And this is how LDAP callback is registered.
Next put the jbpm.usergroup.callback.properties on the root of the classpath inside jbpm-human-task.war web application and your LDAP callback will be ready to rock!
In addition, when using deadlines on your tasks together with notification, there is one more step to configure so user information (for instance email address) could be retrieved from LDAP server. UserInfo interface is dedicated to providing this sort of information to the deadline handler and thus it's implementation needs to registered as well.
Similar as user group callback was registered it can be done via web.xml of human task web application:
It requires to be configured as well and it could be done via property file that should be named jbpm.user.info.properties and be placed on root of the class path.
As it shares most of the properties with callback configuration, in many cases users could use single file that contains all required values and instruct both implementation where to find this file with system properties:
With all that jBPM will now utilize your LDAP server for users and groups information whenever it needs them.
P.S.
This post is more of introduction to the LDAP integration rather than complete and comprehensive guide as it touches on high level all the components involved. More detailed information about configuring particular pieces can be found in jBPM documentation for 5.3 release.