📄 ramjobstore.java
字号:
/*
* 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.simpl;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.quartz.Calendar;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobPersistenceException;
import org.quartz.ObjectAlreadyExistsException;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.core.SchedulingContext;
import org.quartz.spi.ClassLoadHelper;
import org.quartz.spi.JobStore;
import org.quartz.spi.SchedulerSignaler;
import org.quartz.spi.TriggerFiredBundle;
/**
* <p>
* This class implements a <code>{@link org.quartz.spi.JobStore}</code> that
* utilizes RAM as its storage device.
* </p>
*
* <p>
* As you should know, the ramification of this is that access is extrememly
* fast, but the data is completely volatile - therefore this <code>JobStore</code>
* should not be used if true persistence between program shutdowns is
* required.
* </p>
*
* @author James House
* @author Sharada Jambula
* @author Eric Mueller
*/
public class RAMJobStore implements JobStore {
/*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* Data members.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
protected HashMap jobsByFQN = new HashMap(1000);
protected HashMap triggersByFQN = new HashMap(1000);
protected HashMap jobsByGroup = new HashMap(25);
protected HashMap triggersByGroup = new HashMap(25);
protected TreeSet timeTriggers = new TreeSet(new TriggerComparator());
protected HashMap calendarsByName = new HashMap(25);
protected ArrayList triggers = new ArrayList(1000);
protected final Object triggerLock = new Object();
protected HashSet pausedTriggerGroups = new HashSet();
protected HashSet pausedJobGroups = new HashSet();
protected HashSet blockedJobs = new HashSet();
protected long misfireThreshold = 5000l;
protected SchedulerSignaler signaler;
private final Log log = LogFactory.getLog(getClass());
/*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* Constructors.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
/**
* <p>
* Create a new <code>RAMJobStore</code>.
* </p>
*/
public RAMJobStore() {
}
/*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* Interface.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
protected Log getLog() {
return log;
}
/**
* <p>
* Called by the QuartzScheduler before the <code>JobStore</code> is
* used, in order to give the it a chance to initialize.
* </p>
*/
public void initialize(ClassLoadHelper loadHelper,
SchedulerSignaler signaler) {
this.signaler = signaler;
getLog().info("RAMJobStore initialized.");
}
public void schedulerStarted() throws SchedulerException {
// nothing to do
}
public long getMisfireThreshold() {
return misfireThreshold;
}
/**
* The number of milliseconds by which a trigger must have missed its
* next-fire-time, in order for it to be considered "misfired" and thus
* have its misfire instruction applied.
*
* @param misfireThreshold
*/
public void setMisfireThreshold(long misfireThreshold) {
if (misfireThreshold < 1) {
throw new IllegalArgumentException("Misfirethreashold must be larger than 0");
}
this.misfireThreshold = misfireThreshold;
}
/**
* <p>
* Called by the QuartzScheduler to inform the <code>JobStore</code> that
* it should free up all of it's resources because the scheduler is
* shutting down.
* </p>
*/
public void shutdown() {
}
public boolean supportsPersistence() {
return false;
}
/**
* <p>
* Store the given <code>{@link org.quartz.JobDetail}</code> and <code>{@link org.quartz.Trigger}</code>.
* </p>
*
* @param newJob
* The <code>JobDetail</code> to be stored.
* @param newTrigger
* The <code>Trigger</code> to be stored.
* @throws ObjectAlreadyExistsException
* if a <code>Job</code> with the same name/group already
* exists.
*/
public void storeJobAndTrigger(SchedulingContext ctxt, JobDetail newJob,
Trigger newTrigger) throws JobPersistenceException {
storeJob(ctxt, newJob, false);
storeTrigger(ctxt, newTrigger, false);
}
/**
* <p>
* Store the given <code>{@link org.quartz.Job}</code>.
* </p>
*
* @param newJob
* The <code>Job</code> to be stored.
* @param replaceExisting
* If <code>true</code>, any <code>Job</code> existing in the
* <code>JobStore</code> with the same name & group should be
* over-written.
* @throws ObjectAlreadyExistsException
* if a <code>Job</code> with the same name/group already
* exists, and replaceExisting is set to false.
*/
public void storeJob(SchedulingContext ctxt, JobDetail newJob,
boolean replaceExisting) throws ObjectAlreadyExistsException {
JobWrapper jw = new JobWrapper((JobDetail)newJob.clone());
boolean repl = false;
if (jobsByFQN.get(jw.key) != null) {
if (!replaceExisting) {
throw new ObjectAlreadyExistsException(newJob);
}
repl = true;
}
synchronized (triggerLock) {
if (!repl) {
// get job group
HashMap grpMap = (HashMap) jobsByGroup.get(newJob.getGroup());
if (grpMap == null) {
grpMap = new HashMap(100);
jobsByGroup.put(newJob.getGroup(), grpMap);
}
// add to jobs by group
grpMap.put(newJob.getName(), jw);
// add to jobs by FQN map
jobsByFQN.put(jw.key, jw);
} else {
// update job detail
JobWrapper orig = (JobWrapper) jobsByFQN.get(jw.key);
orig.jobDetail = jw.jobDetail; // already cloned
}
}
}
/**
* <p>
* Remove (delete) the <code>{@link org.quartz.Job}</code> with the given
* name, and any <code>{@link org.quartz.Trigger}</code> s that reference
* it.
* </p>
*
* @param jobName
* The name of the <code>Job</code> to be removed.
* @param groupName
* The group name of the <code>Job</code> to be removed.
* @return <code>true</code> if a <code>Job</code> with the given name &
* group was found and removed from the store.
*/
public boolean removeJob(SchedulingContext ctxt, String jobName,
String groupName) {
String key = JobWrapper.getJobNameKey(jobName, groupName);
boolean found = false;
Trigger[] trigger = getTriggersForJob(ctxt, jobName,
groupName);
for (int i = 0; i < trigger.length; i++) {
Trigger trig = trigger[i];
this.removeTrigger(ctxt, trig.getName(), trig.getGroup());
found = true;
}
synchronized (triggerLock) {
found = (jobsByFQN.remove(key) != null) | found;
if (found) {
HashMap grpMap = (HashMap) jobsByGroup.get(groupName);
if (grpMap != null) {
grpMap.remove(jobName);
if (grpMap.size() == 0) {
jobsByGroup.remove(groupName);
}
}
}
}
return found;
}
/**
* <p>
* Store the given <code>{@link org.quartz.Trigger}</code>.
* </p>
*
* @param newTrigger
* The <code>Trigger</code> to be stored.
* @param replaceExisting
* If <code>true</code>, any <code>Trigger</code> existing in
* the <code>JobStore</code> with the same name & group should
* be over-written.
* @throws ObjectAlreadyExistsException
* if a <code>Trigger</code> with the same name/group already
* exists, and replaceExisting is set to false.
*
* @see #pauseTriggerGroup(SchedulingContext, String)
*/
public void storeTrigger(SchedulingContext ctxt, Trigger newTrigger,
boolean replaceExisting) throws JobPersistenceException {
TriggerWrapper tw = new TriggerWrapper((Trigger)newTrigger.clone());
if (triggersByFQN.get(tw.key) != null) {
if (!replaceExisting) {
throw new ObjectAlreadyExistsException(newTrigger);
}
removeTrigger(ctxt, newTrigger.getName(), newTrigger.getGroup(), false);
}
if (retrieveJob(ctxt, newTrigger.getJobName(), newTrigger.getJobGroup()) == null) {
throw new JobPersistenceException("The job ("
+ newTrigger.getFullJobName()
+ ") referenced by the trigger does not exist.");
}
synchronized (triggerLock) {
// add to triggers array
triggers.add(tw);
// add to triggers by group
HashMap grpMap = (HashMap) triggersByGroup.get(newTrigger
.getGroup());
if (grpMap == null) {
grpMap = new HashMap(100);
triggersByGroup.put(newTrigger.getGroup(), grpMap);
}
grpMap.put(newTrigger.getName(), tw);
// add to triggers by FQN map
triggersByFQN.put(tw.key, tw);
if (pausedTriggerGroups.contains(newTrigger.getGroup())
|| pausedJobGroups.contains(newTrigger.getJobGroup())) {
tw.state = TriggerWrapper.STATE_PAUSED;
if (blockedJobs.contains(tw.jobKey)) {
tw.state = TriggerWrapper.STATE_PAUSED_BLOCKED;
}
} else if (blockedJobs.contains(tw.jobKey)) {
tw.state = TriggerWrapper.STATE_BLOCKED;
} else {
timeTriggers.add(tw);
}
}
}
/**
* <p>
* Remove (delete) the <code>{@link org.quartz.Trigger}</code> with the
* given name.
* </p>
*
* @param triggerName
* The name of the <code>Trigger</code> to be removed.
* @param groupName
* The group name of the <code>Trigger</code> to be removed.
* @return <code>true</code> if a <code>Trigger</code> with the given
* name & group was found and removed from the store.
*/
public boolean removeTrigger(SchedulingContext ctxt, String triggerName,
String groupName) {
return removeTrigger(ctxt, triggerName, groupName, true);
}
private boolean removeTrigger(SchedulingContext ctxt, String triggerName,
String groupName, boolean removeOrphanedJob) {
String key = TriggerWrapper.getTriggerNameKey(triggerName, groupName);
boolean found = false;
synchronized (triggerLock) {
// remove from triggers by FQN map
found = (triggersByFQN.remove(key) == null) ? false : true;
if (found) {
TriggerWrapper tw = null;
// remove from triggers by group
HashMap grpMap = (HashMap) triggersByGroup.get(groupName);
if (grpMap != null) {
grpMap.remove(triggerName);
if (grpMap.size() == 0) {
triggersByGroup.remove(groupName);
}
}
// remove from triggers array
Iterator tgs = triggers.iterator();
while (tgs.hasNext()) {
tw = (TriggerWrapper) tgs.next();
if (key.equals(tw.key)) {
tgs.remove();
break;
}
}
timeTriggers.remove(tw);
if (removeOrphanedJob) {
JobWrapper jw = (JobWrapper) jobsByFQN.get(JobWrapper
.getJobNameKey(tw.trigger.getJobName(), tw.trigger
.getJobGroup()));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -