jBPM 3 annotations
Blog: PlanetjBPM's Weblog
Everybody using seam probably knows about the fact that Seam provides access to process instances, tasks and a (kind of) process context via annotations. But the seam process context does not always play nice with the plain jbpm context.
A few months ago, I was working on a ‘new’ JSF/Seam based jBPM web console and needed the real JbpmContext. Now everybody using jBPM knows about the basic try/finally block
public void myMethod() { // Lookup the pojo persistence context-builder that is configured above JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext(); try { // Do work on the jBPM context } finally { // Tear down the pojo persistence context. // This includes flush the SQL for inserting the process definition // to the database. jbpmContext.close(); } } }
Since I had many classes and inside that many methods where I needed the jBPM context, I decided to take a quick look at creating a custom annotation. Well, it turned out to be very simple. The result is:
@Jbpm3Method public void myMethod() { //Do work on the jBPM context }
Much cleaner isn’t it? Since I created this as a proof of concept and I am not an expert in this area, it is (most likely) not optimized and dependent on seam (tips are of course welcome to make it better and more generic). You also need a @Jbpm3 annotation on the class level and have to annotate a variable of type JbpmContext. But when you put this in a base class:
@Jbpm3 public abstract class Jbpm3AbstractBaseClass { @Jbpm3Context public JbpmContext jBPMContext; }
All you have to do is extend this base class.
For everybody who is interested, the code off all classes:
Jbpm3Interceptor.java package org.jboss.jbpm.console.interceptor; import java.io.Serializable; import java.lang.reflect.Field; import java.lang.reflect.Method; import org.jboss.seam.annotations.Logger; import org.jboss.seam.annotations.intercept.AroundInvoke; import org.jboss.seam.annotations.intercept.Interceptor; import org.jboss.seam.intercept.AbstractInterceptor; import org.jboss.seam.intercept.InvocationContext; import org.jboss.seam.log.Log; import org.jbpm.JbpmConfiguration; import org.jbpm.JbpmContext; @Interceptor public class Jbpm3Interceptor extends AbstractInterceptor implements Serializable { /** * */ private static final long serialVersionUID = 9077871878937632746L; @Logger Log log; JbpmContext jBPMContext = null; @AroundInvoke public Object aroundInvoke(InvocationContext invocationContext) throws Exception { Method method = invocationContext.getMethod(); if (method.isAnnotationPresent(Jbpm3Method.class)) { Field jBPM3Context = null; Object invocationTarget = invocationContext.getTarget(); Field[] fields = invocationTarget.getClass().getFields(); for (Field field : fields) { if (field.isAnnotationPresent(Jbpm3Context.class)) { jBPM3Context = field; JbpmContext jBPMContext = JbpmConfiguration.getInstance().createJbpmContext(); field.set(invocationTarget, jBPMContext); Object returnVal = invocationContext.proceed(); if (jBPMContext != null) jBPMContext.close(); return returnVal; } } if (jBPM3Context == null) { log.warn("Class " + invocationContext.getClass().getName() + " has Jbpm3 annotation, but no field public field has @Jbpm3Context annotation"); } } return invocationContext.proceed(); } public boolean isInterceptorEnabled() { log.debug("isInterceptorEnabled() = " + true + " for " + getComponent().getName() ); return getComponent().beanClassHasAnnotation(Jbpm3.class); } } Jbpm3.java package org.jboss.jbpm.console.interceptor; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.jboss.seam.annotations.intercept.Interceptors; @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Interceptors(Jbpm3Interceptor.class) @Documented @Inherited public @interface Jbpm3 {} Jbpm3Context.java package org.jboss.jbpm.console.interceptor; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target({ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited public @interface Jbpm3Context {} JbpmMethod.java package org.jboss.jbpm.console.interceptor; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.jboss.seam.annotations.intercept.Interceptors; /** * Opens a JbpmContext before the method is called and closes it afterwards. */ @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Interceptors(Jbpm3Interceptor.class) @Documented @Inherited public @interface Jbpm3Method {}