Announcement Announcement Module
Collapse
No announcement yet.
Persistent Job using Quartz and Spring Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Persistent Job using Quartz and Spring

    hello all,
    i am trying to schedule a persistent Job using Spring and Quartz.
    I have defined in applicationContext.xml a bean named persistenceManager which is in charge of inserting data into a database via HibernateDaoSupport.
    I want to schedule a job (via the web) that uses that persistenceManager in order to insert data into the database.
    I have then created a BudgetJob class which extends QuartzJobBean, and i have declared it in applicationContext as follows
    <code>
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">

    <!--
    - Application context definition for JPetStore's business layer.
    - Contains bean references to the transaction manager and to the DAOs in
    - dataAccessContext-local/jta.xml (see web.xml's "contextConfigLocation").
    -->
    <beans>

    <!-- ========================= GENERAL DEFINITIONS ========================= -->



    <!-- Configurer that replaces ${...} placeholders with values from properties files -->
    <!-- (in this case, mail and JDBC related properties) -->

    <bean id="dataSource"
    class="org.springframework.jdbc.datasource.DriverM anagerDataSource">

    <property name="driverClassName">
    <value>com.mysql.jdbc.Driver</value>
    </property>
    <property name="url">
    <value>jdbc:mysql://localhost:3306/menagerie?autoReconnect=true</value>
    </property>

    <property name="username">
    <value>root</value>
    </property>
    <property name="password">
    <value>mypass</value>
    </property>
    </bean>



    <bean id="sessionFactory" class="org.springframework.orm.hibernate.LocalSess ionFactoryBean">
    <property name="mappingResources">
    <list>
    <value>com/myapp/hibernate/HibernateEntry.hbm.xml</value>
    <value>com/myapp/hibernate/HibernateExpenseType.hbm.xml</value>
    <value>com/myapp/hibernate/HibernateUser.hbm.xml</value>
    <value>com/myapp/hibernate/HibernateStock.hbm.xml</value>

    </list>
    </property>
    <property name="dataSource">
    <ref local="dataSource"/>
    </property>
    <property name="hibernateProperties">
    <props>
    <prop key="hibernate.dialect">net.sf.hibernate.dialect.M ySQLDialect</prop>
    <prop key="hibernate.hbm2ddl.auto">update</prop>


    </props>
    </property>
    </bean>



    <bean id="transactionManager" class="org.springframework.orm.hibernate.Hibernate TransactionManager">
    <property name="sessionFactory">
    <ref bean="sessionFactory"/>
    </property>
    </bean>


    <!-- Persistence Layer -->


    <bean id="persistenceManager" class="com.myapp.common.PersistenceManagerImpl">
    <property name="budgetDAO">
    <ref local="budgetDAO"/>
    </property>
    </bean>



    <bean id="stockPersistenceManager" class="com.myapp.common.StockPersistenceManagerImp l">
    <property name="stockDAO">
    <ref local="stockDAO"/>
    </property>
    </bean>


    <bean id="budgetDAO" class="com.myapp.hibernate.HibernateDAOImpl">
    <property name="sessionFactory">
    <ref local="sessionFactory"/>
    </property>
    </bean>

    <bean id="stockDAO" class="com.myapp.hibernate.HibernateStockDAOImpl">
    <property name="sessionFactory">
    <ref local="sessionFactory"/>
    </property>
    </bean>

    <!-- Web Layer -->

    <bean name="/logon" class="com.myapp.action.LoginAction"
    singleton="false">
    <property name="persistenceManager">
    <ref bean="persistenceManager"/>
    </property>
    </bean>

    <bean name="/insert" class="com.myapp.action.InsertAction"
    singleton="false">
    <property name="persistenceManager">
    <ref bean="persistenceManager"/>
    </property>
    </bean>

    <bean name="/delete" class="com.myapp.action.DeleteAction"
    singleton="false">
    <property name="persistenceManager">
    <ref bean="persistenceManager"/>
    </property>
    </bean>


    <bean name="/query" class="com.myapp.action.QueryAction"
    singleton="false">
    <property name="persistenceManager">
    <ref bean="persistenceManager"/>
    </property>
    </bean>

    <bean name="/schedule" class="com.myapp.action.SchedulerAction"
    singleton="false">
    <property name="persistenceManager">
    <ref bean="persistenceManager"/>
    </property>
    <property name="scheduler">
    <ref bean="scheduler"/>
    </property>
    </bean>


    <bean name="/scheduleSetUp" class="com.myapp.action.SchedulerSetUpAction"
    singleton="false">
    <property name="scheduler">
    <ref bean="scheduler"/>
    </property>
    </bean>

    <bean name="/stock" class="com.myapp.action.StockNewsAction"
    singleton="false">
    <property name="stockPersistenceManager">
    <ref bean="stockPersistenceManager"/>
    </property>
    </bean>


    <!-- Scheduler Layer -->

    <bean name="budgetJob" class="org.springframework.scheduling.quartz.JobDe tailBean">
    <property name="jobClass">
    <value>com.myapp.scheduler.BudgetJob</value>
    </property>
    <property name="jobDataAsMap">
    <map>
    <entry key="persistenceManager">
    <ref bean="persistenceManager"/>
    </entry>

    </map>
    </property>

    </bean>

    <bean name="scheduler" class="com.myapp.scheduler.WorldCorpScheduler">
    <property name="budgetJob">
    <ref bean="budgetJob"/>
    </property>
    </bean>



    </beans>
    </code>

    Now, jobs scheduled are persistent, they get scheduled properly. HOwever, whenever the execution time comes, i always get a java.lang.NullPointerException in my DAO, at following line:

    getHibernateTemplate().saveOrUpdate(tmp);

    My guess is that it is because the 'persistenceManager' property is persisted.. but i can't figure out a solution for not making persistenceManager NOT persistent and still use it from applicationContext.
    Here is the code of my BudgetJob
    <code>
    /*
    * Copyright Marco Mistroni2004
    *
    * Implementation for a Budget Job to be scheduled
    *
    */
    package com.myapp.scheduler;



    import java.util.*;

    import com.myapp.hibernate.*;
    import org.quartz.StatefulJob;
    import org.quartz.JobDataMap;
    import org.quartz.JobExecutionContext;
    import org.quartz.JobExecutionException;

    import org.springframework.scheduling.quartz.QuartzJobBea n;

    import com.myapp.common.*;

    /**
    * <p>
    * A dumb implementation of Job, for unittesting purposes.
    * </p>
    *
    * @author James House
    */
    public class BudgetJob extends QuartzJobBean implements StatefulJob {

    private PersistenceManager pMgr = null;

    public void setPersistenceManager(PersistenceManager mgr) {
    System.err.println("**** BudgetJob. Setting PersistenceManager..");
    pMgr = mgr;
    }



    /*
    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~
    *
    * Interface.
    *
    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~
    */

    /**
    * <p>
    * Called by the <code>{@link org.quartz.Scheduler}</code> when a <code>{@link org.quartz.Trigger}</code>
    * fires that is associated with the <code>Job</code>.
    * </p>
    *
    * @throws JobExecutionException
    * if there is an exception while executing the job.
    */
    protected void executeInternal(JobExecutionContext context)
    throws JobExecutionException {
    System.err.println("---" + context.getJobDetail().getFullName()
    + " executing.[" + new Date() + "]");

    JobDataMap map = context.getJobDetail().getJobDataMap();
    try {
    System.err.println("*BJob.JobDataMap is:");
    for(Iterator it = context.getJobDetail().getJobDataMap().keySet().it erator(); it.hasNext() {
    System.err.println("WSC.BJDMAP:" + it.next());
    }
    Entry entry = (Entry)map.get(Constants.BUDGET_ENTRY);
    entry.setDate(new Date());
    System.err.println("Inserting entry:" + entry);
    if(pMgr == null){
    System.err.println("BJ. PersistenceManager isnull. getting it from jobdetail..");
    pMgr = (PersistenceManager)map.get("persistenceManager");
    } else
    System.err.println("BJ. PersistenceManager is NOT null...");
    pMgr.insert(entry);
    } catch(Exception e) {
    System.err.println(e);
    }
    }

    }
    </code>

    Anyone can give me help?

    how can i schedule a persistent Job which uses a bean defined in applicationContext?

    thanx in advance and regards
    marco

  • #2
    Can't be so difficult

    Now I have the same problem as you had.

    I have tried quite a lot and have read quite a lot and still can't get it working. I can't find any good documentation or tutorial or best practice on how to combine spring, hibernate and quartz.

    The closest I got was with that
    http://forum.springframework.org/sho...43&postcount=3

    What is the secret????

    Comment


    • #3
      What exactly are you having problems with? It would be useful if you could add some information, stacktrace if you have one, configuration, explanation of the problem, etc...... I think the imagedb example that ships with Spring has Quartz examples. The reference manual also covers this.
      http://www.springframework.org/docs/...eduling-quartz

      Comment


      • #4
        When using quartz persistent jobs, objects stored in JobDataMap must be serializable.

        Anyway, you can retrieve your beans from the applicationContext:
        Code:
        public class MyJob extends QuartzJobBean {
          private ApplicationContext applicationContext;
        
          public void setApplicationContext(ApplicationContext appContext) {
            applicationContext = appContext;
          }
        
           protected void executeInternal(JobExecutionContext context) {
               MyBean bean = (MyBean) applicationContext.getBean("MyBean");
               ....
           }
           ...
        }
        The Scheduler bean declaration:
        Code:
        <bean id="Scheduler"
            class="org.springframework.scheduling.quartz.SchedulerFactoryBean"
            lazy-init="false">
            <property name="applicationContextSchedulerContextKey"
              value="applicationContext"/>
            ....
        </bean>

        Comment


        • #5
          I'm using the configuration suggested by croudet above, with one addition: I have a Hibernate interceptor. The problem I'm having is that my interceptor is not being used. I have tried two approaches.

          1. Declare interceptor in Spring configuration:

          Code:
          	<bean id="temporalInterceptor" class="com.acme.TemporalInterceptor">
          		<property name="sessionFactory" ref="sessionFactory"/>
          	</bean>
          	<bean id="schedulerTransactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
          		<property name="sessionFactory" ref="sessionFactory"/>
          		<property name="entityInterceptorBeanName" value="temporalInterceptor"/>
          	</bean>
          	<bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
          		<property name="applicationContextSchedulerContextKey" value="applicationContext"/>
          		<property name="configLocation" value="classpath:quartz.properties"/>
          		<property name="dataSource" ref="jndiDataSource"/>
          		<property name="transactionManager" ref="schedulerTransactionManager"/>
          		<property name="triggerListeners">
          			<list>
          				<bean class="com.acme.TriggerListener"/>
          			</list>
          		</property>
          	</bean>
          The interceptor appears to be initialized during startup, but when a Quartz job gets fired off, it's no where to be found.

          2. Programmatically apply interceptor:

          Code:
          public class MyJob extends QuartzJobBean {
            private ApplicationContext applicationContext;
          
            public void setApplicationContext(ApplicationContext appContext) {
              applicationContext = appContext;
            }
          
             protected void executeInternal(JobExecutionContext context) {
                 MyBean bean = (MyBean) applicationContext.getBean("MyBean");
          
                 SessionFactory sessionFactory = bean.getSessionFactory();
                 TemporalInterceptor interceptor = new TemporalInterceptor();
                 Session session = SessionFactoryUtils.getSession(sessionFactory, interceptor, null);
          
                 session.setFlushMode(FlushMode.AUTO);
                 interceptor.setSessionFactory(sessionFactory);
                 ....
             }
             ...
          }
          This fails one at
          Code:
          SessionFactoryUtils.getSession(sessionFactory, interceptor, null)
          with a NullPointerException because the sessionFactory is NULL.

          Any suggestions welcome.

          Comment


          • #6
            Quick follow-up: #1 works fine. The reason it wasn't working for me initially was because I was triggering the job to run manually. This action used a different transactionManager that didn't have the intercepter applied to it.

            Comment


            • #7
              Milkwat,

              Could you please post your quartz.properties file ? I'm trying to do something similar to your setup, but without success. I'd really appreciate it. Thank you kindly.

              Comment


              • #8
                org.quartz.scheduler.instanceName=MyJobScheduler
                org.quartz.scheduler.instanceId=test01

                org.quartz.threadPool.class=org.quartz.simpl.Simpl eThreadPool
                org.quartz.threadPool.threadCount=5
                org.quartz.threadPool.threadPriority=5

                org.quartz.dataSource.myDS.jndiURL=java:comp/env/jdbc/MyDS

                org.quartz.jobStore.class=org.quartz.impl.jdbcjobs tore.JobStoreTX
                org.quartz.jobStore.driverDelegateClass=org.quartz .impl.jdbcjobstore.MSSQLDelegate
                org.quartz.jobStore.dataSource=myDS
                org.quartz.jobStore.tablePrefix=JB_
                org.quartz.jobStore.useProperties=true
                org.quartz.jobStore.isClustered=false

                Comment


                • #9
                  Thank you very much for your response. I managed to get things working after all

                  Comment

                  Working...
                  X