1
2 /*
3 * Copyright 2004-2005 OpenSymphony
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
6 * use this file except in compliance with the License. You may obtain a copy
7 * of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 * License for the specific language governing permissions and limitations
15 * under the License.
16 *
17 */
18
19 /*
20 * Previously Copyright (c) 2001-2004 James House
21 */
22 package org.quartz;
23
24 import java.util.Date;
25 import java.util.HashMap;
26
27 import org.quartz.spi.TriggerFiredBundle;
28
29 /**
30 * <p>
31 * A context bundle containing handles to various environment information, that
32 * is given to a <code>{@link org.quartz.JobDetail}</code> instance as it is
33 * executed, and to a <code>{@link Trigger}</code> instance after the
34 * execution completes.
35 * </p>
36 *
37 * <p>
38 * The <code>JobDataMap</code> found on this object (via the
39 * <code>getMergedJobDataMap()</code> method) serves as a convenience -
40 * it is a merge of the <code>JobDataMap</code> found on the
41 * <code>JobDetail</code> and the one found on the <code>Trigger</code>, with
42 * the value in the latter overriding any same-named values in the former.
43 * <i>It is thus considered a 'best practice' that the execute code of a Job
44 * retrieve data from the JobDataMap found on this object</i> NOTE: Do not
45 * expect value 'set' into this JobDataMap to somehow be set back onto a
46 * <code>StatefulJob</code>'s own JobDataMap.
47 * </p>
48 *
49 * <p>
50 * <code>JobExecutionContext</code> s are also returned from the
51 * <code>Scheduler.getCurrentlyExecutingJobs()</code>
52 * method. These are the same instances as those passed into the jobs that are
53 * currently executing within the scheduler. The exception to this is when your
54 * application is using Quartz remotely (i.e. via RMI) - in which case you get
55 * a clone of the <code>JobExecutionContext</code>s, and their references to
56 * the <code>Scheduler</code> and <code>Job</code> instances have been lost (a
57 * clone of the <code>JobDetail</code> is still available - just not a handle
58 * to the job instance that is running).
59 * </p>
60 *
61 * @see #getJobDetail()
62 * @see #getScheduler()
63 * @see #getMergedJobDataMap()
64 *
65 * @see Job
66 * @see Trigger
67 * @see JobDataMap
68 *
69 * @author James House
70 */
71 public class JobExecutionContext implements java.io.Serializable {
72
73 /*
74 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
75 *
76 * Data members.
77 *
78 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
79 */
80
81 private transient Scheduler scheduler;
82
83 private Trigger trigger;
84
85 private JobDetail jobDetail;
86
87 private JobDataMap jobDataMap;
88
89 private transient Job job;
90
91 private Calendar calendar;
92
93 private boolean recovering = false;
94
95 private int numRefires = 0;
96
97 private Date fireTime;
98
99 private Date scheduledFireTime;
100
101 private Date prevFireTime;
102
103 private Date nextFireTime;
104
105 private long jobRunTime = -1;
106
107 private Object result;
108
109 private HashMap data = new HashMap();
110
111 /*
112 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
113 *
114 * Constructors.
115 *
116 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
117 */
118
119 /**
120 * <p>
121 * Create a JobExcecutionContext with the given context data.
122 * </p>
123 */
124 public JobExecutionContext(Scheduler scheduler,
125 TriggerFiredBundle firedBundle, Job job) {
126 this.scheduler = scheduler;
127 this.trigger = firedBundle.getTrigger();
128 this.calendar = firedBundle.getCalendar();
129 this.jobDetail = firedBundle.getJobDetail();
130 this.job = job;
131 this.recovering = firedBundle.isRecovering();
132 this.fireTime = firedBundle.getFireTime();
133 this.scheduledFireTime = firedBundle.getScheduledFireTime();
134 this.prevFireTime = firedBundle.getPrevFireTime();
135 this.nextFireTime = firedBundle.getNextFireTime();
136
137 this.jobDataMap = new JobDataMap();
138 this.jobDataMap.putAll(jobDetail.getJobDataMap());
139 this.jobDataMap.putAll(trigger.getJobDataMap());
140 }
141
142 /*
143 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
144 *
145 * Interface.
146 *
147 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
148 */
149
150 /**
151 * <p>
152 * Get a handle to the <code>Scheduler</code> instance that fired the
153 * <code>Job</code>.
154 * </p>
155 */
156 public Scheduler getScheduler() {
157 return scheduler;
158 }
159
160 /**
161 * <p>
162 * Get a handle to the <code>Trigger</code> instance that fired the
163 * <code>Job</code>.
164 * </p>
165 */
166 public Trigger getTrigger() {
167 return trigger;
168 }
169
170 /**
171 * <p>
172 * Get a handle to the <code>Calendar</code> referenced by the <code>Trigger</code>
173 * instance that fired the <code>Job</code>.
174 * </p>
175 */
176 public Calendar getCalendar() {
177 return calendar;
178 }
179
180 /**
181 * <p>
182 * If the <code>Job</code> is being re-executed because of a 'recovery'
183 * situation, this method will return <code>true</code>.
184 * </p>
185 */
186 public boolean isRecovering() {
187 return recovering;
188 }
189
190 public void incrementRefireCount() {
191 numRefires++;
192 }
193
194 public int getRefireCount() {
195 return numRefires;
196 }
197
198 /**
199 * <p>
200 * Get the convenience <code>JobDataMap</code> of this execution context.
201 * </p>
202 *
203 * <p>
204 * The <code>JobDataMap</code> found on this object serves as a convenience -
205 * it is a merge of the <code>JobDataMap</code> found on the
206 * <code>JobDetail</code> and the one found on the <code>Trigger</code>, with
207 * the value in the latter overriding any same-named values in the former.
208 * <i>It is thus considered a 'best practice' that the execute code of a Job
209 * retrieve data from the JobDataMap found on this object</i>
210 * </p>
211 *
212 * <p>NOTE: Do not
213 * expect value 'set' into this JobDataMap to somehow be set back onto a
214 * <code>StatefulJob</code>'s own JobDataMap.
215 * </p>
216 *
217 * <p>
218 * Attempts to change the contents of this map typically result in an
219 * <code>IllegalStateException</code>.
220 * </p>
221 *
222 */
223 public JobDataMap getMergedJobDataMap() {
224 return jobDataMap;
225 }
226
227 /**
228 * <p>
229 * Get the <code>JobDetail</code> associated with the <code>Job</code>.
230 * </p>
231 */
232 public JobDetail getJobDetail() {
233 return jobDetail;
234 }
235
236 /**
237 * <p>
238 * Get the instance of the <code>Job</code> that was created for this
239 * execution.
240 * </p>
241 *
242 * <p>
243 * Note: The Job instance is not available through remote scheduler
244 * interfaces.
245 * </p>
246 */
247 public Job getJobInstance() {
248 return job;
249 }
250
251 /**
252 * The actual time the trigger fired. For instance the scheduled time may
253 * have been 10:00:00 but the actual fire time may have been 10:00:03 if
254 * the scheduler was too busy.
255 *
256 * @return Returns the fireTime.
257 * @see #getScheduledFireTime()
258 */
259 public Date getFireTime() {
260 return fireTime;
261 }
262
263 /**
264 * The scheduled time the trigger fired for. For instance the scheduled
265 * time may have been 10:00:00 but the actual fire time may have been
266 * 10:00:03 if the scheduler was too busy.
267 *
268 * @return Returns the scheduledFireTime.
269 * @see #getFireTime()
270 */
271 public Date getScheduledFireTime() {
272 return scheduledFireTime;
273 }
274
275 public Date getPreviousFireTime() {
276 return prevFireTime;
277 }
278
279 public Date getNextFireTime() {
280 return nextFireTime;
281 }
282
283 public String toString() {
284 return "JobExecutionContext:" + " trigger: '"
285 + getTrigger().getFullName() + " job: "
286 + getJobDetail().getFullName() + " fireTime: '" + getFireTime()
287 + " scheduledFireTime: " + getScheduledFireTime()
288 + " previousFireTime: '" + getPreviousFireTime()
289 + " nextFireTime: " + 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 }