/*
* Copyright 1999-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.cocoon.components.cron;
import java.text.ParseException;
import java.util.Arrays;
import java.util.Date;
import java.util.Map;
import java.util.NoSuchElementException;
import org.apache.avalon.framework.CascadingException;
import org.apache.avalon.framework.activity.Disposable;
import org.apache.avalon.framework.activity.Initializable;
import org.apache.avalon.framework.activity.Startable;
import org.apache.avalon.framework.component.Component;
import org.apache.avalon.framework.configuration.Configurable;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.context.Context;
import org.apache.avalon.framework.context.ContextException;
import org.apache.avalon.framework.context.Contextualizable;
import org.apache.avalon.framework.logger.AbstractLogEnabled;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.avalon.framework.service.ServiceException;
import org.apache.avalon.framework.service.ServiceManager;
import org.apache.avalon.framework.service.Serviceable;
import org.apache.avalon.framework.thread.ThreadSafe;
import org.apache.cocoon.Constants;
import org.quartz.CronTrigger;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SimpleTrigger;
import org.quartz.Trigger;
import org.quartz.impl.DirectSchedulerFactory;
import org.quartz.simpl.RAMJobStore;
import EDU.oswego.cs.dl.util.concurrent.BoundedBuffer;
import EDU.oswego.cs.dl.util.concurrent.LinkedQueue;
import EDU.oswego.cs.dl.util.concurrent.PooledExecutor;
/**
* This component can either schedule jobs or directly execute one.
*
* @author <a href="mailto:giacomo@apache.org">Giacomo Pati</a>
* @version CVS $Id: QuartzJobScheduler.java,v 1.12 2004/03/11 22:05:12 sylvain Exp $
*
* @since 2.1.1
*/
public class QuartzJobScheduler
extends AbstractLogEnabled
implements JobScheduler, Component, ThreadSafe, Serviceable, Configurable, Startable, Disposable,
Contextualizable, Initializable {
private org.apache.cocoon.environment.Context environmentContext;
/** ThreadPool policy RUN */
private static final String POLICY_RUN = "RUN";
/** ThreadPool policy WAIT */
private static final String POLICY_WAIT = "WAIT";
/** ThreadPool policy ABORT */
private static final String POLICY_ABORT = "ABORT";
/** ThreadPool policy DISCARD */
private static final String POLICY_DISCARD = "DISCARD";
/** ThreadPool policy DISCARD-OLDEST */
private static final String POLICY_DISCARD_OLDEST = "DISCARDOLDEST";
/** Map key for the component role */
static final String DATA_MAP_ROLE = "QuartzJobScheduler.ROLE";
/** Map key for the job object */
static final String DATA_MAP_OBJECT = "QuartzJobScheduler.Object";
/** Map key for the job name */
static final String DATA_MAP_NAME = "QuartzJobScheduler.JobName";
/** Map key for the service manager */
static final String DATA_MAP_MANAGER = "QuartzJobScheduler.ServiceManager";
/** Map key for the environment context (needed by BackgroundEnvironment) */
static final String DATA_MAP_ENV_CONTEXT = "QuartzJobScheduler.EnvironmentContext";
/** Map key for the logger */
static final String DATA_MAP_LOGGER = "QuartzJobScheduler.Logger";
/** Map key for the concurrent run property */
static final String DATA_MAP_RUN_CONCURRENT = "QuartzJobScheduler.RunConcurrently";
/** Map key for additional Parameters */
static final String DATA_MAP_PARAMETERS = "QuartzJobScheduler.Parameters";
/** Map key for additional Object Map */
static final String DATA_MAP_OBJECTMAP = "QuartzJobScheduler.Map";
/** Map key for the last JobExecutionContext */
static final String DATA_MAP_JOB_EXECUTION_CONTEXT = "QuartzJobScheduler.JobExecutionContext";
/** The group name */
static final String DEFAULT_QUARTZ_JOB_GROUP = "Cocoon";
/** The scheduler name */
static final String DEFAULT_QUARTZ_SCHEDULER_NAME = "Cocoon";
/** The PooledExecutor instance */
private PooledExecutor executor;
/** The quartz scheduler */
private Scheduler scheduler;
/** The ServiceManager instance */
private ServiceManager manager;
/** The configuration, parsed in initialize() */
private Configuration config;
/** Should we wait for running jobs to terminate on shutdown ? */
private boolean m_shutdownGraceful;
/* (non-Javadoc)
* @see org.apache.cocoon.components.cron.JobScheduler#getJobNames()
*/
public String[] getJobNames() {
try {
final String[] names = scheduler.getJobNames(DEFAULT_QUARTZ_JOB_GROUP);
Arrays.sort(names);
return names;
} catch (final SchedulerException se) {
getLogger().error("could not gather job names", se);
}
return new String[0];
}
/* (non-Javadoc)
* @see org.apache.cocoon.components.cron.JobScheduler#getSchedulerEntry(java.lang.String)
*/
public JobSchedulerEntry getJobSchedulerEntry(String jobname) {
try {
return new QuartzJobSchedulerEntry(jobname, scheduler);
} catch (final Exception e) {
getLogger().error("cannot create QuartzJobSchedulerEntry", e);
}
return null;
}
/* (non-Javadoc)
* @see org.apache.cocoon.components.cron.JobScheduler#addJob(java.lang.String, java.lang.Object, java.lang.String, boolean, org.apache.avalon.framework.parameters.Parameters, java.util.Map)
*/
public void addJob(final String name, final Object job, final String cronSpec, final boolean canRunConcurrently,
final Parameters params, final Map objects)
throws CascadingException {
final JobDataMap jobDataMap = new JobDataMap();
jobDataMap.put(DATA_MAP_OBJECT, job);
addJob(name, jobDataMap, cronSpec, canRunConcurrently, params, objects);
}
/* (non-Javadoc)
* @see org.apache.cocoon.components.cron.JobScheduler#addJob(java.lang.String, java.lang.String, java.lang.String, boolean, org.apache.avalon.framework.parameters.Parameters, java.util.Map)
*/
public void addJob(final String name, final String jobrole, final String cronSpec,
final boolean canRunConcurrently, final Parameters params, final Map objects)
throws CascadingException {
final JobDataMap jobDataMap = new JobDataMap();
jobDataMap.put(DATA_MAP_ROLE, jobrole);
addJob(name, jobDataMap, cronSpec, canRunConcurrently, params, objects);
}
/* (non-Javadoc)
* @see org.apache.cocoon.components.cron.JobScheduler#addJob(java.lang.String, java.lang.Object, java.lang.String, boolean)
*/
public void addJob(final String name, final Object job, final String cronSpec, final boolean canRunConcurrently)
throws CascadingException {
if (!(job instanceof CronJob) && !(job instanceof Runnable) && !(job instanceof Job)) {
throw new CascadingException("Job object is neither an instance of " + CronJob.class.getName() + "," +
Runnable.class.getName() + " nor " + Job.class.getName());
}
addJob(name, job, cronSpec, canRunConcurrently, null, null);
}
/* (non-Javadoc)
* @see org.apache.cocoon.components.cron.JobScheduler#addJob(java.lang.String, java.lang.String, java.lang.String, boolean)
*/
public void addJob(final String name, final String jobrole, final String cronSpec, final boolean canRunConcurrently)
throws CascadingException {
addJob(name, jobrole, cronSpec, canRunConcurrently, null, null);
}
/**
* Schedule a period job. Note that if a Job already has same name then it is overwritten.
*
* @param name the name of the job
* @param jobrole The Avalon components role name of the job itself
* @param period Every period seconds this job is started
* @param canRunConcurrently whether this job can run even previous scheduled runs are still running
* @param params additional Parameters to be passed to the job
* @param objects additional objects to be passed to the job
*
* @throws CascadingException in case of failures
*/
public void addPeriodicJob(String name, String jobrole, long period, boolean canRunConcurrently, Parameters params,
Map objects)
throws CascadingException {
final JobDataMap jobDataMap = new JobDataMap();
jobDataMap.put(DATA_MAP_ROLE, jobrole);
final long ms = period * 1000;
final SimpleTrigger timeEntry =
new SimpleTrigger(name, DEFAULT_QUARTZ_JOB_GROUP, new Date(System.currentTimeMillis() + ms), null,
SimpleTrigger.REPEAT_INDEFINITELY, ms);
addJob(name, jobDataMap, timeEntry, canRunConcurrently, params, objects);
}
/**
* Schedule a periodic job. The job is started the first time when the period has passed. Note that if a job with
* the same name has already beed added it is overwritten.
*
* @param name the name of the job
* @param job The job object itself. It must implement either CronJob, Runnable or might also be an implementation
* specific class (i.e. org.quartz.Job)
* @param period Every period seconds this job is started
* @param canRunConcurrently whether this job can run even previous scheduled runs are still running
* @param params Additional Parameters to setup CronJob
* @param objects A Map with additional object to setup CronJob
*/
public void addPeriodicJob(String name, Object job, long period, boolean canRunConcurrently, Parameters params,
Map objects)
throws CascadingException {
if (!(job instanceof CronJob) && !(job instanceof Runnable) && !(job instanceof Job)) {
throw new CascadingException("Job object is neither an instance of " + CronJob.class.getName() + "," +
Runnable.class.getName() + " nor " + Job.class.getName());
}
final JobDataMap jobDataMap = new JobDataMap();
jobDataMap.put(DATA_MAP_OBJECT, job);
final long ms = period * 1000;
final SimpleTrigger timeEntry =
new SimpleTrigger(name, DEFAULT_QUARTZ_JOB_GROUP, new Date(System.currentTimeMillis() + ms), null,
SimpleTrigger.REPEAT_INDEFINITELY, ms);
addJob(name, jobDataMap, timeEntry, canRunConcurrently, params, objects);
}
/* (non-Javadoc)
* @see org.apache.avalon.framework.configuration.Configurable#configure(org.apache.avalon.framework.configuration.Configuration)
*/
public void configure(final Configuration config)
throws ConfigurationException {
this.config = config;
}
/* (non-Javadoc)
* @see org.apache.avalon.framework.activity.Disposable#dispose()
*/
public void dispose() {
try {
if (getLogger().isInfoEnabled()) {
getLogger().info("shutting down scheduler " +
(m_shutdownGraceful ? "graceful (waiting for running jobs to complete)"
: "immediately (killing running jobs)"));
}
scheduler.shutdown(m_shutdownGraceful);
scheduler = null;
} catch (final SchedulerException se) {
getLogger().error("failure during scheduler shutdown", se);
}
this.executor = null;
}
/* (non-Javadoc)
* @see org.apache.avalon.framework.context.Contextualizable#contextualize(org.apache.avalon.framework.context.Context)
*/
public void contextualize(Context context) throws ContextException {
this.environmentContext = (org.apache.cocoon.environment.Context)context.get(Constants.CONTEXT_ENVIRONMENT_CONTEXT);
}
public void initialize() throws Exception {
try {
// If cocoon reloads (or is it the container that reload us?)
// we cannot create the same scheduler again
final String runID = new Date().toString().replace(' ', '_');
final ThreadPool pool = createThreadPool(this.config.getChild("thread-pool"));
DirectSchedulerFactory.getInstance().createScheduler(DEFAULT_QUARTZ_SCHEDULER_NAME, runID, pool,
new RAMJobStore());
// scheduler = DirectSchedulerFactory.getInstance().getScheduler(DEFAULT_QUARTZ_SCHEDULER_NAME, runID);
scheduler = DirectSchedulerFactory.getInstance().getScheduler(DEFAULT_QUARTZ_SCHEDULER_NAME);
} catch (final SchedulerException se) {
throw new ConfigurationException("cannot create a quartz scheduler", se);
}
final Configuration[] triggers = this.config.getChild("triggers").getChildren("trigger");
createTriggers(triggers);
// We're finished with the configuration
this.config = null;
if (getLogger().isDebugEnabled() && (triggers.length == 0)) {
getLogger().debug("no triggers configured at startup");
}
}
/* (non-Javadoc)
* @see org.apache.cocoon.components.cron.JobScheduler#fireTarget(java.lang.Object)
*/
public boolean fireJob(final Object job) {
return fireJob(job.getClass().getName(), job);
}
/* (non-Javadoc)
* @see org.apache.cocoon.components.cron.JobScheduler#fireTarget(java.lang.String)
*/
public boolean fireJob(final String jobrole) {
Object job = null;
try {
job = manager.lookup(jobrole);
return fireJob(jobrole, job);
} catch (final ServiceException se) {
getLogger().error("cannot fire job " + jobrole, se);
} finally {
manager.release(job);
}
return false;
}
/* (non-Javadoc)
* @see org.apache.cocoon.components.cron.JobScheduler#fireJob(java.lang.Object, org.apache.avalon.framework.parameters.Parameters, java.util.Map)
*/
public boolean fireJob(final Object job, final Parameters params, final Map objects)
throws CascadingException {
if (job instanceof ConfigurableCronJob) {
((ConfigurableCronJob)job).setup(params, objects);
}
return fireJob(job);
}
/* (non-Javadoc)
* @see org.apache.cocoon.components.cron.JobScheduler#fireJob(java.lang.String, org.apache.avalon.framework.parameters.Parameters, java.util.Map)
*/
public boolean fireJob(final String jobrole, final Parameters params, final Map objects)
throws CascadingException {
Object job = null;
try {
job = manager.lookup(jobrole);
if (job instanceof ConfigurableCronJob) {
((ConfigurableCronJob)job).setup(params, objects);
}
return fireJob(jobrole, job);
} catch (final ServiceException se) {
getLogger().error("cannot fire job " + jobrole, se);
} finally {
manager.release(job);
}
return false;
}
/* (non-Javadoc)
* @see org.apache.cocoon.components.cron.JobScheduler#fireJobAt(java.util.Date, java.lang.String, java.lang.Object)
*/
public void fireJobAt(final Date date, final String name, final Object job)
throws CascadingException {
fireJobAt(date, name, job, null, null);
}
/* (non-Javadoc)
* @see org.apache.cocoon.components.cron.JobScheduler#fireJobAt(java.util.Date, java.lang.String, java.lang.String)
*/
public void fireJobAt(final Date date, final String name, final String jobrole)
throws CascadingException {
fireJobAt(date, name, jobrole, null, null);
}
/* (non-Javadoc)
* @see org.apache.cocoon.components.cron.JobScheduler#fireJobAt(java.util.Date, java.lang.String, java.lang.Object, org.apache.avalon.framework.parameters.Parameters, java.util.Map)
*/
public void fireJobAt(final Date date, final String name, final Object job, final Parameters params,
final Map objects)
throws CascadingException {
final JobDataMap jobDataMap = new JobDataMap();
jobDataMap.put(DATA_MAP_OBJECT, job);
addJob(name, jobDataMap, date, true, params, objects);
}
/* (non-Javadoc)
* @see org.apache.cocoon.components.cron.JobScheduler#fireJobAt(java.util.Date, java.lang.String, java.lang.String, org.apache.avalon.framework.parameters.Parameters, java.util.Map)
*/
public void fireJobAt(final Date date, final String name, final String jobrole, final Parameters params,
final Map objects)
throws CascadingException {
final JobDataMap jobDataMap = new JobDataMap();
jobDataMap.put(DATA_MAP_ROLE, jobrole);
addJob(name, jobDataMap, date, true, params, objects);
}
/* (non-Javadoc)
* @see org.apache.cocoon.components.cron.JobScheduler#removeJob(java.lang.String)
*/
public void removeJob(final String name)
throws NoSuchElementException {
try {
if (scheduler.deleteJob(name, DEFAULT_QUARTZ_JOB_GROUP)) {
getLogger().info("job " + name + " removed by request");
} else {
getLogger().error("couldn't remove requested job " + name);
}
} catch (final SchedulerException se) {
getLogger().error("cannot remove job " + name, se);
throw new NoSuchElementException(se.getMessage());
}
}
/* (non-Javadoc)
* @see org.apache.avalon.framework.service.Serviceable#service(org.apache.avalon.framework.service.ServiceManager)
*/
public void service(final ServiceManager manager)
throws ServiceException {
this.manager = manager;
}
/* (non-Javadoc)
* @see org.apache.avalon.framework.activity.Startable#start()
*/
public void start()
throws Exception {
scheduler.start();
}
/* (non-Javadoc)
* @see org.apache.avalon.framework.activity.Startable#stop()
*/
public void stop()
throws Exception {
scheduler.pause();
}
/**
* Add a job to the scheduler
*
* @param name The name of the job to add
* @param jobDataMap The JobDataMap to use for this job
* @param date the date to schedule this job
* @param canRunConcurrently whether this job can be run concurrently
* @param params Additional Parameters to setup CronJob
* @param objects A Map with additional object to setup CronJob
*
* @throws CascadingException thrown in case of errors
*/
private void addJob(final String name, final JobDataMap jobDataMap, final Date date,
final boolean canRunConcurrently, final Parameters params, final Map objects)
throws CascadingException {
final SimpleTrigger trigger = new SimpleTrigger(name, DEFAULT_QUARTZ_JOB_GROUP, date);
addJob(name, jobDataMap, trigger, canRunConcurrently, params, objects);
}
/**
* Add a job to the scheduler
*
* @param name The name of the job to add
* @param jobDataMap The JobDataMap to use for this job
* @param cronSpec a Cron time expression
* @param canRunConcurrently whether this job can be run concurrently
* @param params Additional Parameters to setup CronJob
* @param objects A Map with additional object to setup CronJob
*
* @throws CascadingException thrown in case of errors
*/
private void addJob(final String name, final JobDataMap jobDataMap, final String cronSpec,
final boolean canRunConcurrently, final Parameters params, final Map objects)
throws CascadingException {
final CronTrigger cronJobEntry = new CronTrigger(name, DEFAULT_QUARTZ_JOB_GROUP);
try {
cronJobEntry.setCronExpression(cronSpec);
} catch (final ParseException pe) {
throw new CascadingException(pe.getMessage(), pe);
}
addJob(name, jobDataMap, cronJobEntry, canRunConcurrently, params, objects);
}
/**
* Add a job to the scheduler
*
* @param name The name of the job to add
* @param jobDataMap The JobDataMap to use for this job
* @param trigger a Trigger
* @param canRunConcurrently whether this job can be run concurrently
* @param params Additional Parameters to setup CronJob (might be null)
* @param objects A Map with additional object to setup CronJob (might be null)
*
* @throws CascadingException thrown in case of errors
*/
private void addJob(final String name, final JobDataMap jobDataMap, final Trigger trigger,
final boolean canRunConcurrently, final Parameters params, final Map objects)
throws CascadingException {
try {
final JobDetail jobdetail = scheduler.getJobDetail(name, DEFAULT_QUARTZ_JOB_GROUP);
if (jobdetail != null) {
removeJob(name);
}
} catch (final SchedulerException se) {
}
jobDataMap.put(DATA_MAP_NAME, name);
jobDataMap.put(DATA_MAP_LOGGER, getLogger());
jobDataMap.put(DATA_MAP_MANAGER, manager);
jobDataMap.put(DATA_MAP_RUN_CONCURRENT, new Boolean(canRunConcurrently));
jobDataMap.put(DATA_MAP_ENV_CONTEXT, this.environmentContext);
if (null != params) {
jobDataMap.put(DATA_MAP_PARAMETERS, params);
}
if (null != objects) {
jobDataMap.put(DATA_MAP_OBJECTMAP, objects);
}
final JobDetail detail = new JobDetail(name, DEFAULT_QUARTZ_JOB_GROUP, QuartzJobExecutor.class);
detail.setJobDataMap(jobDataMap);
if (getLogger().isInfoEnabled()) {
getLogger().info("Adding CronJob '" + trigger.getFullName() + "'");
}
try {
scheduler.scheduleJob(detail, trigger);
} catch (final SchedulerException se) {
throw new CascadingException(se.getMessage(), se);
}
if (getLogger().isDebugEnabled()) {
if (trigger instanceof CronTrigger) {
getLogger().debug("Time schedule summary:\n" + ((CronTrigger)trigger).getExpressionSummary());
} else {
getLogger().debug("Next scheduled time: " + trigger.getNextFireTime());
}
}
}
/**
* Create a ThreadPool
*
* @param poolConfig Configuration element for the thread pool
*
* @return ThreadPool
*/
private ThreadPool createThreadPool(final Configuration poolConfig) {
final boolean useQueueing = poolConfig.getChild("use-queueing").getValueAsBoolean(false);
final int queueSize = poolConfig.getChild("queue-size").getValueAsInteger(-1);
if (useQueueing) {
if (queueSize > 0) {
this.executor = new PooledExecutor(new BoundedBuffer(queueSize));
} else {
this.executor = new PooledExecutor(new LinkedQueue());
}
} else {
this.executor = new PooledExecutor();
}
final int maxPoolSize = poolConfig.getChild("max-pool-size").getValueAsInteger(-1);
if (maxPoolSize > 0) {
this.executor.setMaximumPoolSize(maxPoolSize);
} else {
this.executor.setMaximumPoolSize(PooledExecutor.DEFAULT_MAXIMUMPOOLSIZE);
}
final int minPoolSize = poolConfig.getChild("min-pool-size").getValueAsInteger(-1);
if (minPoolSize > 0) {
this.executor.setMinimumPoolSize(minPoolSize);
} else {
this.executor.setMinimumPoolSize(PooledExecutor.DEFAULT_MINIMUMPOOLSIZE);
}
final int keepAliveTimeMs = poolConfig.getChild("keep-alive-time-ms").getValueAsInteger(-1);
if (keepAliveTimeMs > 0) {
this.executor.setKeepAliveTime(keepAliveTimeMs);
} else {
this.executor.setKeepAliveTime(PooledExecutor.DEFAULT_KEEPALIVETIME);
}
final String blockPolicy = poolConfig.getChild("block-policy").getValue(null);
if (blockPolicy != null) {
if (blockPolicy.equalsIgnoreCase(POLICY_ABORT)) {
this.executor.abortWhenBlocked();
} else if (blockPolicy.equalsIgnoreCase(POLICY_DISCARD)) {
this.executor.discardWhenBlocked();
} else if (blockPolicy.equalsIgnoreCase(POLICY_DISCARD_OLDEST)) {
this.executor.discardOldestWhenBlocked();
} else if (blockPolicy.equalsIgnoreCase(POLICY_RUN)) {
this.executor.runWhenBlocked();
} else if (blockPolicy.equalsIgnoreCase(POLICY_WAIT)) {
this.executor.waitWhenBlocked();
} else {
getLogger().warn("Unknown block-policy configuration '" + blockPolicy + "'. Should be one of '" +
POLICY_ABORT + "','" + POLICY_DISCARD + "','" + POLICY_DISCARD_OLDEST + "','" +
POLICY_RUN + "','" + POLICY_WAIT + "'. Will use '" + POLICY_RUN + "'");
}
}
m_shutdownGraceful = poolConfig.getChild("shutdown-graceful").getValueAsBoolean(true);
final int shutdownWaitTimeMs = poolConfig.getChild("shutdown-wait-time-ms").getValueAsInteger(-1);
final ThreadPool pool = new ThreadPool(this.executor, shutdownWaitTimeMs);
pool.enableLogging(getLogger());
if (getLogger().isInfoEnabled()) {
getLogger().info("using a PooledExecutor as ThreadPool with queueing=" + useQueueing +
(useQueueing ? (",queue-size=" + ((queueSize > 0) ? ("" + queueSize) : "default")) : "") +
",max-pool-size=" + this.executor.getMaximumPoolSize() + ",min-pool-size=" +
this.executor.getMinimumPoolSize() + ",keep-alive-time-ms=" + this.executor.getKeepAliveTime() +
",block-policy='" + blockPolicy + "',shutdown-wait-time-ms=" +
((shutdownWaitTimeMs > 0) ? ("" + shutdownWaitTimeMs) : "default"));
}
return pool;
}
/**
* Create the tiggers
*
* @param tiggers array of tigger configuration elements
*
* @throws ConfigurationException thrown in case of configuration failures
*/
private void createTriggers(final Configuration[] tiggers)
throws ConfigurationException {
for (int i = 0; i < tiggers.length; i++) {
String cron = tiggers[i].getChild("cron").getValue(null);
if (null == cron) {
final String seconds = tiggers[i].getChild("seconds").getValue("0");
final String minutes = tiggers[i].getChild("minutes").getValue("*");
final String hours = tiggers[i].getChild("hours").getValue("*");
final String days = tiggers[i].getChild("days").getValue("*");
final String months = tiggers[i].getChild("months").getValue("*");
final String weekdays = tiggers[i].getChild("weekdays").getValue("?");
final String years = tiggers[i].getChild("years").getValue("*");
cron = seconds + " " + minutes + " " + hours + " " + days + " " + months + " " + weekdays + " " +
years;
}
try {
addJob(tiggers[i].getAttribute("name"), tiggers[i].getAttribute("target"), cron,
tiggers[i].getAttributeAsBoolean("concurrent-runs", true));
} catch (final CascadingException ce) {
throw new ConfigurationException("failed adding trigger to scheduler", ce);
}
}
}
/* (non-Javadoc)
* @see org.apache.cocoon.components.cron.JobScheduler#fireTarget(java.lang.Object)
*/
private boolean fireJob(final String name, final Object job) {
try {
if (job instanceof CronJob) {
this.executor.execute(new Runnable() {
public void run() {
((CronJob)job).execute(name);
}
});
} else if (job instanceof Runnable) {
this.executor.execute((Runnable)job);
} else {
getLogger().error("job named '" + name + "' is of invalid class: " + job.getClass().getName());
return false;
}
return true;
} catch (final InterruptedException ie) {
getLogger().error("job " + name + " interrupted", ie);
}
return false;
}
/**
* A ThreadPool for the Quartz Scheduler based on Doug Leas concurrency utilities PooledExecutor
*
* @author <a href="mailto:giacomo@otego.com">Giacomo Pati</a>
* @version CVS $Id: QuartzJobScheduler.java,v 1.12 2004/03/11 22:05:12 sylvain Exp $
*/
private static class ThreadPool extends AbstractLogEnabled implements org.quartz.spi.ThreadPool {
/** Our executor thread pool */
private PooledExecutor executor;
/** How long to wait for running jobs to terminate on disposition */
private int m_shutdownWaitTimeMs;
/**
*
*/
public ThreadPool(final PooledExecutor executor, final int shutownWaitTimeMs) {
super();
this.executor = executor;
m_shutdownWaitTimeMs = shutownWaitTimeMs;
}
/* (non-Javadoc)
* @see org.quartz.spi.ThreadPool#getPoolSize()
*/
public int getPoolSize() {
return this.executor.getMaximumPoolSize();
}
/* (non-Javadoc)
* @see org.quartz.spi.ThreadPool#initialize()
*/
public void initialize() {
}
/* (non-Javadoc)
* @see org.quartz.spi.ThreadPool#runInThread(java.lang.Runnable)
*/
public boolean runInThread(final Runnable job) {
try {
this.executor.execute(job);
} catch (final InterruptedException ie) {
getLogger().error("Cronjob failed", ie);
}
return true;
}
/* (non-Javadoc)
* @see org.quartz.spi.ThreadPool#shutdown(boolean)
*/
public void shutdown(final boolean waitForJobsToComplete) {
if (waitForJobsToComplete) {
this.executor.shutdownAfterProcessingCurrentlyQueuedTasks();
} else {
this.executor.shutdownNow();
}
try {
if (m_shutdownWaitTimeMs > 0) {
if (!this.executor.awaitTerminationAfterShutdown(m_shutdownWaitTimeMs)) {
getLogger().warn("scheduled cron jobs are not terminating within " + m_shutdownWaitTimeMs +
"ms, Will shut them down by interruption");
this.executor.interruptAll();
this.executor.shutdownNow();
}
}
this.executor.awaitTerminationAfterShutdown();
} catch (final InterruptedException ie) {
getLogger().error("cannot shutdown Executor", ie);
}
}
}
}