11 Replies Latest reply on Oct 24, 2008 4:49 AM by Ronald van Kuijk

    Job Executor and Spring

    Stojan Sljivic Newbie

      Hi,

      I was trying to use the solution posted by Joram Barrez for integrating JobExecutor with Spring http://www.jorambarrez.be/blog/2008/08/26/jbpm-job-executor-for-spring/, but when I run the server, I am getting the following error:

      2008-10-09 16:06:38,627 [JbpmJobExecutor:192.168.100.132:1] ERROR org.jbpm.job.executor.JobExecutorThread - exception in job executor thread. waiting 10000 milliseconds
      java.lang.NullPointerException
      at org.jbpm.job.executor.JobExecutorThread.acquireJobs(JobExecutorThread.java:110)
      at org.jbpm.job.executor.JobExecutorThread.run(JobExecutorThread.java:58)


      The relevant Spring configuration is:

      <bean id="jbpmConfiguration" class="org.springmodules.workflow.jbpm31.LocalJbpmConfigurationFactoryBean">
       <property name="sessionFactory" ref="sessionFactory" />
       <property name="configuration" value="classpath:org/jbpm/default.jbpm.cfg.xml" />
      
       <property name="processDefinitionsResources">
       <list>
      
       </list>
       </property>
      </bean>
      
      <bean id="jbpmJobExecutorLoader" class="JbpmJobExecutorLoader">
       <property name="jbpmConfiguration" ref="jbpmConfiguration" />
      </bean>


      It seems that JobExecutor does not get the reference to the jbpmConfiguration, but I do not know why.

      Any help is appreciated.


        • 1. Re: Job Executor and Spring
          James Cook Newbie

          Funny, but I just wrote this class:


          
          import org.jbpm.JbpmConfiguration;
          import org.jbpm.job.executor.JobExecutor;
          import org.slf4j.Logger;
          import org.slf4j.LoggerFactory;
          import org.springframework.beans.factory.DisposableBean;
          import org.springframework.beans.factory.InitializingBean;
          import org.springframework.beans.factory.annotation.Required;
          
          /**
           *
           */
          public class JobExecutorInitializingBean implements InitializingBean, DisposableBean {
          
           // Statics -----------------------------------------------------------------
          
           private static final Logger LOG = LoggerFactory.getLogger(JobExecutorInitializingBean.class);
          
           // Instances ---------------------------------------------------------------
          
           private JbpmConfiguration _jbpmConfiguration;
          
           /**
           * Invoked by a BeanFactory after it has set all bean properties supplied
           * (and satisfied BeanFactoryAware and ApplicationContextAware).
           * <p>This method allows the bean instance to perform initialization only
           * possible when all bean properties have been set and to throw an
           * exception in the event of misconfiguration.
           *
           * @throws Exception in the event of misconfiguration (such
           * as failure to set an essential property) or if initialization fails.
           */
           public void afterPropertiesSet() throws Exception {
           JobExecutor jobExecutor = _jbpmConfiguration.getJobExecutor();
           if (jobExecutor != null)
           jobExecutor.start();
           else
           LOG.warn("No JobExecutor was found in the jBPM configuration.");
           }
          
          
           /**
           * Invoked by a BeanFactory on destruction of a singleton.
           *
           * @throws Exception in case of shutdown errors.
           * Exceptions will get logged but not rethrown to allow
           * other beans to release their resources too.
           */
           public void destroy() throws Exception {
           JobExecutor jobExecutor = _jbpmConfiguration.getJobExecutor();
           if (jobExecutor != null) jobExecutor.stop();
           }
          
           @Required
           public void setJbpmConfiguration(final JbpmConfiguration jbpmConfiguration) {
           _jbpmConfiguration = jbpmConfiguration;
           }
          }
          
          


          • 2. Re: Job Executor and Spring
            James Cook Newbie

            I haven't yet got timers working for me so take that code with a grain of salt. Also note that I use the LocalJbpmConfigurationFactoryBean in my spring config, so I don't want to declare the same config twice. For this reason my spring.xml file looks like this:

             <bean id="jbpmConfig" class="org.springmodules.workflow.jbpm31.LocalJbpmConfigurationFactoryBean"
             p:sessionFactory-ref="sessionFactory"
             p:configuration="classpath:org/jbpm/default.jbpm.cfg.xml"
             >
             <property name="processDefinitionsResources">
             <list>
             <value>classpath:workflow/**/processdefinition.xml</value>
             </list>
             </property>
            
             </bean>
            
             <bean id="jbpmTemplate" class="org.springmodules.workflow.jbpm31.JbpmTemplate">
             <constructor-arg index="0" ref="jbpmConfig"/>
             </bean>
            
             <bean class="md.signmeup.workflow.jbpm.JobExecutorInitializingBean"
             p:jbpmConfiguration-ref="jbpmConfig" />
            


            and I had a problem in my code. This overcomes it:


            import org.jbpm.JbpmConfiguration;
            import org.jbpm.job.executor.JobExecutor;
            import org.slf4j.Logger;
            import org.slf4j.LoggerFactory;
            import org.springframework.beans.factory.DisposableBean;
            import org.springframework.beans.factory.InitializingBean;
            import org.springframework.beans.factory.annotation.Required;
            
            /**
             *
             */
            public class JobExecutorInitializingBean implements InitializingBean, DisposableBean {
            
             // Statics -----------------------------------------------------------------
            
             private static final Logger LOG = LoggerFactory.getLogger(JobExecutorInitializingBean.class);
            
             // Instances ---------------------------------------------------------------
            
             private JbpmConfiguration _jbpmConfiguration;
            
             public void afterPropertiesSet() throws Exception {
             JobExecutor jobExecutor = _jbpmConfiguration.getJobExecutor();
             if (jobExecutor != null) {
             jobExecutor.setJbpmConfiguration(_jbpmConfiguration);
             jobExecutor.start();
             } else {
             if (LOG.isWarnEnabled())
             LOG.warn("No JobExecutor was found in the jBPM configuration.");
             }
             }
            
            
             public void destroy() throws Exception {
             JobExecutor jobExecutor = _jbpmConfiguration.getJobExecutor();
             if (jobExecutor != null) jobExecutor.stop();
             }
            
             @Required
             public void setJbpmConfiguration(final JbpmConfiguration jbpmConfiguration) {
             _jbpmConfiguration = jbpmConfiguration;
             }
            }
            
            


            • 3. Re: Job Executor and Spring
              Stojan Sljivic Newbie

              The provided solution worked, but I had to extract all jBPM *.hbm.xml files to the source/classes folder, because Spring was unable to load them from the JAR file.

              I have another question. I have Job Executor configured in jbpm.cfg.xml file like this:

              <bean name="jbpm.job.executor" class="org.jbpm.job.executor.JobExecutor">
               <field name="jbpmConfiguration"> <ref bean="jbpmConfiguration" /> </field>
               <field name="name"><string value="JbpmJobExecutor" /></field>
               <field name="nbrOfThreads"><int value="1" /></field>
               <field name="idleInterval"><int value="5000" /></field>
               <field name="maxIdleInterval"><int value="3600000" /></field> <!-- 1 hour -->
               <field name="historyMaxSize"><int value="20" /></field>
               <field name="maxLockTime"><int value="600000" /></field> <!-- 10 minutes -->
               <field name="lockMonitorInterval"><int value="60000" /></field> <!-- 1 minute -->
               <field name="lockBufferTime"><int value="5000" /></field> <!-- 5 seconds -->
               </bean>


              How can I move that definition into the Spring XML configuration? Is it possible to entirely ignore jbpm.cfg.xml and move entire jBPM configuration into the Spring XML files?

              Thanks

              • 4. Re: Job Executor and Spring
                Ronald van Kuijk Master

                Warning: Partly threadjacking although it is related to the question

                You know... maybe I missed something in my upbringing, but maybe now is the time to 'learn' that.

                I can understand that you want to be able to inject other pojo's at some moment in time or in a speciic situation and use e.g. seam, guice, spring etc for that. What I do not understand is that people also want to move the config's (that are already in xml) for which you can have (or 'inject') different ones for different environments to a new xml file (a spring config).... In seam people do not do this, they just leverage, but spring users most always want this (or is that my impression?). What is the advantage of this?

                • 5. Re: Job Executor and Spring
                  Stojan Sljivic Newbie

                  Hi,

                  The reason for moving the configuration to the Spring XML is in order to be able to use PropertyPlaceholderConfigurer. That way no values would be "hard coded" in the XML, but rather defined in the properties file.

                  Can I achieve that with jbpm.cfg.xml, so that I can define "idleInterval" in the properties file?

                  Thanks

                  • 6. Re: Job Executor and Spring
                    James Cook Newbie

                    JobExecutor seems to be exposed as a property of the jbpmConfiguration. It is not one of the built-in service factories like authentication, persistence or scheduler.

                    That said, if you were to externalize the bootstrapping of JobExecutor, you will have to get JbpmConfiguration to be knowledgable about your instance of JobExecutor.

                    Now, JbpmConfiguration uses the object factory to locate the job executor using a string key value of "jbpm.job.executor". I haven't tried this, but if you are using the spring modules jbpm integration, they replace the default ObjectFactory with one that uses object factory keys as lookups in a spring context. Theoretically, this should mean that you can instantiate the JobExecutor in Spring and all you have to do is make sure the id value is 'jbpm.job.executor'.

                    • 7. Re: Job Executor and Spring
                      James Cook Newbie

                      I tried my suggestion and it works, but the JbpmObjectFactory supplied in the spring modules integration is a bit lacking. It isn't wired in as the default object factory out of the gate. You have to do this yourself. Also, it is an all or nothing proposition, meaning if you use this object factory, all of the resources used by jBPM need to be defined in Spring.

                      Here is a new class that will attempt to find resource names in Spring, and if that fails, it will delegate to the original jBPM mechanism.


                      import org.springmodules.workflow.jbpm31.JbpmObjectFactory;
                      import org.jbpm.configuration.ObjectFactoryImpl;
                      import org.jbpm.configuration.ObjectFactoryParser;
                      import org.jbpm.JbpmConfiguration;
                      import org.springframework.core.io.Resource;
                      import org.springframework.beans.factory.InitializingBean;
                      import org.springframework.beans.factory.NoSuchBeanDefinitionException;
                      import org.slf4j.Logger;
                      import org.slf4j.LoggerFactory;
                      
                      import java.io.*;
                      
                      /**
                       *
                       */
                      public class SpringJbpmObjectFactory extends JbpmObjectFactory implements InitializingBean {
                      
                       // Statics -----------------------------------------------------------------
                      
                       private static final Logger LOG = LoggerFactory.getLogger(SpringJbpmObjectFactory.class);
                      
                       // Instances ---------------------------------------------------------------
                      
                       protected ObjectFactoryImpl _objectFactory;
                      
                       protected Resource _configuration;
                      
                       // InitializingBean implementation -----------------------------------------
                      
                       public void afterPropertiesSet() throws Exception {
                       if (_configuration != null) {
                       LOG.info("creating JbpmConfiguration from resource " + _configuration.getDescription());
                       InputStream stream = _configuration.getInputStream();
                       _objectFactory = ObjectFactoryParser.parseInputStream(stream);
                       stream.close();
                       }
                       JbpmConfiguration.Configs.setDefaultObjectFactory(this);
                       }
                      
                       // JbpmObjectFactory overrides ---------------------------------------------
                      
                       @Override
                       public Object createObject(final String name) {
                       Object result = null;
                       try {
                       result = super.createObject(name);
                       } catch (NoSuchBeanDefinitionException e) {
                       result = _objectFactory.createObject(name);
                       }
                       return result;
                       }
                      
                       @Override
                       public boolean hasObject(final String name) {
                       boolean result = false;
                       try {
                       result = super.hasObject(name);
                       } catch (NoSuchBeanDefinitionException e) {
                       result = _objectFactory.hasObject(name);
                       }
                       return result;
                       }
                      
                       // Properties --------------------------------------------------------------
                      
                       public void setConfiguration(final Resource configuration) {
                       _configuration = configuration;
                       }
                      }
                      


                      If you are already using spring module for jBPM, you are probably using the LocalJbpmConfigurationFactoryBean class and you are more than likely specifying the path to a jbpm.xml config file. That's a problem, since the presence of a config file causes a fallback to the original object factory even if you specify your own object factory.

                      Here's how to configure spring to use the new object factory and a JobExecutor defined in the spring config file.


                       <bean id="jbpmObjectFactory" class="com.example.jbpm.SpringJbpmObjectFactory"
                       p:configuration="classpath:META-INF/jbpm.cfg.xml"
                       />
                      
                       <bean id="jbpmConfig" class="org.springmodules.workflow.jbpm31.LocalJbpmConfigurationFactoryBean"
                       p:sessionFactory-ref="sessionFactory"
                       p:objectFactory-ref="jbpmObjectFactory"
                       >
                       <property name="processDefinitionsResources">
                       <list>
                       <value>classpath:workflow/**/processdefinition.xml</value>
                       </list>
                       </property>
                      
                       </bean>
                      
                       <bean name="jbpm.job.executor" class="org.jbpm.job.executor.JobExecutor"
                       p:jbpmConfiguration-ref="jbpmConfig"
                       p:nbrOfThreads="1"
                       p:idleInterval="5000"
                       p:maxIdleInterval="3600000"
                       p:historyMaxSize="20"
                       p:maxLockTime="600000"
                       p:lockMonitorInterval="60000"
                       p:lockBufferTime="5000"
                       >
                       <property name="name" value="JbpmJobExecutor" />
                       </bean>
                      


                      • 8. Re: Job Executor and Spring
                        Ronald van Kuijk Master

                         

                        That way no values would be "hard coded" in the XML, but rather defined in the properties file.
                        Ahhh cool... "hardcoded" in a properties file instead of an xml file....

                        • 9. Re: Job Executor and Spring
                          James Cook Newbie

                          I don't want to quibble over configuration placement. For those applications that make heavy use of Spring configuration already, doing some or all of this configuration makes sense, especially when it comes to a unified transaction manager. After all, jBPM has an object factory for a reason.

                          • 10. Re: Job Executor and Spring
                            Leo de Blaauw Newbie

                            Uhh,

                            The use case is quite common actually to have one spring configuration xml and have property files for your different environments like test,
                            production etc to minimize the configuration data and make for easy
                            deployment of a spring app. So nothing unusual there really...

                            But to stay on topic we just use the EJB timerservice with our spring
                            app and jBPM works fine.

                            Regards,
                            Leo

                            "kukeltje" wrote:
                            That way no values would be "hard coded" in the XML, but rather defined in the properties file.
                            Ahhh cool... "hardcoded" in a properties file instead of an xml file....


                            • 11. Re: Job Executor and Spring
                              Ronald van Kuijk Master

                              Leo, I know the usecase is quite common, but that does not mean it makes sense in all cases (to me)

                              My initial question was real and serious. But if I talk to people who use spring this way, I always get the answer about the config files and a statement like 'that is the way we do it' (often that is what they were tought/told and have no clue about advantages and mostly have problems like this one because of the way they use it)

                              Personally I use config files in a different way and do not miss Spring *for this* (not needed it for other things) So maybe I therefore reacted a little sarcasticly, but I am really interested in 'profoundly' discussing this. Can you send me an email on ronald (dot) jbpm (at) org (replace the not so obvious) so we can discuss this out-of-band?