KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > oddjob > quartz > TriggerSchedule


1 /*
2  * (c) Rob Gordon 2005
3  */

4 package org.oddjob.quartz;
5
6 import java.io.IOException JavaDoc;
7 import java.io.ObjectInputStream JavaDoc;
8 import java.io.ObjectOutputStream JavaDoc;
9 import java.io.Serializable JavaDoc;
10 import java.util.Date JavaDoc;
11
12 import org.oddjob.Iconic;
13 import org.oddjob.Resetable;
14 import org.oddjob.Stateful;
15 import org.oddjob.arooa.registry.ComponentRegistry;
16 import org.oddjob.framework.BasePrimary;
17 import org.oddjob.images.IconEvent;
18 import org.oddjob.images.IconListener;
19 import org.oddjob.state.JobState;
20 import org.oddjob.state.JobStateEvent;
21 import org.oddjob.state.JobStateListener;
22 import org.oddjob.util.OddjobConfigException;
23 import org.oddjob.util.OddjobConstantException;
24 import org.quartz.JobDataMap;
25 import org.quartz.JobDetail;
26 import org.quartz.Scheduler;
27 import org.quartz.SchedulerException;
28 import org.quartz.SimpleTrigger;
29
30 /**
31  * @oddjob.description The schedule component the
32  * {@link org.oddjob.quartz.QuartzSchedulerJob} creates to handle a
33  * {@link org.oddjob.scheduling.TriggerScheduleInstruction} schedule instruction.
34  * <p>
35  * The state of this component is a reflection of the job it schedules.
36  * Thus another trigger can be triggered on a trigger.
37  *
38  * @author Rob Gordon.
39  */

40 public class TriggerSchedule extends BasePrimary
41 implements Serializable JavaDoc, Stateful, QuartzSchedule, JobStateListener {
42     private static final long serialVersionUID = 20051121;
43     
44     /** The quartz schedule group. */
45     private static final String JavaDoc GROUP_NAME = Scheduler.DEFAULT_GROUP;
46     
47     /**
48      */

49     private JobToken jobToken;
50     
51     private transient ComponentRegistry componentRegistry;
52     
53     /**
54      * @oddjob.property
55      * @oddjob.description The job the trigger will trigger on.
56      * @oddjob.required Read only.
57      */

58     private transient Stateful on;
59     
60     private JobToken onToken;
61     
62     
63     /**
64      * @oddjob.property
65      * @oddjob.description The state to trigger on.
66      * @oddjob.required Read only.
67      */

68     private String JavaDoc state;
69
70     /** The JobState equivelant of state for testing state against. */
71     private JobState jobState;
72     
73     /** The last time the trigger fired. */
74     private Date JavaDoc lastTime;
75     
76     /** The scheduler to schedule on. */
77     private transient Scheduler scheduler;
78
79     /** The schedule id. */
80     private String JavaDoc id;
81     
82     
83     private transient JobStateListener jobListener;
84     
85     private transient IconListener iconListener;
86     
87     public TriggerSchedule() {
88         completeConstruction();
89     }
90     
91     private void completeConstruction() {
92         jobListener = new JobStateListener() {
93             public void jobStateChange(JobStateEvent event) {
94                 stateHandler.fireEvent(new JobStateEvent(
95                         TriggerSchedule.this, event.getJobState(),
96                         event.getTime(), event.getException()));
97             }
98         };
99         
100         iconListener = new IconListener() {
101             public void iconEvent(IconEvent e) {
102                 iconHelper.changeIcon(e.getIconId());
103             }
104         };
105     }
106     
107     /**
108      * Set the id for this schedule. This will be set when the schedule is
109      * created and can't be changed.
110      *
111      * @param id The id.
112      */

113     public void setId(String JavaDoc id) {
114         if (this.id != null) {
115             throw new OddjobConfigException("Id can't be changed.");
116         }
117         this.id = id;
118     }
119     
120     /**
121      * Helper funtion to build a trigger name.
122      *
123      * @return A quartz trigger name.
124      */

125     private String JavaDoc triggerName() {
126         return id + "-Trigger";
127     }
128     
129     /* (non-Javadoc)
130      * @see org.oddjob.quartz.QuartzSchedule#scheduleWith(org.oddjob.quartz.SimpleQuartzScheduler)
131      */

132     public void scheduleWith(Scheduler scheduler) throws SchedulerException {
133         if (jobToken == null) {
134             throw new NullPointerException JavaDoc("Job to schedule must be specified.");
135         }
136         if (onToken == null) {
137             throw new NullPointerException JavaDoc("Job to trigger on must be specified.");
138         }
139         
140         this.scheduler = scheduler;
141         
142         // retrieve data which might have been persisted in the job data map.
143
JobDetail jobDetail = scheduler.getJobDetail(toString(), Scheduler.DEFAULT_GROUP);
144         OddjobData ojd = null;
145         if (jobDetail != null) {
146             JobDataMap jobDataMap = jobDetail.getJobDataMap();
147             if (jobDataMap != null) {
148                 ojd = (OddjobData) jobDataMap.get(OddjobData.ODDJOB_DATA);
149             }
150         }
151         if (ojd != null) {
152             lastTime = ojd.getLast();
153         }
154
155         if (jobState == null) {
156             if (state == null) {
157                 jobState = JobState.COMPLETE;
158             }
159             else {
160                 jobState = JobState.stateFor(state);
161             }
162         }
163         if (jobState == null) {
164             throw new OddjobConfigException("State is invalid.");
165         }
166         
167         on = (Stateful) JobToken.retrieve(componentRegistry, onToken);
168         on.addJobStateListener(this);
169     }
170     
171     /* (non-Javadoc)
172      * @see org.oddjob.state.JobStateListener#jobStateChange(org.oddjob.state.JobStateEvent)
173      */

174     public void jobStateChange(JobStateEvent event) {
175         logger().debug("Trigger has state [" + event.getJobState() + "]");
176         if (event.getJobState() == jobState) {
177             // don't fire if event time hasn't changed.
178
if (event.getTime().equals(lastTime)) {
179                 logger().debug("Already had this event.");
180                 return;
181             }
182             lastTime = event.getTime();
183                         
184             SimpleTrigger trigger = new SimpleTrigger(triggerName(),
185                           GROUP_NAME,
186                           new Date JavaDoc(),
187                           null,
188                           0,
189                           0L);
190             try {
191                 JobDetail jobDetail = scheduler.getJobDetail(toString(), Scheduler.DEFAULT_GROUP);
192                 if (jobDetail == null) {
193
194                     OddjobData ojd = new OddjobData();
195                     ojd.setJob(new Execute());
196                     ojd.setLast(lastTime);
197                     
198                     JobDataMap jobDataMap = new JobDataMap();
199                     
200                     jobDataMap.put(OddjobData.ODDJOB_DATA, ojd);
201                     
202                     jobDetail = new JobDetail(toString(),
203                             Scheduler.DEFAULT_GROUP,
204                             RunnableQuartzJob.class);
205                     
206                     jobDetail.setJobDataMap(jobDataMap);
207                     scheduler.scheduleJob(jobDetail, trigger);
208                 }
209                 else {
210                     JobDataMap jobDataMap = jobDetail.getJobDataMap();
211                     OddjobData ojd = (OddjobData) jobDataMap.get(OddjobData.ODDJOB_DATA);
212                     // it's a reference so we don't need to add it back.
213
ojd.setLast(lastTime);
214                     trigger.setJobName(jobDetail.getName());
215                     trigger.setJobGroup(jobDetail.getGroup());
216                     scheduler.rescheduleJob(trigger.getName(), jobDetail.getGroup(), trigger);
217                 }
218             } catch (SchedulerException e) {
219                 logger().error("Failed to schedule.", e);
220             }
221         }
222     }
223     
224     /*
225      * (non-Javadoc)
226      * @see org.oddjob.quartz.QuartzSchedule#unschedule(org.quartz.Scheduler)
227      */

228     public void unscheduleFrom(Scheduler scheduler) throws SchedulerException {
229         scheduler.unscheduleJob(triggerName(), GROUP_NAME);
230     }
231     
232     public String JavaDoc getState() {
233         return state;
234     }
235     
236     public void setState(String JavaDoc state) {
237         this.state = state;
238     }
239         
240     public void setComponentRegistry(ComponentRegistry componentRegistry) {
241         this.componentRegistry = componentRegistry;
242     }
243     
244     public void setJob(Runnable JavaDoc job) {
245         if (job == null) {
246             throw new OddjobConfigException("No job to schedule specified!");
247         }
248         if (this.jobToken != null) {
249             throw new OddjobConstantException("[" + this
250                     + "] job can't be changed.");
251         }
252
253         this.jobToken = JobToken.create(componentRegistry, job);
254     }
255     
256     public void onDestroy() {
257         on.removeJobStateListener(this);
258     }
259     
260     
261     public String JavaDoc toString() {
262         if (getName() == null) {
263             return "Trigger [" + jobToken + "] on [" + on + "] [" + jobState + "]";
264         }
265         return getName();
266     }
267
268     public void setOn(Stateful triggerOn) {
269         this.onToken = JobToken.create(componentRegistry, triggerOn);
270     }
271     
272     private void writeObject(ObjectOutputStream JavaDoc os)
273     throws IOException JavaDoc {
274         os.defaultWriteObject();
275     }
276     
277     private void readObject(ObjectInputStream JavaDoc is)
278     throws IOException JavaDoc, ClassNotFoundException JavaDoc {
279         is.defaultReadObject();
280         completeConstruction();
281     }
282     
283     /**
284      */

285     class Execute implements Runnable JavaDoc {
286         synchronized public void run() {
287             logger().debug("Executing at [" + new Date JavaDoc()+ "]");
288             Runnable JavaDoc job = (Runnable JavaDoc) JobToken.retrieve(componentRegistry, jobToken);
289             if (job == null) {
290                 setJobStateException(
291                         new NullPointerException JavaDoc("Failed to find job for [" + jobToken + "]"));
292             }
293             
294             if (job instanceof Resetable) {
295                     ((Resetable) job).hardReset();
296             }
297             
298             if (job instanceof Stateful) {
299                 ((Stateful) job).addJobStateListener(jobListener);
300             }
301             if (job instanceof Iconic) {
302                 ((Iconic) job).addIconListener(iconListener);
303             }
304             
305             try {
306                 job.run();
307             }
308             catch (Throwable JavaDoc t) {
309                 setJobStateException(t);
310             }
311             finally {
312                 if (job instanceof Stateful) {
313                     ((Stateful) job).removeJobStateListener(jobListener);
314                 }
315                 if (job instanceof Iconic) {
316                     ((Iconic) job).removeIconListener(iconListener);
317                 }
318             }
319         }
320     }
321 }
322
Popular Tags