View Javadoc
1 /*** 2 * Redistribution and use of this software and associated documentation 3 * ("Software"), with or without modification, are permitted provided 4 * that the following conditions are met: 5 * 6 * 1. Redistributions of source code must retain copyright 7 * statements and notices. Redistributions must also contain a 8 * copy of this document. 9 * 10 * 2. Redistributions in binary form must reproduce the 11 * above copyright notice, this list of conditions and the 12 * following disclaimer in the documentation and/or other 13 * materials provided with the distribution. 14 * 15 * 3. The name "Exolab" must not be used to endorse or promote 16 * products derived from this Software without prior written 17 * permission of Exoffice Technologies. For written permission, 18 * please contact info@exolab.org. 19 * 20 * 4. Products derived from this Software may not be called "Exolab" 21 * nor may "Exolab" appear in their names without prior written 22 * permission of Exoffice Technologies. Exolab is a registered 23 * trademark of Exoffice Technologies. 24 * 25 * 5. Due credit should be given to the Exolab Project 26 * (http://www.exolab.org/). 27 * 28 * THIS SOFTWARE IS PROVIDED BY EXOFFICE TECHNOLOGIES AND CONTRIBUTORS 29 * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT 30 * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 31 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 32 * EXOFFICE TECHNOLOGIES OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 33 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 34 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 35 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 37 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 38 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 39 * OF THE POSSIBILITY OF SUCH DAMAGE. 40 * 41 * Copyright 2000-2003 (C) Exoffice Technologies Inc. All Rights Reserved. 42 * 43 * $Id: BasicEventManager.java,v 1.8 2003/08/17 01:32:22 tanderson Exp $ 44 * 45 * Date Author Changes 46 * 07/27/00 jima Created 47 */ 48 package org.exolab.jms.events; 49 50 import java.io.IOException; 51 import java.io.Serializable; 52 import java.util.Comparator; 53 import java.util.HashMap; 54 import java.util.Iterator; 55 56 import org.apache.commons.logging.Log; 57 import org.apache.commons.logging.LogFactory; 58 59 import org.exolab.core.service.BasicService; 60 import org.exolab.core.service.ServiceException; 61 import org.exolab.core.service.ServiceState; 62 import org.exolab.core.threadPool.ThreadPool; 63 import org.exolab.core.util.OrderedQueue; 64 import org.exolab.jms.threads.ThreadPoolExistsException; 65 import org.exolab.jms.threads.ThreadPoolManager; 66 67 68 /*** 69 * The EventManager manages {@link Event} objects. It has methods to 70 * register and unregister events. It also extends {@link Runnable} interface 71 * which defines the thread responsible for dispatching events. 72 * <p> 73 * An event is defined to occur at sometime in the future, as specified either 74 * by an absolute time through {@link #registerEvent} or as relative time 75 * through {@link #registerEventRelative}. An event must have an associated 76 * event type and may have an attached <code>Serializable</code>, 77 * which is used when the EventManager makes a callback to the registered 78 * handler when the event fires. 79 * <p> 80 * The register methids will return an event identifier which can subsequently 81 * be used to unregister the event through the {@link #unregisterEvent} event. 82 * This is the only means of unregister an event. 83 * <p> 84 * If the {@link Event} object is incorrectly specified then the 85 * {@link IllegalEventDefinedException} exception is raised. 86 * <p> 87 * When an event fires the {@link EventManager} is responsible for ensuring 88 * that the event handler is notified. If the event handler has since been 89 * removed then the EventManager must gracefully abort the delivery and 90 * continue processing the next event. 91 * <p> 92 * Objects of type {@link Event} need to survive subsequent 93 * {@link EventManager} restarts, as such they must be persisted, which 94 * implies that the {@link EventHandler} needs to also be persisted. The 95 * ability to store the {@link EventHandler} as a <code>HandleIfc</code> object 96 * which can later be resolved to an object will be required. 97 * 98 * @version $Revision: 1.8 $ $Date: 2003/08/17 01:32:22 $ 99 * @author <a href="mailto:wood@intalio.com">Chris Wood</a> 100 */ 101 public class BasicEventManager 102 extends BasicService 103 implements EventManager { 104 105 // The unique name of this ThreadPool. 106 public transient static final String NAME = "EventManager"; 107 108 // The max number of threads for this pool. 109 public transient static final int MAX_THREADS = 5; 110 111 // serialized state. 112 113 /*** 114 * Maps ids to events. 115 */ 116 private HashMap _events = new HashMap(); 117 118 // nonserialized state. 119 120 /*** 121 * Thread pool manager. 122 */ 123 private transient ThreadPool _pool; 124 125 /*** 126 * Synchonization for the following two collections. 127 */ 128 private transient Object _queueSync = new Object(); 129 130 /*** 131 * Event queue. 132 */ 133 private transient OrderedQueue _queue = new OrderedQueue(_queueComparator); 134 135 /*** 136 * Used to generate unique queue entry ids. 137 */ 138 private transient long _seed; 139 140 /*** 141 * this is the name of the EventManagerThread in which events excecute. 142 */ 143 transient final static private String EVENT_MANAGER_THREAD_NAME = "EventManagerThread"; 144 145 /*** 146 * Singleton instance. 147 */ 148 transient static private EventManager _instance = null; 149 150 /*** 151 * The logger 152 */ 153 private static final Log _log = LogFactory.getLog(BasicEventManager.class); 154 155 156 /*** 157 * Return the singleton instance of the EventManager 158 * 159 * @return EventManager 160 */ 161 public static EventManager instance() { 162 if (_instance == null) 163 _instance = new BasicEventManager(); 164 165 return _instance; 166 } 167 168 protected BasicEventManager() { 169 super(EVENT_MANAGER_THREAD_NAME); 170 } 171 172 /*** 173 * Register an event to be fired once and only once at the specified 174 * abolsute time. The event object must be Serializable so that it can 175 * be persisted and restored across EventManager restarts. 176 * <p> 177 * If the specified event is ill-defined then the IllegalEventDefined- 178 * Exception exception is thrown. 179 * <p> 180 * Similarly, if the abolsute time has already passed then the exception 181 * IllegalEventDefinedException is raised. 182 * <p> 183 * The method returns an unique event identifier, which can subsequently 184 * be used to deregister the event. 185 * 186 * @param event information about the event 187 * @param abolsute the abolsute time, in ms, that the event 188 * must fire 189 * @return String unique event identifier 190 * @exception IllegalEventDefinedException 191 */ 192 public String registerEvent(Event event, long absolute) 193 throws IllegalEventDefinedException { 194 synchronized (_queueSync) { 195 QueueEntry entry = new QueueEntry(event, absolute, generateId()); 196 197 // add entry to the queue. 198 _queue.add(entry); 199 _events.put(entry.id, entry); 200 201 // notify the event thread. 202 _queueSync.notifyAll(); 203 return entry.id; 204 } 205 } 206 207 /*** 208 * Register an event to be fired once and only once at a time relative to 209 * now. The event object must be Serializable so that it can be persisted 210 * and restored across EventManager restarts. 211 * <p> 212 * If the specified event is ill-defined then the IllegalEventDefined- 213 * Exception exception is thrown. 214 * <p> 215 * The method returns an unique event identifier, which can subsequently 216 * be used to deregister the event. 217 * 218 * @param event information about the event 219 * @param relative the relative time in ms 220 * (currently no reference to locale). 221 * @return String unique event identifier, 222 * @exception IllegalEventDefinedException 223 */ 224 public String registerEventRelative(Event event, long relative) 225 throws IllegalEventDefinedException { 226 return registerEvent(event, System.currentTimeMillis() + relative); 227 } 228 229 /*** 230 * Unregister the event specified by the event identifier. If the event 231 * does not exist then fail silently. 232 * 233 * @param String unique event identifier. 234 */ 235 public void unregisterEvent(String id) { 236 synchronized (_queueSync) { 237 // remove from the events list 238 Object obj = _events.remove(id); 239 if (obj == null) 240 return; 241 // remove from the queue. 242 _queue.remove(obj); 243 } 244 } 245 246 // implementation of BasicService.run 247 public void run() { 248 synchronized (_queueSync) { 249 QueueEntry entry; 250 long currentTime; 251 while (getState() != ServiceState.STOPPED) { 252 currentTime = System.currentTimeMillis(); 253 try { 254 entry = (QueueEntry) _queue.firstElement(); 255 } catch (java.util.NoSuchElementException ex) { 256 // queue is empty. 257 try { 258 _queueSync.wait(); 259 } catch (InterruptedException ex1) { 260 break; 261 } 262 continue; 263 } 264 265 if (entry.absolute <= currentTime) { 266 // trigger any expired events 267 try { 268 getThreadPool().execute(entry); 269 } catch (InterruptedException ex) { 270 } 271 _queue.removeFirstElement(); 272 _events.remove(entry.id); 273 } else { 274 // wait for either the next event to expire or an element to be 275 // added to the queue. 276 try { 277 _queueSync.wait(entry.absolute - currentTime); 278 } catch (InterruptedException ex) { 279 // ignore 280 } 281 } 282 } 283 } 284 } 285 286 /*** 287 * Generate unique queued object identifier. 288 */ 289 private synchronized String generateId() { 290 return Long.toString(++_seed); 291 } 292 293 /*** 294 * Add events back to the event queue. 295 */ 296 private void readObject(java.io.ObjectInputStream in) 297 throws IOException, ClassNotFoundException { 298 synchronized (_queueSync) { 299 in.defaultReadObject(); 300 301 // fillin the queue 302 Iterator itt = _events.values().iterator(); 303 while (itt.hasNext()) 304 _queue.add(itt.next()); 305 } 306 } 307 308 private void writeObject(java.io.ObjectOutputStream out) 309 throws IOException { 310 synchronized (_queueSync) { 311 // pause the queue thread while we serialize 312 out.defaultWriteObject(); 313 } 314 } 315 316 public void start() throws ServiceException { 317 super.start(); 318 } 319 320 /*** 321 * Return a reference ot the thread pool manager. This object is chached 322 * for future reference 323 * 324 * @return ThreadPool 325 */ 326 private ThreadPool getThreadPool() { 327 if (_pool == null) { 328 // At startup Event Mgr is triggered before the Service 329 // locator has registered the ThreadPoolMgr, causing 330 // an exception. Use the instance variable for now to 331 // avoid this problem. jimm 332 // _pool = (ThreadPoolMgr)ServiceLocator.locateService( 333 // ServiceConstants.ThreadPoolManager); 334 try { 335 _pool = ThreadPoolManager.instance().createThreadPool 336 (NAME, MAX_THREADS); 337 } catch (ThreadPoolExistsException err) { 338 _log.error("Thread pool " + NAME + " already exists"); 339 } 340 } 341 342 return _pool; 343 } 344 345 /*** 346 * Compare queue entries on expiration times 347 */ 348 private transient static final Comparator _queueComparator = 349 new Comparator() { 350 351 public int compare(Object obj1, Object obj2) { 352 QueueEntry qe1 = (QueueEntry) obj1; 353 QueueEntry qe2 = (QueueEntry) obj2; 354 355 if (qe1.absolute < qe2.absolute) 356 return -1; 357 if (qe1.absolute > qe2.absolute) 358 return 1; 359 return 0; 360 } 361 362 public boolean equals(Object that) { 363 return (this == that); 364 } 365 }; 366 367 /*** 368 * Entry on the task queue. 369 */ 370 class QueueEntry implements Serializable, Runnable { 371 372 QueueEntry(Event event, long absolute, String id) { 373 this.absolute = absolute; 374 this.event = event; 375 this.id = id; 376 } 377 378 private long absolute; 379 private Event event; 380 private String id; 381 382 public void run() { 383 event.getEventListener().handleEvent(event.getEventType(), 384 event.getCallbackObject(), System.currentTimeMillis()); 385 } 386 } 387 388 } //-- BasicEventManager

This page was automatically generated by Maven