Sorry for the delay - still trying to get this thing off the ground. Here's the code for the .sar that I've found very useful for deployment AND JUNIT testing...
JbpmHelperMBean excuse the formatting logging etc... its functional not pretty ;)
package jmx.service.jbpm;
import jmx.service.jndi.JNDIMBean;
import javax.naming.NamingException;
import org.apache.log4j.Logger;
import jmx.service.jms.JMSMBean;
interface JbpmHelperMBean {
public void deployProcessDefinition(String xmlString) throws Exception;
public String deployParFile(String fullQualifiedFile, String processName) throws Exception;
public void lookup(String jndiName) throws Exception;
public String createNewProcessInstance(String processName);
public String signalProcess(String processId, String transition);
public String getProcessState(String processId, String tokenStr);
public boolean processHasEnded(String processId);
}
JbpmHelper package jmx.service.jbpm;
import javax.naming.InitialContext;
import javax.jms.JMSException;
import jmx.service.jms.JMS;
import org.apache.log4j.*;
import org.jbpm.db.GraphSession;
import org.jbpm.db.JbpmSession;
import org.jbpm.db.JbpmSessionFactory;
import org.jbpm.db.JbpmSchema;
import org.jbpm.graph.def.ProcessDefinition;
import org.jbpm.graph.exe.ProcessInstance;
import org.jbpm.graph.exe.Token;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URL;
import java.util.zip.ZipInputStream;
import org.jbpm.jpdl.par.ProcessArchiveDeployer;
import javax.management.Notification;
import javax.management.MBeanRegistration;
import javax.management.NotificationListener;
public class JbpmHelper implements JbpmHelperMBean {
private static Logger LOG = Logger.getLogger(JbpmHelper.class);
static JbpmSessionFactory jbpmSessionFactory = null;
private String processDefinitionStr =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?> " +
" " +
"<process-definition " +
" name=\"payrollProcessed\"> " +
" <start-state name=\"start\"> " +
" <transition name=\"request DS work request\" to=\"create DS work request\"></transition> " +
" </start-state> " +
" <node name=\"create DS work request\"> " +
" <action class=\"jmx.service.jbpm.NIActionHandler\"></action> " +
" <transition name=\"work request created\" to=\"DS work request created\"></transition> " +
" </node> " +
" <node name=\"DS work request created\"> " +
" <transition name=\"CoreDB load succeeded\" to=\"CoreDB loaded\"></transition> " +
" <transition name=\"CoreDB loaded failed\" to=\"CoreDB load fails\"></transition> " +
" </node> " +
" <node name=\"CoreDB loaded\"> " +
" <transition name=\"register CoreDB loaded\" to=\"end1\"></transition> " +
" </node> " +
" <node name=\"CoreDB load fails\"> " +
" <transition name=\"dont retry load\" to=\"end1\"></transition> " +
" <transition name=\"retry load\" to=\"create DS work request\"></transition> " +
" </node> " +
" <end-state name=\"end1\"></end-state> " +
"</process-definition> ";
public void lookup(String jndiName) throws Exception {
LOG.debug("JbpmHelper: called lookup:" + jndiName);
InitialContext iniCtx = new InitialContext();
if (jndiName == null || jndiName.trim().length() == 0) {
jndiName = "java:/jbpm/JbpmSessionFactory";
}
LOG.debug("looking up:" + jndiName);
Object o = iniCtx.lookup(jndiName);
jbpmSessionFactory = (JbpmSessionFactory) o;
LOG.debug("got JbpmSessionFactory:" + jbpmSessionFactory);
}
public String createNewProcessInstance(String processName) {
long processId = 0;
LOG.debug("createNewProcessInstance:" + processName);
if (processName != null && processName.trim().length() > 0) {
LOG.debug("creating processInstnace");
try {
LOG.debug("about to get JbpmSessionFactory");
InitialContext iniCtx = new InitialContext();
jbpmSessionFactory = (JbpmSessionFactory) iniCtx.lookup("java:/jbpm/JbpmSessionFactory");
LOG.debug("got JbpmSessionFactory");
}
catch (Exception e) {
LOG.error("coulnd't buildJbpmSessionFactory", e);
return null;
}
try {
JbpmSession jbpmSession = jbpmSessionFactory.openJbpmSession();
LOG.debug("got a jbpmSession");
// ... and begin a transaction on the persistence session.
jbpmSession.beginTransaction();
LOG.debug("after beginTransaction");
// Now we can query the database for the process definition that we
// deployed above.
ProcessDefinition processDefinition =
jbpmSession
.getGraphSession()
.findLatestProcessDefinition(processName);
LOG.debug("got processDefinition=" + processDefinition);
ProcessInstance processInstance = new ProcessInstance(processDefinition);
LOG.debug("got processInstance=" + processInstance);
processId = processInstance.getId();
LOG.debug("processInstance id:" + processId);
LOG.debug("about to commit");
jbpmSession.commitTransaction();
LOG.debug("after commit");
// And close the jbpmSession.
jbpmSession.close();
}
catch (Exception e) {
LOG.error("createNewProcessInstance: cant createProcessInstance", e);
}
}
LOG.debug("JbpmHelper: ending createNewProcessInstance:" + processName);
return processId + "";
}
public String signalProcess(String processIdStr, String transition) {
LOG.debug("createNewProcessInstance:" + processIdStr + " transition:" + transition);
String currentState = null;
long processId = Long.parseLong(processIdStr);
if (processId > 0) {
LOG.debug("signalProcess");
try {
LOG.debug("about to get JbpmSessionFactory");
InitialContext iniCtx = new InitialContext();
jbpmSessionFactory = (JbpmSessionFactory) iniCtx.lookup("java:/jbpm/JbpmSessionFactory");
LOG.debug("got JbpmSessionFactory");
}
catch (Exception e) {
LOG.error("coulnd't buildJbpmSessionFactory", e);
return null;
}
try {
JbpmSession jbpmSession = jbpmSessionFactory.openJbpmSession();
LOG.debug("got a jbpmSession");
// ... and begin a transaction on the persistence session.
jbpmSession.beginTransaction();
LOG.debug("after beginTransaction");
// Now we can query the database for the process definition that we
// deployed above.
ProcessInstance processInstance =
jbpmSession
.getGraphSession()
.loadProcessInstance(processId);
if (processInstance == null) {
LOG.debug("unable to load processInstance with processId:" + processId);
return null;
}
LOG.debug("got processInstance=" + processInstance);
processId = processInstance.getId();
LOG.debug("processInstance id:" + processId);
Token token = processInstance.getRootToken();
LOG.debug("got token=" + token);
currentState = token.getNode().getName();
LOG.debug("current state:" + currentState);
LOG.debug("transition='" + transition + "'" + " length=" + transition.trim().length());
// Let's signal the process execution
if (transition == null || transition.trim().length() == 0) {
token.signal();
}
else {
// add error checking for existence of transition name here
token.signal(transition);
}
currentState = token.getNode().getName();
LOG.debug("current state:" + currentState);
// token.signal("work request created");
// LOG.debug("current state:" + token.getNode().getName());
// token.signal("CoreDB load succeeded");
// LOG.debug("current state:" + token.getNode().getName());
// token.signal("register CoreDB loaded");
// LOG.debug("current state:" + token.getNode().getName());
LOG.debug("about to commit");
jbpmSession.commitTransaction();
LOG.debug("after commit");
// And close the jbpmSession.
jbpmSession.close();
}
catch (Exception e) {
LOG.error("cant signalProcess", e);
}
}
LOG.debug("JbpmHelper: ending signalProcess:" + processId);
return currentState;
}
public void deployProcessDefinition(String xmlString) throws Exception {
LOG.debug("JbpmHelper: called deployProcessDefinition:" + xmlString);
if (xmlString != null && xmlString.trim().length() > 0) {
processDefinitionStr = xmlString;
}
LOG.debug("processDefinitionStr=" + processDefinitionStr);
try {
LOG.debug("about to get JbpmSessionFactory");
InitialContext iniCtx = new InitialContext();
jbpmSessionFactory = (JbpmSessionFactory) iniCtx.lookup("java:/jbpm/JbpmSessionFactory");
LOG.debug("got JbpmSessionFactory");
}
catch (Exception e) {
LOG.error("coulnd't buildJbpmSessionFactory", e);
}
try {
LOG.debug("about to getJbpmSchema().createSchema()");
JbpmSchema schema = jbpmSessionFactory.getJbpmSchema();
boolean createSchema = !schema.hasJbpmTables();
LOG.debug("need to createSchema:" + createSchema);
if (createSchema) {
LOG.debug("creating JbpmSchema");
jbpmSessionFactory.getJbpmSchema().createSchema();
}
else {
LOG.debug("JbpmSchema exists, so don't create it");
}
LOG.debug("after getJbpmSchema().createSchema()");
}
catch (Exception e) {
LOG.error("couldn't getJbpmSchema().createSchema()", e);
}
ProcessDefinition processDefinition = null;
try {
LOG.debug("about to ProcessDefinition.parseXmlString");
processDefinition = ProcessDefinition.parseXmlString(processDefinitionStr);
LOG.debug("after ProcessDefinition.parseXmlString");
}
catch (Exception e) {
LOG.error("couldn't ProcessDefinition.parseXmlString");
}
try {
LOG.debug("getting jbpmsession");
JbpmSession jbpmSession = jbpmSessionFactory.openJbpmSession();
// ... and begin a transaction on the persistence session
LOG.debug("beginning trans");
jbpmSession.beginTransaction();
// Save the process definition in the database
LOG.debug("saving process definition");
jbpmSession.getGraphSession().saveProcessDefinition(processDefinition);
// Commit the transaction
LOG.debug("commiting trans");
jbpmSession.commitTransaction();
// And close the jbpmSession.
LOG.debug("closing jbpmsession");
jbpmSession.close();
LOG.debug("done loading definition");
}
catch (Exception e) {
LOG.error("couldn't load process definition");
}
}
public String deployParFile(String fullQualifiedFile, String processName) throws Exception {
String msg = null;
long prevProcessId;
fullQualifiedFile = "file:///" + fullQualifiedFile;
LOG.debug("deploying archive " + fullQualifiedFile);
try {
LOG.debug("about to get JbpmSessionFactory");
InitialContext iniCtx = new InitialContext();
jbpmSessionFactory = (JbpmSessionFactory) iniCtx.lookup("java:/jbpm/JbpmSessionFactory");
LOG.debug("got JbpmSessionFactory");
LOG.debug("getting jbpmsession");
JbpmSession jbpmSession = jbpmSessionFactory.openJbpmSession();
ProcessDefinition processDefinition =
jbpmSession
.getGraphSession()
.findLatestProcessDefinition(processName);
prevProcessId = processDefinition.getId();
LOG.debug("previous processDefinitionId: " + prevProcessId);
LOG.debug("closing jbpmsession");
jbpmSession.close();
}
catch (Exception e) {
LOG.debug("couldnt find previous definition of process:" + processName);
prevProcessId = 0;
}
try {
URL archiveUrl = new URL(fullQualifiedFile);
ZipInputStream zis = new ZipInputStream(archiveUrl.openStream());
ProcessArchiveDeployer.deployZipInputStream(zis);
zis.close();
}
catch (Exception e) {
e.printStackTrace();
}
try {
JbpmSession jbpmSession = jbpmSessionFactory.openJbpmSession();
ProcessDefinition processDefinition =
jbpmSession
.getGraphSession()
.findLatestProcessDefinition(processName);
long newProcessId = processDefinition.getId();
if (newProcessId != prevProcessId) {
msg = "Loaded:" + fullQualifiedFile + " successfully." + "previous processDefinitionId: " + prevProcessId + " new processDefinitonid:" + newProcessId;
LOG.debug(msg);
}
else {
msg = "Unsuccessful in loading process definition:" + fullQualifiedFile;
LOG.debug(msg);
}
LOG.debug("closing jbpmsession");
jbpmSession.close();
}
catch (Exception e) {
msg = "Unsuccessful in loading process definition:" + fullQualifiedFile;
LOG.debug(msg);
}
return msg;
}
public String getProcessState(String processIdStr, String tokenStr) {
long processId = Long.parseLong(processIdStr);
if (processId > 0) {
LOG.debug("getProcessState:" + processId);
try {
LOG.debug("about to get JbpmSessionFactory");
InitialContext iniCtx = new InitialContext();
jbpmSessionFactory = (JbpmSessionFactory) iniCtx.lookup("java:/jbpm/JbpmSessionFactory");
LOG.debug("got JbpmSessionFactory");
}
catch (Exception e) {
LOG.error("coulnd't buildJbpmSessionFactory", e);
return null;
}
try {
JbpmSession jbpmSession = jbpmSessionFactory.openJbpmSession();
ProcessInstance processInstance =
jbpmSession
.getGraphSession()
.loadProcessInstance(processId);
if (processInstance == null) {
LOG.debug("unable to load processInstance with processId:" + processId);
return null;
}
if (tokenStr == null || tokenStr.trim().length() == 0 || tokenStr.equals("/")) {
Token token = processInstance.getRootToken();
return token.getNode().getName();
}
else {
Token token = processInstance.findToken(tokenStr);
return token.getNode().getName();
}
}
catch (Exception e) {
return "unable to get process:" + processId + " state.";
}
}
return null;
}
public boolean processHasEnded(String processIdStr) {
long processId = Long.parseLong(processIdStr);
ProcessInstance processInstance = null;
LOG.debug("processHasEnded:" + processId);
processInstance = getProcessInstance(processId);
if (processInstance != null) {
return processInstance.hasEnded();
}
else {
return false;
}
}
ProcessInstance getProcessInstance(long processId) {
ProcessInstance processInstance = null;
try {
LOG.debug("about to get JbpmSessionFactory");
InitialContext iniCtx = new InitialContext();
jbpmSessionFactory = (JbpmSessionFactory) iniCtx.lookup("java:/jbpm/JbpmSessionFactory");
LOG.debug("got JbpmSessionFactory");
}
catch (Exception e) {
LOG.error("coulnd't buildJbpmSessionFactory", e);
return null;
}
try {
JbpmSession jbpmSession = jbpmSessionFactory.openJbpmSession();
return processInstance =
jbpmSession
.getGraphSession()
.loadProcessInstance(processId);
}
catch (Exception e) {
LOG.error("coulnd't obtain processInstance with processId:" + processId, e);
return null;
}
}
}
jboss-service.xml <server>
<mbean code="jmx.service.jbpm.JbpmHelper" name="jmx.service.jbpm:service=JbpmHelper"
description="jBPM Helper Service"
xmbean-dd="META-INF/jbpmhelper-xmbean.xml">
<depends>jboss:service=Naming</depends>
</mbean>
</server>
jbpmhelper-xmbean.xml <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mbean PUBLIC
"-//JBoss//DTD JBOSS XMBEAN 1.0//EN"
"http://www.jboss.org/j2ee/dtd/jboss_xmbean_1_0.dtd">
<mbean>
<description>jbpm helper MBean</description>
<descriptors>
<!--
<persistence persistPolicy="Never" persistPeriod="10" persistLocation="data/DataSyncAdaptor.data" persistName="jbpm helper mbean"/>
<currencyTimeLimit value="10"/>
<state-action-on-update value="keep-running"/>
-->
</descriptors>
<class>jmx.service.jbpm.JbpmHelper</class>
<!-- Operations
<operation>
<description>The start lifecycle operation</description>
<name>start</name>
</operation>
<operation>
<description>The stop lifecycle operation</description>
<name>stop</name>
</operation>
<operation>
<description>The create lifecycle operation</description>
<name>create</name>
</operation>
<operation>
<description>The destroy lifecycle operation</description>
<name>destroy</name>
</operation>
-->
<operation impact="ACTION">
<description>Looks up jbpm session factory</description>
<name>lookup</name>
<parameter>
<description>The JNDI name of the session factory</description>
<name>jndiName</name>
<type>java.lang.String</type>
</parameter>
<return-type>void</return-type>
</operation>
<operation impact="ACTION">
<description>Creates a new process instance</description>
<name>createNewProcessInstance</name>
<parameter>
<description>The Name of the process</description>
<name>processName</name>
<type>java.lang.String</type>
</parameter>
<return-type>java.lang.String</return-type>
</operation>
<operation impact="ACTION">
<description>Deploys an archived .par file</description>
<name>deployParFile</name>
<parameter>
<description>A fully qualified file name</description>
<name>fullQualifiedFile</name>
<type>java.lang.String</type>
</parameter>
<parameter>
<description>The Name of the process</description>
<name>processName</name>
<type>java.lang.String</type>
</parameter>
<return-type>java.lang.String</return-type>
</operation>
<operation impact="ACTION">
<description>Signals a process</description>
<name>signalProcess</name>
<parameter>
<description>The process Id</description>
<name>processId</name>
<type>java.lang.String</type>
</parameter>
<parameter>
<description>The transition to take</description>
<name>transition</name>
<type>java.lang.String</type>
</parameter>
<return-type>java.lang.String</return-type>
</operation>
<operation impact="ACTION">
<description>gets the current state of a process</description>
<name>getProcessState</name>
<parameter>
<description>The process Id</description>
<name>processId</name>
<type>java.lang.String</type>
</parameter>
<parameter>
<description>The token to return the state of</description>
<name>token</name>
<type>java.lang.String</type>
</parameter>
<return-type>java.lang.String</return-type>
</operation>
<operation impact="ACTION">
<description>returns whether a process has ended</description>
<name>processHasEnded</name>
<parameter>
<description>The process Id</description>
<name>processId</name>
<type>java.lang.String</type>
</parameter>
<return-type>boolean</return-type>
</operation>
</mbean>
For those unfamilar with MBeans
Build your .sar file (named Whatever.sar) with the following structure:
\jmx\server\jbpm\JbpmHelper.class
\jmx\server\jbpm\JbpmHelperMBean.class
\meta-inf\jboss-service.xml
\meta-inf\jbpmhelper-xmbean.xml
Drop it into your \deploy directory and access it as:
http://localhost:8080/jmx-console/HtmlAdaptor?action=inspectMBean&name=jmx.service.jbpm%3Aservice%3DJbpmHelper
Call the deployParFile supplying the fully qualified name (e.g. c:\blah\foo.par) and specify the name of the process defintion (e.g. MyProcess).
That should do it. Hope this is helpful.