Zwar gibt es mit den Spring-Modules bereits Support für die Verwendung von Spring zusammen mit jBPM, aber die Verwendung von Spring-Beans als Actions mit Hilfe des Delegate von Spring-Modules ist etwas umständlich:
<action name="myAction" config-type="bean"
class="org.springmodules.workflow.jbpm31.JbpmHandlerProxy">
<targetBean>jbpmAction</targetBean>
<factoryKey>jbpmConfiguration</factoryKey>
</action>
Es muss also jedesmal der ProxyHandler hingeschrieben werden und die Target-Bean konfiguriert werden, das sieht doch sehr unschön aus. Meine Vorstellung war eher eine Action-Definition wie diese:
<spring-action bean="myAction" />
Wie sich zeigt ist jBPM so flexibel, dass diese Vereinfachung mit etwas Konfiguration und einer Hilfsklasse leicht erreicht werden kann.
jBPM Action-Types
jBPM bringt von Haus aus konfigurierbare Action-Types mit. Standardmässig sind dass “action”, “script”, “create-timer” und “cancel-timer”. Diese Action-Types werden in einer XML-Datei konfiguriert. Hier fügen wir zunächst unseren neuen Action-Type “spring-action” ein:
<action-types> <action-type element="action" class="org.jbpm.graph.def.Action" /> <action-type element="create-timer" class="org.jbpm.scheduler.def.CreateTimerAction" /> <action-type element="cancel-timer" class="org.jbpm.scheduler.def.CancelTimerAction" /> <action-type element="script" class="org.jbpm.graph.action.Script" /> <action-type element="spring-action" class="rinke.solutions.jbpm.SpringActionSupport" /> </action-types>
Damit jBPM diese neue Definition von Action-Types auch verwendet, muss in der Konfiguration von jBPM die Property “resource.action.types” auf die neue Action-Types.xml verweisen:
<jbpm-configuration> .... <!-- configuration resource files custom for this config --> <string name="resource.action.types" value="action.types.xml" /> .... </jbpm-configuration>
Schließlich wird diese Datei benutzt, um jBPM zu konfigurieren. Hier verwendet man am besten gleich die FactoryBean aus den Spring-Modules, da diese auch die BeanFactory registriert (das wid später gebraucht).
<!-- jBPM configuration -->
<bean id="jbpmConfiguration"
class="org.springmodules.workflow.jbpm31.LocalJbpmConfigurationFactoryBean">
<property name="configuration" value="classpath:jbpm.cfg.xml" />
....
</bean>
Der Action-Handler
Fehlt noch der Action-Handler für die Spring-Action, der die SpringBean lokalisiert und durch delegiert. Hierzu benutzen wird den FactoryLocator aus den Spring-Modules ganz analog wie der JbpmHandlerProxy:
package rinke.solutions.jbpm;
import org.dom4j.Element;
import org.jbpm.graph.def.Action;
import org.jbpm.graph.def.ActionHandler;
import org.jbpm.graph.exe.ExecutionContext;
import org.jbpm.jpdl.xml.JpdlXmlReader;
import org.jbpm.jpdl.xml.Parsable;
import org.springframework.beans.factory.access.BeanFactoryReference;
import org.springmodules.workflow.jbpm31.JbpmFactoryLocator;
/**
* Delegates a spring-action to the referenced spring bean
*/
public class SpringActionSupport extends Action implements Parsable {
private static final long serialVersionUID = 1L;
/**
* stores the name of the spring bean to delegate to.
*/
private String beanname;
/**
* executes the action. 1st the default BeanFactory is located (with JbpmFactoryLocator).
* 2nd the bean is located and delegated to.
*/
public void execute(ExecutionContext executionContext) throws Exception {
JbpmFactoryLocator locator = new JbpmFactoryLocator();
BeanFactoryReference reference = locator.useBeanFactory(null);
ActionHandler springAction = (ActionHandler) reference.getFactory().getBean(beanname, ActionHandler.class);
springAction.execute(executionContext);
reference.release();
}
/**
* read bean name from attribute
*/
public void read(Element element, JpdlXmlReader jpdlReader) {
beanname = element.attributeValue("bean");
}
/**
* not used
*/
public void write(Element element) {
}
}
Eine Antwort auf Spring und jBPM