KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > quartz > JobDetail


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.HashSet JavaDoc;
25 import java.util.Set JavaDoc;
26
27 import org.apache.commons.collections.SetUtils;
28 import org.quartz.utils.Key;
29
30 /**
31  * <p>
32  * Conveys the detail properties of a given <code>Job</code> instance.
33  * </p>
34  *
35  * <p>
36  * Quartz does not store an actual instance of a <code>Job</code> class, but
37  * instead allows you to define an instance of one, through the use of a <code>JobDetail</code>.
38  * </p>
39  *
40  * <p>
41  * <code>Job</code>s have a name and group associated with them, which
42  * should uniquely identify them within a single <code>{@link Scheduler}</code>.
43  * </p>
44  *
45  * <p>
46  * <code>Trigger</code>s are the 'mechanism' by which <code>Job</code>s
47  * are scheduled. Many <code>Trigger</code>s can point to the same <code>Job</code>,
48  * but a single <code>Trigger</code> can only point to one <code>Job</code>.
49  * </p>
50  *
51  * @see Job
52  * @see StatefulJob
53  * @see JobDataMap
54  * @see Trigger
55  *
56  * @author James House
57  * @author Sharada Jambula
58  */

59 public class JobDetail implements Cloneable JavaDoc, java.io.Serializable JavaDoc {
60
61     /*
62      * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
63      *
64      * Data members.
65      *
66      * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
67      */

68
69     private String JavaDoc name;
70
71     private String JavaDoc group = Scheduler.DEFAULT_GROUP;
72
73     private String JavaDoc description;
74
75     private Class JavaDoc jobClass;
76
77     private JobDataMap jobDataMap;
78
79     private boolean volatility = false;
80
81     private boolean durability = false;
82
83     private boolean shouldRecover = false;
84
85     private Set JavaDoc jobListeners = SetUtils.orderedSet(new HashSet JavaDoc());
86
87     private transient Key key = null;
88
89     /*
90     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
91     *
92     * Constructors.
93     *
94     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
95     */

96
97     /**
98      * <p>
99      * Create a <code>JobDetail</code> with no specified name or group, and
100      * the default settings of all the other properties.
101      * </p>
102      *
103      * <p>
104      * Note that the {@link #setName(String)},{@link #setGroup(String)}and
105      * {@link #setJobClass(Class)}methods must be called before the job can be
106      * placed into a {@link Scheduler}
107      * </p>
108      */

109     public JobDetail() {
110         // do nothing...
111
}
112
113     /**
114      * <p>
115      * Create a <code>JobDetail</code> with the given name, and group, and
116      * the default settings of all the other properties.
117      * </p>
118      *
119      * @param group if <code>null</code>, Scheduler.DEFAULT_GROUP will be used.
120      *
121      * @exception IllegalArgumentException
122      * if nameis null or empty, or the group is an empty string.
123      */

124     public JobDetail(String JavaDoc name, String JavaDoc group, Class JavaDoc jobClass) {
125         setName(name);
126         setGroup(group);
127         setJobClass(jobClass);
128     }
129
130     /**
131      * <p>
132      * Create a <code>JobDetail</code> with the given name, and group, and
133      * the given settings of all the other properties.
134      * </p>
135      *
136      * @param group if <code>null</code>, Scheduler.DEFAULT_GROUP will be used.
137      *
138      * @exception IllegalArgumentException
139      * if nameis null or empty, or the group is an empty string.
140      */

141     public JobDetail(String JavaDoc name, String JavaDoc group, Class JavaDoc jobClass,
142                      boolean volatility, boolean durability, boolean recover) {
143         setName(name);
144         setGroup(group);
145         setJobClass(jobClass);
146         setVolatility(volatility);
147         setDurability(durability);
148         setRequestsRecovery(recover);
149     }
150
151     /*
152      * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
153      *
154      * Interface.
155      *
156      * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
157      */

158
159     /**
160      * <p>
161      * Get the name of this <code>Job</code>.
162      * </p>
163      */

164     public String JavaDoc getName() {
165         return name;
166     }
167
168     /**
169      * <p>
170      * Set the name of this <code>Job</code>.
171      * </p>
172      *
173      * @exception IllegalArgumentException
174      * if name is null or empty.
175      */

176     public void setName(String JavaDoc name) {
177         if (name == null || name.trim().length() == 0) {
178             throw new IllegalArgumentException JavaDoc("Job name cannot be empty.");
179         }
180
181         this.name = name;
182     }
183
184     /**
185      * <p>
186      * Get the group of this <code>Job</code>.
187      * </p>
188      */

189     public String JavaDoc getGroup() {
190         return group;
191     }
192
193     /**
194      * <p>
195      * Set the group of this <code>Job</code>.
196      * </p>
197      *
198      * @param group if <code>null</code>, Scheduler.DEFAULT_GROUP will be used.
199      *
200      * @exception IllegalArgumentException
201      * if the group is an empty string.
202      */

203     public void setGroup(String JavaDoc group) {
204         if (group != null && group.trim().length() == 0) {
205             throw new IllegalArgumentException JavaDoc(
206                     "Group name cannot be empty.");
207         }
208
209         if (group == null) {
210             group = Scheduler.DEFAULT_GROUP;
211         }
212
213         this.group = group;
214     }
215
216     /**
217      * <p>
218      * Returns the 'full name' of the <code>JobDetail</code> in the format
219      * "group.name".
220      * </p>
221      */

222     public String JavaDoc getFullName() {
223         return group + "." + name;
224     }
225
226     public Key getKey() {
227         if(key == null) {
228             key = new Key(getName(), getGroup());
229         }
230
231         return key;
232     }
233
234     /**
235      * <p>
236      * Return the description given to the <code>Job</code> instance by its
237      * creator (if any).
238      * </p>
239      *
240      * @return null if no description was set.
241      */

242     public String JavaDoc getDescription() {
243         return description;
244     }
245
246     /**
247      * <p>
248      * Set a description for the <code>Job</code> instance - may be useful
249      * for remembering/displaying the purpose of the job, though the
250      * description has no meaning to Quartz.
251      * </p>
252      */

253     public void setDescription(String JavaDoc description) {
254         this.description = description;
255     }
256
257     /**
258      * <p>
259      * Get the instance of <code>Job</code> that will be executed.
260      * </p>
261      */

262     public Class JavaDoc getJobClass() {
263         return jobClass;
264     }
265
266     /**
267      * <p>
268      * Set the instance of <code>Job</code> that will be executed.
269      * </p>
270      *
271      * @exception IllegalArgumentException
272      * if jobClass is null or the class is not a <code>Job</code>.
273      */

274     public void setJobClass(Class JavaDoc jobClass) {
275         if (jobClass == null) {
276             throw new IllegalArgumentException JavaDoc("Job class cannot be null.");
277         }
278
279         if (!Job.class.isAssignableFrom(jobClass)) {
280             throw new IllegalArgumentException JavaDoc(
281                     "Job class must implement the Job interface.");
282         }
283
284         this.jobClass = jobClass;
285     }
286
287     /**
288      * <p>
289      * Get the <code>JobDataMap</code> that is associated with the <code>Job</code>.
290      * </p>
291      */

292     public JobDataMap getJobDataMap() {
293         if (jobDataMap == null) {
294             jobDataMap = new JobDataMap();
295         }
296         return jobDataMap;
297     }
298
299     /**
300      * <p>
301      * Set the <code>JobDataMap</code> to be associated with the <code>Job</code>.
302      * </p>
303      */

304     public void setJobDataMap(JobDataMap jobDataMap) {
305         this.jobDataMap = jobDataMap;
306     }
307
308     /**
309      * <p>
310      * Validates whether the properties of the <code>JobDetail</code> are
311      * valid for submission into a <code>Scheduler</code>.
312      *
313      * @throws IllegalStateException
314      * if a required property (such as Name, Group, Class) is not
315      * set.
316      */

317     public void validate() throws SchedulerException {
318         if (name == null) {
319             throw new SchedulerException("Job's name cannot be null",
320                     SchedulerException.ERR_CLIENT_ERROR);
321         }
322
323         if (group == null) {
324             throw new SchedulerException("Job's group cannot be null",
325                     SchedulerException.ERR_CLIENT_ERROR);
326         }
327
328         if (jobClass == null) {
329             throw new SchedulerException("Job's class cannot be null",
330                     SchedulerException.ERR_CLIENT_ERROR);
331         }
332     }
333
334     /**
335      * <p>
336      * Set whether or not the <code>Job</code> should be persisted in the
337      * <code>{@link org.quartz.spi.JobStore}</code> for re-use after program
338      * restarts.
339      * </p>
340      *
341      * <p>
342      * If not explicitly set, the default value is <code>false</code>.
343      * </p>
344      */

345     public void setVolatility(boolean volatility) {
346         this.volatility = volatility;
347     }
348
349     /**
350      * <p>
351      * Set whether or not the <code>Job</code> should remain stored after it
352      * is orphaned (no <code>{@link Trigger}s</code> point to it).
353      * </p>
354      *
355      * <p>
356      * If not explicitly set, the default value is <code>false</code>.
357      * </p>
358      */

359     public void setDurability(boolean durability) {
360         this.durability = durability;
361     }
362
363     /**
364      * <p>
365      * Set whether or not the the <code>Scheduler</code> should re-execute
366      * the <code>Job</code> if a 'recovery' or 'fail-over' situation is
367      * encountered.
368      * </p>
369      *
370      * <p>
371      * If not explicitly set, the default value is <code>false</code>.
372      * </p>
373      *
374      * @see JobExecutionContext#isRecovering()
375      */

376     public void setRequestsRecovery(boolean shouldRecover) {
377         this.shouldRecover = shouldRecover;
378     }
379
380     /**
381      * <p>
382      * Whether or not the <code>Job</code> should not be persisted in the
383      * <code>{@link org.quartz.spi.JobStore}</code> for re-use after program
384      * restarts.
385      * </p>
386      *
387      * <p>
388      * If not explicitly set, the default value is <code>false</code>.
389      * </p>
390      *
391      * @return <code>true</code> if the <code>Job</code> should be garbage
392      * collected along with the <code>{@link Scheduler}</code>.
393      */

394     public boolean isVolatile() {
395         return volatility;
396     }
397
398     /**
399      * <p>
400      * Whether or not the <code>Job</code> should remain stored after it is
401      * orphaned (no <code>{@link Trigger}s</code> point to it).
402      * </p>
403      *
404      * <p>
405      * If not explicitly set, the default value is <code>false</code>.
406      * </p>
407      *
408      * @return <code>true</code> if the Job should remain persisted after
409      * being orphaned.
410      */

411     public boolean isDurable() {
412         return durability;
413     }
414
415     /**
416      * <p>
417      * Whether or not the <code>Job</code> implements the interface <code>{@link StatefulJob}</code>.
418      * </p>
419      */

420     public boolean isStateful() {
421         if (jobClass == null) {
422             return false;
423         }
424
425         return (StatefulJob.class.isAssignableFrom(jobClass));
426     }
427
428     /**
429      * <p>
430      * Instructs the <code>Scheduler</code> whether or not the <code>Job</code>
431      * should be re-executed if a 'recovery' or 'fail-over' situation is
432      * encountered.
433      * </p>
434      *
435      * <p>
436      * If not explicitly set, the default value is <code>false</code>.
437      * </p>
438      *
439      * @see JobExecutionContext#isRecovering()
440      */

441     public boolean requestsRecovery() {
442         return shouldRecover;
443     }
444
445     /**
446      * <p>
447      * Add the specified name of a <code>{@link JobListener}</code> to the
448      * end of the <code>Job</code>'s list of listeners.
449      * </p>
450      */

451     public void addJobListener(String JavaDoc name) {
452         if (jobListeners.add(name) == false) {
453             throw new IllegalArgumentException JavaDoc(
454                 "Job listener '" + name + "' is already registered for job detail: " + getFullName());
455         }
456     }
457
458     /**
459      * <p>
460      * Remove the specified name of a <code>{@link JobListener}</code> from
461      * the <code>Job</code>'s list of listeners.
462      * </p>
463      *
464      * @return true if the given name was found in the list, and removed
465      */

466     public boolean removeJobListener(String JavaDoc name) {
467         return jobListeners.remove(name);
468     }
469
470     /**
471      * <p>
472      * Returns an array of <code>String</code> s containing the names of all
473      * <code>{@link JobListener}</code>s assigned to the <code>Job</code>,
474      * in the order in which they should be notified.
475      * </p>
476      */

477     public String JavaDoc[] getJobListenerNames() {
478         return (String JavaDoc[])jobListeners.toArray(new String JavaDoc[jobListeners.size()]);
479     }
480
481     /**
482      * <p>
483      * Return a simple string representation of this object.
484      * </p>
485      */

486     public String JavaDoc toString() {
487         return "JobDetail '" + getFullName() + "': jobClass: '"
488                 + ((getJobClass() == null) ? null : getJobClass().getName())
489                 + " isStateful: " + isStateful() + " isVolatile: "
490                 + isVolatile() + " isDurable: " + isDurable()
491                 + " requestsRecovers: " + requestsRecovery();
492     }
493
494     public Object JavaDoc clone() {
495         JobDetail copy;
496         try {
497             copy = (JobDetail) super.clone();
498             copy.jobListeners = SetUtils.orderedSet(new HashSet JavaDoc(jobListeners));
499             if (jobDataMap != null) {
500                 copy.jobDataMap = (JobDataMap) jobDataMap.clone();
501             }
502         } catch (CloneNotSupportedException JavaDoc ex) {
503             throw new IncompatibleClassChangeError JavaDoc("Not Cloneable.");
504         }
505
506         return copy;
507     }
508 }
509
Popular Tags