All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.quartz.impl.jdbcjobstore.JobStoreCMT Maven / Gradle / Ivy

Go to download

SDK for dev_appserver (local development) with some of the dependencies shaded (repackaged)

There is a newer version: 2.0.31
Show newest version
/* 
 * Copyright 2004-2005 OpenSymphony 
 * 
 * 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.
 * 
 */

/*
 * Previously Copyright (c) 2001-2004 James House
 */
package org.quartz.impl.jdbcjobstore;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import java.util.Set;

import org.quartz.Calendar;
import org.quartz.JobDetail;
import org.quartz.JobPersistenceException;
import org.quartz.ObjectAlreadyExistsException;
import org.quartz.SchedulerConfigException;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.core.SchedulingContext;
import org.quartz.spi.ClassLoadHelper;
import org.quartz.spi.SchedulerSignaler;
import org.quartz.spi.TriggerFiredBundle;
import org.quartz.utils.DBConnectionManager;

/**
 * 

* JobStoreCMT is meant to be used in an application-server * environment that provides container-managed-transactions. No commit / * rollback will be1 handled by this class. *

* *

* If you need commit / rollback, use {@link * org.quartz.impl.jdbcjobstore.JobStoreTX} * instead. *

* * @author Jeffrey Wescott * @author James House * @author Srinivas Venkatarangaiah * */ public class JobStoreCMT extends JobStoreSupport { /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * Data members. * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ protected String nonManagedTxDsName; // Great name huh? protected boolean dontSetNonManagedTXConnectionAutoCommitFalse = false; protected boolean setTxIsolationLevelReadCommitted = false; /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * Interface. * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /** *

* Set the name of the DataSource that should be used for * performing database functions. *

*/ public void setNonManagedTXDataSource(String nonManagedTxDsName) { this.nonManagedTxDsName = nonManagedTxDsName; } /** *

* Get the name of the DataSource that should be used for * performing database functions. *

*/ public String getNonManagedTXDataSource() { return nonManagedTxDsName; } public boolean isDontSetNonManagedTXConnectionAutoCommitFalse() { return dontSetNonManagedTXConnectionAutoCommitFalse; } /** * Don't call set autocommit(false) on connections obtained from the * DataSource. This can be helpfull in a few situations, such as if you * have a driver that complains if it is called when it is already off. * * @param b */ public void setDontSetNonManagedTXConnectionAutoCommitFalse(boolean b) { dontSetNonManagedTXConnectionAutoCommitFalse = b; } public boolean isTxIsolationLevelReadCommitted() { return setTxIsolationLevelReadCommitted; } /** * Set the transaction isolation level of DB connections to sequential. * * @param b */ public void setTxIsolationLevelReadCommitted(boolean b) { setTxIsolationLevelReadCommitted = b; } public void initialize(ClassLoadHelper loadHelper, SchedulerSignaler signaler) throws SchedulerConfigException { if (nonManagedTxDsName == null) throw new SchedulerConfigException( "Non-ManagedTX DataSource name not set!"); setUseDBLocks(true); // *must* use DB locks with CMT... super.initialize(loadHelper, signaler); getLog().info("JobStoreCMT initialized."); } public void shutdown() { super.shutdown(); try { DBConnectionManager.getInstance().shutdown(getNonManagedTXDataSource()); } catch (SQLException sqle) { getLog().warn("Database connection shutdown unsuccessful.", sqle); } } //--------------------------------------------------------------------------- // JobStoreSupport methods //--------------------------------------------------------------------------- /** *

* Recover any failed or misfired jobs and clean up the data store as * appropriate. *

* * @throws JobPersistenceException * if jobs could not be recovered */ protected void recoverJobs() throws JobPersistenceException { Connection conn = null; boolean transOwner = false; try { conn = getNonManagedTXConnection(); getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); transOwner = true; //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); recoverJobs(conn); conn.commit(); } catch (JobPersistenceException e) { rollbackConnection(conn); throw e; } catch (Exception e) { rollbackConnection(conn); throw new JobPersistenceException("Error recovering jobs: " + e.getMessage(), e); } finally { try { releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); } finally { closeConnection(conn); } } } protected void cleanVolatileTriggerAndJobs() throws JobPersistenceException { Connection conn = null; boolean transOwner = false; try { conn = getNonManagedTXConnection(); getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); transOwner = true; //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); cleanVolatileTriggerAndJobs(conn); conn.commit(); } catch (JobPersistenceException e) { rollbackConnection(conn); throw e; } catch (Exception e) { rollbackConnection(conn); throw new JobPersistenceException("Error cleaning volatile data: " + e.getMessage(), e); } finally { try { releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); } finally { closeConnection(conn); } } } //--------------------------------------------------------------------------- // job / trigger storage methods //--------------------------------------------------------------------------- /** *

* Store the given {@link org.quartz.JobDetail} and {@link org.quartz.Trigger}. *

* * @param newJob * The JobDetail to be stored. * @param newTrigger * The Trigger to be stored. * @throws ObjectAlreadyExistsException * if a Job with the same name/group already * exists. */ public void storeJobAndTrigger(SchedulingContext ctxt, JobDetail newJob, Trigger newTrigger) throws ObjectAlreadyExistsException, JobPersistenceException { Connection conn = getConnection(); boolean transOwner = false; try { if(isLockOnInsert()) { getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); transOwner = true; //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); } if (newJob.isVolatile() && !newTrigger.isVolatile()) { JobPersistenceException jpe = new JobPersistenceException( "Cannot associate non-volatile " + "trigger with a volatile job!"); jpe.setErrorCode(SchedulerException.ERR_CLIENT_ERROR); throw jpe; } storeJob(conn, ctxt, newJob, false); storeTrigger(conn, ctxt, newTrigger, newJob, false, Constants.STATE_WAITING, false, false); } finally { try { releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); } finally { closeConnection(conn); } } } /** *

* Store the given {@link org.quartz.JobDetail}. *

* * @param newJob * The JobDetail to be stored. * @param replaceExisting * If true, any Job existing in the * JobStore with the same name & group should be * over-written. * @throws ObjectAlreadyExistsException * if a Job with the same name/group already * exists, and replaceExisting is set to false. */ public void storeJob(SchedulingContext ctxt, JobDetail newJob, boolean replaceExisting) throws ObjectAlreadyExistsException, JobPersistenceException { Connection conn = getConnection(); boolean transOwner = false; try { if(isLockOnInsert() || replaceExisting) { getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); transOwner = true; //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); } storeJob(conn, ctxt, newJob, replaceExisting); } finally { try { releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); } finally { closeConnection(conn); } } } /** *

* Remove (delete) the {@link org.quartz.Job} with the given * name, and any {@link org.quartz.Trigger} s that reference * it. *

* *

* If removal of the Job results in an empty group, the * group should be removed from the JobStore's list of * known group names. *

* * @param jobName * The name of the Job to be removed. * @param groupName * The group name of the Job to be removed. * @return true if a Job with the given name & * group was found and removed from the store. */ public boolean removeJob(SchedulingContext ctxt, String jobName, String groupName) throws JobPersistenceException { Connection conn = getConnection(); boolean transOwner = false; try { getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); transOwner = true; //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); return removeJob(conn, ctxt, jobName, groupName, true); } finally { try { releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); } finally { closeConnection(conn); } } } /** *

* Retrieve the {@link org.quartz.JobDetail} for the given * {@link org.quartz.Job}. *

* * @param jobName * The name of the Job to be retrieved. * @param groupName * The group name of the Job to be retrieved. * @return The desired Job, or null if there is no match. */ public JobDetail retrieveJob(SchedulingContext ctxt, String jobName, String groupName) throws JobPersistenceException { Connection conn = getConnection(); try { // no locks necessary for read... return retrieveJob(conn, ctxt, jobName, groupName); } finally { closeConnection(conn); } } /** *

* Store the given {@link org.quartz.Trigger}. *

* * @param newTrigger * The Trigger to be stored. * @param replaceExisting * If true, any Trigger existing in * the JobStore with the same name & group should * be over-written. * @throws ObjectAlreadyExistsException * if a Trigger with the same name/group already * exists, and replaceExisting is set to false. */ public void storeTrigger(SchedulingContext ctxt, Trigger newTrigger, boolean replaceExisting) throws ObjectAlreadyExistsException, JobPersistenceException { Connection conn = getConnection(); boolean transOwner = false; try { if(isLockOnInsert() || replaceExisting) { getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); transOwner = true; } storeTrigger(conn, ctxt, newTrigger, null, replaceExisting, STATE_WAITING, false, false); } finally { try { releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); } finally { closeConnection(conn); } } } /** *

* Remove (delete) the {@link org.quartz.Trigger} with the * given name. *

* *

* If removal of the Trigger results in an empty group, the * group should be removed from the JobStore's list of * known group names. *

* *

* If removal of the Trigger results in an 'orphaned' Job * that is not 'durable', then the Job should be deleted * also. *

* * @param triggerName * The name of the Trigger to be removed. * @param groupName * The group name of the Trigger to be removed. * @return true if a Trigger with the given * name & group was found and removed from the store. */ public boolean removeTrigger(SchedulingContext ctxt, String triggerName, String groupName) throws JobPersistenceException { Connection conn = getConnection(); boolean transOwner = false; try { getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); transOwner = true; return removeTrigger(conn, ctxt, triggerName, groupName); } finally { try { releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); } finally { closeConnection(conn); } } } /** * @see org.quartz.spi.JobStore#replaceTrigger(org.quartz.core.SchedulingContext, java.lang.String, java.lang.String, org.quartz.Trigger) */ public boolean replaceTrigger(SchedulingContext ctxt, String triggerName, String groupName, Trigger newTrigger) throws JobPersistenceException { Connection conn = getConnection(); boolean transOwner = false; try { getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); transOwner = true; return replaceTrigger(conn, ctxt, triggerName, groupName, newTrigger); } finally { try { releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); } finally { closeConnection(conn); } } } /** *

* Retrieve the given {@link org.quartz.Trigger}. *

* * @param triggerName * The name of the Trigger to be retrieved. * @param groupName * The group name of the Trigger to be retrieved. * @return The desired Trigger, or null if there is no * match. */ public Trigger retrieveTrigger(SchedulingContext ctxt, String triggerName, String groupName) throws JobPersistenceException { Connection conn = getConnection(); try { // no locks necessary for read... return retrieveTrigger(conn, ctxt, triggerName, groupName); } finally { closeConnection(conn); } } /** *

* Store the given {@link org.quartz.Calendar}. *

* * @param calName * The name of the calendar. * @param calendar * The Calendar to be stored. * @param replaceExisting * If true, any Calendar existing * in the JobStore with the same name & group * should be over-written. * @throws ObjectAlreadyExistsException * if a Calendar with the same name already * exists, and replaceExisting is set to false. */ public void storeCalendar(SchedulingContext ctxt, String calName, Calendar calendar, boolean replaceExisting, boolean updateTriggers) throws ObjectAlreadyExistsException, JobPersistenceException { Connection conn = getConnection(); boolean lockOwner = false; try { if(isLockOnInsert() || updateTriggers) { getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); lockOwner = true; } storeCalendar(conn, ctxt, calName, calendar, replaceExisting, updateTriggers); } finally { try { releaseLock(conn, LOCK_TRIGGER_ACCESS, lockOwner); } finally { closeConnection(conn); } } } /** *

* Remove (delete) the {@link org.quartz.Calendar} with the * given name. *

* *

* If removal of the Calendar would result in * s pointing to non-existent calendars, then a * JobPersistenceException will be thrown.

* * * @param calName The name of the Calendar to be removed. * @return true if a Calendar with the given name * was found and removed from the store. */ public boolean removeCalendar(SchedulingContext ctxt, String calName) throws JobPersistenceException { Connection conn = getConnection(); boolean lockOwner = false; try { getLockHandler().obtainLock(conn, LOCK_CALENDAR_ACCESS); lockOwner = true; return removeCalendar(conn, ctxt, calName); } finally { try { releaseLock(conn, LOCK_TRIGGER_ACCESS, lockOwner); } finally { closeConnection(conn); } } } /** *

* Retrieve the given {@link org.quartz.Trigger}. *

* * @param calName * The name of the Calendar to be retrieved. * @return The desired Calendar, or null if there is no * match. */ public Calendar retrieveCalendar(SchedulingContext ctxt, String calName) throws JobPersistenceException { Connection conn = getConnection(); try { // no locks necessary for read... return retrieveCalendar(conn, ctxt, calName); } finally { closeConnection(conn); } } //--------------------------------------------------------------------------- // informational methods //--------------------------------------------------------------------------- /** *

* Get the number of {@link org.quartz.Job} s that are * stored in the JobStore. *

*/ public int getNumberOfJobs(SchedulingContext ctxt) throws JobPersistenceException { Connection conn = getConnection(); try { // no locks necessary for read... return getNumberOfJobs(conn, ctxt); } finally { closeConnection(conn); } } /** *

* Get the number of {@link org.quartz.Trigger} s that are * stored in the JobsStore. *

*/ public int getNumberOfTriggers(SchedulingContext ctxt) throws JobPersistenceException { Connection conn = getConnection(); try { // no locks necessary for read... return getNumberOfTriggers(conn, ctxt); } finally { closeConnection(conn); } } /** *

* Get the number of {@link org.quartz.Calendar} s that are * stored in the JobsStore. *

*/ public int getNumberOfCalendars(SchedulingContext ctxt) throws JobPersistenceException { Connection conn = getConnection(); try { // no locks necessary for read... return getNumberOfCalendars(conn, ctxt); } finally { closeConnection(conn); } } public Set getPausedTriggerGroups(SchedulingContext ctxt) throws JobPersistenceException { Connection conn = getConnection(); try { // no locks necessary for read... Set groups = getPausedTriggerGroups(conn, ctxt); return groups; } finally { closeConnection(conn); } } /** *

* Get the names of all of the {@link org.quartz.Job} s that * have the given group name. *

* *

* If there are no jobs in the given group name, the result should be a * zero-length array (not null). *

*/ public String[] getJobNames(SchedulingContext ctxt, String groupName) throws JobPersistenceException { Connection conn = getConnection(); try { // no locks necessary for read... return getJobNames(conn, ctxt, groupName); } finally { closeConnection(conn); } } /** *

* Get the names of all of the {@link org.quartz.Trigger} s * that have the given group name. *

* *

* If there are no triggers in the given group name, the result should be a * zero-length array (not null). *

*/ public String[] getTriggerNames(SchedulingContext ctxt, String groupName) throws JobPersistenceException { Connection conn = getConnection(); try { // no locks necessary for read... return getTriggerNames(conn, ctxt, groupName); } finally { closeConnection(conn); } } /** *

* Get the names of all of the {@link org.quartz.Job} * groups. *

* *

* If there are no known group names, the result should be a zero-length * array (not null). *

*/ public String[] getJobGroupNames(SchedulingContext ctxt) throws JobPersistenceException { Connection conn = getConnection(); try { // no locks necessary for read... return getJobGroupNames(conn, ctxt); } finally { closeConnection(conn); } } /** *

* Get the names of all of the {@link org.quartz.Trigger} * groups. *

* *

* If there are no known group names, the result should be a zero-length * array (not null). *

*/ public String[] getTriggerGroupNames(SchedulingContext ctxt) throws JobPersistenceException { Connection conn = getConnection(); try { // no locks necessary for read... return getTriggerGroupNames(conn, ctxt); } finally { closeConnection(conn); } } /** *

* Get the names of all of the {@link org.quartz.Calendar} s * in the JobStore. *

* *

* If there are no Calendars in the given group name, the result should be * a zero-length array (not null). *

*/ public String[] getCalendarNames(SchedulingContext ctxt) throws JobPersistenceException { Connection conn = getConnection(); try { // no locks necessary for read... return getCalendarNames(conn, ctxt); } finally { closeConnection(conn); } } /** *

* Get all of the Triggers that are associated to the given Job. *

* *

* If there are no matches, a zero-length array should be returned. *

*/ public Trigger[] getTriggersForJob(SchedulingContext ctxt, String jobName, String groupName) throws JobPersistenceException { Connection conn = getConnection(); try { // no locks necessary for read... return getTriggersForJob(conn, ctxt, jobName, groupName); } finally { closeConnection(conn); } } /** *

* Get the current state of the identified {@link Trigger}. *

* * @see Trigger#STATE_NORMAL * @see Trigger#STATE_PAUSED * @see Trigger#STATE_COMPLETE * @see Trigger#STATE_ERROR * @see Trigger#STATE_NONE */ public int getTriggerState(SchedulingContext ctxt, String triggerName, String groupName) throws JobPersistenceException { Connection conn = getConnection(); try { // no locks necessary for read... return getTriggerState(conn, ctxt, triggerName, groupName); } finally { closeConnection(conn); } } //--------------------------------------------------------------------------- // trigger state manipulation methods //--------------------------------------------------------------------------- /** *

* Pause the {@link org.quartz.Trigger} with the given name. *

* * @see #resumeTrigger(SchedulingContext, String, String) */ public void pauseTrigger(SchedulingContext ctxt, String triggerName, String groupName) throws JobPersistenceException { Connection conn = getConnection(); boolean transOwner = false; try { getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); transOwner = true; //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); pauseTrigger(conn, ctxt, triggerName, groupName); } finally { try { releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); } finally { closeConnection(conn); } } } /** *

* Pause all of the {@link org.quartz.Trigger}s in the * given group. *

* * @see #resumeTriggerGroup(SchedulingContext, String) */ public void pauseTriggerGroup(SchedulingContext ctxt, String groupName) throws JobPersistenceException { Connection conn = getConnection(); boolean transOwner = false; try { getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); transOwner = true; //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); pauseTriggerGroup(conn, ctxt, groupName); } finally { try { releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); } finally { closeConnection(conn); } } } /** *

* Pause the {@link org.quartz.Job} with the given name - by * pausing all of its current Triggers. *

* * @see #resumeJob(SchedulingContext, String, String) */ public void pauseJob(SchedulingContext ctxt, String jobName, String groupName) throws JobPersistenceException { Connection conn = getConnection(); boolean transOwner = false; try { getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); transOwner = true; //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); Trigger[] triggers = getTriggersForJob(conn, ctxt, jobName, groupName); for (int j = 0; j < triggers.length; j++) { pauseTrigger(conn, ctxt, triggers[j].getName(), triggers[j] .getGroup()); } } finally { try { releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); } finally { closeConnection(conn); } } } /** *

* Pause all of the {@link org.quartz.Job}s in the given * group - by pausing all of their Triggers. *

* * @see #resumeJobGroup(SchedulingContext, String) */ public void pauseJobGroup(SchedulingContext ctxt, String groupName) throws JobPersistenceException { Connection conn = getConnection(); boolean transOwner = false; try { getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); transOwner = true; //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); String[] jobNames = getJobNames(conn, ctxt, groupName); for (int i = 0; i < jobNames.length; i++) { Trigger[] triggers = getTriggersForJob(conn, ctxt, jobNames[i], groupName); for (int j = 0; j < triggers.length; j++) { pauseTrigger(conn, ctxt, triggers[j].getName(), triggers[j] .getGroup()); } } } finally { try { releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); } finally { closeConnection(conn); } } } /** *

* Resume (un-pause) the {@link org.quartz.Trigger} with the * given name. *

* *

* If the Trigger missed one or more fire-times, then the * Trigger's misfire instruction will be applied. *

* * @see #pauseTrigger(SchedulingContext, String, String) */ public void resumeTrigger(SchedulingContext ctxt, String triggerName, String groupName) throws JobPersistenceException { Connection conn = getConnection(); boolean transOwner = false; try { getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); transOwner = true; //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); resumeTrigger(conn, ctxt, triggerName, groupName); } finally { try { releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); } finally { closeConnection(conn); } } } /** *

* Resume (un-pause) all of the {@link org.quartz.Trigger}s * in the given group. *

* *

* If any Trigger missed one or more fire-times, then the * Trigger's misfire instruction will be applied. *

* * @see #pauseTriggerGroup(SchedulingContext, String) */ public void resumeTriggerGroup(SchedulingContext ctxt, String groupName) throws JobPersistenceException { Connection conn = getConnection(); boolean transOwner = false; try { getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); transOwner = true; //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); resumeTriggerGroup(conn, ctxt, groupName); } finally { try { releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); } finally { closeConnection(conn); } } } /** *

* Resume (un-pause) the {@link org.quartz.Job} with the * given name. *

* *

* If any of the Job'sTrigger s missed one * or more fire-times, then the Trigger's misfire * instruction will be applied. *

* * @see #pauseJob(SchedulingContext, String, String) */ public void resumeJob(SchedulingContext ctxt, String jobName, String groupName) throws JobPersistenceException { Connection conn = getConnection(); boolean transOwner = false; try { getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); transOwner = true; //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); Trigger[] triggers = getTriggersForJob(conn, ctxt, jobName, groupName); for (int j = 0; j < triggers.length; j++) { resumeTrigger(conn, ctxt, triggers[j].getName(), triggers[j] .getGroup()); } } finally { try { releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); } finally { closeConnection(conn); } } } /** *

* Resume (un-pause) all of the {@link org.quartz.Job}s in * the given group. *

* *

* If any of the Job s had Trigger s that * missed one or more fire-times, then the Trigger's * misfire instruction will be applied. *

* * @see #pauseJobGroup(SchedulingContext, String) */ public void resumeJobGroup(SchedulingContext ctxt, String groupName) throws JobPersistenceException { Connection conn = getConnection(); boolean transOwner = false; try { getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); transOwner = true; //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); String[] jobNames = getJobNames(conn, ctxt, groupName); for (int i = 0; i < jobNames.length; i++) { Trigger[] triggers = getTriggersForJob(conn, ctxt, jobNames[i], groupName); for (int j = 0; j < triggers.length; j++) { resumeTrigger(conn, ctxt, triggers[j].getName(), triggers[j].getGroup()); } } } finally { try { releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); } finally { closeConnection(conn); } } } /** *

* Pause all triggers - equivalent of calling pauseTriggerGroup(group) * on every group. *

* *

* When resumeAll() is called (to un-pause), trigger misfire * instructions WILL be applied. *

* * @see #resumeAll(SchedulingContext) * @see #pauseTriggerGroup(SchedulingContext, String) */ public void pauseAll(SchedulingContext ctxt) throws JobPersistenceException { Connection conn = getConnection(); boolean transOwner = false; try { getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); transOwner = true; //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); pauseAll(conn, ctxt); } finally { try { releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); } finally { closeConnection(conn); } } } /** *

* Resume (un-pause) all triggers - equivalent of calling resumeTriggerGroup(group) * on every group. *

* *

* If any Trigger missed one or more fire-times, then the * Trigger's misfire instruction will be applied. *

* * @see #pauseAll(SchedulingContext) */ public void resumeAll(SchedulingContext ctxt) throws JobPersistenceException { Connection conn = getConnection(); boolean transOwner = false; try { getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); transOwner = true; //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); resumeAll(conn, ctxt); } finally { try { releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); } finally { closeConnection(conn); } } } //--------------------------------------------------------------------------- // trigger firing methods //--------------------------------------------------------------------------- /** *

* Get a handle to the next trigger to be fired, and mark it as 'reserved' * by the calling scheduler. *

* * @see #releaseAcquiredTrigger(SchedulingContext, Trigger) */ public Trigger acquireNextTrigger(SchedulingContext ctxt, long noLaterThan) throws JobPersistenceException { Connection conn = null; boolean transOwner = false; try { conn = getNonManagedTXConnection(); getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); transOwner = true; //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); Trigger trigger = acquireNextTrigger(conn, ctxt, noLaterThan); conn.commit(); return trigger; } catch (JobPersistenceException e) { rollbackConnection(conn); throw e; } catch (Exception e) { rollbackConnection(conn); throw new JobPersistenceException( "Error acquiring next firable trigger: " + e.getMessage(), e); } finally { try { releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); } finally { closeConnection(conn); } } } /** *

* Inform the JobStore that the scheduler no longer plans to * fire the given Trigger, that it had previously acquired * (reserved). *

*/ public void releaseAcquiredTrigger(SchedulingContext ctxt, Trigger trigger) throws JobPersistenceException { Connection conn = null; boolean transOwner = false; try { conn = getNonManagedTXConnection(); getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); transOwner = true; //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); releaseAcquiredTrigger(conn, ctxt, trigger); conn.commit(); } catch (JobPersistenceException e) { rollbackConnection(conn); throw e; } catch (Exception e) { rollbackConnection(conn); throw new JobPersistenceException( "Error releasing acquired trigger: " + e.getMessage(), e); } finally { try { releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); } finally { closeConnection(conn); } } } /** *

* Inform the JobStore that the scheduler is now firing the * given Trigger (executing its associated Job), * that it had previously acquired (reserved). *

* * @return null if the trigger or it's job or calendar no longer exist, or * if the trigger was not successfully put into the 'executing' * state. */ public TriggerFiredBundle triggerFired(SchedulingContext ctxt, Trigger trigger) throws JobPersistenceException { Connection conn = null; boolean transOwner = false; try { conn = getNonManagedTXConnection(); getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); transOwner = true; //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); TriggerFiredBundle tfb = null; JobPersistenceException err = null; try { tfb = triggerFired(conn, ctxt, trigger); } catch (JobPersistenceException jpe) { if (jpe.getErrorCode() != SchedulerException.ERR_PERSISTENCE_JOB_DOES_NOT_EXIST) throw jpe; err = jpe; } if (err != null) throw err; conn.commit(); return tfb; } catch (JobPersistenceException e) { rollbackConnection(conn); throw e; } catch (Exception e) { rollbackConnection(conn); throw new JobPersistenceException("TX failure: " + e.getMessage(), e); } finally { try { releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); } finally { closeConnection(conn); } } } /** *

* Inform the JobStore that the scheduler has completed the * firing of the given Trigger (and the execution its * associated Job), and that the {@link org.quartz.JobDataMap} * in the given JobDetail should be updated if the Job * is stateful. *

*/ public void triggeredJobComplete(SchedulingContext ctxt, Trigger trigger, JobDetail jobDetail, int triggerInstCode) throws JobPersistenceException { Connection conn = null; boolean transOwner = false; try { conn = getNonManagedTXConnection(); getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); transOwner = true; //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); triggeredJobComplete(conn, ctxt, trigger, jobDetail, triggerInstCode); conn.commit(); } catch (JobPersistenceException e) { rollbackConnection(conn); throw e; } catch (Exception e) { rollbackConnection(conn); throw new JobPersistenceException("TX failure: " + e.getMessage(), e); } finally { try { releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); } finally { closeConnection(conn); } } } protected boolean doRecoverMisfires() throws JobPersistenceException { Connection conn = null; boolean transOwner = false; boolean moreToDo = false; try { conn = getNonManagedTXConnection(); getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); transOwner = true; try { moreToDo = recoverMisfiredJobs(conn, false); } catch (Exception e) { throw new JobPersistenceException(e.getMessage(), e); } conn.commit(); return moreToDo; } catch (JobPersistenceException e) { rollbackConnection(conn); throw e; } catch (Exception e) { rollbackConnection(conn); throw new JobPersistenceException("TX failure: " + e.getMessage(), e); } finally { try { releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); } finally { closeConnection(conn); } } } protected boolean doCheckin() throws JobPersistenceException { Connection conn = null; boolean transOwner = false; boolean transStateOwner = false; boolean recovered = false; try { conn = getNonManagedTXConnection(); // Other than the first time, always checkin first to make sure there is // work to be done before we aquire / the lock (since that is expensive, // and is almost never necessary) List failedRecords = (firstCheckIn) ? null : clusterCheckIn(conn); if (firstCheckIn || (failedRecords.size() > 0)) { getLockHandler().obtainLock(conn, LOCK_STATE_ACCESS); transStateOwner = true; // Now that we own the lock, make sure we still have work to do. // The first time through, we also need to make sure we update/create our state record failedRecords = (firstCheckIn) ? clusterCheckIn(conn) : findFailedInstances(conn); if (failedRecords.size() > 0) { getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS); //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS); transOwner = true; clusterRecover(conn, failedRecords); recovered = true; } } conn.commit(); } catch (JobPersistenceException e) { rollbackConnection(conn); throw e; } catch (Exception e) { rollbackConnection(conn); throw new JobPersistenceException("TX failure: " + e.getMessage(), e); } finally { try { releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner); } finally { try { releaseLock(conn, LOCK_STATE_ACCESS, transStateOwner); } finally { closeConnection(conn); } } } firstCheckIn = false; return recovered; } //--------------------------------------------------------------------------- // private helpers //--------------------------------------------------------------------------- protected Connection getNonManagedTXConnection() throws JobPersistenceException { try { Connection conn = DBConnectionManager.getInstance().getConnection( getNonManagedTXDataSource()); if (conn == null) { throw new SQLException( "Could not get connection from DataSource '" + getNonManagedTXDataSource() + "'"); } try { if (!isDontSetNonManagedTXConnectionAutoCommitFalse()) conn.setAutoCommit(false); if (isTxIsolationLevelReadCommitted()) conn.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED); } catch (SQLException ingore) { } catch (Exception e) { if(conn != null) try { conn.close(); } catch(Throwable tt) {} throw new JobPersistenceException( "Failure setting up connection.", e); } return conn; } catch (SQLException sqle) { throw new JobPersistenceException( "Failed to obtain DB connection from data source '" + getNonManagedTXDataSource() + "': " + sqle.toString(), sqle); } catch (Exception e) { throw new JobPersistenceException( "Failed to obtain DB connection from data source '" + getNonManagedTXDataSource() + "': " + e.toString(), e, JobPersistenceException.ERR_PERSISTENCE_CRITICAL_FAILURE); } } } // EOF




© 2015 - 2024 Weber Informatics LLC | Privacy Policy