5 Replies Latest reply on Aug 9, 2011 6:01 AM by garytse

    Why is Timer event not triggered in J2EE container?

    garytse

      Hi all,

       

      I have a timer event that is suppose to automatically trigger after 3 minutes. 

       

      When I'm testing it on standalone Java program, the bpmn works fine and the task following the timer event gets triggered.

       

      However, the timer event just never gets triggered after I put the StatefulKnowledgeSession into a EJB on the server.

       

      This is a portion of the timer :

       

          <boundaryEvent id="_5" name="TimerEvent" attachedToRef="_4" cancelActivity="false" >
            <timerEventDefinition>
              <timeDuration xsi:type="tFormalExpression">180s</timeDuration>
            </timerEventDefinition>
          </boundaryEvent>
      

       

       

      My stateless session EJB looks like this :

      ...
      public class CommandDelegate implements SessionBean {
      
      private StatefulKnowledgeSession  stateful;
      
      public void startProcess(String processId, Map<String, Object> parameters) {
         //start bean-managed transaction
         ...
         stateful.startProcess(processId, parameters);
          ...
        //commit the bean-managed transaction
      }
      ...
      

       

       

      Here is my test client:

       

      context = new InitialContext(env);
      Object obj = context.lookup("ejb/CommandDelegateRemote");
      remoteHome = (CommandDelegateRemoteHome)PortableRemoteObject.narrow(obj,CommandDelegateRemoteHome.class);
      remote = remoteHome.create();
      ...
      remote.startProcess("TestTimerBPMN", params);
      

       

       

      Any ideas anyone?  The process starts and I'm able to see that from the audit logs (NODEINSTANCELOG, PROCESSINSTANCELOG).  However, the process cannot end because the timer doesn't get triggered.

        • 1. Re: Why is Timer event not triggered in J2EE container?
          garytse

          It seems this is the problem.  The timer kick start correctly but somehow failed to start/ commit the transaction. 

           

          If anyone has any ideas, anything I can try will be much appreciated.

           

          [WARN][JtaTransactionManager] Unable to begin transaction

          java.lang.NullPointerException

                    at com.ibm.ejs.container.EJSContainer.processTxContextChange(EJSContainer.java:2117)

                    at com.ibm.ejs.container.UserTransactionWrapper.begin(UserTransactionWrapper.java:181)

                    at org.drools.persistence.jta.JtaTransactionManager.begin(JtaTransactionManager.java:153)

                    at org.drools.persistence.SingleSessionCommandService.execute(SingleSessionCommandService.java:281)

                    at org.drools.persistence.jpa.JpaJDKTimerService$JpaJDKCallableJob.call(JpaJDKTimerService.java:75)

                    at org.drools.persistence.jpa.JpaJDKTimerService$JpaJDKCallableJob.call(JpaJDKTimerService.java:63)

                    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:284)

                    at java.util.concurrent.FutureTask.run(FutureTask.java:138)

                    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:80)

                    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:183)

                    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:665)

                    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:690)

                    at java.lang.Thread.run(Thread.java:810)

          [ERROR][SingleSessionCommandService] Could not commit session

          java.lang.RuntimeException: Unable to begin transaction

                    at org.drools.persistence.jta.JtaTransactionManager.begin(JtaTransactionManager.java:156)

                    at org.drools.persistence.SingleSessionCommandService.execute(SingleSessionCommandService.java:281)

                    at org.drools.persistence.jpa.JpaJDKTimerService$JpaJDKCallableJob.call(JpaJDKTimerService.java:75)

                    at org.drools.persistence.jpa.JpaJDKTimerService$JpaJDKCallableJob.call(JpaJDKTimerService.java:63)

                    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:284)

                    at java.util.concurrent.FutureTask.run(FutureTask.java:138)

                    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:80)

                    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:183)

                    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:665)

                    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:690)

                    at java.lang.Thread.run(Thread.java:810)

          Caused by: java.lang.NullPointerException

                    at com.ibm.ejs.container.EJSContainer.processTxContextChange(EJSContainer.java:2117)

                    at com.ibm.ejs.container.UserTransactionWrapper.begin(UserTransactionWrapper.java:181)

                    at org.drools.persistence.jta.JtaTransactionManager.begin(JtaTransactionManager.java:153)

                    ... 10 more

          • 2. Re: Why is Timer event not triggered in J2EE container?
            mgeldenhuys

            HI Gary,

             

            Are you using User managed Transactions in your bean? If so, you need to register the transaction manger in the environment. You can look at this :

             

            http://docs.jboss.org/jbpm/v5.1/userguide/ch07.html#d0e2820

             

            Mare

            • 3. Re: Why is Timer event not triggered in J2EE container?
              garytse

              Yes, sorry I've stripped too much from my code.  It's updated.

               

              The exception comes after 3 minutes when the timer kicks in. 

               

              This line suggests that the timer is triggered:

              at org.drools.persistence.jpa.JpaJDKTimerService$JpaJDKCallableJob.call(JpaJDKTimerService.java:75)

               

              However, I suspect that Websphere's cannot find the transaction/ context for it?  Is there anything to do with the EJB starting its own threads (by Drools) ? 

               

              com.ibm.ejs.container.EJSContainer.processTxContextChange

               

              Thanks for the suggestion Mare.

              • 4. Re: Why is Timer event not triggered in J2EE container?
                mgeldenhuys

                Hi Gary,

                 

                I think that your suspicion is correct. The original transaction you use to create the process finishes successfully, since it is only mandated to create the process and that happens without a problem. Therefore the original transaction has already commited and is not available when the timer fires.

                 

                Since the timer is executing now in the engine (StatefullKnowledgeSession) and transaction management has been specified as BMT. the engine now requires a transaction manager to get a transaction from it. And this is probably where the problem arises.

                 

                The way you do that is by registering the Transaction Manager with the StatefullKnowledgeSession, and that is done upon creation/retrieval of the said StatefullKnowledgeSession. That means getting the Transaction Manager which is managed by Websphere in your case and passing it to the KnowledgeService through an Environment.

                 

                The question now really is, how are you creating your StatefullKnowledgeSession? If you are using the jbpm-gwt-core jar's sources CommandDelegate as an example, you will have to look at the following lines,

                 

                 

                Environment env = KnowledgeBaseFactory.newEnvironment(); env.set(EnvironmentName.ENTITY_MANAGER_FACTORY, emf);

                 

                This is where you will need to add the reference to your transaction manager,

                 

                env.set( EnvironmentName.TRANSACTION_MANAGER, TransactionManagerServices.getTransactionManager() ); // Change second parameter to where you get your transaction manager from
                

                 

                 

                If this does not work, someone from the community with more experience will need to assist. Whichever way, please post your findings, as I would like to see how it pans out.

                 

                Mare

                • 5. Re: Why is Timer event not triggered in J2EE container?
                  garytse

                  Thanks for the suggestion, Mare.

                   

                  The transaction manager is where I'm having problem with, and that's why I am unable to get a TransactionManager for the 2nd parameter. 

                   

                  According to this: http://www.ibm.com/developerworks/websphere/techjournal/0609_alcott/0609_alcott.html

                  "...WebSphere Application Server does not expose the javax.transaction.TransactionManager interface to applications or application frameworks deployed into WebSphere Application Server..."

                   

                  As far as I know, both Hibernate and Spring have something of their own to work around this problem, something like :

                   

                  • org.hibernate.transaction.WebSphereExtendedJTATransactionLookup
                  • org.springframework.transaction.jta.WebSphereUowTransactionManager

                   

                   

                   

                  While I do not know the how Spring and Hibernate work around on TransactionManager, I found a work-around to this problem; and it goes in 2 parts :--

                   

                  1. WebSphere does not like threads being created in EJB, and it's against J2EE practise

                   

                  The first part of the solution is to fix the threads created directly using J2SE.  The class doing that is : org.drools.time.impl.JDKTimerService.  Using the example and classes from: http://www.ibm.com/developerworks/websphere/techjournal/0606_johnson/0606_johnson.html   I was then able to create the thread pool using the WebSphere's WorkerManager.  Now, the threads under this are under J2EE context.

                   

                  org.drools.time.impl.JDKTimerService:

                  public JDKTimerService(int size) {
                      ...
                      InitialContext ctx = new InitialContext();
                      WorkManager wm = (WorkManager)ctx.lookup("wm/default");
                      WASThreadFactory wasThreadFactory = new WASThreadFactory(wm);
                      this.scheduler = new ScheduledThreadPoolExecutor( size, wasThreadFactory );
                  
                  

                   

                  WASThreadFactory coming from the example classes in IBM developer works.

                   

                   

                  2. Re-initialize the "UserTransaction"

                   

                  When the timer service kicks in, it tries to call the single command service class (forgot actual class at the moment).  I perform a JNDI UserTransaction lookup to make it so that the drools transaction manager is new.

                   

                  Gary