Building a Workflow Application - Part II
In this part of my tutorial I will explain how to implement the Business Logic using the Imixs IX Open Source Workflow components. If you followed the first part you have setup an environment and created the workflow model using the IX Workflow Modeler. The model file is part of the maven parent project and located in the /src folder.
Now I add a maven ejb modul to implement a session EJB using the IX JEE Workflow Implementation. This Implementation makes it very easy to implement business logic because I need not to care about JPA or a lot of the EJB stuff.
Create a EJB Maven module
As I explained in Part I maven is very useful to develop jee applications. Because Maven excuses me to worry about libaries versions and the structure of a JEE component. When you have created a Maven Parent project you can now add a new maven module to create an EJB artifact. We provide a full tutorial how to build a multi module project with maven on our project home page. But I will explain the necessary steps here.
So select you parent project and click the menu -> new -> other - > Maven module

Choose a Module name and select the option "Create a simple project. The parent Project is automatically selected.

In the next page select Packaging "jar" to advise maven to create an EJB module.
After you finish Maven creates the full ejb project structure inside your parent project and creates a pom.xml file with a default configuration. Next you need to modify the pom.xml file. So open the pom.xml file with the editor. As we don't like to spent a lot of time with developing our business logic we add the IX JEE Components as dependencies to the pom file. Also two Maven plugins are to be defined here so advice maven to build a EJB artifact. So I just have to add the following plugins and dependencies to my pom.xml:
<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/maven-v4_0_0.xsd">
<parent>
<artifactId>org.imixs.callcenter</artifactId>
<groupId>org.imixs</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.imixs.examples</groupId>
<artifactId>org.imixs.callcenter.ejb</artifactId>
<name>org.imixs.callcenter.ejb</name>
<version>0.0.1-SNAPSHOT</version>
<description/>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-ejb-plugin</artifactId>
<configuration>
<ejbVersion>3.0</ejbVersion>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>javaee</groupId>
<artifactId>javaee-api</artifactId>
<version>5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>org.imixs.workflow.jee.api</artifactId>
<version>1.5.7</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>org.imixs.workflow.api</artifactId>
<version>1.5.3</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>org.imixs.workflow.manik.model</artifactId>
<version>0.0.2</version>
</dependency>
</dependencies>
</project>
These build and dependency tags define the module as EJB 3.0 artifact and include the IX JEE Workflow Components.
Define a Interface
In the next step I define a Business Interface. The business interface is the part I use later in my web frontend to communicate with my backend. Therefor I add a package in the /src/main/java folder of my EJB Modul and define a simple POJO Interface like this:
package org.imixs.callcenter.business;
import java.util.List;
import org.imixs.workflow.ItemCollection;
public interface TicketService {
public ItemCollection createTicket();
public ItemCollection processTicket(ItemCollection aIssue,int activityID) throws Exception;
public List<ItemCollection> findWorkList(String project, int row, int count) ;
}
The ItemCollection Class is a generic dataobject which is defined by the IX Workflow API. If this class could not be resolved by Eclipse just try to install the new modul so maven can download the necessary parts from the internet. Select your EJB Modul Project and select the command : Run as...->maven install
You should receive a success message in the console file:

If maven was unable to download the Imixs IX Workflow artifacts check your settings.xml file for the following repository location:
<repository>
<id>maven2-repository.dev.java.net</id>
<name>Java.net Repository for Maven</name>
<url>http://download.java.net/maven/2</url>
<layout>default</layout>
</repository>
The settings.xml file is located in you home directory ("document and settings/USER/.m2" on windows, home/USER/.m2/ on linux)
In some cases it can happen that Eclipse bring up a lot of compile errors. This happens if Eclipse and maven is not configured correctly. If the "run as->maven install" command is successfully you can be sure your project will be deployable. To fix Eclipse error messages please see the Maven Homepage for help. The maven integration in Eclipse Ganymede is much better as in Eclipse Europe. Also Sun NetBeans IDE have a very good Maven integration. So don't give up hope and don't stopp here if you get a compile error in eclipse ;-)
Implement the Interface
Next I need to implement my business interface. This is not so much code as you may think. The Imixs IX JEE Workflow encapsulates a lot of the workflow stuff and you can access a lot of powerful methods of the IX Workflow Manager.
First I implement the createTicket method. This method returns a new Ticket represented by an ItemCollection with some predefined attributes. These attributes I will later use in my Web frontend to be displayed as input fields. So I have to predefine these attributes here.
public ItemCollection createTicket() throws Exception {
ItemCollection itemCol=new ItemCollection();
itemCol.replaceItemValue("type","workitem");
itemCol.replaceItemValue("subject","");
itemCol.replaceItemValue("team","");
Calendar cal = Calendar.getInstance();
itemCol.replaceItemValue("deadline", cal.getTime());
return itemCol;
}
The processTicket method is also very simple. This method uses the IX WorkflowManager to process a ticket. The workflow Manager took all the work of processing a workitem as defined in the workflow model. So this is the powerfull part of the application. You need to add a WorkflowManager Instance in your code using dependency injection:
@EJB
org.imixs.workflow.jee.ejb.WorkflowManager wm;
ItemCollection workItem = null;
........
public ItemCollection processTicket(ItemCollection issue, int activityID)
throws Exception {
int iProcessID = issue.getItemValueInteger("$processID");
String sUniversalID = issue.getItemValueString("$uniqueid");
workItem = null;
// check if a t has been created yet?
if (!"".equals(sUniversalID))
workItem = wm.getWorkItem(sUniversalID);
// create new TeamEntity?
if (workItem == null)
workItem = wm.createWorkItem(iProcessID);
updateWorkItem(issue);
// Process workitem...
ItemCollection result = wm.processWorkItem(workItem, activityID);
return result;
}
As you can see the method is very simple. I first check if a ticket (workitem) with the same $uniqueid was created before. If so I lookup the existing ticket otherwise I create a new workitem. I overhand the workitem to the workflowmanger to process the workitem with a defined workflow activity (activityID). The workflow manager will return a new workitem instance with updated workflow informations.
The updateWorkItem method is a typical helper method to overhand the attributes from your webfrontend to the EJB as you can not use a object reference.
private void updateWorkItem(ItemCollection aworkitem) throws Exception {
Iterator iter = aworkitem.getAllItems().entrySet().iterator();
while (iter.hasNext()) {
Map.Entry mapEntry = (Map.Entry) iter.next();
String sName = mapEntry.getKey().toString();
Object o = mapEntry.getValue();
workItem.replaceItemValue(sName, o);
}
}
Finally I need to implement the findWorkList method. This method should return a list of tickets to be processed by the current user. Therefor I make use of the EntiyService EJB from the IX JEE Workflow to access tickes using the EQL standard. Also I make use of a SessionConext to get the current username for which I should return the worklist.
@Resource
SessionContext ctx;
@EJB
org.imixs.workflow.jee.ejb.EntityService entityService;
........
public List<ItemCollection> findWorkList(int row, int count) {
ArrayList<ItemCollection> workList = new ArrayList<ItemCollection>();
String name = ctx.getCallerPrincipal().getName();
String sQuery = "SELECT wi from Entity as wi JOIN wi.authorItems as t1"
+ " JOIN wi.textItems as t2 "
+ " where t1.itemName = 'namworkflowwriteaccess' and t1.itemValue = '"
+ name + "'"
+ " and t2.itemName = 'type' and t2.itemValue = 'workitem'"
+ " order by wi.created desc";
Collection<ItemCollection> col = entityService.findAllEntities(sQuery,
row, count);
for (ItemCollection aworkitem : col) {
workList.add(aworkitem);
}
return workList;
}
So thats all! You see you need not to handle with JPA or EJB patterns. Using the IX JEE Workflow makes it easy to implement a workflow component.
Deployment Descriptors
Now I need to create the deployment descriptors so my EJB module can be deployed correctly in the glassfish server.
The Descriptors are located in the maven ejb module in /src/main/resources
The first descriptor is the ejb-jar.xml which is the standard deployment descriptor.
<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:ejb="http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd"
version="3.0">
<enterprise-beans>
<!-- #### Imixs IX JEE EJBs -->
<session>
<ejb-name>ModelServiceManagerImplementation</ejb-name>
<ejb-class>
org.imixs.workflow.jee.ejb.ModelServiceManagerImplementation
</ejb-class>
<session-type>Stateless</session-type>
</session>
<session>
<ejb-name>WorkflowServiceManagerImplementation</ejb-name>
<ejb-class>
org.imixs.workflow.jee.ejb.WorkflowServiceManagerImplementation
</ejb-class>
<session-type>Stateless</session-type>
</session>
<session>
<ejb-name>ModelManagerImplementation</ejb-name>
<ejb-class>
org.imixs.workflow.jee.ejb.ModelManagerImplementation
</ejb-class>
<session-type>Stateless</session-type>
</session>
<session>
<ejb-name>WorkflowManagerImplementation</ejb-name>
<ejb-class>
org.imixs.workflow.jee.ejb.WorkflowManagerImplementation
</ejb-class>
<session-type>Stateless</session-type>
</session>
<session>
<ejb-name>EntityPersistenceManagerImplementation</ejb-name>
<ejb-class>
org.imixs.workflow.jee.ejb.EntityPersistenceManagerImplementation
</ejb-class>
<session-type>Stateless</session-type>
<env-entry>
<description>
Activate programmatic DISTINCT Function
(default=true)
</description>
<env-entry-name>PROGRAMMATIC_DISTINCT</env-entry-name>
<env-entry-type>java.lang.Boolean</env-entry-type>
<env-entry-value>true</env-entry-value>
</env-entry>
</session>
<session>
<ejb-name>EntityServiceImplementation</ejb-name>
<ejb-class>
org.imixs.workflow.jee.ejb.EntityServiceImplementation
</ejb-class>
<session-type>Stateless</session-type>
</session>
<!-- #### Project specific EJBs -->
<session>
<ejb-name>ModelServiceBean</ejb-name>
<ejb-class>
org.imixs.workflow.manik.model.ModelServiceBean
</ejb-class>
<session-type>Stateless</session-type>
</session>
<session>
<ejb-name>TicketServiceBean</ejb-name>
<ejb-class>
org.imixs.callcenter.business.TicketServiceBean
</ejb-class>
<session-type>Stateless</session-type>
</session>
</enterprise-beans>
</ejb-jar>
If you ask yourself why you need descriptors in JEE5? This is because the annotations used by the IX JEE Workflow need to be overwritten to create unique components and need also to be defined as EJBs so the JEE Server can recognize these beans. So don't be afraid about these descriptors they are not so complex.
The second descriptor is the persitence.xml. This file is to tell the server where to store my Tickets. I need to define the datapool which I created in part I. during the setup of the server envoronment:
<persistence>
<persistence-unit name="org.imixs.workflow.jee.ejb">
<jta-data-source>jdbc/imixs_db</jta-data-source>
<properties>
<property name="toplink.ddl-generation"
value="create-tables" />
</properties>
<!-- Make sure that the library version maches the library included in ear/lib -->
<jar-file>lib/org.imixs.workflow.jee.api-1.5.7.jar</jar-file>
</persistence-unit>
</persistence>
The last descriptor is the sun-ejb-jar.xml file which defines unique JNDI Names for the ejbs and also defines the webservice endpoints:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sun-ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Application Server 9.0 EJB 3.0//EN" "http://www.sun.com/software/appserver/dtds/sun-ejb-jar_3_0-0.dtd">
<sun-ejb-jar>
<enterprise-beans>
<!-- ### Imixs IX JEE EJBs ##### -->
<ejb>
<ejb-name>ModelManagerImplementation</ejb-name>
<jndi-name>
ejb/CallcenterModelManagerImplementation
</jndi-name>
</ejb>
<ejb>
<ejb-name>WorkflowManagerImplementation</ejb-name>
<jndi-name>
ejb/CallcenterWorkflowManagerImplementation
</jndi-name>
</ejb>
<ejb>
<ejb-name>EntityPersistenceManagerImplementation</ejb-name>
<jndi-name>
ejb/CallcenterEntityPersistenceManagerImplementation
</jndi-name>
</ejb>
<ejb>
<ejb-name>EntityServiceImplementation</ejb-name>
<jndi-name>
ejb/CallcenterEntityServiceImplementation
</jndi-name>
</ejb>
<!-- #### Imixs IX JEE Web Services ##### -->
<ejb>
<ejb-name>ModelServiceManagerImplementation</ejb-name>
<jndi-name>
ejb/CallcenterModelServiceManagerImplementation
</jndi-name>
<webservice-endpoint>
<!-- ModelServiceManagerImplementation WorkflowModelServicePort-->
<port-component-name>
WorkflowModelService
</port-component-name>
<endpoint-address-uri>
CallcenterWorkflowModelService
</endpoint-address-uri>
<login-config>
<auth-method>BASIC</auth-method>
<realm>wolf-wurst</realm>
</login-config>
</webservice-endpoint>
</ejb>
<ejb>
<ejb-name>WorkflowServiceManagerImplementation</ejb-name>
<jndi-name>
ejb/CallcenterWorkflowServiceManagerImplementation
</jndi-name>
<webservice-endpoint>
<!-- ModelServiceManagerImplementation WorkflowModelServicePort-->
<port-component-name>
WorkflowManagerService
</port-component-name>
<endpoint-address-uri>
CallcenterWorkflowManagerService
</endpoint-address-uri>
<login-config>
<auth-method>BASIC</auth-method>
<realm>imixsrealm</realm>
</login-config>
</webservice-endpoint>
</ejb>
<!-- #### Project specific EJBs ###-->
<ejb>
<ejb-name>ModelServiceBean</ejb-name>
<jndi-name>
ejb/CallcenterModelServiceBean
</jndi-name>
</ejb>
<ejb>
<ejb-name>CallcenterTicketServiceBean</ejb-name>
<jndi-name>
ejb/CallcenterTicketServiceBean
</jndi-name>
</ejb>
</enterprise-beans>
</sun-ejb-jar>
Finally you need to create a /wsdl folder in your META-INF directory and add the wsdl files for the webservices there. You can download these files directly from the org.imixs.workflow.jee.api-1.5.7.jar which is found in your local maven2 repository. Maven downloads this jar during the first maven Install process.
So finally I make a new "run as - maven install" to see if the build is sucessfull.
Now I have implemented successful a EJB Workflow Modul. In the next Part I will implement a web frontend and fit all together.
- Part I. - Setup and Modeling
- Part II. - Building Business Logic with EJB 3.0
- Part III. - Building a Web Frontend
Posted at 11:17AM Jul 26, 2008
Posted by: Ralph
Category: Business
Posted by Eberhard Beilharz on April 07, 2009 at 03:39 PM CEST #