/*
* JBoss, Home of Professional Open Source
* Copyright 2006, JBoss Inc., and others contributors as indicated
* by the @authors tag. All rights reserved.
* See the copyright.txt in the distribution for a
* full listing of individual contributors.
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License, v. 2.1.
* This program is distributed in the hope that it will be useful, but WITHOUT A
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public License,
* v.2.1 along with this distribution; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
* (C) 2005-2006, JBoss Inc.
*/
package org.jboss.soa.esb.schedule;
import java.text.ParseException;
import java.util.Date;
import java.util.Properties;
import org.apache.log4j.Logger;
import org.quartz.CronTrigger;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.SimpleTrigger;
import org.quartz.StatefulJob;
import org.quartz.Trigger;
/**
* Scheduler job tied to the lifecycle.
*/
public class SchedulerJob
{
/**
* The logger for this class.
*/
private static Logger LOGGER = Logger.getLogger(SchedulerJob.class);
/**
* The job group used by scheduled jobs.
*/
private static final String JOB_GROUP = "ESBScheduler" ;
/**
* The base job name used by scheduled jobs.
*/
private static final String JOB_NAME = "ESBJob" ;
/**
* The job counter.
*/
private static long jobCounter ;
/**
* The name associated with this scheduler.
*/
private final String name ;
/**
* The job details.
*/
private final JobDetail jobDetail ;
/**
* The trigger associated with this job.
*/
private final Trigger trigger ;
/**
* The scheduler properties.
*/
private final Properties properties ;
/**
* Construct the job with the specified listener, trigger and properties.
* @param listener The job listener.
* @param trigger The associated trigger.
* @param properties Scheduler properties.
*/
private SchedulerJob(final String name, final SchedulerJobListener listener,
final Trigger trigger, final Properties properties)
{
this.name = name ;
this.jobDetail = new JobDetail(trigger.getName(), JOB_GROUP, ESBScheduledJob.class) ;
final JobDataMap jobDataMap = new JobDataMap() ;
jobDataMap.put(SchedulerJobListener.class.getName(), listener) ;
jobDataMap.put(ClassLoader.class.getName(), Thread.currentThread().getContextClassLoader()) ;
jobDetail.setJobDataMap(jobDataMap) ;
this.trigger = trigger ;
this.properties = properties ;
}
/**
* Start or resume the operation of the trigger.
* @throws SchedulingException for errors during the operation.
*/
public void start()
throws SchedulingException
{
if (LOGGER.isDebugEnabled())
{
LOGGER.debug("Starting SchedulerJob " + getName()) ;
}
SchedulerResource.getSchedulerResource().start(trigger, jobDetail, properties) ;
}
/**
* Pause the operation of the trigger.
* @throws SchedulingException for errors during the operation.
*/
public void pause()
throws SchedulingException
{
if (LOGGER.isDebugEnabled())
{
LOGGER.debug("Pausing SchedulerJob " + getName()) ;
}
SchedulerResource.getSchedulerResource().pause(trigger) ;
}
/**
* Destroy the trigger.
* @throws SchedulingException for errors during the operation.
*/
public void destroy()
throws SchedulingException
{
if (LOGGER.isDebugEnabled())
{
LOGGER.debug("Destroying SchedulerJob " + getName()) ;
}
SchedulerResource.getSchedulerResource().destroy(trigger) ;
}
/**
* Get a name associated with this schedule.
* @return a name for this schedule.
*/
private String getName()
{
if (name != null)
{
return name + '/' + trigger.getName();
}
else
{
return trigger.getName() ;
}
}
/**
* Create a job based on an interval.
* @param name The name for the job.
* @param listener The listener to fire on schedule.
* @param interval The specified interval.
* @param properties Any scheduler properties that may be required.
* @return The Scheduler Job managing the schedule.
*/
public static SchedulerJob createIntervalSchedulerJob(final String name, final SchedulerJobListener listener,
final long interval, final Properties properties)
{
final SimpleTrigger trigger = new SimpleTrigger(getJobName(), JOB_GROUP, SimpleTrigger.REPEAT_INDEFINITELY, interval) ;
trigger.setMisfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT) ;
return new SchedulerJob(name, listener, trigger, properties) ;
}
/**
* Create a job based on an interval.
* @param name The name for the job.
* @param listener The listener to fire on schedule.
* @param interval The specified interval.
* @param startDate The start date of the trigger or null if not constrained.
* @param endDate The end date of the trigger or null if not constrained.
* @param properties Any scheduler properties that may be required.
* @return The Scheduler Job managing the schedule.
*/
public static SchedulerJob createIntervalSchedulerJob(final String name, final SchedulerJobListener listener,
final long interval, final Date startDate, final Date endDate, final Properties properties)
{
final SimpleTrigger trigger = new SimpleTrigger(getJobName(), JOB_GROUP, SimpleTrigger.REPEAT_INDEFINITELY, interval) ;
trigger.setMisfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT) ;
if (startDate != null)
{
trigger.setStartTime(startDate) ;
}
if (endDate != null)
{
trigger.setEndTime(endDate) ;
}
return new SchedulerJob(name, listener, trigger, properties) ;
}
/**
* Create a job based on an interval.
* @param name The name for the job.
* @param listener The listener to fire on schedule.
* @param interval The specified interval.
* #param execCount The execution count.
* @param startDate The start date of the trigger or null if not constrained.
* @param endDate The end date of the trigger or null if not constrained.
* @param properties Any scheduler properties that may be required.
* @return The Scheduler Job managing the schedule.
*/
public static SchedulerJob createIntervalSchedulerJob(final String name, final SchedulerJobListener listener,
final long interval, final int execCount, final Date startDate, final Date endDate, final Properties properties)
{
final SimpleTrigger trigger = new SimpleTrigger(getJobName(), JOB_GROUP, execCount-1, interval) ;
trigger.setMisfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT) ;
if (startDate != null)
{
trigger.setStartTime(startDate) ;
}
if (endDate != null)
{
trigger.setEndTime(endDate) ;
}
return new SchedulerJob(name, listener, trigger, properties) ;
}
/**
* Create a job based on cron.
* @param name The name for the job.
* @param listener The listener to fire on schedule.
* @param cronExpression The cron expression.
* @param startDate The start date of the trigger or null if not constrained.
* @param endDate The end date of the trigger or null if not constrained.
* @param properties Any scheduler properties that may be required.
* @return The Scheduler Job managing the schedule.
* @throws ParseException for errors in the cron expression.
*/
public static SchedulerJob createCronSchedulerJob(final String name, final SchedulerJobListener listener,
final String cronExpression, final Date startDate, final Date endDate, final Properties properties)
throws ParseException
{
final CronTrigger trigger = new CronTrigger(getJobName(), JOB_GROUP, cronExpression) ;
trigger.setMisfireInstruction(CronTrigger.MISFIRE_INSTRUCTION_FIRE_ONCE_NOW) ;
if (startDate != null)
{
trigger.setStartTime(startDate) ;
}
if (endDate != null)
{
trigger.setEndTime(endDate) ;
}
return new SchedulerJob(name, listener, trigger, properties) ;
}
/**
* Get the name of the next job.
* @return The job name.
*/
private static String getJobName()
{
final long id ;
synchronized(SchedulerJob.class)
{
id = ++jobCounter ;
}
return JOB_NAME + id ;
}
/**
* The scheduled job for executing the listener.
* @author kevin
*/
public static class ESBScheduledJob implements StatefulJob
{
/**
* Execute the current job.
*/
public void execute(final JobExecutionContext jobExecutionContext)
throws JobExecutionException
{
final JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap() ;
final SchedulerJobListener listener = (SchedulerJobListener) jobDataMap.get(SchedulerJobListener.class.getName()) ;
final ClassLoader tcc = (ClassLoader)jobDataMap.get(ClassLoader.class.getName()) ;
final Thread thread = Thread.currentThread() ;
final ClassLoader currentClassLoader = thread.getContextClassLoader() ;
thread.setContextClassLoader(tcc) ;
try
{
listener.onSchedule() ;
}
catch (final SchedulingException se)
{
final JobExecutionException jobException = new JobExecutionException("Scheduling exception on " + jobExecutionContext.getTrigger().getName()) ;
jobException.initCause(se) ;
throw jobException ;
}
catch (final Throwable th)
{
final JobExecutionException jobException = new JobExecutionException("Unexpected exception on " + jobExecutionContext.getTrigger().getName()) ;
jobException.initCause(th) ;
throw jobException ;
}
finally
{
thread.setContextClassLoader(currentClassLoader) ;
}
}
}
}