001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.ejb.txtimer;
023:
024: // $Id: TimerServiceImpl.java 57209 2006-09-26 12:21:57Z dimitris@jboss.org $
025:
026: import java.io.Serializable;
027: import java.util.ArrayList;
028: import java.util.Collection;
029: import java.util.Date;
030: import java.util.HashMap;
031: import java.util.Iterator;
032: import java.util.Map;
033:
034: import javax.ejb.EJBException;
035: import javax.ejb.Timer;
036: import javax.ejb.TimerHandle;
037: import javax.ejb.TimerService;
038: import javax.transaction.SystemException;
039: import javax.transaction.Transaction;
040: import javax.transaction.TransactionManager;
041:
042: import org.jboss.logging.Logger;
043:
044: /**
045: * The TimerService provides enterprise bean components with access to the
046: * container-provided Timer Service. The EJB Timer Service allows entity beans, stateless
047: * session beans, and message-driven beans to be registered for timer callback events at
048: * a specified time, after a specified elapsed time, or after a specified interval.
049: *
050: * @author Thomas.Diesler@jboss.org
051: * @author Dimitris.Andreadis@jboss.org
052: * @version $Revision: 57209 $
053: * @since 07-Apr-2004
054: */
055: public class TimerServiceImpl implements TimerService {
056: // logging support
057: private static Logger log = Logger
058: .getLogger(TimerServiceImpl.class);
059:
060: // The tx manager
061: private TransactionManager transactionManager;
062: // The persistence policy plug-in
063: private PersistencePolicy persistencePolicy;
064: // The timerId generator
065: private TimerIdGenerator timerIdGenerator;
066: // The retry policy
067: private RetryPolicy retryPolicy;
068:
069: // The timed object id
070: private TimedObjectId timedObjectId;
071: // The invoker for the timed object
072: private TimedObjectInvoker timedObjectInvoker;
073:
074: // Map<TimerHandleImpl,TimerImpl>
075: private Map timers = new HashMap();
076:
077: // Constructors --------------------------------------------------
078:
079: /**
080: * CTOR
081: *
082: * All the dependencies are supplied by the caller
083: */
084: public TimerServiceImpl(TimedObjectId timedObjectId,
085: TimedObjectInvoker timedObjectInvoker,
086: TransactionManager transactionManager,
087: PersistencePolicy persistencePolicy,
088: RetryPolicy retryPolicy, TimerIdGenerator timerIdGenerator) {
089: this .timedObjectId = timedObjectId;
090: this .timedObjectInvoker = timedObjectInvoker;
091: this .transactionManager = transactionManager;
092: this .persistencePolicy = persistencePolicy;
093: this .timerIdGenerator = timerIdGenerator;
094: this .retryPolicy = retryPolicy;
095: }
096:
097: // Public --------------------------------------------------------
098:
099: /**
100: * Get the list of all registerd timers, both active and inactive
101: */
102: public Collection getAllTimers() {
103: synchronized (timers) {
104: return new ArrayList(timers.values());
105: }
106: }
107:
108: /**
109: * Get the Timer for the given timedObjectId
110: */
111: public Timer getTimer(TimerHandle handle) {
112: TimerImpl timer = (TimerImpl) timers.get(handle);
113: if (timer != null && timer.isActive())
114: return timer;
115: else
116: return null;
117: }
118:
119: /**
120: * Kill all timers
121: *
122: * @param keepState Whether to maintain or remove timer persistent state
123: */
124: public void shutdown(boolean keepState) {
125: synchronized (timers) {
126: Iterator it = timers.values().iterator();
127: while (it.hasNext()) {
128: TimerImpl timer = (TimerImpl) it.next();
129: timer.stopTimer();
130:
131: if (keepState == false)
132: persistencePolicy.deleteTimer(timer.getTimerId(),
133: timer.getTimedObjectId());
134: }
135: timers.clear();
136: }
137: }
138:
139: /**
140: * Get the TimedObjectInvoker associated with this TimerService
141: */
142: public TimedObjectInvoker getTimedObjectInvoker() {
143: return timedObjectInvoker;
144: }
145:
146: // javax.ejb.TimerService ----------------------------------------
147:
148: /**
149: * Create a single-action txtimer that expires after a specified duration.
150: *
151: * @param duration The number of milliseconds that must elapse before the txtimer expires.
152: * @param info Application information to be delivered along with the txtimer expiration
153: * notification. This can be null.
154: * @return The newly created Timer.
155: * @throws IllegalArgumentException If duration is negative
156: * @throws IllegalStateException If this method is invoked while the instance is in
157: * a state that does not allow access to this method.
158: * @throws javax.ejb.EJBException If this method could not complete due to a system-level failure.
159: */
160: public Timer createTimer(long duration, Serializable info)
161: throws IllegalArgumentException, IllegalStateException,
162: EJBException {
163: if (duration < 0)
164: throw new IllegalArgumentException("duration is negative");
165:
166: return createTimer(new Date(System.currentTimeMillis()
167: + duration), 0, info);
168: }
169:
170: /**
171: * Create an interval txtimer whose first expiration occurs after a specified duration,
172: * and whose subsequent expirations occur after a specified interval.
173: *
174: * @param initialDuration The number of milliseconds that must elapse before the first
175: * txtimer expiration notification.
176: * @param intervalDuration The number of milliseconds that must elapse between txtimer
177: * expiration notifications. Expiration notifications are
178: * scheduled relative to the time of the first expiration. If
179: * expiration is delayed(e.g. due to the interleaving of other
180: * method calls on the bean) two or more expiration notifications
181: * may occur in close succession to "catch up".
182: * @param info Application information to be delivered along with the txtimer expiration
183: * notification. This can be null.
184: * @return The newly created Timer.
185: * @throws IllegalArgumentException If initialDuration is negative, or intervalDuration
186: * is negative.
187: * @throws IllegalStateException If this method is invoked while the instance is in
188: * a state that does not allow access to this method.
189: * @throws javax.ejb.EJBException If this method could not complete due to a system-level failure.
190: */
191: public Timer createTimer(long initialDuration,
192: long intervalDuration, Serializable info)
193: throws IllegalArgumentException, IllegalStateException,
194: EJBException {
195: if (initialDuration < 0)
196: throw new IllegalArgumentException(
197: "initial duration is negative");
198: if (intervalDuration < 0)
199: throw new IllegalArgumentException(
200: "interval duration is negative");
201:
202: return createTimer(new Date(System.currentTimeMillis()
203: + initialDuration), intervalDuration, info);
204: }
205:
206: /**
207: * Create a single-action txtimer that expires at a given point in time.
208: *
209: * @param expiration The point in time at which the txtimer must expire.
210: * @param info Application information to be delivered along with the txtimer expiration
211: * notification. This can be null.
212: * @return The newly created Timer.
213: * @throws IllegalArgumentException If expiration is null, or expiration.getTime() is negative.
214: * @throws IllegalStateException If this method is invoked while the instance is in
215: * a state that does not allow access to this method.
216: * @throws javax.ejb.EJBException If this method could not complete due to a system-level failure.
217: */
218: public Timer createTimer(Date expiration, Serializable info)
219: throws IllegalArgumentException, IllegalStateException,
220: EJBException {
221: if (expiration == null)
222: throw new IllegalArgumentException("expiration is null");
223:
224: return createTimer(expiration, 0, info);
225: }
226:
227: /**
228: * Create an interval txtimer whose first expiration occurs at a given point in time and
229: * whose subsequent expirations occur after a specified interval.
230: *
231: * @param initialExpiration The point in time at which the first txtimer expiration must occur.
232: * @param intervalDuration The number of milliseconds that must elapse between txtimer
233: * expiration notifications. Expiration notifications are
234: * scheduled relative to the time of the first expiration. If
235: * expiration is delayed(e.g. due to the interleaving of other
236: * method calls on the bean) two or more expiration notifications
237: * may occur in close succession to "catch up".
238: * @param info Application information to be delivered along with the txtimer expiration
239: * notification. This can be null.
240: * @return The newly created Timer.
241: * @throws IllegalArgumentException If initialExpiration is null, or initialExpiration.getTime()
242: * is negative, or intervalDuration is negative.
243: * @throws IllegalStateException If this method is invoked while the instance is in
244: * a state that does not allow access to this method.
245: * @throws javax.ejb.EJBException If this method could not complete due to a system-level failure.
246: */
247: public Timer createTimer(Date initialExpiration,
248: long intervalDuration, Serializable info)
249: throws IllegalArgumentException, IllegalStateException,
250: EJBException {
251: if (initialExpiration == null)
252: throw new IllegalArgumentException(
253: "initial expiration is null");
254: if (intervalDuration < 0)
255: throw new IllegalArgumentException(
256: "interval duration is negative");
257:
258: try {
259: String timerId = timerIdGenerator.nextTimerId();
260: TimerImpl timer = new TimerImpl(this , timerId,
261: timedObjectId, timedObjectInvoker, info);
262: persistencePolicy.insertTimer(timerId, timedObjectId,
263: initialExpiration, intervalDuration, info);
264: timer.startTimer(initialExpiration, intervalDuration);
265: return timer;
266: } catch (Exception e) {
267: log.error("Cannot create txtimer", e);
268: return null;
269: }
270: }
271:
272: /**
273: * Get all the active timers associated with this bean.
274: *
275: * @return A collection of javax.ejb.Timer objects.
276: * @throws IllegalStateException If this method is invoked while the instance is in
277: * a state that does not allow access to this method.
278: * @throws javax.ejb.EJBException If this method could not complete due to a system-level failure.
279: */
280: public Collection getTimers() throws IllegalStateException,
281: EJBException {
282: ArrayList activeTimers = new ArrayList();
283: synchronized (timers) {
284: Iterator it = timers.values().iterator();
285: while (it.hasNext()) {
286: TimerImpl timer = (TimerImpl) it.next();
287: if (timer.isActive())
288: activeTimers.add(timer);
289: }
290: }
291: return activeTimers;
292: }
293:
294: // Package protected ---------------------------------------------
295:
296: /**
297: * Get the current transaction
298: */
299: Transaction getTransaction() {
300: try {
301: return transactionManager.getTransaction();
302: } catch (SystemException e) {
303: return null;
304: }
305: }
306:
307: /**
308: * Add a txtimer to the list of active timers
309: */
310: void addTimer(TimerImpl txtimer) {
311: synchronized (timers) {
312: TimerHandle handle = new TimerHandleImpl(txtimer);
313: timers.put(handle, txtimer);
314: }
315: }
316:
317: /**
318: * Remove a txtimer from the list of active timers
319: */
320: void removeTimer(TimerImpl txtimer) {
321: synchronized (timers) {
322: persistencePolicy.deleteTimer(txtimer.getTimerId(), txtimer
323: .getTimedObjectId());
324: timers.remove(new TimerHandleImpl(txtimer));
325: }
326: }
327:
328: void retryTimeout(TimerImpl txtimer) {
329: try {
330: retryPolicy.retryTimeout(timedObjectInvoker, txtimer);
331: } catch (Exception e) {
332: log.error("Retry timeout failed for timer: " + txtimer, e);
333: }
334: }
335: }
|