<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<body link="#355491" alink="#4262a1" vlink="#355491" style="background: #e2e2e2; margin: 0; padding: 20px;">

<div>
        <table cellpadding="0" bgcolor="#FFFFFF" border="0" cellspacing="0" style="border: 1px solid #dadada; margin-bottom: 30px; width: 100%; -moz-border-radius: 6px; -webkit-border-radius: 6px;">
                <tbody>
                        <tr>

                                <td>

                                        <table border="0" cellpadding="0" cellspacing="0" bgcolor="#FFFFFF" style="border: solid 2px #ccc; background: #dadada; width: 100%; -moz-border-radius: 6px; -webkit-border-radius: 6px;">
                                                <tbody>
                                                        <tr>
                                                                <td bgcolor="#000000" valign="middle" height="58px" style="border-bottom: 1px solid #ccc; padding: 20px; -moz-border-radius-topleft: 3px; -moz-border-radius-topright: 3px; -webkit-border-top-right-radius: 5px; -webkit-border-top-left-radius: 5px;">
                                                                        <h1 style="color: #333333; font: bold 22px Arial, Helvetica, sans-serif; margin: 0; display: block !important;">
                                                                        <!-- To have a header image/logo replace the name below with your img tag -->
                                                                        <!-- Email clients will render the images when the message is read so any image -->
                                                                        <!-- must be made available on a public server, so that all recipients can load the image. -->
                                                                        <a href="http://community.jboss.org/index.jspa" style="text-decoration: none; color: #E1E1E1">JBoss Community</a></h1>
                                                                </td>

                                                        </tr>
                                                        <tr>
                                                                <td bgcolor="#FFFFFF" style="font: normal 12px Arial, Helvetica, sans-serif; color:#333333; padding: 20px;  -moz-border-radius-bottomleft: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 5px; -webkit-border-bottom-left-radius: 5px;"><h3 style="margin: 10px 0 5px; font-size: 17px; font-weight: normal;">
    SOA-P Creating Custom GUIs for jBPM
</h3>
<span style="margin-bottom: 10px;">
    modified by <a href="http://community.jboss.org/people/admin">Administrator Administrator</a> in <i>jBPM</i> - <a href="http://community.jboss.org/docs/DOC-14765">View the full document</a>
</span>
<hr style="margin: 20px 0; border: none; background-color: #dadada; height: 1px;">

<div class="jive-rendered-content"><p>jBPM is a BPM capability included with SOA Platform.&#160; At its core, it is a simple Java API wrapping Hibernate.&#160; It can be used to orchestrate ESB services, orchestrate Java actions, create user tasks, submit user tasks, and a host of other activities.</p><p style="min-height: 8pt; height: 8pt; padding: 0px;">&#160;</p><p>One common question is how users can create GUIs to interact with the jBPM processes.&#160; There are several ways to do this.&#160; Developers could utilize Seam which has built in annotations for interacting with jBPM.&#160; Developers could create a custom web application (JSP, Servlet, Spring, Struts, Seam, etc.) that uses the jBPM Java API directly.&#160; Developers could modify an existing Java client of any type to add interaction with the jBPM processes via the jBPM Java APIs.</p><p style="min-height: 8pt; height: 8pt; padding: 0px;">&#160;</p><p>In this wiki, we will see how to create a very simple web based GUI that interacts with jBPM.&#160; This GUI will be a single, simple JSP file in a WAR.&#160; The JSP file will provide the capability to:</p><p style="min-height: 8pt; height: 8pt; padding: 0px;">&#160;</p><p>1.)&#160; Create process definitions</p><p>2.)&#160; Delete process definitions</p><p>3.)&#160; Create process instances</p><p>4.)&#160; Signal process instances</p><p>5.)&#160; Show tasks for a given user</p><p>6.)&#160; Submit tasks</p><p>7.)&#160; Add new variables when submitting a task</p><p>8.)&#160; List variables associated with a process</p><p style="min-height: 8pt; height: 8pt; padding: 0px;">&#160;</p><p>If a single JSP file has all this functionality, it must be huge right?&#160; Actually, it's less than 200 total lines of code (including all the HTML, comments, and whitespace).&#160; I would not recommend writing a single JSP with everything in it (GUI, buisiness logic, control logic, etc.).&#160; I only did it this way for sake of simplicity for this example.</p><p style="min-height: 8pt; height: 8pt; padding: 0px;">&#160;</p><p><span>First, note the attached jBPMProject.war.&#160; This can be directly deployed to SOA-P 4.3 or 5.0 in the "deploy" directory of your server configuration and accessed via "</span><a class="jive-link-external-small" href="http://localhost:8080/jBPMProject" target="_blank">http://localhost:8080/jBPMProject</a><span>".</span></p><p style="min-height: 8pt; height: 8pt; padding: 0px;">&#160;</p><p>You should see a screen like this below.&#160; If you have other processes already deployed with jBPM, you will see them as well and can interact with them also.&#160; So on this screen, click "DeployDefaultProcessDefinition" to deploy an example jBPM process.</p><p style="min-height: 8pt; height: 8pt; padding: 0px;">&#160;</p><p><a href="http://community.jboss.org/servlet/JiveServlet/showImage/102-14765-3-2063/1.png"><span> http://community.jboss.org/servlet/JiveServlet/downloadImage/102-14765-3-2063/450-252/1.png </span></a></p><p style="min-height: 8pt; height: 8pt; padding: 0px;">&#160;</p><p>Now we should see the process definition deployed below.&#160; Click the "CreateInstance 101" button to create an instance of this process.</p><p style="min-height: 8pt; height: 8pt; padding: 0px;">&#160;</p><p><a href="http://community.jboss.org/servlet/JiveServlet/showImage/102-14765-3-2064/2.png"><span> http://community.jboss.org/servlet/JiveServlet/downloadImage/102-14765-3-2064/450-252/2.png </span></a></p><p style="min-height: 8pt; height: 8pt; padding: 0px;">&#160;</p><p>Now we see the instance we created and that it has 5 nodes:&#160; Start, three tasks, and End.&#160; Also note that there are currently no tasks assigned to "Aaron" as shown at the top of the screen.&#160; Now, we will click the "Signal 122" button to move this process to the "Submit Order Node".</p><p style="min-height: 8pt; height: 8pt; padding: 0px;">&#160;</p><p><a href="http://community.jboss.org/servlet/JiveServlet/showImage/102-14765-3-2065/4.png"><span> http://community.jboss.org/servlet/JiveServlet/downloadImage/102-14765-3-2065/450-293/4.png </span></a></p><p style="min-height: 8pt; height: 8pt; padding: 0px;">&#160;</p><p>Now we are in the "Submit Order Node", and we see that there is now a task for Aaron.&#160; The text box below the task is a list of comma separated properties that can be associated with the process as part of submitting the task.&#160; The JSP error handling is not very robust, so make sure you have at least one variable defined, then click the "SubmitTask 149" button to submit Aaron's task.</p><p style="min-height: 8pt; height: 8pt; padding: 0px;">&#160;</p><p><a href="http://community.jboss.org/servlet/JiveServlet/showImage/102-14765-3-2066/5.png"><span> http://community.jboss.org/servlet/JiveServlet/downloadImage/102-14765-3-2066/450-299/5.png </span></a></p><p style="min-height: 8pt; height: 8pt; padding: 0px;">&#160;</p><p>Note that the process has moved to the next task which is "Approve Order Node".&#160; Also note that there are no more tasks assigned to Aaron.&#160; So who is the "Approve Order Node" task assigned to?&#160; Well, if you click the "Aaron" dropdown, you'll see there is also a "Bob" user - so select him.</p><p style="min-height: 8pt; height: 8pt; padding: 0px;">&#160;</p><p><a href="http://community.jboss.org/servlet/JiveServlet/showImage/102-14765-3-2067/6.png"><span> http://community.jboss.org/servlet/JiveServlet/downloadImage/102-14765-3-2067/450-299/6.png </span></a></p><p style="min-height: 8pt; height: 8pt; padding: 0px;">&#160;</p><p>Sure enough, the "Approve Order Task" is assigned to Bob.&#160; You can add new variable (see Hello World below) and submit this task as well.</p><p style="min-height: 8pt; height: 8pt; padding: 0px;">&#160;</p><p><a href="http://community.jboss.org/servlet/JiveServlet/showImage/102-14765-3-2069/10.png"><span> http://community.jboss.org/servlet/JiveServlet/downloadImage/102-14765-3-2069/450-299/10.png </span></a></p><p style="min-height: 8pt; height: 8pt; padding: 0px;">&#160;</p><p>Now we are in the last node of the process, and it is also a task node assigned to Bob.&#160; Note that on the process instance, there are three variables currently associated with it - the two default ones and the new Hello World variable that we added.&#160; Now, click "SubmitTask 151" to finish the last task of this process.</p><p style="min-height: 8pt; height: 8pt; padding: 0px;">&#160;</p><p><a href="http://community.jboss.org/servlet/JiveServlet/showImage/102-14765-3-2070/11.png"><span> http://community.jboss.org/servlet/JiveServlet/downloadImage/102-14765-3-2070/450-290/11.png </span></a></p><p style="min-height: 8pt; height: 8pt; padding: 0px;">&#160;</p><p>Now we see that there are no more tasks and the process is in the end state.</p><p style="min-height: 8pt; height: 8pt; padding: 0px;">&#160;</p><p><a href="http://community.jboss.org/servlet/JiveServlet/showImage/102-14765-3-2071/12.png"><span> http://community.jboss.org/servlet/JiveServlet/downloadImage/102-14765-3-2071/450-290/12.png </span></a></p><p style="min-height: 8pt; height: 8pt; padding: 0px;">&#160;</p><p>Congratulations on using an ~200 line JSP to create process definitions, proces instances, search tasks, submit tasks, add variables, and signal processes!</p><p style="min-height: 8pt; height: 8pt; padding: 0px;">&#160;</p><p>Next we'll show the content of the JSP file that is embedded in the attached WAR.&#160; Note that the JSP has basically three sections.</p><p style="min-height: 8pt; height: 8pt; padding: 0px;">&#160;</p><p>The first section is a set of helper functions to deploy process definitions, signal processes, get user tasks, etc.&#160; These are functions that would likely be reused in any GUI - and note how simple they are.&#160; Note that the deploy process definition actually reads the process definition from an XML file also in the WAR.&#160; Alternatively, this process definition could be deployed:&#160; 1.)&#160; From JBDS, 2.)&#160; From Ant, 3.)&#160; From the jBPM admin console.</p><p style="min-height: 8pt; height: 8pt; padding: 0px;">&#160;</p><p>The second section is the controller logic that makes sure that when the user clicks something on the GUI, it does what the user wanted it to do.</p><p style="min-height: 8pt; height: 8pt; padding: 0px;">&#160;</p><p>The third section is what actually renders the GUI that we have seen above.</p><p style="min-height: 8pt; height: 8pt; padding: 0px;">&#160;</p><blockquote class="jive-quote"><p><span style="font-size: 6pt;">&lt;%@ page language="java" contentType="text/html; charset=UTF-8"<br/>&#160;&#160;&#160; pageEncoding="UTF-8" import="java.util.*,org.jbpm.graph.exe.*,org.jbpm.graph.def.*,org.jbpm.*,org.jbpm.db.*,org.jbpm.taskmgmt.exe.*"%&gt;<br/>&lt;%!<br/><br/>//////////////////////////////////////////////////////////////////////<br/>//<br/>// Section 1:&#160; Helper functions<br/>//<br/>//////////////////////////////////////////////////////////////////////<br/><br/>public void deployDefaultProcessDefinition(JbpmContext context) {<br/>&#160;&#160;&#160;&#160; <br/>&#160;&#160;&#160; //You probably would never deploy processes this way, instead would deploy them from JBoss<br/>&#160;&#160;&#160; //Developer Studio or Ant.&#160; However, this mechanism allows this JSP to create <br/>&#160;&#160;&#160; //process definitions if none have been deployed.<br/>&#160;&#160;&#160; context.deployProcessDefinition(ProcessDefinition.parseXmlInputStream(<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; this.getClass().getResourceAsStream("/processDefinition.xml")));<br/>}<br/><br/>public static List&lt;ProcessDefinition&gt; GetProcessDefinitions(JbpmContext context) {<br/>&#160;&#160;&#160; GraphSession session = context.getGraphSession();<br/>&#160;&#160;&#160; return session.findAllProcessDefinitions();<br/>}<br/><br/>public static void DeleteProcessDefinition(JbpmContext context, long definitionId) {<br/>&#160;&#160;&#160; GraphSession session = context.getGraphSession();<br/>&#160;&#160;&#160; session.deleteProcessDefinition(definitionId);<br/>}<br/><br/>public static List&lt;ProcessInstance&gt; GetProcessInstances(JbpmContext context, long definitionId) {<br/>&#160;&#160;&#160; GraphSession session = context.getGraphSession();<br/>&#160;&#160;&#160; return session.findProcessInstances(definitionId);<br/>}<br/><br/>public static void CreateProcessInstance(JbpmContext context, long definitionId) {<br/>&#160;&#160;&#160; GraphSession session = context.getGraphSession();<br/>&#160;&#160;&#160; ProcessInstance process = session.getProcessDefinition(definitionId).createProcessInstance();<br/>&#160;&#160;&#160; context.save(process);<br/>}<br/><br/>public static void DeleteProcessInstance(JbpmContext context, long instanceId) {<br/>&#160;&#160;&#160; GraphSession session = context.getGraphSession();<br/>&#160;&#160;&#160; session.deleteProcessInstance(instanceId);<br/>}<br/><br/>public static List&lt;TaskInstance&gt; GetUserTasks(JbpmContext context, String user) {<br/>&#160;&#160;&#160; return (List&lt;TaskInstance&gt;)context.getTaskList(user);<br/>}<br/><br/>public static void SubmitTask(JbpmContext context, long taskId, String properties) {<br/>&#160;&#160;&#160; Map&lt;String,String&gt; propMap = new TreeMap&lt;String,String&gt;();<br/>&#160;&#160;&#160; String[] propArray = properties.split(",");<br/>&#160;&#160;&#160; for(String prop : propArray) {<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; String[] propPieces = prop.split("=");<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; propMap.put(propPieces[0].trim(), propPieces[1].trim());<br/>&#160;&#160;&#160; }<br/>&#160;&#160;&#160; <br/>&#160;&#160;&#160; TaskInstance task = context.getTaskInstance(taskId);<br/>&#160;&#160;&#160; task.start();<br/>&#160;&#160;&#160; task.addVariables(propMap);&#160;&#160;&#160; <br/>&#160;&#160;&#160; task.end();<br/>}<br/><br/>public static void SignalToken(JbpmContext context, long tokenId) {<br/>&#160;&#160;&#160; Token token = context.getTokenForUpdate(tokenId);<br/>&#160;&#160;&#160; token.signal();<br/>}<br/>public static void MoveToken(JbpmContext context, long tokenId) {<br/>&#160;&#160;&#160; Token token = context.getTokenForUpdate(tokenId);<br/>&#160;&#160;&#160; //Should call signal, but can't do this because some processes <br/>&#160;&#160;&#160; //require real data to be there...<br/>&#160;&#160;&#160; //token.signal();<br/><br/>&#160;&#160;&#160; //Instead, we'll find all the nodes and move to the next or end the process.<br/>&#160;&#160;&#160; //This is not reality, but for demonstration<br/>&#160;&#160;&#160; Node currentNode = token.getNode();<br/>&#160;&#160;&#160; ProcessInstance processInstance = token.getProcessInstance();<br/>&#160;&#160;&#160; List&lt;Node&gt; nodes = processInstance.getProcessDefinition().getNodes();<br/>&#160;&#160;&#160; for(int i=0; i&lt;nodes.size(); i++) {<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; <br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; //If we found the current node and there are more available...<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; if(nodes.get(i).getId() == currentNode.getId() &amp;&amp; (i+1) &lt; nodes.size()) {<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; token.setNode(nodes.get(i+1));<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; continue;<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; }<br/>&#160;&#160;&#160; }<br/>}<br/>%&gt;<br/>&lt;%<br/><br/>//////////////////////////////////////////////////////////////////////<br/>//<br/>// Section 2:&#160; Controller logic<br/>//<br/>//////////////////////////////////////////////////////////////////////<br/><br/>JbpmContext context = JbpmConfiguration.getInstance().createJbpmContext();<br/>String action = request.getParameter("action");<br/>if(action != null) {<br/>&#160;&#160;&#160; if(action.startsWith("CreateInstance")) {<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; long definitionId = Long.parseLong(action.split(" ")[1]);<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; CreateProcessInstance(context, definitionId);<br/>&#160;&#160;&#160; }<br/>&#160;&#160;&#160; else if(action.startsWith("DeleteInstance")) {<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; long definitionId = Long.parseLong(action.split(" ")[1]);<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; DeleteProcessInstance(context, definitionId);<br/>&#160;&#160;&#160; }<br/>&#160;&#160;&#160; else if(action.startsWith("Signal")) {<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; long definitionId = Long.parseLong(action.split(" ")[1]);<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; SignalToken(context, definitionId);<br/>&#160;&#160;&#160; }<br/>&#160;&#160;&#160; else if(action.startsWith("Move")) {<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; long definitionId = Long.parseLong(action.split(" ")[1]);<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; MoveToken(context, definitionId);<br/>&#160;&#160;&#160; }<br/>&#160;&#160;&#160; else if(action.startsWith("DeleteDefinition")) {<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; long definitionId = Long.parseLong(action.split(" ")[1]);<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; DeleteProcessDefinition(context, definitionId);<br/>&#160;&#160;&#160; }<br/>&#160;&#160;&#160; else if(action.startsWith("DeployDefaultProcessDefinition")) {<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; deployDefaultProcessDefinition(context);<br/>&#160;&#160;&#160; }<br/>&#160;&#160;&#160; else if(action.startsWith("SubmitTask")) {<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; SubmitTask(context, Long.parseLong(action.split(" ")[1]), request.getParameter("properties"));<br/>&#160;&#160;&#160; }<br/>}<br/><br/>//////////////////////////////////////////////////////////////////////<br/>//<br/>// Section 3:&#160; Rendering the GUI<br/>//<br/>//////////////////////////////////////////////////////////////////////<br/><br/>%&gt;<br/>&lt;html&gt;<br/>&lt;body&gt;<br/>&lt;form method="POST"&gt;<br/>&lt;table border="1" cellpadding="5" cellspacing="1"&gt; <br/>&lt;tr bgcolor="#aaaaff"&gt;&lt;td&gt;Tasks for user <br/>&#160;&#160; &lt;select name="username" onchange="form.submit()"&gt;<br/>&#160;&#160;&#160;&#160;&#160; &lt;option value="Aaron" &lt;%=("Aaron".equals(request.getParameter("username"))?"SELECTED=\"SELECTED\"":"")%&gt;&gt;Aaron&lt;/option&gt;<br/>&#160;&#160;&#160;&#160;&#160; &lt;option value="Bob" &lt;%=("Bob".equals(request.getParameter("username"))?"SELECTED=\"SELECTED\"":"")%&gt;&gt;Bob&lt;/option&gt;<br/>&#160;&#160; &lt;/select&gt; <br/>&#160;&#160; &lt;input type="submit" value="Refresh"/&gt;&lt;/td&gt;&lt;/tr&gt;<br/><br/>&lt;%<br/>for(TaskInstance task : GetUserTasks(context, request.getParameter("username"))) {<br/>%&gt;<br/>&lt;tr bgcolor="#eeeeff"&gt;&lt;td&gt;Task: &lt;%=task.getName()%&gt; <br/>&lt;input type="submit" name="action" value="SubmitTask &lt;%=task.getId()%&gt;"/&gt;<br/>Add Properties to Process: &lt;input type="text" name="properties" value="key1=val1, key2=val2"/&gt;<br/>&lt;/td&gt;&lt;/tr&gt;<br/>&lt;% } %&gt;<br/><br/>&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;<br/>&lt;tr bgcolor="#0000ff"&gt;&lt;td align="center"&gt;<br/>&lt;input type="submit" name="action" value="DeployDefaultProcessDefinition"/&gt;<br/>&lt;/td&gt;&lt;/tr&gt;<br/>&lt;% <br/>List&lt;ProcessDefinition&gt; processDefinitions = GetProcessDefinitions(context);<br/><br/>for(ProcessDefinition definition : processDefinitions) {<br/>&#160;&#160;&#160; out.println("&lt;tr bgcolor=\"#aaaaff\"&gt;&lt;td nowrap&gt;&lt;b&gt;&lt;font size=\"+1\"&gt;");<br/>&#160;&#160;&#160; out.println(definition.getName());<br/>&#160;&#160;&#160; out.println("(version " + definition.getVersion() + ")&lt;/font&gt;&lt;/b&gt;");<br/>&#160;&#160;&#160; out.println("&lt;input type=\"submit\" name=\"action\" value=\"CreateInstance " + definition.getId() + "\"/&gt;");<br/>&#160;&#160;&#160; out.println("&lt;input type=\"submit\" name=\"action\" value=\"DeleteDefinition " + definition.getId() + "\"/&gt;");<br/>&#160;&#160;&#160; out.println("&lt;/td&gt;&lt;/tr&gt;");<br/>&#160;&#160;&#160; <br/>&#160;&#160;&#160; for(ProcessInstance instance : GetProcessInstances(context, definition.getId())) {<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; out.println("&lt;tr bgcolor=\"#eeeeff\"&gt;&lt;td&gt;");<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; out.println("&#160; Instance #" + instance.getId() + " &lt;input type=\"submit\" name=\"action\" value=\"DeleteInstance " + instance.getId() + "\"/&gt;");<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; Map&lt;?,?&gt; variables = instance.getContextInstance().getVariables();<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; if(variables != null &amp;&amp; variables.entrySet() != null) {<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; for(Map.Entry&lt;?,?&gt; e : variables.entrySet()) {<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; out.println(e.getKey() +" = " + e.getValue());<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; }} else {<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; out.println("No variables");<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; }<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; List&lt;Node&gt; nodes = instance.getProcessDefinition().getNodes();<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; <br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; Token token = (Token)instance.findAllTokens().get(0);<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; Node currentNode = token.getNode();<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; for(Node node : nodes) {<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; out.println("&lt;br&gt;&#160;&#160;&#160; Node: " + node.getName());<br/><br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if(node.getId()&#160; == currentNode.getId()) {<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; out.println("&lt;font color=\"red\"&gt; - (active)&lt;/font&gt;");<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; //If not the last node<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if(node.getId() != nodes.get(nodes.size()-1).getId()) {<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; out.println(" &lt;input type=\"submit\" name=\"action\" value=\"Signal " + token.getId() + "\"/&gt;");<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; out.println(" &lt;input type=\"submit\" name=\"action\" value=\"Move " + token.getId() + "\"/&gt;");<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; }<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; out.println("&lt;/td&gt;&lt;/tr&gt;");<br/>&#160;&#160;&#160; }<br/>}<br/><br/>context.close();<br/>%&gt;<br/>&lt;/table&gt;<br/>&lt;/form&gt;<br/>&lt;/body&gt; <br/>&lt;/html&gt;</span></p></blockquote><p style="min-height: 8pt; height: 8pt; padding: 0px;">&#160;</p><p>Note that the template for almost everything done with jBPM looks like this:</p><blockquote class="jive-quote"><span style="font-size: 8pt;">JbpmContext context = JbpmConfiguration.getInstance().createJbpmContext();<br/></span><span style="font-size: 8pt;">GraphSession session = context.getGraphSession();<br/><br/>//Get process defintion, processes, tasks, signal, submit, etc.<br/></span><span style="font-size: 8pt;"><br/>context.close();</span></blockquote><p style="min-height: 8pt; height: 8pt; padding: 0px;">&#160;</p><p>I hope this has been helpful in showing how you can utilize the jBPM APIs to very easily interact with jBPM processes.&#160; If you are using JBoss Seam or ESB in the SOA Platform, there is other integration that is out of the box.&#160; But anytime you want to interact directly with jBPM via the APIs to create task inboxes, integrate with existing GUIs, or anything like that, it should be as simple as a few lines of code.</p></div>

<div style="background-color: #f4f4f4; padding: 10px; margin-top: 20px;">
    <p style="margin: 0;">Comment by <a href="http://community.jboss.org/docs/DOC-14765">going to Community</a></p>

        <p style="margin: 0;">Create a new document in jBPM at <a href="http://community.jboss.org/choose-container!input.jspa?contentType=102&containerType=14&container=2034">Community</a></p>
</div></td>
                        </tr>
                    </tbody>
                </table>


                </td>
            </tr>
        </tbody>
    </table>

</div>

</body>
</html>