Red Hat Training

A Red Hat training course is available for JBoss Enterprise Application Platform Common Criteria Certification

1.4. Seam and jBPM: the todo list example

jBPM provides sophisticated functionality for workflow and task management. As an example of jBPM's integration with Seam, what follows is a simple "todo list" application. Managing task lists is a core function of jBPM, so little Java is required in this example.

1.4.1. Understanding the code

This example revolves around the jBPM process definition. It also uses two JSPs and two basic JavaBeans. (Session beans are not required here since they would not access the database or have any transactional behavior.) We will start with the process definition:

Example 1.16. todo.jpdl.xml

<process-definition name="todo">
  
  <start-state name="start">                                    1
    <transition to="todo"/>
  </start-state>
  
  <task-node name="todo">                                       2
    <task name="todo" description="#{todoList.description}">    3
      <assignment actor-id="#{actor.id}"/>                      4
    </task>
    <transition to="done"/>
  </task-node>
  
  <end-state name="done"/>                                      5
  
</process-definition>

1

The <start-state> node represents the logical start of the process. When the process starts, it immediately transitions to the todo node.

2

The <task-node> node represents a wait state, where business process execution pauses, waiting for one or more tasks to be performed.

3

The <task> element defines a task to be performed by a user. Since there is only one task defined on this node, when it is complete, execution resumes, and we transition to the end state. The task gets its description from a Seam component named todoList (one of the JavaBeans).

4

Tasks need to be assigned to a user or group of users when they are created. In this case, the task is assigned to the current user, which we get from a built-in Seam component named actor. Any Seam component may be used to perform task assignment.

5

The <end-state> node defines the logical end of the business process. When execution reaches this node, the process instance is destroyed.
Viewed with the process definition editor provided by JBossIDE, the process definition looks like this:
This document defines our business process as a graph of nodes. This is the simplest possible business process: there is one task to be performed, and when that task is complete, the business process ends.
The first JavaBean handles the login screen, login.jsp. Here, it simply initializes the jBPM actor ID with the actor component. In a real application, it would also need to authenticate the user.

Example 1.17. Login.java

@Name("login")
public class Login {
    @In
    private Actor actor;
  
    private String user;

    public String getUser() {
        return user;
    }

    public void setUser(String user) {
        this.user = user;
    }
  
    public String login() {
        actor.setId(user);
        return "/todo.jsp";
    }
}
Here we see the use of @In to inject the built-in Actor component.
The JSP itself is trivial:

Example 1.18. login.jsp

<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<html>
  <head>
    <title>Login</title>
  </head>
  <body>
    <h1>Login</h1>
    <f:view>
      <h:form>
        <div>
          <h:inputText value="#{login.user}"/>
          <h:commandButton value="Login" action="#{login.login}"/>
        </div>
      </h:form>
    </f:view>
  </body>
</html>
The second JavaBean is responsible for starting business process instances, and ending tasks.

Example 1.19. TodoList.java

@Name("todoList")
public class TodoList
{
   private String description;                       1
   
   public String getDescription()
   {
      return description;
   }

   public void setDescription(String description)
   {
      this.description = description;
   }
   
   @CreateProcess(definition="todo")                 2
   public void createTodo() {}
   
   @StartTask @EndTask                               3
   public void done() {}

}

1

The description property accepts user input from the JSP page, and exposes it to the process definition, allowing the task description to be set.

2

The Seam @CreateProcess annotation creates a new jBPM process instance for the named process definition.

3

The Seam @StartTask annotation starts work on a task. The @EndTask ends the task, and allows the business process execution to resume.
In a more realistic example, @StartTask and @EndTask would not appear on the same method, because some work would need to be done with the application in order to complete the task.
Finally, the core of the application is in todo.jsp:

Example 1.20. todo.jsp

<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@ taglib uri="http://jboss.com/products/seam/taglib" prefix="s" %>
<html>
  <head>
    <title>Todo List</title>
  </head>
  <body>
    <h1>Todo List</h1>
    <f:view>
      <h:form id="list">
        <div>
          <h:outputText value="There are no todo items." 
                        rendered="#{empty taskInstanceList}"/>
          <h:dataTable value="#{taskInstanceList}" var="task" 
                       rendered="#{not empty taskInstanceList}">
            <h:column>
              <f:facet name="header">
                <h:outputText value="Description"/>
              </f:facet>
              <h:inputText value="#{task.description}"/>
            </h:column>
            <h:column>
              <f:facet name="header">
                <h:outputText value="Created"/>
              </f:facet>
              <h:outputText value=
                            "#{task.taskMgmtInstance.processInstance.start}">
                <f:convertDateTime type="date"/>
              </h:outputText>
            </h:column>
            <h:column>
              <f:facet name="header">
                <h:outputText value="Priority"/>
              </f:facet>
              <h:inputText value="#{task.priority}" style="width: 30"/>
            </h:column>
            <h:column>
              <f:facet name="header">
                <h:outputText value="Due Date"/>
              </f:facet>
              <h:inputText value="#{task.dueDate}" style="width: 100">
                <f:convertDateTime type="date" dateStyle="short"/>
              </h:inputText>
            </h:column>
            <h:column>
              <s:button value="Done" action="#{todoList.done}" 
                        taskInstance="#{task}"/>
            </h:column>
          </h:dataTable>
        </div>
        <div>
          <h:messages/>
        </div>
        <div>
          <h:commandButton value="Update Items" action="update"/>
        </div>
      </h:form>
      <h:form id="new">
        <div>
          <h:inputText value="#{todoList.description}"/>
          <h:commandButton value="Create New Item" 
                           action="#{todoList.createTodo}"/>
        </div>
      </h:form>
    </f:view>
  </body>
</html>
For simplicity's sake, we will look at this once section at a time.
The page renders a list of tasks, which it retrieves from a built-in Seam component named taskInstanceList. The list is defined inside a JSF form.

Example 1.21. todo.jsp (taskInstanceList)

<h:form id="list">
  <div>
    <h:outputText value="There are no todo items." 
                  rendered="#{empty taskInstanceList}"/>
    <h:dataTable value="#{taskInstanceList}" var="task" 
                 rendered="#{not empty taskInstanceList}">
      ...
    </h:dataTable>
  </div>
</h:form>
Each element of the list is an instance of the jBPM class TaskInstance. The following code displays certain properties for every task in the list. Input controls are used for description, priority, and due date to allow users to update these values.

Example 1.22. TaskInstance List Properties

<h:column>
  <f:facet name="header">
    <h:outputText value="Description"/>
  </f:facet>
  <h:inputText value="#{task.description}"/>
</h:column>
<h:column>
  <f:facet name="header">
    <h:outputText value="Created"/>
  </f:facet>
  <h:outputText value="#{task.taskMgmtInstance.processInstance.start}">
    <f:convertDateTime type="date"/>
  </h:outputText>
</h:column>
<h:column>
  <f:facet name="header">
    <h:outputText value="Priority"/>
  </f:facet>
  <h:inputText value="#{task.priority}" style="width: 30"/>
</h:column>
<h:column>
  <f:facet name="header">
    <h:outputText value="Due Date"/>
  </f:facet>
  <h:inputText value="#{task.dueDate}" style="width: 100">
    <f:convertDateTime type="date" dateStyle="short"/>
  </h:inputText>
</h:column>

Note

Seam provides a default JSF date converter for converting a string into a date, so no converter is necessary for the field bound to #{task.dueDate}.
This button ends the task by calling the action method annotated @StartTask @EndTask. It passes the task ID to Seam as a request parameter:
<h:column> 
  <s:button value="Done" action="#{todoList.done}" 
            taskInstance="#{task}"/>
</h:column>
			
			
			
			

Note that this uses a Seam <s:button> JSF control from the seam-ui.jar package. This button updates the properties of the tasks. When the form is submitted, Seam and jBPM will make any changes to the tasks persistent. There is no need for any action listener method:
 <h:commandButton value="Update Items" action="update"/>
A second form on the page creates new items with the action method annotated @CreateProcess.
 <h:form id="new">
   <div> 
      <h:inputText value="#{todoList.description}"/> 
      <h:commandButton value="Create New Item" 
         action="#{todoList.createTodo}"/>
    </div> 
</h:form>