5 Replies Latest reply on Oct 24, 2012 9:39 AM by Calvin Chu

    Async service task questions

    Calvin Chu Newbie

      I am playing around jBPM 5.3.0.Final in pass weeks, I am working on a simple demo that jBPM to start an external ETL process by JMS. When the external process are done, a JMS message is sent back to the server to feedback the result and finish the process in jBPM. I am using jBPM-console to start the process.


      I have developed my WorkItemHandler to send the JMS message, and I didn't call the workItemMgr.completeWorkItem(workItem.getId(), map) ; in my executeWorkItem() method. I am expecting this would keep the process in wait state and the process would be completed by a MDB listening the response JMS message from external process.


      The problem I have now is I am not able to restore the session in my MDB to complete the process. From other threads I get the idea to call JPAKnowledgeService.loadStatefulKnowledgeSession() with the session id  and then complete the work item by ksession.getWorkItemManager().completeWorkItem(). However, from my WorkItemHandler executeWorkItem(WorkItem workItem, WorkItemManager workItemMgr) I am not able to get the session Id, also, I registered my handler through jBPM-console, it seems like that I am not able to pass the session id from the constructor as well.


      So can some experts give me some advise on how to get the session id and how to complete the jBPM task in my MDB ? And what is the best way to have external process to acknowledge jBPM for task completion ? Thanks!

        • 1. Re: Async service task questions
          Maciej Swiderski Master

          If you don't have any state kept in the session (facts or timers) you can use any session to complete your process. That means in your MDB instead of loading same session you could create new session and complete your process with it. Please keep in mind that loading same session in two different threads can cause optimitic locking errors when both threads will make changes to it.



          • 2. Re: Async service task questions
            Calvin Chu Newbie

            I have finally make it working by putting my MDB in the jbpm-gwt-console-server-5.3.0.Final.war (I am using JBoss AS 7.1.1) and successfully share the StatefulKnowledgeSessionUtil in jbpm-gwt-core.jar to create the session and complete the service task.

            • 3. Re: Async service task questions
              Mauricio Salatino Master

              Cool, can you write a blog post or a wiki page about your changes?


              • 4. Re: Async service task questions
                Cyrine Bjaoui Newbie

                Hi Calvin,


                Please, can you tell us about your changes and how you did it, on a small tutorial. It will be great and helpfull.


                Thanks a lot!

                • 5. Re: Async service task questions
                  Calvin Chu Newbie

                  Here's my quick and dirty changes for my demo.


                  First, I implement a WorkItemHandler to send JMS message to a request queue,

                  public class JmsRequestWorkItemHandler implements WorkItemHandler {
                  public void executeWorkItem(WorkItem workItem, WorkItemManager workItemMgr) {
                            MessageProducer producer ;
                  //Some initialization of your JMS MessageProducer
                              MapMessage mapMsg = session.createMapMessage() ;
                              // Put the task ID in JMS message
                              mapMsg.setString("taskid",String.valueOf(workItem.getId())) ;
                              // Send the JMS message to queue
                             //DON'T complete the workitem here
                             //workItemMgr.completeWorkItem(workItem.getId(), map) ;


                  Then register the handler in src/main/resources/META-INF/CustomWorkItemHandlers.conf of the jpm-gwt-console-server project,

                    "Log": new org.jbpm.process.instance.impl.demo.SystemOutWorkItemHandler(),
                      "JmsRequest": new my.process.workitem.jms.JmsRequestWorkItemHandler(),


                  And then create a MDB in the jpm-gwt-console-server project,

                  @MessageDriven(name = "ExternalResponseMDB", activationConfig = {
                          @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
                          @ActivationConfigProperty(propertyName = "destination", propertyValue = "queue/response"),
                          @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge") })
                  public class ExternalResponseMDB implements MessageListener {
                      private final static Logger log = Logger.getLogger(ExternalResponseMDB.class.getName());
                      public void onMessage(Message rcvMessage) {
                          MapMessage msg = null;
                          log.info("Message received by ExternalResponseMDB") ;
                              if (rcvMessage instanceof MapMessage) {
                                  msg = (MapMessage) rcvMessage;
                                  // retrieve sessionId from message
                                 String id = msg.getString("taskid") ;                
                                  if (id != null && id.length()>0) {
                                      try {
                                           // Get knowledge session by StatefulKnowledgeSessionUtil which provided in jbpm-gwt-core-5.3.0.Final.jar
                                           // As your MDB is deployed within the jbpm-gwt-console-server.war, gwt-core jar already in lib
                                          StatefulKnowledgeSession session = StatefulKnowledgeSessionUtil.getStatefulKnowledgeSession() ;
                                          // With the session, you can complete the work item here
                                          session.getWorkItemManager().completeWorkItem(Long.parseLong(id), null) ;
                                      } catch (Throwable t) {
                                          log.severe("completeWorkItem:"+t.getMessage()) ;
                              } else {
                                  log.warning("Message of wrong type: "
                                          + rcvMessage.getClass().getName());


                  Maven clean install your jpm-gwt-console-server project and deploy it. Then you can use the JmsRequest service task in your workflow to send request to external application. The external application should keep the "taskid" and reply back to the response queue such that the MDB can complete the process. Please be noted that the StatefulKnowledgeSessionUtil would try to find and reuse a serialized session ID, not sure if there are any issue if the session created by jbpm-console and MDB shares the same session ID.


                  As I mention above, it is my quick and dirty approach. I think a more appropiate way to do this is to wait for a signal and let the JmsRequestWorkItemHandler to complete the work item, when response received the MDB then signal the workflow to continue. i.e. calling session.signalEvent(arg0, arg1) in MDB instead of session.getWorkItemManager().completeWorkItem(arg0, arg1)


                  Like this, unfortunately I don't have any working sample yet.