KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > jonas_ejb > container > JTimer


1 /**
2  * JOnAS: Java(TM) Open Application Server
3  * Copyright (C) 1999 Bull S.A.
4  * Contact: jonas-team@objectweb.org
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19  * USA
20  *
21  * --------------------------------------------------------------------------
22  * $Id: JTimer.java,v 1.13 2005/07/12 08:48:04 durieuxp Exp $
23  * --------------------------------------------------------------------------
24  */

25
26 package org.objectweb.jonas_ejb.container;
27
28 import java.io.Serializable JavaDoc;
29 import java.util.Date JavaDoc;
30
31 import javax.ejb.EJBException JavaDoc;
32 import javax.ejb.NoSuchObjectLocalException JavaDoc;
33 import javax.ejb.Timer JavaDoc;
34 import javax.ejb.TimerHandle JavaDoc;
35 import javax.transaction.RollbackException JavaDoc;
36 import javax.transaction.Status JavaDoc;
37 import javax.transaction.Synchronization JavaDoc;
38 import javax.transaction.SystemException JavaDoc;
39 import javax.transaction.Transaction JavaDoc;
40 import javax.transaction.TransactionManager JavaDoc;
41
42 import org.objectweb.jonas_timer.TimerEvent;
43 import org.objectweb.jonas_timer.TimerEventListener;
44 import org.objectweb.jonas_timer.TimerManager;
45 import org.objectweb.jonas_timer.TraceTimer;
46 import org.objectweb.util.monolog.api.BasicLevel;
47
48 /**
49  * JOnAS Implementation of the Timer interface (from EJB 2.1) This is a basic
50  * implementation based on jonas_timer. A later (and better ?) implementation
51  * could be based on Quartz.
52  * @author Philippe Durieux
53  */

54 public class JTimer implements Timer JavaDoc, TimerEventListener, Synchronization JavaDoc {
55
56     /**
57      * true if "one-shot" timer
58      */

59     private boolean oneshot;
60
61     /**
62      * period in case of repeatable timer (millisec)
63      */

64     private long period;
65
66     /**
67      * initial duration (millisec)
68      */

69     private long initial;
70
71     /**
72      * The TimerService that manages this Timer.
73      */

74     private JTimerService timerservice;
75
76     /**
77      * Info provided at Timer Creation time.
78      */

79     private Serializable JavaDoc info;
80
81     /**
82      * Jonas Timer Manager
83      */

84     private TimerManager tim = TimerManager.getInstance();
85
86     /**
87      * jonas timer initial
88      */

89     private TimerEvent te1 = null;
90
91     /**
92      * repeatable jonas timer
93      */

94     private TimerEvent te2 = null;
95
96     /**
97      * Start Time of this Timer (millisec) used for Timer identification.
98      */

99     private long starttime;
100
101     /**
102      * Next expiration time Used to compute the remaining time.
103      */

104     private long endtime;
105
106     /**
107      * true when timer has been created inside current tx
108      */

109     private boolean createdInTx = false;
110
111     /**
112      * true when timer has been cancelled inside current tx
113      */

114     private boolean cancelledInTx = false;
115
116     /**
117      * true when timer has been cancelled
118      */

119     private boolean cancelled = false;
120
121     /**
122      * TimerHandle for this Timer
123      */

124     private TimerHandle JavaDoc myHandle = null;
125
126     /**
127      * constructor
128      */

129     public JTimer(JTimerService timerservice, long initial, long period, Serializable JavaDoc info) {
130         if (TraceTimer.isDebug()) {
131             TraceTimer.logger.log(BasicLevel.DEBUG, "New JTimer initial = " + initial + ", period = " + period);
132         }
133         this.timerservice = timerservice;
134         this.info = info;
135         this.period = period;
136         this.initial = initial;
137         oneshot = (period == 0);
138
139     }
140
141     /**
142      * @return the start time in millisec.
143      */

144     public long getStartTime() {
145         return starttime;
146     }
147
148     /**
149      * @return the initial duration in millisec.
150      */

151     public long getInitial() {
152         return initial;
153     }
154
155     /**
156      * @return the period in millisec. (periodic timers only)
157      */

158     public long getPeriod() {
159         return period;
160     }
161
162     /**
163      * @return the Jonas Timer Service that manages this Timer
164      */

165     public JTimerService getTimerService() {
166         return timerservice;
167     }
168
169     /**
170      * start the Timer
171      */

172     public void startTimer() {
173
174         // If this is created inside a transaction, register this object as a synchronization.
175
TransactionManager JavaDoc tm = timerservice.getTransactionManager();
176         try {
177             Transaction JavaDoc tx = tm.getTransaction();
178             if (tx != null) {
179                 tx.registerSynchronization(this);
180                 createdInTx = true;
181             }
182         } catch (SystemException JavaDoc e) {
183             TraceTimer.logger.log(BasicLevel.ERROR, "Cannot get Transaction", e);
184         } catch (IllegalStateException JavaDoc e) {
185             TraceTimer.logger.log(BasicLevel.ERROR, "Cannot register synchronization:", e);
186         } catch (RollbackException JavaDoc e) {
187             TraceTimer.logger.log(BasicLevel.ERROR, "transaction already rolled back", e);
188         }
189
190         // init time
191
starttime = System.currentTimeMillis();
192         endtime = starttime + initial;
193
194         // Create the jonas timer
195
te1 = tim.addTimerMs(this, initial, null, false);
196     }
197
198     /**
199      * Stop a timer. Used internally.
200      */

201     public void stopTimer() {
202         if (TraceTimer.isDebug()) {
203             TraceTimer.logger.log(BasicLevel.DEBUG, "Stop JTimer");
204         }
205         cancelled = true;
206         if (te1 != null) {
207             te1.unset();
208             te1 = null;
209         }
210         if (te2 != null) {
211             te2.unset();
212             te2 = null;
213         }
214     }
215
216     /**
217      * @return true if timer has been cancelled
218      */

219     public boolean isCancelled() {
220         return (cancelled || cancelledInTx);
221     }
222
223     // ------------------------------------------------------------------------------------
224
// The container must implement suitable equals() and hashCode() methods
225
// ------------------------------------------------------------------------------------
226

227     /**
228      * Indicates whether some other object is "equal to" this one.
229      * @param obj - the reference object with which to compare.
230      * @return true if this object is the same as the obj argument; false
231      * otherwise.
232      */

233     public boolean equals(Object JavaDoc obj) {
234         if (obj instanceof JTimer) {
235             JTimer timer2 = (JTimer) obj;
236             if (timer2.getInitial() != getInitial()) {
237                 if (TraceTimer.isDebug()) {
238                     TraceTimer.logger.log(BasicLevel.DEBUG, "different initial duration");
239                 }
240                 return false;
241             }
242             if (timer2.getPeriod() != getPeriod()) {
243                 if (TraceTimer.isDebug()) {
244                     TraceTimer.logger.log(BasicLevel.DEBUG, "different period");
245                 }
246                 return false;
247             }
248             if (timer2.getTimerService() != getTimerService()) {
249                 if (TraceTimer.isDebug()) {
250                     TraceTimer.logger.log(BasicLevel.DEBUG, "different timerservice");
251                 }
252                 return false;
253             }
254             if (TraceTimer.isDebug()) {
255                 TraceTimer.logger.log(BasicLevel.DEBUG, "timers are equal");
256             }
257             return true;
258         } else {
259             if (TraceTimer.isDebug()) {
260                 TraceTimer.logger.log(BasicLevel.DEBUG, "not a Timer");
261             }
262             return false;
263         }
264     }
265
266     /**
267      * Returns a hash code value for the object.
268      * @return a hash code value for this object.
269      */

270     public int hashCode() {
271         return (int) (getPeriod() / 1000);
272     }
273
274     // ------------------------------------------------------------------------------------
275
// TimerEventListener implemetation
276
// ------------------------------------------------------------------------------------
277

278     /**
279      * The timer has just expired.
280      */

281     public void timeoutExpired(Object JavaDoc arg) {
282         if (TraceTimer.isDebug()) {
283             TraceTimer.logger.log(BasicLevel.DEBUG, "JTimer expires");
284         }
285         // propagate the timeout
286
timerservice.notify(this);
287         if (cancelled) {
288             if (TraceTimer.isDebug()) {
289                 TraceTimer.logger.log(BasicLevel.DEBUG, "JTimer cancelled during timeout");
290             }
291             return;
292         }
293         if (te2 == null) {
294             te1 = null;
295             if (oneshot) {
296                 timerservice.remove(this);
297                 cancelled = true;
298             } else {
299                 // start a new jonas timer (periodic)
300
if (TraceTimer.isDebug()) {
301                     TraceTimer.logger.log(BasicLevel.DEBUG, "Start periodic jonas timer");
302                 }
303                 endtime = System.currentTimeMillis() + period;
304                 te2 = tim.addTimerMs(this, period, null, true);
305             }
306         } else {
307             // recompute time of next expiration
308
endtime = System.currentTimeMillis() + period;
309         }
310     }
311
312     // ------------------------------------------------------------------------------------
313
// Timer implemetation
314
// ------------------------------------------------------------------------------------
315

316     /**
317      * Cause the timer and all its associated expiration notifications to be
318      * cancelled.
319      * @throws IllegalStateException the instance is in a state that does not
320      * allow access to this method.
321      * @throws NoSuchObjectLocalException If invoked on a timer that has expired
322      * or has been cancelled.
323      * @throws EJBException If this method could not complete due to a
324      * system-level failure.
325      */

326     public void cancel() throws IllegalStateException JavaDoc, NoSuchObjectLocalException JavaDoc, EJBException JavaDoc {
327         if (cancelled || cancelledInTx) {
328             TraceTimer.logger.log(BasicLevel.DEBUG, "Timer cancelled");
329             throw new NoSuchObjectLocalException JavaDoc("Timer already cancelled");
330         }
331         if (TraceTimer.isDebug()) {
332             TraceTimer.logger.log(BasicLevel.DEBUG, "");
333         }
334
335         // If this is called inside a transaction, register this object as a synchronization.
336
TransactionManager JavaDoc tm = timerservice.getTransactionManager();
337         try {
338             Transaction JavaDoc tx = tm.getTransaction();
339             if (tx != null) {
340                 // will be cancelled at commit.
341
tx.registerSynchronization(this);
342                 cancelledInTx = true;
343             } else {
344                 doCancel();
345             }
346         } catch (SystemException JavaDoc e) {
347             TraceTimer.logger.log(BasicLevel.ERROR, "Cannot get Transaction", e);
348         } catch (IllegalStateException JavaDoc e) {
349             TraceTimer.logger.log(BasicLevel.ERROR, "Cannot register synchronization:", e);
350         } catch (RollbackException JavaDoc e) {
351             TraceTimer.logger.log(BasicLevel.ERROR, "transaction already rolled back", e);
352         }
353     }
354
355     private void doCancel() {
356         stopTimer();
357         timerservice.remove(this);
358     }
359
360     /**
361      * Get the number of milliseconds that will elapse before the next scheduled
362      * timer expiration.
363      * @return the number of milliseconds that will elapse before the next
364      * scheduled timer expiration.
365      * @throws IllegalStateException the instance is in a state that does not
366      * allow access to this method.
367      * @throws NoSuchObjectLocalException If invoked on a timer that has expired
368      * or has been cancelled.
369      * @throws EJBException If this method could not complete due to a
370      * system-level failure.
371      */

372     public long getTimeRemaining() throws IllegalStateException JavaDoc, NoSuchObjectLocalException JavaDoc, EJBException JavaDoc {
373         if (cancelled || cancelledInTx) {
374             TraceTimer.logger.log(BasicLevel.DEBUG, "Timer cancelled");
375             throw new NoSuchObjectLocalException JavaDoc("Timer cancelled or expired");
376         }
377         if (TraceTimer.isDebug()) {
378             TraceTimer.logger.log(BasicLevel.DEBUG, "");
379         }
380         return endtime - System.currentTimeMillis();
381     }
382
383     /**
384      * Get the point in time at which the next timer expiration is scheduled to
385      * occur.
386      * @return the point in time at which the next timer expiration is scheduled
387      * to occur.
388      * @throws IllegalStateException the instance is in a state that does not
389      * allow access to this method.
390      * @throws NoSuchObjectLocalException If invoked on a timer that has expired
391      * or has been cancelled.
392      * @throws EJBException If this method could not complete due to a
393      * system-level failure.
394      */

395     public Date JavaDoc getNextTimeout() throws IllegalStateException JavaDoc, NoSuchObjectLocalException JavaDoc, EJBException JavaDoc {
396         if (cancelled || cancelledInTx) {
397             TraceTimer.logger.log(BasicLevel.DEBUG, "Timer cancelled");
398             throw new NoSuchObjectLocalException JavaDoc("Timer cancelled or expired");
399         }
400         if (TraceTimer.isDebug()) {
401             TraceTimer.logger.log(BasicLevel.DEBUG, "");
402         }
403         return new Date JavaDoc(endtime);
404     }
405
406     /**
407      * Get the information associated with the timer at the time of creation.
408      * @return The Serializable object that was passed in at timer creation, or
409      * null if the info argument passed in at timer creation was null.
410      * @throws IllegalStateException the instance is in a state that does not
411      * allow access to this method.
412      * @throws NoSuchObjectLocalException If invoked on a timer that has expired
413      * or has been cancelled.
414      * @throws EJBException If this method could not complete due to a
415      * system-level failure.
416      */

417     public Serializable JavaDoc getInfo() throws IllegalStateException JavaDoc, NoSuchObjectLocalException JavaDoc, EJBException JavaDoc {
418         if (cancelled || cancelledInTx) {
419             TraceTimer.logger.log(BasicLevel.DEBUG, "Timer cancelled");
420             throw new NoSuchObjectLocalException JavaDoc("Timer cancelled or expired");
421         }
422         if (TraceTimer.isDebug()) {
423             TraceTimer.logger.log(BasicLevel.DEBUG, "");
424         }
425         return info;
426     }
427
428     /**
429      * Get a serializable handle to the timer. This handle can be used at a
430      * later time to re-obtain the timer reference.
431      * @return a serializable handle to the timer.
432      * @throws IllegalStateException the instance is in a state that does not
433      * allow access to this method.
434      * @throws NoSuchObjectLocalException If invoked on a timer that has expired
435      * or has been cancelled.
436      * @throws EJBException If this method could not complete due to a
437      * system-level failure.
438      */

439     public TimerHandle JavaDoc getHandle() throws IllegalStateException JavaDoc, NoSuchObjectLocalException JavaDoc, EJBException JavaDoc {
440         if (cancelled || cancelledInTx) {
441             TraceTimer.logger.log(BasicLevel.DEBUG, "Timer cancelled");
442             throw new NoSuchObjectLocalException JavaDoc("Timer cancelled or expired");
443         }
444         if (TraceTimer.isDebug()) {
445             TraceTimer.logger.log(BasicLevel.DEBUG, "");
446         }
447         if (myHandle == null) {
448             myHandle = new JTimerHandle(initial, period, info, timerservice.getEjbName(),
449                                         timerservice.getContainer(), timerservice.getPK());
450         }
451         return myHandle;
452     }
453
454     // ------------------------------------------------------------------------------------
455
// Synchronization implemetation
456
// ------------------------------------------------------------------------------------
457

458     /**
459      * The afterCompletion method is called by the transaction manager after the
460      * transaction is committed or rolled back. This method executes without a
461      * transaction context.
462      * @param status The status of the transaction completion.
463      */

464     public void afterCompletion(int status) {
465         if (TraceEjb.isDebugTx()) {
466             TraceEjb.tx.log(BasicLevel.DEBUG, "");
467         }
468
469         // Timers created in a transaction that is rolled back must be removed.
470
if (createdInTx) {
471             if (status != Status.STATUS_COMMITTED && !cancelled) {
472                 doCancel();
473             }
474             createdInTx = false;
475         }
476
477         // Cancel timers only if transaction is committed
478
if (cancelledInTx) {
479             if (status == Status.STATUS_COMMITTED && !cancelled) {
480                 doCancel();
481             }
482             cancelledInTx = false;
483         }
484     }
485
486     /*
487      * @see javax.transaction.Synchronization#beforeCompletion()
488      */

489     public void beforeCompletion() {
490         // nothing to do
491
}
492
493 }
494
Popular Tags