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