Microservice Architecture for Workflow Applications

With our new project Imixs-Microservice we now provide a solution to build workflow management applications based on a modern microservice architecture.

Imixs-Microservice encapsulates the Imixs-Workflow Engine into a microservice architecture. The service can be bound to any business application, independent from the technology behind. This allows business applications to change the business logic without changing a single line of code. Thus the state of a business object can be controlled through the workflow model.

Based on the comprehensive functionality of the Imixs-Workflow Engine the Imixs-Microservice is empowered to control business data in various ways. Imixs-Microservice can send E-Mail notifications, log business transactions and secures any kind of business data.

The Imixs-Workflow Modeller can set an ACL for each single state in a business process model. This allows the definition of highly complex business applications and waves a security layer around each process instance.

 

The Rest Service API

Imixs-Microservice provides a flexible REST Service API which can be accessed from any platform and any kind of application. The Web Service is based on JSON and XML objects and allows an easy integration in existing projects (Java, .Net, PHP, …). Once deployed a new Workflow Model can be defined using the Eclipse based Imixs-Workflow Modeller. Any business object can be bound to a new business process by posting a JSON or XML based process instance. The state is then controlled by the Imixs-Workflow engine and can be requested and updated in various ways.

Runns with Docker

DockerImixs-Microservice provides a docker image. This makes is easy to run Imixs-Microservice in a Docker container and provides a powerful way to integrate a full featured workflow engine into a microservice architecture. The Docker image can be used as a template for custom projects and provides a scaffold to start with a microservice achitecture.

 

Imixs-Workflow and Imixs-Microservice are Open Source projects and can simplify the development of business applications in various ways. The Imixs Software Solutions provides professional services and support for building enterprise workflow management solutions.

 

Drag & Drop Fileuploads with Imixs-Workflow

With the latest Update of the Imixs-Workflow the project now supports Drag&Drop functionallity for FileUplods. The Imixs-Web-Tool libray provide several JSF Components for building workflow forms fast and easy. The library extends the functionality of the FileUpload Component.

Files which where uploaded can now be viewed in the browser before they are persisted by the Imixs-Workflow Engine. The new FileUpload widget includes the jquery fileupload plugin and supports most browser platforms.

In different to most other frameworks Imixs-Workflow persists files with an access-control-list (ACL). This ACL can be configured by the Workflow Model and restricts access to files for different actors. Each process instance controlled by Imixs-Workflow can have an individual access list. With this functionality also confidential documents can be controlled by the Workflow Engine.

The integration of the new FileUpload control is quite simple as Imixs-Workflow provides a custom tag library:

<i:imixsFileUpload workitem="#{workflowController.workitem}"
   context_url="#{facesContext.externalContext.requestContextPath}/rest/workflow/workitem/#{workflowController.workitem.item['$uniqueid']}" />

The component can be tested within the Imixs Sample Web Application.

imixs_fileupload_032

 

 

Building transaction save business logic

As I posted in my last blog about JSF and Transactioncontext, it is importend to keep the transaction context in mind when developing a business application within JSF. When you use the Imixs-Workflow Engine you normaly don’t need to think about transactions because Imixs-Workflow takes care about processing a workitem in a full controlled transaction context. But developing with JSF can lead into situations where the business logic is not allways encapsulated correctly in a single transaction. Look at the following example of an Imixs-Workflow web application based on JSF:

//jsf bean...
@EJB WorkflowService workflowService;
...
public String process(ItemCollection workitem) {
 workitem=workflowService.process(workitem);
 // evaluate result and trigger another process step...
 if (workitem.getItemValueString('department').equals('finance')) {
    workitem.replaceItemValue('$activity',APPROVE_BY_MANAGEMENT);
    workitem=workflowService.process(workitem);
 }
 ....
}

In this example, the process method of the front-end controller evaluates the result of a process step and calls a second process for the same business object. Now you have the problem that the workflowService will run in two separate transactions. As I mentioned in my blog this can result into unexpected database results.

When you are working with Imixs-Workflow, the solution is quite simple: Just put your business logic into Imixs-Workflow Plugi-In. Plug-Ins are always controlled by the WorkflowManager and called inside a single transaction. So there is no risk that your business process runs in an undefined context.

How to generate PDF output containing embedded html tags using xsl-fo

With the report capabilities of Imixs Workflow it is possible to generate PDF files from a process instance using the XML and Rest API. A description and examples of how to generate a PDF Template can be found here.

With the latest Version of the Imixs Rest API it is now also possible to embed HTML output into a PDF file generated using xsl-fo. The Report-Plugin from Imixs-Workflow now preserve embedded HTML and XML structures in a workitem property if the name of the property starts with ‘html’ or ‘xml’.

To transform the HTML block (which have to be well formed XHTML) inside xsl-fo for each html tag a fo template can be applied in the xsl template.

This is a short example how to use this template technique:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">

    <xsl:output encoding="UTF-8" method="xml" indent="yes" />
    <xsl:strip-space elements="*" />
    <xsl:param name="font-size" select="''" />
    <xsl:param name="font.symbol" select="'Arial Unicode MS'" />
    <xsl:template match="/">
        <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
            <fo:layout-master-set>
                <fo:simple-page-master master-name="A4"
                    page-width="210mm" page-height="297mm">
                    <fo:region-body region-name="xsl-region-body"
                        margin="20mm" />
                </fo:simple-page-master>
                <fo:simple-page-master master-name="A4-landscape"
                    page-width="297mm" page-height="210mm">
                    <fo:region-body region-name="xsl-region-body"
                        margin="20mm" />
                </fo:simple-page-master>
            </fo:layout-master-set>

            <fo:page-sequence master-reference="A4">
                <fo:flow flow-name="xsl-region-body">
                    <fo:block space-after="20mm">
                        <fo:block text-align="end" font-size="16pt" font-weight="bold">
                            <fo:inline>
                                HTML - PDF - Example
                            </fo:inline>
                        </fo:block>
                    </fo:block>
                    <fo:block>
                        <fo:block font-weight="bold">Text Output:</fo:block>
                        <fo:block>
                            <xsl:value-of
                                select="/collection/entity[normalize-space(item[name = 'txtworkflowgroup']/value) = 'Frage']/item[name='txtname']/value" />
                        </fo:block>

                        <!-- format html output -->
                        <fo:block font-weight="bold">HTML Output:</fo:block>
                        <fo:block>
                            <xsl:apply-templates
                                select="/collection/entity[normalize-space(item[name = 'txtworkflowgroup']/value) = 'Frage']/item[name='htmlanswer']/value" />
                        </fo:block>
                    </fo:block>
                </fo:flow>
            </fo:page-sequence>
        </fo:root>
    </xsl:template>

    <xsl:template
        match="/collection/entity[normalize-space(item[name = 'txtworkflowgroup']/value) = 'Frage']/item[name='htmlanswer']/value">
        <xsl:apply-templates />
    </xsl:template>
   
    <!-- html format -->
    <xsl:template match="p">
        <fo:block>
            <fo:inline>
                <xsl:text disable-output-escaping="yes">
                <xsl:apply-templates />
                </xsl:text>
            </fo:inline>
        </fo:block>
    </xsl:template>
    <xsl:template match="b|strong">
        <fo:inline font-weight="bold">
            <xsl:apply-templates />
        </fo:inline>
    </xsl:template>

    <xsl:template match="table">
        <fo:table table-layout="auto" width="100%">
            <fo:table-body>
                <xsl:apply-templates />
            </fo:table-body>
        </fo:table>
    </xsl:template>
    <xsl:template match="tr">
        <fo:table-row>
            <xsl:apply-templates />
        </fo:table-row>
    </xsl:template>

    <xsl:template match="td">
        <fo:table-cell>
            <fo:block>
                <xsl:apply-templates />
            </fo:block>
        </fo:table-cell>
    </xsl:template>

    <xsl:template match="address">
        <fo:block font-style="italic">
            <xsl:apply-templates />
        </fo:block>
    </xsl:template>
    <xsl:template match="blockquote">
        <fo:block space-before="1em" space-after="1em" start-indent="3em"
            end-indent="3em">

            <xsl:apply-templates />
        </fo:block>
    </xsl:template>

    <xsl:template match="caption">
        <fo:block keep-with-next="always" text-align="center">
            <xsl:apply-templates />
        </fo:block>
    </xsl:template>
    <xsl:template match="center">
        <fo:block text-align="center">
            <xsl:apply-templates />
        </fo:block>
    </xsl:template>
    <xsl:template match="div|multicol|noembed|noframes   |nolayer|noscript">
        <fo:block>
            <xsl:apply-templates />
        </fo:block>
    </xsl:template>

    <xsl:template match="h1">
        <fo:block font-size="180%" font-weight="bold">
            <xsl:apply-templates />
        </fo:block>
    </xsl:template>
    <xsl:template match="h2">
        <fo:block font-size="160%" font-weight="bold">
            <xsl:apply-templates />
        </fo:block>
    </xsl:template>
    <xsl:template match="h3">
        <fo:block font-size="140%" font-weight="bold">
            <xsl:apply-templates />
        </fo:block>
    </xsl:template>
    <xsl:template match="h4">
        <fo:block font-size="120%" font-weight="bold">
            <xsl:apply-templates />
        </fo:block>
    </xsl:template>
    <xsl:template match="h5">
        <fo:block font-size="110%" font-weight="bold">
            <xsl:apply-templates />
        </fo:block>
    </xsl:template>

    <xsl:template match="br">
        <fo:block white-space="pre">
            <xsl:text disable-output-escaping="yes">&#10;</xsl:text>
        </fo:block>
    </xsl:template>

    <xsl:template match="ol">
        <fo:list-block provisional-label-separation=".2em"
            provisional-distance-between-starts="{string-length(count(li))*.9+.6}em">
            <xsl:apply-templates />
        </fo:list-block>
    </xsl:template>

    <xsl:template match="ol/li">
        <fo:list-item>
            <fo:list-item-label end-indent="label-end()">
                <fo:block text-align="end">
                    <xsl:variable name="value">
                        <xsl:choose>
                            <xsl:when test="@value">
                                <xsl:value-of select="@value" />
                            </xsl:when>
                            <xsl:otherwise>
                                <xsl:number />
                            </xsl:otherwise>
                        </xsl:choose>
                    </xsl:variable>
                    <xsl:choose>
                        <xsl:when test="@type='I'">
                            <xsl:number format="I" value="$value" />
                        </xsl:when>
                        <xsl:when test="@type='A'">
                            <xsl:number format="A" value="$value" />
                        </xsl:when>
                        <xsl:when test="@type='i'">
                            <xsl:number format="i" value="$value" />
                        </xsl:when>
                        <xsl:when test="@type='a'">
                            <xsl:number format="a" value="$value" />
                        </xsl:when>
                        <xsl:when test="parent::ol/@type='I'">
                            <xsl:number format="I" value="$value" />
                        </xsl:when>
                        <xsl:when test="parent::ol/@type='I'">
                            <xsl:number format="A" value="$value" />
                        </xsl:when>
                        <xsl:when test="parent::ol/@type='I'">
                            <xsl:number format="i" value="$value" />
                        </xsl:when>
                        <xsl:when test="parent::ol/@type='I'">
                            <xsl:number format="a" value="$value" />
                        </xsl:when>
                        <xsl:otherwise>
                            <xsl:number format="1" value="$value" />
                        </xsl:otherwise>
                    </xsl:choose>
                    <xsl:text>.</xsl:text>
                </fo:block>
            </fo:list-item-label>
            <fo:list-item-body start-indent="body-start()">
                <fo:block>
                    <xsl:apply-templates />
                </fo:block>
            </fo:list-item-body>
        </fo:list-item>
    </xsl:template>

    <xsl:template match="ul|menu">
        <fo:list-block provisional-label-separation=".2em"
            provisional-distance-between-starts="1.6em">
            <xsl:apply-templates />
        </fo:list-block>
    </xsl:template>
    <xsl:template match="ul/li|menu/li">
        <fo:list-item>
            <fo:list-item-label end-indent="label-end()">
                <fo:block text-align="end">
                    <fo:inline font-family="{$font.symbol}">
                        <xsl:choose>
                            <xsl:when test="@type='square'">
                                <xsl:text disable-output-escaping="yes">&#x25AA;</xsl:text>
                            </xsl:when>
                            <xsl:when test="@type='circle'">
                                <xsl:text disable-output-escaping="yes">&#x25CB;</xsl:text>
                            </xsl:when>
                            <xsl:when test="parent::ul/@type='square'">
                                <xsl:text disable-output-escaping="yes">&#x25AA;</xsl:text>
                            </xsl:when>
                            <xsl:when test="parent::ul/@type='circle'">
                                <xsl:text disable-output-escaping="yes">&#x25CB;</xsl:text>
                            </xsl:when>
                            <xsl:otherwise>
                                <xsl:text disable-output-escaping="yes">&#x2022;</xsl:text>
                            </xsl:otherwise>
                        </xsl:choose>
                    </fo:inline>
                </fo:block>
            </fo:list-item-label>
            <fo:list-item-body start-indent="body-start()">
                <fo:block>
                    <xsl:apply-templates />
                </fo:block>
            </fo:list-item-body>
        </fo:list-item>
    </xsl:template>

    <xsl:template match="font">
        <fo:inline>
            <xsl:choose>
                <xsl:when test="@size=1">
                    <xsl:attribute name="font-size">xx-small</xsl:attribute>
                </xsl:when>
                <xsl:when test="@size=2">
                    <xsl:attribute name="font-size">x-small</xsl:attribute>
                </xsl:when>
                <xsl:when test="@size=3">
                    <xsl:attribute name="font-size">small</xsl:attribute>
                </xsl:when>
                <xsl:when test="@size=4">
                    <xsl:attribute name="font-size">medium</xsl:attribute>
                </xsl:when>
                <xsl:when test="@size=5">
                    <xsl:attribute name="font-size">large</xsl:attribute>
                </xsl:when>
                <xsl:when test="@size=6">
                    <xsl:attribute name="font-size">x-large</xsl:attribute>
                </xsl:when>
                <xsl:when test="@size=7">
                    <xsl:attribute name="font-size">xx-large</xsl:attribute>
                </xsl:when>
            </xsl:choose>
            <xsl:if test="@face">
                <xsl:attribute name="font-family"><xsl:value-of select="@face" /></xsl:attribute>
            </xsl:if>
            <xsl:apply-templates />
        </fo:inline>
    </xsl:template>

    <xsl:template match="small">
        <fo:inline font-size="smaller">
            <xsl:apply-templates />
        </fo:inline>
    </xsl:template>

    <xsl:template match="span">
        <xsl:choose>
            <xsl:when test="self::node()[contains(@style,'underline')]">
                <fo:inline text-decoration="underline">
                    <xsl:apply-templates />
                </fo:inline>
            </xsl:when>
            <xsl:otherwise>
                <fo:inline>
                    <xsl:apply-templates />
                </fo:inline>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

    <xsl:template match="sub">
        <fo:inline baseline-shift="sub">
            <xsl:apply-templates />
        </fo:inline>
    </xsl:template>
    <xsl:template match="sup">
        <fo:inline baseline-shift="super">
            <xsl:apply-templates />
        </fo:inline>
    </xsl:template>


    <xsl:template match="ins|u">
        <fo:inline text-decoration="underline">
            <xsl:apply-templates />
        </fo:inline>
    </xsl:template>
</xsl:stylesheet>

A complete example of a xsl-fo template for html tags can be found here.

Entity Encoding!

If you need to parse XML content make sure that this content did not contain HTML encoded characters like &auml; – this entities contained in the xml source can not be processed by the XSL processor. You need to work with raw utf-8 or unicode encoded characters. For example:

"ä" or "&#228;" works, but "&auml;" wont work!

As we are using TinyMCE Edtior in most of our web applications we need to set the “raw” format to initialize TinyMCE. Otherwise characters will be HTML encoded!

$('textarea.imixs-editor')            
            .tinymce(
                    { ....
                    .... // set entity encoding
                        entity_encoding: "raw"
                    });
        }

Building a Web application with Imixs-Workflow – Part III.

NOTE: Please see the latest tutorial how to run Imixs-Workflow with Jakarta EE.

In the first part of my tutorial I explained how to define a business model using the Imixs Workflow Modeler. The second part describes how to setup the Java EE Application server. Now its time to complete the tutorial and deploy the workflow application!

As you have seen I spent much time in explaining the modeling process and the server configuration. The reason is that the deployment of the Imixs Workflow application is really easy and did not take much time. I will explain two szenarious. First I will show how to dpeloy the Imixs Workflow Sample application. Next I explain how to checkout the sources and use the Sample Application as a scaffolder to build your own application. Continue reading “Building a Web application with Imixs-Workflow – Part III.”

Building a Web application with Imixs-Workflow – Part II.

NOTE: Please see the latest tutorial how to run Imixs-Workflow with Jakarta EE.

In the first part of my tutorial I explained how you create a workflow model using the Imixs Workflow Modeler. This part now concerns about the setup of your application server on which you can run the workflow application later. I will describe the setup of the Application Server Glassfish which is common running a JEE application. But you can also use a different JEE application servers (e.g. JBoss, WildFly). Continue reading “Building a Web application with Imixs-Workflow – Part II.”

Building a Web application with Imixs-Workflow – Part I.

NOTE: Please see the latest tutorial how to run Imixs-Worklfow with Jakarta EE.

This Tutorial shows how to build a web based workflow application using the Open Source framework Imixs-Workflow. Imixs-Workflow gives you a powerful technology building a business process management system (BPMS). It is mostly easy to setup a new web application without spending to much time into development. So you can focus on the business process and your customers needs.

The Tutorial consist of three parts.

  • Part I. – shows the creation of a workflow model. The workflow model is the blueprint where you describe how your business process should work. You can use the Eclipse based graphical Imixs-Workflow Modeler to create a Workflow model.
  • Part II. – concerns about the setup of your application server which is responsible to authenticate users and store workitems (a running process instance) into a database.
  • Part III. – will show you how to build and deploy the web application. This is mostly easy as you can use Maven to setup a scaffold in a few seconds which will provide you with a typical web application project based on the latest JEE/JSF Technology. You can use the scaffold to start further development or just start you own implementation. Its up to you.

The hole tutorial will take less than one hour. You can find the Example Application also on GitHub. Continue reading “Building a Web application with Imixs-Workflow – Part I.”

DMS with Imixs-Workflow and MySQL

The Imixs-Workflow project offers a professional and modern way to manage a business process in enterprises and organizations. This Workflow platform focus mainly on human-based workflows with means long living business processes and also business processes with a lot of data. Typical you can also use Imixs Workflow for DMS functionality as it cares about not only the data access and an easy way to find a business workflow but also Imixs-Workflow can managed large data objects like documents (PDF, MS-Word, MS-Excel, Photos or documents provided from a scan process).

DMS with MySQL

As Imixs-Workflow solutions are mostly running on open source platforms the Database Management System (DBMS) MySQL is a typical platform to store the process information. Imixs-Workflow uses an Binary-Large-Object format (BLOB) to store documents together with other process data.

But storing large data into MySQL can become a little bit tricky if your data exceeds the 1MB border which can happen immediately if your store documents. To prepare you MySQL Server to handle such amount of big data there are some MySQL settings witch need to be checked before. The settings can be set global by editing the [mysqld] section int the /etc/mysql/my.cnf file.

max_allowed_packet

The setting “max_allowed_packet”  defines the maximum size of the data included int sql statement. It shuld be set to a size of the expected maximum file size.  Example:

max_allowed_packet = 16MB

innodb log buffer size

The second important setting is the parameter “innodb_log_file_size” which should be large enough to do two things:

  • Accommodate any big BLOB or TEXT fields
  • Holding bigger transactions

If the innodb_lof_file_size is to small the EJB container can throw the following kind of exception:

11:19:34.237+0200|WARNING|glassfish3.1.2|org.eclipse.persistence.session.file:/mnt/opt/glassfish3/glassfish/domains/domain1/applications/reemtsma_pl/office-aeo-mms-ejb-1.1.1_jar/_org.imixs.workflow.jee.jpa|_ThreadID=96;_ThreadName=Thread-2;|Local Exception Stack: 
 Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.DatabaseException
 Internal Exception: java.sql.SQLException: Lock wait timeout exceeded; try restarting transaction
 Error Code: 1205
 Call: UPDATE SEQUENCE SET SEQ_COUNT = SEQ_COUNT + ? WHERE SEQ_NAME = ?
     bind => [2 parameters bound]

We recommend the following setting:

innodb_log_buffer_size = 100M
innodb_buffer_pool_size = 1G
innodb_log_file_size = 1G

After changing the configuration restart mysql with the following command:

mysql -uroot -p -e"SET GLOBAL innodb_fast_shutdown = 0;"
service mysql stop
rm -f /var/lib/mysql/ib_logfile*
service mysql start

Using the innodb_fast_shutdown = 0 forces InnoDB to completely purge transactional changes from all of InnoDB moving parts, including the transactional logs (ib_logfile0, ib_logfile1). Thus, there is no need to backup the old ib_logfile0, ib_logfile1.

Read more details about this topic here.

Imixs BPMN

Imixs Workflow is an open source project providing a powerful workflow engine to manage any kind of business process. The main objective of such a Workflow Engine is to control the states defined in the business process. The transmission from one state into another is defined by Activities. The typcial way to describe such a process flow is a state diagram. As the common standard the Business Process Modelling Notation – BPMN has been established in the last years.

BPMN Modelling

BPMN provides an easy way to describe a business process from the perspective of an user or a software system. In case of a human based workflow BPMN can also be used to describe the view from one or may users participating in such a process. In the following section we will demonstrate how to use BPMN to create a model for the Imixs-Workflow.

First of all you need to remember that one of the most important tasks of a workflow engine is to control the state of a business process. This means that a process instance can always be defined by its state. So the first step using BPMN is to model the states of a business workflow.

In BPMN there are only two predefined states known. The Start Event and the End Event. They are describing the begin and the end of a business process:

bpmn-modelling-example1

Each state between the Start and the End event can be described with the BPMN Task element. A Task describes not only the state of the process but also the general task which need to be performed in a specific situation. So we can extend the model by defining additional BPMN tasks to describe our states the process can take:

bpmn-modelling-example2

This example describes the states of a simple Ticket Workflow. The different states a Ticket can have are

  • Open a new Ticket
  • Processing Ticket
  • Solving the Ticket

Defining Events and Transitions

What we have done so far is an important step in describing a workflow model with BPMN. We defined all the tasks a business process can take and which can be identified by the workflow system to control the status of the process. Now we extend this model by adding new elements.

A business process typically defines activities which can be performed on a specific process instance. Each task depends on a state and defines a transition from one state into another. This is the workflow logic we need to design a complex business process. Using BPMN we can model this by using Gateways and Event Elements. A Gateway is used to define on ore many transistions from one state into another. A Event Element is used to describe the activity which can be performed by an actor during the workflow.  Lets see the next example:

bpmn-modelling-example3

Here we extended our simple state diagram with Gateway and Event elements to describe the activities in our ticket workflow.

If new ticket was created we defined the State ‘Open Ticket’. From this state we defined the events ‘accept’ or ‘close’ which can be triggered by the actor creating the ticket. When the event ‘accept’ is performed the state of the Ticket changes in ‘Processing Ticket’. Again we define a Gateway with now two possible transitions. When the event ‘solve’ is triggered by the actor the business process ends in the state ‘Solved’. If the event ‘reopen’ is performed we go back to the first state ‘Open Ticket’ to repeat the Workflow.

What you have seen here is a simple business process. We use the BPMN to describe the different states a process instance can have and also the Events which can be performed by an actor to process a ticket. A workflow system like the Imixs Workflow Engine can control the status of a process instance in the business model. Also the events triggered in this model can now be controlled by the workflow engine to change the states.

The Imixs Workflow System

The Imixs Wokflow provides a rich set of functions to control a business process and define the state of a process instance. In each change of a state triggered by an activity (task) Imixs Workflow updates a lot of properties of each singe instance. For example:

  • Read- and write-access to a process instance
  • Process documentation and process history
  • Ownership of a process instance
  • E-Mail notification to the next participant
  • Business-Rules to perform complex business logic
  • Versions of a process instance
  • Scheduled Events triggered by a timer
  • Summary and detail description of an instance
  • Form elements for a user frontend

These technical descriptions can be added into a workflow model and also in a BPMN model using the BPMN Version 2.0.

Read more about the Imixs Workflow technology at: