7 Replies Latest reply on Nov 24, 2009 6:07 AM by mauromol

    How to use timers?

    mauromol

      Hello all,
      I spent some hours now trying to get a simple timer use-case to work using jBPM 3 with no success. I did a lot of search to find solutions and I could make some very little progress, but I think I'm doing something wrong again.

      First of all: is there any documentation on it? The jBPM 3 user guide explains something like NOTHING on this subject...

      First of all, my environment:

      - jBPM Version : 3.3.0GA
      - Database : none, working with a unit test
      - JDK : 1.5.0_15
      - Container : none
      - Configuration : no custom configuration used
      - Libraries : no custom libraries used

      === Process ==================================

      PROCESS DEFINITION:

      <?xml version="1.0" encoding="UTF-8"?>
      
      <process-definition xmlns="urn:jbpm.org:jpdl-3.2" name="simple">
       <start-state name="start">
       <transition name="to_state" to="first">
       <action name="action" class="com.sample.action.MessageActionHandler">
       <message>Going to the first state!</message>
       </action>
       </transition>
       </start-state>
       <state name="first">
       <timer duedate="5 seconds" name="Timer1" transition="to_end">
       <action class="com.sample.action.TimerActionHandler" name="TimerAction"></action>
       </timer>
       <transition name="to_end" to="end">
       <action name="action" class="com.sample.action.MessageActionHandler">
       <message>About to finish!</message>
       </action>
       </transition>
       </state>
       <end-state name="end"></end-state>
      </process-definition>
      


      TIMER ACTION HANDLER:

      package com.sample.action;
      
      import org.jbpm.graph.def.ActionHandler;
      import org.jbpm.graph.exe.ExecutionContext;
      
      public class TimerActionHandler implements ActionHandler
      {
       public TimerActionHandler()
       {
       System.out.println("TimerActionHandler created");
       }
      
       public void execute(ExecutionContext executionContext) throws Exception
       {
       System.out.println("Executing timer action");
       // signal
       executionContext.getProcessInstance().signal();
       }
      }
      


      TEST CASE SOURCE:

      TRIAL 1 (see problem description):
      package com.sample;
      
      import junit.framework.TestCase;
      
      import org.jbpm.graph.def.ProcessDefinition;
      import org.jbpm.graph.exe.ProcessInstance;
      
      public class SimpleProcessTest extends TestCase
      {
      
       public void testSimpleProcess() throws Exception
       {
      
       // Extract a process definition from the processdefinition.xml file.
       ProcessDefinition processDefinition =
       ProcessDefinition.parseXmlResource("simple/processdefinition.xml");
       assertNotNull("Definition should not be null", processDefinition);
      
       // Create an instance of the process definition.
       ProcessInstance instance = new ProcessInstance(processDefinition);
       assertEquals("Instance is in start state", instance.getRootToken()
       .getNode().getName(), "start");
       assertNull("Message variable should not exist yet", instance
       .getContextInstance().getVariable("message"));
      
       // Move the process instance from its start state to the first state.
       // The configured action should execute and the appropriate message
       // should appear in the message process variable.
       instance.signal();
       assertEquals("Instance is in first state", instance.getRootToken()
       .getNode().getName(), "first");
       assertEquals("Message variable contains message", instance
       .getContextInstance().getVariable("message"), "Going to the first state!");
      
       // process should move to the end sate thanks to the timer action
      
       // // Move the process instance to the end state. The configured action
       // // should execute again. The message variable contains a new value.
       // instance.signal();
       // assertEquals(
       // "Instance is in end state",
       // instance.getRootToken().getNode().getName(),
       // "end");
       // assertTrue("Instance has ended", instance.hasEnded());
       // assertEquals(
       // "Message variable is changed",
       // instance.getContextInstance().getVariable("message"),
       // "About to finish!");
      
       }
      
      }
      


      ##############

      TRIAL 2 (see problem description):

      package com.sample;
      
      import junit.framework.TestCase;
      
      import org.jbpm.JbpmConfiguration;
      import org.jbpm.JbpmContext;
      import org.jbpm.graph.def.ProcessDefinition;
      import org.jbpm.graph.exe.ProcessInstance;
      
      public class SimpleProcessTest extends TestCase
      {
      
       public void testSimpleProcess() throws Exception
       {
      
       JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();
       JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
      
       try
       {
       // Extract a process definition from the processdefinition.xml file.
       ProcessDefinition processDefinition =
       ProcessDefinition.parseXmlResource("simple/processdefinition.xml");
       assertNotNull("Definition should not be null", processDefinition);
      
       // without this, it doesn't work!
       jbpmContext.deployProcessDefinition(processDefinition);
      
       // Create an instance of the process definition.
       ProcessInstance instance = new ProcessInstance(processDefinition);
       assertEquals("Instance is in start state", instance.getRootToken()
       .getNode().getName(), "start");
       assertNull("Message variable should not exist yet", instance
       .getContextInstance().getVariable("message"));
      
       // Move the process instance from its start state to the first state.
       // The configured action should execute and the appropriate message
       // should appear in the message process variable.
       instance.signal();
       assertEquals("Instance is in first state", instance.getRootToken()
       .getNode().getName(), "first");
       assertEquals("Message variable contains message", instance
       .getContextInstance().getVariable("message"),
       "Going to the first state!");
      
       // process should move to the end sate thanks to the timer action
      
       // try to wait for the timer action to be executed
       Thread.sleep(10000l);
      
       // // Move the process instance to the end state. The configured action
       // // should execute again. The message variable contains a new value.
       // instance.signal();
       // assertEquals(
       // "Instance is in end state",
       // instance.getRootToken().getNode().getName(),
       // "end");
       // assertTrue("Instance has ended", instance.hasEnded());
       // assertEquals(
       // "Message variable is changed",
       // instance.getContextInstance().getVariable("message"),
       // "About to finish!");
      
       }
       finally
       {
       jbpmContext.close();
       }
       }
      
      }
      


      === Stacktrace ==============================
      TRIAL 1 (see problem description):

      org.jbpm.svc.JbpmServiceException: service 'scheduler' unavailable
       at org.jbpm.svc.Services.getCurrentService(Services.java:97)
       at org.jbpm.svc.Services.getCurrentService(Services.java:87)
       at org.jbpm.scheduler.def.CreateTimerAction.execute(CreateTimerAction.java:79)
       at org.jbpm.graph.def.GraphElement.executeAction(GraphElement.java:256)
       at org.jbpm.graph.def.GraphElement.executeActions(GraphElement.java:212)
       at org.jbpm.graph.def.GraphElement.fireAndPropagateEvent(GraphElement.java:182)
       at org.jbpm.graph.def.GraphElement.fireEvent(GraphElement.java:166)
       at org.jbpm.graph.def.Node.enter(Node.java:298)
       at org.jbpm.graph.def.Transition.take(Transition.java:151)
       at org.jbpm.graph.def.Node.leave(Node.java:389)
       at org.jbpm.graph.node.StartState.leave(StartState.java:70)
       at org.jbpm.graph.exe.Token.signal(Token.java:192)
       at org.jbpm.graph.exe.Token.signal(Token.java:140)
       at org.jbpm.graph.exe.ProcessInstance.signal(ProcessInstance.java:271)
       at com.sample.SimpleProcessTest.testSimpleProcess(SimpleProcessTest.java:29)
       at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
       at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
       at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
       at java.lang.reflect.Method.invoke(Method.java:585)
       at junit.framework.TestCase.runTest(TestCase.java:154)
       at junit.framework.TestCase.runBare(TestCase.java:127)
       at junit.framework.TestResult$1.protect(TestResult.java:106)
       at junit.framework.TestResult.runProtected(TestResult.java:124)
       at junit.framework.TestResult.run(TestResult.java:109)
       at junit.framework.TestCase.run(TestCase.java:118)
       at junit.framework.TestSuite.runTest(TestSuite.java:208)
       at junit.framework.TestSuite.run(TestSuite.java:203)
       at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:130)
       at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
       at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
       at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
       at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
       at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
      


      ##############

      TRIAL 2 (before creating an own context, see problem description):

      java.lang.NoClassDefFoundError: javax/transaction/Synchronization
       at org.hibernate.impl.SessionImpl.<init>(SessionImpl.java:213)
       at org.hibernate.impl.SessionFactoryImpl.openSession(SessionFactoryImpl.java:473)
       at org.hibernate.impl.SessionFactoryImpl.openSession(SessionFactoryImpl.java:497)
       at org.hibernate.impl.SessionFactoryImpl.openSession(SessionFactoryImpl.java:505)
       at org.jbpm.persistence.db.DbPersistenceService.getSession(DbPersistenceService.java:117)
       at org.jbpm.persistence.db.DbPersistenceService.getJobSession(DbPersistenceService.java:369)
       at org.jbpm.JbpmContext.getJobSession(JbpmContext.java:630)
       at org.jbpm.scheduler.db.DbSchedulerService.<init>(DbSchedulerService.java:50)
       at org.jbpm.scheduler.db.DbSchedulerServiceFactory.openService(DbSchedulerServiceFactory.java:32)
       at org.jbpm.svc.Services.getService(Services.java:156)
       at org.jbpm.svc.Services.getCurrentService(Services.java:94)
       at org.jbpm.svc.Services.getCurrentService(Services.java:87)
       at org.jbpm.scheduler.def.CreateTimerAction.execute(CreateTimerAction.java:79)
       at org.jbpm.graph.def.GraphElement.executeAction(GraphElement.java:256)
       at org.jbpm.graph.def.GraphElement.executeActions(GraphElement.java:212)
       at org.jbpm.graph.def.GraphElement.fireAndPropagateEvent(GraphElement.java:182)
       at org.jbpm.graph.def.GraphElement.fireEvent(GraphElement.java:166)
       at org.jbpm.graph.def.Node.enter(Node.java:298)
       at org.jbpm.graph.def.Transition.take(Transition.java:151)
       at org.jbpm.graph.def.Node.leave(Node.java:389)
       at org.jbpm.graph.node.StartState.leave(StartState.java:70)
       at org.jbpm.graph.exe.Token.signal(Token.java:192)
       at org.jbpm.graph.exe.Token.signal(Token.java:140)
       at org.jbpm.graph.exe.ProcessInstance.signal(ProcessInstance.java:271)
       at com.sample.SimpleProcessTest.testSimpleProcess(SimpleProcessTest.java:36)
       at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
       at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
       at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
       at java.lang.reflect.Method.invoke(Method.java:585)
       at junit.framework.TestCase.runTest(TestCase.java:154)
       at junit.framework.TestCase.runBare(TestCase.java:127)
       at junit.framework.TestResult$1.protect(TestResult.java:106)
       at junit.framework.TestResult.runProtected(TestResult.java:124)
       at junit.framework.TestResult.run(TestResult.java:109)
       at junit.framework.TestCase.run(TestCase.java:118)
       at junit.framework.TestSuite.runTest(TestSuite.java:208)
       at junit.framework.TestSuite.run(TestSuite.java:203)
       at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:130)
       at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
       at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
       at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
       at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
       at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
      


      === Debug logs ==============================

      TRIAL 1 (see problem description):

      [INFO ] 2009/11/23 15:53:48 - main - org.jbpm.JbpmConfiguration - using jbpm configuration resource 'jbpm.cfg.xml'
      [DEBUG] 2009/11/23 15:53:48 - main - org.jbpm.JbpmConfiguration - loading defaults in jbpm configuration
      [DEBUG] 2009/11/23 15:53:48 - main - org.jbpm.configuration.ObjectFactoryImpl - adding object info 'default.jbpm.context'
      [DEBUG] 2009/11/23 15:53:48 - main - org.jbpm.configuration.ObjectFactoryImpl - adding object info 'resource.hibernate.cfg.xml'
      [DEBUG] 2009/11/23 15:53:48 - main - org.jbpm.configuration.ObjectFactoryImpl - adding object info 'resource.business.calendar'
      [DEBUG] 2009/11/23 15:53:48 - main - org.jbpm.configuration.ObjectFactoryImpl - adding object info 'resource.default.modules'
      [DEBUG] 2009/11/23 15:53:48 - main - org.jbpm.configuration.ObjectFactoryImpl - adding object info 'resource.converter'
      [DEBUG] 2009/11/23 15:53:48 - main - org.jbpm.configuration.ObjectFactoryImpl - adding object info 'resource.action.types'
      [DEBUG] 2009/11/23 15:53:48 - main - org.jbpm.configuration.ObjectFactoryImpl - adding object info 'resource.node.types'
      [DEBUG] 2009/11/23 15:53:48 - main - org.jbpm.configuration.ObjectFactoryImpl - adding object info 'resource.parsers'
      [DEBUG] 2009/11/23 15:53:48 - main - org.jbpm.configuration.ObjectFactoryImpl - adding object info 'resource.varmapping'
      [DEBUG] 2009/11/23 15:53:48 - main - org.jbpm.configuration.ObjectFactoryImpl - adding object info 'resource.mail.templates'
      [DEBUG] 2009/11/23 15:53:48 - main - org.jbpm.configuration.ObjectFactoryImpl - adding object info 'jbpm.byte.block.size'
      [DEBUG] 2009/11/23 15:53:48 - main - org.jbpm.configuration.ObjectFactoryImpl - adding object info 'jbpm.task.instance.factory'
      [DEBUG] 2009/11/23 15:53:48 - main - org.jbpm.configuration.ObjectFactoryImpl - adding object info 'jbpm.variable.resolver'
      [DEBUG] 2009/11/23 15:53:48 - main - org.jbpm.configuration.ObjectFactoryImpl - adding object info 'jbpm.mail.smtp.host'
      [DEBUG] 2009/11/23 15:53:48 - main - org.jbpm.configuration.ObjectFactoryImpl - adding object info 'jbpm.mail.address.resolver'
      [DEBUG] 2009/11/23 15:53:48 - main - org.jbpm.configuration.ObjectFactoryImpl - adding object info 'jbpm.mail.from.address'
      [DEBUG] 2009/11/23 15:53:48 - main - org.jbpm.configuration.ObjectFactoryImpl - adding object info 'jbpm.job.executor'
      [DEBUG] 2009/11/23 15:53:48 - main - org.jbpm.JbpmConfiguration - loading specific configuration...
      [DEBUG] 2009/11/23 15:53:48 - main - org.jbpm.configuration.ObjectFactoryImpl - adding object info 'jbpmConfiguration'
      [INFO ] 2009/11/23 15:53:48 - main - org.jbpm.persistence.db.StaleObjectLogConfigurer - stale object exceptions will be hidden from logging
      [DEBUG] 2009/11/23 15:53:48 - main - org.jbpm.jpdl.xml.JpdlParser - schema resource found: org/jbpm/jpdl/xml/jpdl-3.3.xsd
      [DEBUG] 2009/11/23 15:53:48 - main - org.jbpm.jpdl.xml.JpdlParser - schema resource found: org/jbpm/jpdl/xml/jpdl-3.1.xsd
      [DEBUG] 2009/11/23 15:53:48 - main - org.jbpm.jpdl.xml.JpdlParser - schema resource found: org/jbpm/jpdl/xml/jpdl-3.0.xsd
      [DEBUG] 2009/11/23 15:53:48 - main - org.jbpm.jpdl.xml.JpdlParser - schema resource found: org/jbpm/jpdl/xml/jpdl-3.2.xsd
      [DEBUG] 2009/11/23 15:53:49 - main - org.jbpm.graph.node.NodeTypes - node 'page' will not be available. class 'org.jboss.seam.pageflow.Page' couldn't be loaded
      [DEBUG] 2009/11/23 15:53:49 - main - org.jbpm.graph.node.NodeTypes - node 'start-page' will not be available. class 'org.jboss.seam.pageflow.Page' couldn't be loaded
      [DEBUG] 2009/11/23 15:53:49 - main - org.jbpm.graph.def.GraphElement - event 'process-start' on 'ProcessDefinition(simple)' for 'Token(/)'
      [DEBUG] 2009/11/23 15:53:49 - main - org.jbpm.graph.def.GraphElement - event 'before-signal' on 'StartState(start)' for 'Token(/)'
      [DEBUG] 2009/11/23 15:53:49 - main - org.jbpm.graph.def.GraphElement - event 'node-leave' on 'StartState(start)' for 'Token(/)'
      [DEBUG] 2009/11/23 15:53:49 - main - org.jbpm.graph.def.GraphElement - event 'transition' on 'Transition(to_state)' for 'Token(/)'
      [DEBUG] 2009/11/23 15:53:49 - main - org.jbpm.graph.def.GraphElement - executing action 'action[action]'
      [DEBUG] 2009/11/23 15:53:49 - main - org.jbpm.graph.exe.Token - token[0] is locked by token[0]
      [DEBUG] 2009/11/23 15:53:49 - main - org.jbpm.context.exe.VariableContainer - create variable 'message' in 'TokenVariableMap10ad8659' with value 'Going to the first state!'
      [DEBUG] 2009/11/23 15:53:49 - main - org.jbpm.db.hibernate.Converters - adding converter 'D', 'org.jbpm.context.exe.converter.DoubleToStringConverter'
      [DEBUG] 2009/11/23 15:53:49 - main - org.jbpm.db.hibernate.Converters - adding converter 'C', 'org.jbpm.context.exe.converter.CharacterToStringConverter'
      [DEBUG] 2009/11/23 15:53:49 - main - org.jbpm.db.hibernate.Converters - adding converter 'B', 'org.jbpm.context.exe.converter.BooleanToStringConverter'
      [DEBUG] 2009/11/23 15:53:49 - main - org.jbpm.db.hibernate.Converters - adding converter 'Y', 'org.jbpm.context.exe.converter.BytesToByteArrayConverter'
      [DEBUG] 2009/11/23 15:53:49 - main - org.jbpm.db.hibernate.Converters - adding converter 'A', 'org.jbpm.context.exe.converter.DateToLongConverter'
      [DEBUG] 2009/11/23 15:53:49 - main - org.jbpm.db.hibernate.Converters - adding converter 'R', 'org.jbpm.context.exe.converter.SerializableToByteArrayConverter'
      [DEBUG] 2009/11/23 15:53:49 - main - org.jbpm.db.hibernate.Converters - adding converter 'I', 'org.jbpm.context.exe.converter.IntegerToLongConverter'
      [DEBUG] 2009/11/23 15:53:49 - main - org.jbpm.db.hibernate.Converters - adding converter 'H', 'org.jbpm.context.exe.converter.ShortToLongConverter'
      [DEBUG] 2009/11/23 15:53:49 - main - org.jbpm.db.hibernate.Converters - adding converter 'G', 'org.jbpm.context.exe.converter.FloatToDoubleConverter'
      [DEBUG] 2009/11/23 15:53:49 - main - org.jbpm.db.hibernate.Converters - adding converter 'F', 'org.jbpm.context.exe.converter.FloatToStringConverter'
      [DEBUG] 2009/11/23 15:53:49 - main - org.jbpm.db.hibernate.Converters - adding converter 'E', 'org.jbpm.context.exe.converter.ByteToLongConverter'
      [DEBUG] 2009/11/23 15:53:49 - main - org.jbpm.graph.exe.Token - token[0] is unlocked by token[0]
      [DEBUG] 2009/11/23 15:53:49 - main - org.jbpm.graph.def.GraphElement - event 'node-enter' on 'State(first)' for 'Token(/)'
      [DEBUG] 2009/11/23 15:53:49 - main - org.jbpm.graph.def.GraphElement - executing action 'CreateTimerAction(5d6d2633)'
      [DEBUG] 2009/11/23 15:53:49 - main - org.jbpm.graph.exe.Token - token[0] is locked by token[0]
      [DEBUG] 2009/11/23 15:53:49 - main - org.jbpm.graph.def.GraphElement - event 'timer-create' on 'State(first)' for 'Token(/)'
      [DEBUG] 2009/11/23 15:53:49 - main - org.jbpm.graph.exe.Token - token[0] is unlocked by token[0]
      [ERROR] 2009/11/23 15:53:49 - main - org.jbpm.graph.def.GraphElement - action threw exception: service 'scheduler' unavailable
      


      ##############

      TRIAL 2 (see problem description):

      Too long to attach here, please click ftp://guest:guest@mauromol.dyndns.org/part0/public/jbpm.log

      === Problem description =========================

      As you can see from the attached test cases, you can get to TRIAL 1 scenario by doing the following:
      - create new process project and leave the wizard create the standard example process, classes and handlers for you; a new sample process will be created with a "start" node, a "first" state node and an "end" node
      - change the SimpleProcessTest class so that a new Timer is defined at the "first" state, configured to call and action handler (TimerActionHandler) after 3 seconds; this action handler, when invoked, prints a message on the standard output and then does the actual signal to the process instance, to reach the end state

      The first problem I encounter is a "service 'scheduler' unavailable" error. Searching on the net I found some hints like "start the scheduler" or "change the configuration in src/main/config/jbpm.cfg.xml. But nobody explains WHAT is the scheduler, how to start it, etc.. However, after some trials and debugging sessions I found that the solution to this problem is another one: you need to create a JbpmContext by yourself:

      JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();
      JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
      try
      {
       // test case code here
      }
      finally
      {
       jbpmContext.close();
      }
      


      This because org.jbpm.svc.Services.getCurrentService(String, boolean) fails if there's no current JbpmContext... This is obviously a bug, otherwise I can't understand why the test case works if I remove the timer... Moreover, as I said, the test case is the built-in one...

      Anyway, now let's switch to TRIAL 2. In this case I did what I just explained, but I get an error related to the fact that Hibernate is searching for a JTA class... However, as I'm working with no database at all, I wouldn't expect that. Anyway, by adding JTA classes to the project build path I now get another Hibernate error: commit failed because "object references an unsaved transient instance - save the transient instance before flushing: org.jbpm.graph.exe.ProcessInstance".
      After searching again on the Internet I could find that the "secret" here is to deploy the process definition after it is created by parsing the XML. By doing that, no exception is thrown!

      But now... how to test the timer action? In my test case it isn't ever executed. I can even place a Thread.sleep(10000l) to make the JUnit runner wait for 10 seconds, but the timer action is not executed anyway.

      How should it work?

      Thanks in advance for any help.

        • 1. Re: How to use timers?
          kukeltje

          more detailed response later this evening but for now:

          First of all: is there any documentation on it? The jBPM 3 user guide explains something like NOTHING on this subject...


          http://docs.jboss.com/jbpm/v3.2/userguide/html_single/#tasktimers
          http://docs.jboss.com/jbpm/v3.2/userguide/html_single/#scheduler
          http://docs.jboss.com/jbpm/v3.2/userguide/html_single/#timer.element
          http://fisheye.jboss.org/changelog/JbpmSvn/jbpm3/trunk/modules/core/src/test/java/org/jbpm/scheduler/exe?todate=1248416261336

          etc (including several posts in the forum)... so saying there is no documentation is plain wrong ;-).


          • 2. Re: How to use timers?
            kukeltje

            First of all, let me point you to http://catb.org/~esr/faqs/smart-questions.html#volume

            Personally, when I started reading your post and encounter very basic questions with statements that are plain wrong (see further on, and my previous post) in combination with LOTS of data (will not call it information), I really hesitate to respond, but since I'm in a really good mood


            The first problem I encounter is a "service 'scheduler' unavailable" error. Searching on the net I found some hints like "start the scheduler" or "change the configuration in src/main/config/jbpm.cfg.xml.


            Isn't the internet great

            But nobody explains WHAT is the scheduler,


            Are you serious? You did not ever get the impression that it is used to execute timers? Strange since you have a problem with timers and a message that the scheduler is unavailable and you started searching in this direction. Oh, and it is in the first chapter of the user docs: http://docs.jboss.org/jbpm/v3/userguide/introduction.html#d0e130

            how to start it, etc..


            Besides in the docs: http://docs.jboss.org/jbpm/v3/userguide/deployment.html#webapplication

            Very little searching yielded
            http://www.jboss.org/index.html?module=bb&op=viewtopic&t=80078&postdays=0&postorder=asc&start=10

            and many more links

            However, after some trials and debugging sessions I found that the solution to this problem is another one: you need to create a JbpmContext by yourself:


            This is also very basic jBPM stuff and in almost all examples, getting started. So I it sounds strange to me that you only found this out through debugging.

            However, as I'm working with no database at all, I wouldn't expect that.


            You yourself might not be, but does it come as a surprise that jBPM might need one? jBPM is a statemachine, mainly for workflow, so long running processes. Most people would like that state to be persistent to survive a crash or restart. Most systems use a database for this (as does jBPM).

            I hope this already helps you as I did not look into your two specific cases.

            • 3. Re: How to use timers?
              ardavan

              Nice explanation Ronald !

              Mauromol, make sure you have:

              <service name="scheduler" factory="org.jbpm.scheduler.db.DbSchedulerServiceFactory"/>
              

              in your jbpm.cfg.xml




              • 4. Re: How to use timers?
                mauromol

                Dear kukeltje,
                I was wondering why you decided to loose your time to answer to my stupid questions without even reading them.

                However, I should have remembered your kindness and tendency to discussion from my previous experiences some months ago, both in the forum and in JIRA. But as I am too in a really good mood, I will reply.

                Regarding jBPM documentation:


                http://docs.jboss.com/jbpm/v3.2/userguide/html_single/#tasktimers
                http://docs.jboss.com/jbpm/v3.2/userguide/html_single/#scheduler
                http://docs.jboss.com/jbpm/v3.2/userguide/html_single/#timer.element


                Is this exhaustive documentation for you? Maybe we have a different idea about the mean of "documentation". Have you ever read the documentation for Spring (that's the first example that comes into my mind)? Have you ever looked at jBPM 3 source code just to seek for some basic Javadoc? How much did you find?


                http://fisheye.jboss.org/changelog/JbpmSvn/jbpm3/trunk/modules/core/src/test/java/org/jbpm/scheduler/exe?todate=1248416261336

                etc (including several posts in the forum)... so saying there is no documentation is plain wrong ;-).


                This is NOT documentation, these are web pages that talk about problems like mine because there is poor official documentation available! Especially, pointing me to a series of SVN logs saying they are "documentation" is something that really makes me laugh.

                Before you spend even more time to reply that jBPM is an open source project and that everyone can contribute in either code or documentation, let me say that I can even accept that jBPM has poor documentation, but please at least don't say that my questions are stupid because there is exhaustive documentation available!!!


                First of all, let me point you to http://catb.org/~esr/faqs/smart-questions.html#volume


                It is really frustrating to read these gems of wisdom, especially after I used a http://www.jboss.org/index.html?module=bb&op=viewtopic&t=158610 to post my question and I even followed your "suggestion" to provide a ready to copy-'n'-paste test case. I did that and it is bad... What should I say?



                The first problem I encounter is a "service 'scheduler' unavailable" error. Searching on the net I found some hints like "start the scheduler" or "change the configuration in src/main/config/jbpm.cfg.xml.


                Isn't the internet great


                Yes it is and I use it every day for my work. It is a pity that, in this case, the suggestion given were useless... But you surely missed it, because you were so much happy to start your new controversy that you didn't even try to read and understand my post.



                But nobody explains WHAT is the scheduler,


                Are you serious? You did not ever get the impression that it is used to execute timers? Strange since you have a problem with timers and a message that the scheduler is unavailable and you started searching in this direction. Oh, and it is in the first chapter of the user docs: http://docs.jboss.org/jbpm/v3/userguide/introduction.html#d0e130


                You're really nice. Of course I know WHAT is a scheduler. I meant: what is jBPM Scheduler? Which classes do implement it? How is it meant to be used especially in my case? Doesn't jBPM start a scheduler by its own if it is needed? How is it related to a multi-threaded environment especially in a JUnit test case? How this then translates to a web application environment?



                how to start it, etc..


                Besides in the docs: http://docs.jboss.org/jbpm/v3/userguide/deployment.html#webapplication


                I'm writing a test case, I am not running in a web application for now.


                Very little searching yielded
                http://www.jboss.org/index.html?module=bb&op=viewtopic&t=80078&postdays=0&postorder=asc&start=10


                Interesting. So, please, show me where there's explained how to start the scheduler there?
                Anyway, if you read my post you would have seen that I was able to make the jBPM timer work without starting any scheduler, just by adding a JTA JAR in the classpath, by creating my own jBPM context and by "persisting" the process definition. So... what is the whole Scheduler thing about!?!?!? What am I doing wrong?



                However, after some trials and debugging sessions I found that the solution to this problem is another one: you need to create a JbpmContext by yourself:


                This is also very basic jBPM stuff and in almost all examples, getting started. So I it sounds strange to me that you only found this out through debugging.


                Please, don't talk about the jBPM 3 silly configuration mechanism otherwise we could discuss for an entire week!!! I always throw up my hands in despair when I look at the internals of it... Apart from the fact that there's no evident dependency between the variable jbpmContext and the signal calls (it's solely needed to make the broken "static" mechanism of the "current" jBPM context work), it's even less clear why half of the things work without having to create a jBPM context before and the other half does not.
                Anyway, given that things work in this way, it would be simple enough to highlight it everywhere and make the Eclipse plugin provide a built-in test case that does the same thing, instead of something that doesn't.

                And, regarding the debug thing: how could I understand that the problem was that without debugging if:
                - the error message is saying something different ("the scheduler is anaivalable", while the problem is that a jBPM context cannot be found...)
                - the debug logs don't say anything useful about it



                However, as I'm working with no database at all, I wouldn't expect that.


                You yourself might not be, but does it come as a surprise that jBPM might need one? jBPM is a statemachine, mainly for workflow, so long running processes. Most people would like that state to be persistent to survive a crash or restart. Most systems use a database for this (as does jBPM).


                Really? Oh, I didn't know that! I worked for months to embed jBPM in our web application and make it work in a JTA environment together with Hibernate, Spring and JBoss Transactions and I didn't even know that jBPM used a database at all...................... Again, you are really nice. There's a big difference between the sentences "jBPM CAN use a database to persist processes" and "jBPM MUST persist processes in a database". In my simple test case I just wanted to move a process on, start a timer and see the timer action executed... why should I persist the whole thing in a database?

                If there are some technical limitations that force to persist a process definition and to have JTA classes (!!!) available in the classpath to make the scheduling thing work, just say it instead of enjoyng yourself.

                Given all of this, I'm still waiting for some help regarding my problem (you didn't even get closed to it...).

                • 5. Re: How to use timers?
                  mauromol

                   

                  "ardavan" wrote:

                  Mauromol, make sure you have:
                  <service name="scheduler" factory="org.jbpm.scheduler.db.DbSchedulerServiceFactory"/>
                  

                  in your jbpm.cfg.xml


                  Thank you ardavan, but this doesn't help, as I've written in my original post.

                  • 6. Re: How to use timers?
                    mputz

                    geez, guys, calm down again ;-)

                    "mauromol" wrote:

                    I'm writing a test case, I am not running in a web application for now.


                    In that case, you still need persistence. With the DbSchedulerServiceFactory, timers are stored in the jBPM database and executed by the JobExecutor (which needs to be started, btw).

                    The easiest way to test timers is by extending the AbstractDbTestCase class. Have a look at the processJobs(long maxWait) method, which starts a JobExecutor and waits until jobs are processed:

                    http://anonsvn.jboss.org/repos/jbpm/jbpm3/trunk/modules/core/src/main/java/org/jbpm/db/AbstractDbTestCase.java

                    There are a couple of test cases for timer execution related scenarios, such as this one, for example:

                    http://anonsvn.jboss.org/repos/jbpm/jbpm3/trunk/modules/core/src/test/java/org/jbpm/jbpm2036/JBPM2036Test.java

                    1 of 1 people found this helpful
                    • 7. Re: How to use timers?
                      mauromol

                      Thank you Martin, you actually helped me and I got it to work!!

                      I'm going to summarize it up because I think that certain things are not so intuitive for a "jBPM scheduler"-newbie like me.

                      First of all, the default implementation of the scheduler service, provided by jBPM, is DbSchedulerServiceFactory, which uses the database to store information about scheduled actions associated with timers. This means that a database is needed even to write a simple JUnit test case that uses timers and this justifies the need to deploy your process definition (it's needed to store the related timers and timer jobs in the database, as well). I would assume that a different scheduler service implementation could be made to avoid the use of a database, however let's talk about the default implementation.

                      Even if a database is needed, there's no need to extend AbstractDbTestCase, which provides many methods to create and clean the schema and to interact with the database. In fact, in the simplest case, jBPM (thanks to Hibernate) will create automatically an in-memory database for you when you go to deploy your process definition and/or schedule a timer action. In this case, however, you should take care of the db lifecycle, however I think (but I may be wrong) that if you destory the jbpmConfiguration (by calling close) the in-memory db will be destroyed too...

                      Anyway, in my case I was running an only test method, so it's not so important how the db is handled between multiple test methods invocations.

                      In my previous example (TRIAL 2) timer actions were correctly saved in the database by the DbSchedulerServiceFactory, but they were not executed because no JobExecutor thread was started. The JobExecutor thread is actually a thread that periodically reads from the database, searching for saved timer actions (jobs) and executes them.

                      So, if I change my test case by calling jbpmConfiguration.startJobExecutor() just after the configuration creation, I make sure that the "scheduler" is started. Actually, I would rather say that there is no scheduler to start, but that the default scheduler service implementation expects that a JobExecutor thread is present to execute timer actions. In other words, the JobExecutor is itself part of the default scheduler service implementation. I think that this only sentence would be enough to say that my original problem is not so stupid as kukeltje says and that the documentation could be drastically improved on this subject (I'm also wondering what is http://docs.jboss.com/jbpm/v3.2/userguide/html_single/#schedulerdeployment all about!?).

                      Anyway, this is not enough, because another action is needed in order to make the JobExecutor run timer actions in my test case: just after the signal invocation, that moves my process instance to the waiting state (with attached timer), I have to close the jBPM context in order to commit things (the deployed process definition, the process instance state and the related saved timers and jobs), otherwise the JobExecutor, which works on another thread, wouldn't find anything to executoe. Having the whole scenario cleared, this sounds reasonable and obvious, but I think it might not be so straight away for a first time user that is writing a simple JUnit test case. Using the AbstractDbTestCase class mentioned by Martin, this would be automatically achieved because the method processJobs(long) does a "commit" before starting the JobExecutor.

                      Thank you again Martin and please correct me if I've written something wrong.

                      Anyway, if this is considered to be a simple answer to a basic question (as kukeltje said)... well, I'm wondering why kukeltje couldn't write it himself: he would have certainly spent much less time that writing his two previous smart posts, as Martin's kind answer demonstrated.