Eric D. Schabell: December 2009

Thursday, December 31, 2009

2009 in review


It is that time of year, when Christmas has passed (did you get the things you wished for?) and the New Year is upon us. A time for reflection and appreciating the things we have achieved.

As I look back I tried to come up with a picture to put in this post that would reflect the leading theme in my year. It should come as no surprise, if you have been following my blog at all, that JBoss jBPM logo is the image that has guided my year!

I started 2009 still working at the SNS Bank, leading and implementing jBPM projects to put financial products on-line for her customers. I published many of these experiences and tried to lift the lid as much as one can from inside of a financial institution, even managing to post some code to this blog. Here is a bit of a review:
All of this got the attention of Red Hat and I decided to join the team in May as a JBoss Solution Architect Benelux. It has been amazing to work inside the JBoss house, seeing the latest and greatest software rolling off the development blocks.

I was able to make some rather small contributions to some open source projects, with some translations for meebo.com, a small fix in jBPM 4.2 (can you find it?) which made the jBPM 4.3 release just before the end of 2009 and another patch is still waiting for evaluation in the jBPM 4.4 release.

On the cycling front, I picked up a new road bike, at the end of the year a winter mountain bike and made some great rides this year in several countries:
 The only sad item I have to mention was the trading in of my beloved 1987 Austin Mini, the end of an era for me with regards to Mini's.

Being healthy and happy, I wish you and yours all the best in 2010!

Wednesday, December 30, 2009

jBPM 4.3 released

The latest release posted on sourceforge includes my patch for a very small fix (but it is my first in the jBPM project!) listed here as shown in the release notes readme.html file included in the download:

Patch

  • [JBPM-2520] - The install build.xml is not reporting the new Signavio installtion target (patch attached)
 A nice way to end 2009! ;-)

Monday, December 21, 2009

Book review: jBPM Developer Guide


I have been approached about doing a review of this book, which will be appearing soon. As soon as I receive an e-copy or preview copy in the mail I will be posting my impressions in detail.

The book is available here from PACKT publishing.

Thursday, December 10, 2009

JBoss Enterprise Application Platform (EAP) deployment plans

To be honest with you, I have never heard of deployment plans before. I was aware of deployment descriptors, but not deployment plans.

A bit of searching turned up this bit of information:

Every J2EE application module must include an XML based deployment descriptor that provide configuration information for the asset as well as defining relationships to other components.

There are two types of deployments descriptors:

  • vendor neutral deployment descriptors (a.k.a deployment descriptors)
  • vendor specific deployment descriptor (a.k.a deployment plans)
Deployment descriptors are necessary but are not always sufficient to deploy an asset on your server. Deployment plans provides additional information to map declared resources names, ejb names, security roles, JMS roles (if any) to actual resources in the server. The deployment plans also contain specific server settings and configurations.

So we are looking at a vendor specific deployment descriptor file for the various application modules use. Now I was curious to those for JBoss, so dug around a bit and have come up with this overview.

Vendor neutral:
J2EE module file type Standard deployment descriptors
-------------------------------------------------------------------------------
Enterprise Application Archive (EAR) META-INF/application.xml
Web Application Archive (WAR) WEB-INF/web.xml
Jar containing Enterprise Java Beans (JAR) META-INF/ejb-jar.xml
J2EE Connector Resources Adapter Archive (RAR) META-INF/ra.xml
Enterprise Application Client Archive (JAR) META-INF/application-client.xml

JBoss specific (EAP):
J2EE module file type JBoss deployment plan
-------------------------------------------------------------------------------
Enterprise Application Archive (EAR) jboss-app.xml
Web Application Archive (WAR) jboss-web.xml
Jar containing Enterprise Java Beans (JAR) jboss.xml
J2EE Connector Resources Adapater Archive (RAR) ---
Enterprise Application Client Archive (JAR) jboss-client.xml

There you go, happy deployment planning!

Monday, December 7, 2009

A custom jBPM exception framework for jBPM 3.x

I have spent some time over the last few months (slowly, only one day a week) working on a jBPM exception handling framework. I wanted to present the use case and leave the exact details over to you as an exercise in Java coding.

The idea is that jBPM (here using 3.x supported versions from the Red Hat JBoss Customer Support Portal (CSP) provides the standard jBPM exception and that I want to also have the choice to apply a dynamically generated transition from the point of an exception that takes me to a custom exception flow. This custom exception flow is nothing more than a single decision that, based on the type of exception I have passed, will choose a path to one of the following:

  • task node (human task to evaluate the exception)
  • state node (retry using a timer to wait a bit before trying again)
  • any eventual node desired to process the exception

There are some fairly obvious benefits:

  • no longer just one handling for all your jBPM process exceptions
  • very extensible, just add new nodes into the exception handling process flow to provide new functionality
  • placing exception handling into an apart flow means you can deploy this once and use it with all of your deployed processes
  • provides for decisions, states and node exception handling. Transitions should not be doing anything exciting within my processes, if yours needs to you can extend this concept to these too.

The process flow diagram provided in this post shows the simple testing framework I used to enable this. All code snippets shown are simplified for this post. There is a global attribute that is checked for using our custom exception framework called 'useCustomExceptions'.

Decisions

For a decision node we need to implement the DecisionHandler from jBPM, so I do that in an AbstractDecisionHanlder that implements the decide() method and puts in an extra handleException() method as follows:

public String decide(ExecutionContext ctx) throws Exception {

  try {
         // pick transition from the decision handler.
         transitionName = chooseTransition(ctx); 
         getLogger().debug("Choosing transition " + transitionName);
  } catch (Exception ex) {
         if (useCustomExceptions) {
             getLogger().error("Handler threw exception.", ex);
             ctx.getNode().raiseException(ex, ctx);
         } else {
             getLogger().error("Handler threw exception.", ex);
             ctx.setException(ex);
             // use custom method to create dynamic transition.
             dynamicTransition = handleException(ctx);
         }
  }

  return transitionName;
}


// This method is provided in comment steps only, the rest
// is an exercise for you (I can not publish this code).
private String handleException(ExecutionContext ctx) {

  // Save the current node in the context to make a retry possible.
                
  // Make sure the transition to the Exception handling Node can be made.
                
  // Using handling node name for the transition name.
                
  return name_of_transition_leading_to_exception_handling;
}


Node

For a node we need to implement the ActionHandler from jBPM, so I do that in an AbstractActionHanlder that implements the execute() method. Furthermore I need to come up with a solution for the following issue that is unique to the jBPM 3.x node. When you enter a node, you have an on-node-enter event and when finished it will trigger the on-node-leave event which takes the transition that is assigned during the event on-node-enter event. This means using the Node.leave(some-transition) method will not work.

I got the reaction when I used this Node.leave(take-dynamic-transition-to-exception-handling) it worked fine until it entered the human-task wait state. At this point the originating node then continued onwards, taking the default transition (that was in the TransitionsList for the node) and merrily finishing the process flow. Even stranger, this was done on the same process id that was also assigned to some human task!

My solution is to provide a mechanism to do the following:

  • create the dynamic transition to custom exception handling for the node
  • add the dynamic transition to the TransistionsList for this node
  • put a copy of the TransistionList (without the new dynamic transition) into the jBPM Context
  • remove all transition entries from the TransistionsList except for the new dynamic one
  • use Node.leave() to follow the new dynamic transition
  • deal with exception handling
  • upon returning to the node after exception handling, pick up the transitions from the jBPM Context
  • fill the TransitionsList with those found in the jBPM Context
  • use Node.leave() to use the default

Some code to give you an idea with migrateTransitionsInNodeToContext which shows the transitions being migrated into the jBPM Context. I have left out the recovery of the transitions from the context, as it is trivial to reverse the process. To give you a bit of a hint, when you are in the exception handling process and decide it is time to go back to your originating node, you create a dynamic transition and fill the originating nodes TransitionsList from the jBPM Context. 

Here are some code snippets:

public final void execute(ExecutionContext ctx) throws Exception {

  try {
        if (ctx.getNode() instanceof State) {
           // process a state.
        } else {
   
           try {
  
              // do something in node.
           } catch (Exception ex) {
    
              if (useCustomExceptions) {
                   getLogger().error("Handler threw exception.", ex);
                   ctx.getNode().raiseException(ex, ctx);
              } else {
                   getLogger().error("Handler threw exception.", ex);
                   transitionName = handleException(ctx);

                   migrateTransitionsInNodeToContext(ctx);

                   // Move the process along.
                   if (!StringUtils.isBlank(transitionName) &&
ctx.getNode().hasLeavingTransition(transitionName)) {
                      ctx.getNode().leave(ctx, transitionName);
                   } else {
                       // Use the default transition.
                       ctx.getNode().leave(ctx);
                   }
              }
           }
        }
  } catch (Exception ex) {
      // do something
  }
}

/**
 * Use given context to migrate all transitions in the nodes list that
 * do not match the dynamic transition created for an exception.
 */
private void migrateTransitionsInNodeToContext(ExecutionContext ctx) {
  List existingTransitionsList = ctx.getNode().getLeavingTransitionsList();
  List removedExceptionTransitionList = new ArrayList();

  int i = 0;
  for (Transition transition : existingTransitionsList) {
    i++;
    if (transition.equals(transitionName)) {
      getLogger().debug("List item #" + i 
          + " is our dynamic tranition: " 
          + transition.toString());
    } else {
       getLogger().debug("List item #" + i + " tranition: " 
               + transition.toString() + ", migrating to context.");
       removedExceptionTransitionList.add(transition);
       getLogger().debug("List item #" + i + " tranition: " 
           + transition.toString() + ", removing from node transition list.");
       ctx.getNode().removeLeavingTransition(transition);
    }
  }

  if (!existingTransitionsList.isEmpty()) {
      // place existing transitions into context variable.
      String ctxStoredTranstionsName = 
           ctx.getNode().getName() + "_stored_transitions_list";
      ctx.setVariable(ctxStoredTranstionsName, removedExceptionTransitionList);
  }
}


State

For a state we work analogue to the decision node but within the extended abstract class that implements the jBPM ActionHandler. This is left as an exercise to the reader.