Imixs Workflow ...the open source workflow technology for business applications

Core API

The Imixs Plugin API

The Imixs Plugin API is a powerful concept to extend the Imixs Workflow Engine with the technical aspects of a workflow management system. A plugin provides platform specific functionality to be executed during a workflow process. A plugin is a general building block inside a workflow management system and may be reused in different phases of a business process.

Plugins are bound to the workflow model and controlled by the Imixs Workflow Engine. Each plugin provides a set of call-back methods triggered by the WorkflowKernel. The WorkflowKernel also provides a plugin with detailed informations about the running process instance. This makes it easy to implement certain details of a business process.

Business logic and business rules

Plugins can be used in various situations. They are triggered through the WorkflowKernel and are provided with informations about the process activity as also the workitem processed by the workflow engine.

This means that a plugin typically provides business logic by implementing a business rule. A plugin can analyze and validate the structure of a process instance and may also manipulate the data. Through the information provided by the WorkflowKernel a plugin can determine the context of a process step. A plugin can also navigate through the workflow model to evaluate details about the full business process.

Transaction and Two-Phase Commit

The Imixs Plugin API provides three call-back methods to be implemented by a plugin.

  • init()
  • run()
  • close()

The workflowKernel calls these methods of all all registered plugins in a single transaction. A plugin can terminate this transaction by providing the WorkflowKernel with a specific error code. The WorkflowKernel will finish the transaction in an ordered procedure informing each plugin about the termination. On the other hand the WorkflowKernel will inform each plugin about a successful transaction to finalize its execution.

In the concept of a two-phase commit (2PC) the WorkflowKernel assumes the role of the central coordinator. Before the WorkflowKernel starts the transaction the init() method of each plugin will be called to initialize the transaction. Next the WorkflowKernel executes the two phases that are mapped through CallBack methods "run()" and "close()":

matching phase

During execution of the run() method (matching phase), the WorkflowKernel requests all plugins to check and prepare their actions. A plugin must finish the run() method with the status PLUGIN_OK signaling the WorkflowKernel that execution is possible. If the plugin returns the status PLUGIN_ERROR, the plugin indicates that the action cannot be executed without errors. In this way, the WorkflowKernel gets all votes from the plugins and decides how the transaction should be completed. If there was at least one error, the entire transaction will be undone. Otherwise, the WorkflowKernel decides that the transaction can be executed successfully.

commit phase

During execution of the close() method (commit phase), the WorkflowKernel informs the plugins about its decision. Each plugin must then ensure that the action results in a commit and is actually completed, or execute a rollback if a PLUGIN_ERROR occurs.

The following example shows the general structure of a Imixs Workflow Plugin:

public class MyPlugin implements Plugin {
        WorkflowContext workflowContext;

        public void init(WorkflowContext actx) throws Exception {
                workflowContext = actx;
        }

        public int run(ItemCollection workitem, ItemCollection activity) throws Exception {
                try {
                        // you business logic goes here....
                } catch (Exception e) {
                        // signal exception....
                        return Plugin.PLUGIN_ERROR;
                }
                // signal success 
                return Plugin.PLUGIN_OK;
        }

        public void close(int status) throws Exception {
                try {
                        // restore changes?
                        if (status == Plugin.PLUGIN_ERROR) {
                                // role back....
                        }
                        if (status == Plugin.PLUGIN_OK) {
                                // commit changes....
                        }
                } catch (Exception e) {
                         
                }
                finally {
                        // close resources 
                }
        }
}

How to access the workflow model

Each plugin is provided with an instance of the WorkflowContext during the method call init(). The WorkflowContext enables a plugin to access information from the workflow model through an instance of the class Model:

The following example illustrates how an instance of a model can be fetched during the initialization of a plugin:

 public void init(WorkflowContext actx) throws Exception {
   ctx=actx;
   Model model=ctx.getModel();
   // your code goes here....
 } 

The Extended Model

The ExtendedModel interface extends the Model interface with additional methods to manage different versions of the same model.

  • getProcessListByVersion
  • getActivityListByVersion
  • getEnvironmentListByVerson
  • removeModelVersion

Different model versions are typical used in log running business processes which need to take care of consistent models during the runtime of a process instance. So if the model will be improved, running processes can benefit form new behavior. The ExtendedModel is provided also by the ExtendedWorkflowContext which subclasses the Interface WorkflowContext. The following code example shows how an implementation can verify if a Model or ExtendedModel is provided by the current WorkflowManager Instance

 public void init(WorkflowContext actx) throws Exception {
    ctx=actx;
 
    if (ctx.getModel() instanceof ExtendedModel) {
       // use extended Model
       // try to get from model version
       ExtendedModel extendedModel= (ExtendedModel) ctx.getModel();
       // your code goes here
    } else {
       // use standard Model
       Model model= ctx.getModel();
       // your code goes here
    }
 }