Curt
Curt

Reputation: 3024

How to Get Spring Quartz Trigger to Fire Using Scheduler

I have never used a quartz scheduler before and I am having trouble creating a Quartz Job. The trigger I have configured via a cronExpression does not fire and I do not see what I am missing.

Thanks in advance for any help or advice!

I am using:

Scheduler:

<beans default-autowire="byName"
    xmlns="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"  
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-3.1.xsd">

    <!-- Quartz Scheduler -->
    <bean id="scheduler"
        class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="dataSource" ref="itc5DataSource" />
        <property name="applicationContextSchedulerContextKey" value="applicationContext" />
        <property name="quartzProperties">
            <props>
                <prop key="org.quartz.scheduler.instanceName">${cepis.portal.scheduler.name}</prop>
                <prop key="org.quartz.scheduler.instanceId">${cepis.portal.scheduler.instanceId}</prop>
                <prop key="org.quartz.threadPool.class">${cepis.portal.scheduler.threadPool.class}</prop>
                <prop key="org.quartz.threadPool.threadCount">${cepis.portal.scheduler.threadPool.threadCount}
                </prop>
                <prop key="org.quartz.jobStore.class">${cepis.portal.scheduler.jobStore.class}</prop>
                <prop key="org.quartz.jobStore.isClustered">${cepis.portal.scheduler.jobStore.isClustered}</prop>
                <prop key="org.quartz.jobStore.useProperties">${cepis.portal.scheduler.jobStore.useProperties}
                </prop>
                <prop key="org.quartz.jobStore.tablePrefix">${cepis.portal.scheduler.jobStore.tablePrefix}</prop>
                <prop key="org.quartz.jobStore.driverDelegateClass">${cepis.portal.scheduler.jobStore.driverDelegateClass}
                </prop>
                <prop key="org.quartz.jobStore.selectWithLockSQL">${cepis.portal.scheduler.jobStore.selectWithLockSQL}
                </prop>
            </props>
        </property>

        <property name="jobDetails">
            <list>
                <ref bean="updateNoShowAppointmentJob" />           
            </list>
        </property>

        <property name="triggers">
            <list>
                <ref bean="updateNoShowTrigger" />          
            </list>
        </property>

    </bean>

    <!-- *************************************************************************************************  -->

    <bean id="updateNoShowAppointmentJob" class="org.springframework.scheduling.quartz.JobDetailBean">
        <property name="name" value="CEPIS-UpdateNoShows" />
        <property name="group" value="Appointments" />              
        <property name="jobClass" value="edu.uky.cepis.util.cron.job.UpdateNoShowAppointmentJob" />
    </bean>


    <!-- *************************************************************************************************  --> 

    <bean id="updateNoShowTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
        <property name="name" value="UpdateNoShow" />
        <property name="group" value="Appointments" />
        <property name="jobDetail" ref="updateNoShowAppointmentJob" />
        <!--  Do this every 60 seconds.-->
        <property name="cronExpression" value="0 * * * * ?" />
    </bean>



</beans>

Job:

/**
 * 
 */
package edu.uky.cepis.util.cron.job;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.apache.log4j.Logger;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.SchedulerException;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.quartz.QuartzJobBean;

import edu.uky.cepis.service.AdvisingSessionService;
import edu.uky.cepis.domain.AdvisingSession;

/**
 * @author cawalk4
 * 
 * Purpose: Update all appointments with a date before the current date time
 * Setting the appointmentStatus to "No Show"
 * 
 */
public class UpdateNoShowAppointmentJob extends QuartzJobBean {

    private static Logger log = Logger.getLogger(
        UpdateNoShowAppointmentJob.class);

    private AdvisingSessionService advisingSessionService;

    private static String NO_SHOW = "No Show";

    @Override
    protected void executeInternal(JobExecutionContext context)
            throws JobExecutionException {

        log.debug("Running UpdateNoShowAppointmentJob at " + new Date());

        ApplicationContext appContext = null;

        try {
            appContext = (ApplicationContext) context.getScheduler()
                .getContext().get("applicationContext");
        } catch (SchedulerException se) {
            System.err.println(se);
        }

        try {
            advisingSessionService = (AdvisingSessionService) appContext
                .getBean("advisingSessionService", AdvisingSessionService.class);
        } catch (Exception e) {
            System.err.println(e);
        }
        if (advisingSessionService != null) {
            List<AdvisingSession> advisingSessionList =
                new ArrayList<AdvisingSession>(0);

            advisingSessionList = advisingSessionService.getNewNoShowAdvisingSessions();

            if (advisingSessionList == null) {
                log.debug("advisingSessionSlotlist is null.");
                return;
            } else if (advisingSessionList.isEmpty()) {
                log.debug("There are no new No Show advising appointments.");
                return;
            }

            log.debug("Total no show e-mails are: " + advisingSessionList.size());

            // Update the appointments 

            for(AdvisingSession advisingSession : advisingSessionList){

                advisingSessionService.updateAdvisingSession(                   
                        advisingSession,
                        advisingSession.getSessionType(), 
                        NO_SHOW,
                        advisingSession.getPreSessionText(), 
                        advisingSession.getSessionText(), 
                        advisingSession.getStudentNotes(), 
                        advisingSession.getAdvisorNotes(), 
                        advisingSession.getAdvisingSessionSlot(), 
                        advisingSession.getNoShowEmailSentBoolean());
            }
        } else {
            log.debug("advisingSessionService is null.");
        }
    }

    public void setadvisingSessionService(AdvisingSessionService advisingSessionService) {
        this.advisingSessionService = advisingSessionService;
    }

    public AdvisingSessionService getadvisingSessionService() {
        return advisingSessionService;
    }
}

Upvotes: 2

Views: 2937

Answers (1)

stevevls
stevevls

Reputation: 10843

If you remove the portion of the XML that sets the jobDetails property of your scheduler bean, it should work as expected.

If you look at the javadoc for setTriggers on Spring's SchedulerAccessor class (that's the superclass of SchedulerFactoryBean), you can see that:

If the Trigger determines the corresponding JobDetail itself, the job will be automatically registered with the Scheduler. Else, the respective JobDetail needs to be registered via the "jobDetails" property of this FactoryBean.

What they don't mention is that if you have already registered the JobDetail, it will prevent the Trigger from scheduling its referenced job. The source code for the addTriggerToScheduler method in SchedulerAccessor has this chunk of code:

JobDetail jobDetail = findJobDetail(trigger);
if (jobDetail != null) {
    // Automatically register the JobDetail too.
    if (!this.jobDetails.contains(jobDetail) && addJobToScheduler(jobDetail)) {
        this.jobDetails.add(jobDetail);
    }
}

You can see, then, that if the jobDetails already contains your job, the if condition will fail fast and the addJobToScheduler method will never be invoked.

Upvotes: 1

Related Questions