001: /*
002: * Copyright 2004-2005 OpenSymphony
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005: * use this file except in compliance with the License. You may obtain a copy
006: * of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013: * License for the specific language governing permissions and limitations
014: * under the License.
015: *
016: */
017:
018: /*
019: * Previously Copyright (c) 2001-2004 James House
020: */
021: package org.quartz;
022:
023: import java.util.Date;
024: import java.util.HashMap;
025:
026: import org.quartz.spi.TriggerFiredBundle;
027:
028: /**
029: * <p>
030: * A context bundle containing handles to various environment information, that
031: * is given to a <code>{@link org.quartz.JobDetail}</code> instance as it is
032: * executed, and to a <code>{@link Trigger}</code> instance after the
033: * execution completes.
034: * </p>
035: *
036: * <p>
037: * The <code>JobDataMap</code> found on this object (via the
038: * <code>getMergedJobDataMap()</code> method) serves as a convenience -
039: * it is a merge of the <code>JobDataMap</code> found on the
040: * <code>JobDetail</code> and the one found on the <code>Trigger</code>, with
041: * the value in the latter overriding any same-named values in the former.
042: * <i>It is thus considered a 'best practice' that the execute code of a Job
043: * retrieve data from the JobDataMap found on this object</i> NOTE: Do not
044: * expect value 'set' into this JobDataMap to somehow be set back onto a
045: * <code>StatefulJob</code>'s own JobDataMap.
046: * </p>
047: *
048: * <p>
049: * <code>JobExecutionContext</code> s are also returned from the
050: * <code>Scheduler.getCurrentlyExecutingJobs()</code>
051: * method. These are the same instances as those passed into the jobs that are
052: * currently executing within the scheduler. The exception to this is when your
053: * application is using Quartz remotely (i.e. via RMI) - in which case you get
054: * a clone of the <code>JobExecutionContext</code>s, and their references to
055: * the <code>Scheduler</code> and <code>Job</code> instances have been lost (a
056: * clone of the <code>JobDetail</code> is still available - just not a handle
057: * to the job instance that is running).
058: * </p>
059: *
060: * @see #getJobDetail()
061: * @see #getScheduler()
062: * @see #getMergedJobDataMap()
063: *
064: * @see Job
065: * @see Trigger
066: * @see JobDataMap
067: *
068: * @author James House
069: */
070: public class JobExecutionContext implements java.io.Serializable {
071:
072: /*
073: * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
074: *
075: * Data members.
076: *
077: * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
078: */
079:
080: private transient Scheduler scheduler;
081:
082: private Trigger trigger;
083:
084: private JobDetail jobDetail;
085:
086: private JobDataMap jobDataMap;
087:
088: private transient Job job;
089:
090: private Calendar calendar;
091:
092: private boolean recovering = false;
093:
094: private int numRefires = 0;
095:
096: private Date fireTime;
097:
098: private Date scheduledFireTime;
099:
100: private Date prevFireTime;
101:
102: private Date nextFireTime;
103:
104: private long jobRunTime = -1;
105:
106: private Object result;
107:
108: private HashMap data = new HashMap();
109:
110: /*
111: * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
112: *
113: * Constructors.
114: *
115: * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
116: */
117:
118: /**
119: * <p>
120: * Create a JobExcecutionContext with the given context data.
121: * </p>
122: */
123: public JobExecutionContext(Scheduler scheduler,
124: TriggerFiredBundle firedBundle, Job job) {
125: this .scheduler = scheduler;
126: this .trigger = firedBundle.getTrigger();
127: this .calendar = firedBundle.getCalendar();
128: this .jobDetail = firedBundle.getJobDetail();
129: this .job = job;
130: this .recovering = firedBundle.isRecovering();
131: this .fireTime = firedBundle.getFireTime();
132: this .scheduledFireTime = firedBundle.getScheduledFireTime();
133: this .prevFireTime = firedBundle.getPrevFireTime();
134: this .nextFireTime = firedBundle.getNextFireTime();
135:
136: this .jobDataMap = new JobDataMap();
137: this .jobDataMap.putAll(jobDetail.getJobDataMap());
138: this .jobDataMap.putAll(trigger.getJobDataMap());
139: }
140:
141: /*
142: * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
143: *
144: * Interface.
145: *
146: * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
147: */
148:
149: /**
150: * <p>
151: * Get a handle to the <code>Scheduler</code> instance that fired the
152: * <code>Job</code>.
153: * </p>
154: */
155: public Scheduler getScheduler() {
156: return scheduler;
157: }
158:
159: /**
160: * <p>
161: * Get a handle to the <code>Trigger</code> instance that fired the
162: * <code>Job</code>.
163: * </p>
164: */
165: public Trigger getTrigger() {
166: return trigger;
167: }
168:
169: /**
170: * <p>
171: * Get a handle to the <code>Calendar</code> referenced by the <code>Trigger</code>
172: * instance that fired the <code>Job</code>.
173: * </p>
174: */
175: public Calendar getCalendar() {
176: return calendar;
177: }
178:
179: /**
180: * <p>
181: * If the <code>Job</code> is being re-executed because of a 'recovery'
182: * situation, this method will return <code>true</code>.
183: * </p>
184: */
185: public boolean isRecovering() {
186: return recovering;
187: }
188:
189: public void incrementRefireCount() {
190: numRefires++;
191: }
192:
193: public int getRefireCount() {
194: return numRefires;
195: }
196:
197: /**
198: * <p>
199: * Get the convenience <code>JobDataMap</code> of this execution context.
200: * </p>
201: *
202: * <p>
203: * The <code>JobDataMap</code> found on this object serves as a convenience -
204: * it is a merge of the <code>JobDataMap</code> found on the
205: * <code>JobDetail</code> and the one found on the <code>Trigger</code>, with
206: * the value in the latter overriding any same-named values in the former.
207: * <i>It is thus considered a 'best practice' that the execute code of a Job
208: * retrieve data from the JobDataMap found on this object</i>
209: * </p>
210: *
211: * <p>NOTE: Do not
212: * expect value 'set' into this JobDataMap to somehow be set back onto a
213: * <code>StatefulJob</code>'s own JobDataMap.
214: * </p>
215: *
216: * <p>
217: * Attempts to change the contents of this map typically result in an
218: * <code>IllegalStateException</code>.
219: * </p>
220: *
221: */
222: public JobDataMap getMergedJobDataMap() {
223: return jobDataMap;
224: }
225:
226: /**
227: * <p>
228: * Get the <code>JobDetail</code> associated with the <code>Job</code>.
229: * </p>
230: */
231: public JobDetail getJobDetail() {
232: return jobDetail;
233: }
234:
235: /**
236: * <p>
237: * Get the instance of the <code>Job</code> that was created for this
238: * execution.
239: * </p>
240: *
241: * <p>
242: * Note: The Job instance is not available through remote scheduler
243: * interfaces.
244: * </p>
245: */
246: public Job getJobInstance() {
247: return job;
248: }
249:
250: /**
251: * The actual time the trigger fired. For instance the scheduled time may
252: * have been 10:00:00 but the actual fire time may have been 10:00:03 if
253: * the scheduler was too busy.
254: *
255: * @return Returns the fireTime.
256: * @see #getScheduledFireTime()
257: */
258: public Date getFireTime() {
259: return fireTime;
260: }
261:
262: /**
263: * The scheduled time the trigger fired for. For instance the scheduled
264: * time may have been 10:00:00 but the actual fire time may have been
265: * 10:00:03 if the scheduler was too busy.
266: *
267: * @return Returns the scheduledFireTime.
268: * @see #getFireTime()
269: */
270: public Date getScheduledFireTime() {
271: return scheduledFireTime;
272: }
273:
274: public Date getPreviousFireTime() {
275: return prevFireTime;
276: }
277:
278: public Date getNextFireTime() {
279: return nextFireTime;
280: }
281:
282: public String toString() {
283: return "JobExecutionContext:" + " trigger: '"
284: + getTrigger().getFullName() + " job: "
285: + getJobDetail().getFullName() + " fireTime: '"
286: + getFireTime() + " scheduledFireTime: "
287: + getScheduledFireTime() + " previousFireTime: '"
288: + getPreviousFireTime() + " nextFireTime: "
289: + getNextFireTime() + " isRecovering: "
290: + isRecovering() + " refireCount: " + getRefireCount();
291: }
292:
293: /**
294: * Returns the result (if any) that the <code>Job</code> set before its
295: * execution completed (the type of object set as the result is entirely up
296: * to the particular job).
297: *
298: * <p>
299: * The result itself is meaningless to Quartz, but may be informative
300: * to <code>{@link JobListener}s</code> or
301: * <code>{@link TriggerListener}s</code> that are watching the job's
302: * execution.
303: * </p>
304: *
305: * @return Returns the result.
306: */
307: public Object getResult() {
308: return result;
309: }
310:
311: /**
312: * Set the result (if any) of the <code>Job</code>'s execution (the type of
313: * object set as the result is entirely up to the particular job).
314: *
315: * <p>
316: * The result itself is meaningless to Quartz, but may be informative
317: * to <code>{@link JobListener}s</code> or
318: * <code>{@link TriggerListener}s</code> that are watching the job's
319: * execution.
320: * </p>
321: */
322: public void setResult(Object result) {
323: this .result = result;
324: }
325:
326: /**
327: * The amount of time the job ran for (in milliseconds). The returned
328: * value will be -1 until the job has actually completed (or thrown an
329: * exception), and is therefore generally only useful to
330: * <code>JobListener</code>s and <code>TriggerListener</code>s.
331: *
332: * @return Returns the jobRunTime.
333: */
334: public long getJobRunTime() {
335: return jobRunTime;
336: }
337:
338: /**
339: * @param jobRunTime The jobRunTime to set.
340: */
341: public void setJobRunTime(long jobRunTime) {
342: this .jobRunTime = jobRunTime;
343: }
344:
345: /**
346: * Put the specified value into the context's data map with the given key.
347: * Possibly useful for sharing data between listeners and jobs.
348: *
349: * <p>NOTE: this data is volatile - it is lost after the job execution
350: * completes, and all TriggerListeners and JobListeners have been
351: * notified.</p>
352: *
353: * @param key
354: * @param value
355: */
356: public void put(Object key, Object value) {
357: data.put(key, value);
358: }
359:
360: /**
361: * Get the value with the given key from the context's data map.
362: *
363: * @param key
364: */
365: public Object get(Object key) {
366: return data.get(key);
367: }
368: }
|