001: package org.swingml.event;
002:
003: import java.util.*;
004:
005: /**
006: * @author CrossLogic
007: */
008: public class ThreadedEventHandler {
009:
010: /**
011: * This is the class that manages the cross communication between threads.
012: * If you are out of runnable objects, this queue will block (effectively
013: * making the background thread sleep) until a runnable object is available
014: * (via the emptyMonitor). At the same time, it lets as many runnables as
015: * necessary be queued. There is an out-of-memory danger here if the
016: * background thread can't keep up with the UI. A limit can be set so that
017: * the main thread is forced to block as well if the queue gets too full.
018: */
019: class SimpleUnboundedQueue {
020:
021: private List elements = new ArrayList();
022: private Object emptyMonitor = new Object();
023:
024: public Object dequeue() {
025: synchronized (emptyMonitor) {
026: while (elements.isEmpty()) {
027: try {
028: emptyMonitor.wait(); // wait for an enqueue.
029: } catch (InterruptedException e) {
030: }
031: }
032: // get from head
033: return elements.remove(0);
034: }
035: }
036:
037: public void enqueue(Object element) {
038: synchronized (emptyMonitor) {
039: // put on tail
040: elements.add(element);
041: emptyMonitor.notifyAll(); // wake up any dequeue-ing thread.
042: }
043: }
044:
045: public int size() {
046: return elements.size();
047: }
048: }
049:
050: private class SwingMLEventConsumer implements Runnable {
051:
052: public void run() {
053: while (true) {
054: // blocks until an event is available
055: final ISwingMLEvent event = (ISwingMLEvent) events
056: .dequeue();
057: try {
058: // Execute event on a new thread
059: Runnable aRunnable = new Runnable() {
060:
061: public void run() {
062: executeEvent(event);
063: }
064: };
065: Thread bgThread = new Thread(aRunnable);
066: bgThread.start();
067: } catch (Throwable t) {
068: if (t instanceof ThreadDeath) {
069: throw (ThreadDeath) t;
070: }
071: // handle exception here - this could be via pluggable
072: // exception handler, or a call back on to the event
073: // such as event.onException(t);
074: }
075: }
076: }
077: }
078:
079: private static List eventListeners = new ArrayList();
080: private static ThreadedEventHandler instance = null;
081: private static int runningTasks = 0;
082:
083: public static void addListener(IEventListener eventListener) {
084: if (!getEventListeners().contains(eventListener)) {
085: eventListeners.add(eventListener);
086: }
087: }
088:
089: public static List getEventListeners() {
090: return new ArrayList(eventListeners);
091: }
092:
093: public static ThreadedEventHandler getInstance() {
094: if (instance == null) {
095: instance = new ThreadedEventHandler();
096: instance.start();
097: }
098: return instance;
099: }
100:
101: public static void removeListener(IEventListener eventListener) {
102: if (getEventListeners().contains(eventListener)) {
103: eventListeners.remove(eventListener);
104: }
105: }
106:
107: private SimpleUnboundedQueue events;
108:
109: private ThreadedEventHandler() {
110: }
111:
112: public void executeEvent(ISwingMLEvent event) {
113: notifyEventStarting(event);
114: final Object preExecuteResult = event.preExecute();
115: final Object executeResult = event.execute(preExecuteResult);
116: event.postExecute(executeResult);
117: notifyEventEnded(event);
118: }
119:
120: private void notifyEventEnded(ISwingMLEvent event) {
121: runningTasks--;
122: IEventListener listener;
123: Iterator schmiterator = getEventListeners().iterator();
124: while (schmiterator.hasNext()) {
125: listener = (IEventListener) schmiterator.next();
126: if (listener != null) {
127: listener.eventCompleted(event, runningTasks);
128: }
129: }
130: }
131:
132: private void notifyEventStarting(ISwingMLEvent event) {
133: runningTasks++;
134: IEventListener listener;
135: Iterator schmiterator = getEventListeners().iterator();
136: while (schmiterator.hasNext()) {
137: listener = (IEventListener) schmiterator.next();
138: if (listener != null) {
139: listener.eventStarting(event, runningTasks);
140: }
141: }
142: }
143:
144: public void queueEvent(ISwingMLEvent anEvent) {
145: events.enqueue(anEvent);
146: }
147:
148: /**
149: * Call this to initialize the executor.
150: */
151: public void start() {
152: events = new SimpleUnboundedQueue();
153: Thread t = new Thread(new SwingMLEventConsumer());
154: t.start();
155: }
156:
157: }
|