001: /* ====================================================================
002: The Jicarilla Software License
003:
004: Copyright (c) 2003 Leo Simons.
005: All rights reserved.
006:
007: Permission is hereby granted, free of charge, to any person obtaining
008: a copy of this software and associated documentation files (the
009: "Software"), to deal in the Software without restriction, including
010: without limitation the rights to use, copy, modify, merge, publish,
011: distribute, sublicense, and/or sell copies of the Software, and to
012: permit persons to whom the Software is furnished to do so, subject to
013: the following conditions:
014:
015: The above copyright notice and this permission notice shall be
016: included in all copies or substantial portions of the Software.
017:
018: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
019: EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
020: MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
021: IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
022: CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
023: TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
024: SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
025: ==================================================================== */
026: package org.jicarilla.lang;
027:
028: import EDU.oswego.cs.dl.util.concurrent.Executor;
029: import EDU.oswego.cs.dl.util.concurrent.ThreadedExecutor;
030:
031: /**
032: * <p>Provides generic support for the 'inner worker thread' coding pattern
033: * where child classes are shielded from most of the processing mechanics.
034: * Subclasses will need to implement {@link #work()}, which will be called from
035: * the inner worker thread.</p>
036: *
037: * <p>Exactly how often or in what kind of thread configuration the
038: * <code>work()</code> method can be customized by passing in a custom
039: * {@link Executor}. If none is provided, a single new thread will be created.
040: * The worker passed to this executor will never {@link Thread#sleep(long)},
041: * but it will {@link Thread#yield()} after each call to
042: * <code>work()</code>.</p>
043: *
044: * <p>Note that this class is {@link Active}, and extends from
045: * {@link AbstractActive}. As such, you should not override the
046: * {@link #initialize()} nor the {@link #dispose()} methods, but only ever
047: * override {@link #doInitialize()} and/or {@link #doDispose()}. When you do,
048: * make sure to call the overridden methods as well.</p>
049: *
050: * @author <a href="lsimons at jicarilla dot org">Leo Simons</a>
051: * @version $Id: AbstractExecutable.java,v 1.1 2004/03/23 13:37:57 lsimons Exp $
052: */
053: public abstract class AbstractExecutable extends AbstractActive {
054: /** The executor that will execute our worker. */
055: protected Executor m_executor;
056: /** The worker that calls work(). */
057: protected Worker m_worker;
058: /** The recipient of errors thrown by work(). */
059: protected ExceptionListener m_listener;
060:
061: /**
062: * Create a new instance that uses the {@link ThreadedExecutor}.
063: */
064: public AbstractExecutable() {
065: this (new ThreadedExecutor());
066: }
067:
068: /**
069: * Create a new instance that uses the provided executor.
070: *
071: * @param executor the executor to use.
072: */
073: public AbstractExecutable(final Executor executor) {
074: this (executor, null);
075: }
076:
077: /**
078: * Create a new instance that uses the provided executor and sends all
079: * exceptions thrown by @{link #work()} to the provided listener.
080: *
081: * @param executor the executor to use.
082: * @param listener the listener to send exceptions to.
083: * May be <code>null</code>.
084: */
085: public AbstractExecutable(final Executor executor,
086: final ExceptionListener listener) {
087: Assert.assertNotNull(executor);
088:
089: m_executor = executor;
090: m_listener = listener;
091: }
092:
093: /**
094: * Creates a new worker and tells the executor to execute it.
095: *
096: * @throws InterruptedException if the current thread has been
097: * {@link java.lang.Thread#interrupt()}ed
098: */
099: protected void doInitialize() throws InterruptedException,
100: Throwable {
101: m_worker = new Worker();
102: m_executor.execute(m_worker);
103: m_executor = null; // never needed again!
104: }
105:
106: /**
107: * Stops the worker and disposes of all state.
108: */
109: protected void doDispose() {
110: m_worker.stop();
111: m_worker = null;
112: m_executor = null; // redundant!
113: m_listener = null;
114: }
115:
116: /**
117: * This method is called whenever your 'executable' class should perform 'a
118: * unit' of work. Override it in subclasses to do some meaningful stuff.
119: * Also note that a call to Thread.yield() is made every time this method
120: * returns, so you don't generally need to call yield() yourself...unless
121: * you're doing a pretty intensive operation.
122: *
123: * @throws Throwable if any problem occurs. The exception will be fed to
124: * any exceptionlisteners that may exist.
125: */
126: protected void work() throws Throwable {
127: }
128:
129: /**
130: * Private helper class that will be fed to an <code>Executor</code>. It
131: * loops endlessly until {@link #stop()} is called, calling the {@link
132: * #work()} method on each iteration, and {@link Thread#yield()} after
133: * that.
134: */
135: protected class Worker implements Runnable {
136: /** flag that will be set to false if the worker should stop. */
137: protected boolean m_running = true;
138:
139: /**
140: * The worker method.
141: */
142: public void run() {
143: try {
144: while (m_running) {
145: work();
146: Thread.yield();
147: }
148: } catch (Throwable t) {
149: if (m_listener != null) {
150: m_listener.exceptionOccurred(t);
151: }
152: m_running = false;
153: Thread.currentThread().interrupt();
154: }
155: }
156:
157: /**
158: * Stop the worker.
159: */
160: public void stop() {
161: m_running = false;
162: }
163: }
164: }
|