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.Channel;
029: import EDU.oswego.cs.dl.util.concurrent.Executor;
030: import EDU.oswego.cs.dl.util.concurrent.LinkedQueue;
031:
032: import java.lang.reflect.InvocationTargetException;
033:
034: /**
035: * <p>A basic {@link AsyncEnabled} implementation that inherits actual thread
036: * handling to the {@link AbstractActive} class. Any calls to
037: * {@link #handle(Invocation)} are queued, with the {@link #work()} method
038: * (implementing the 'interface' exposed by <code>AbstractExecutable</code>)
039: * dequeuing an invocation and sending it to
040: * {@link #doHandle(Invocation)}.</p>
041: *
042: * <p>To create concrete <code>AsyncEnabled</code> classes based on this
043: * abstract class, there's usually little you will want or need to do. Likely
044: * entry points for customization include the {@link #getImmediateResult(Invocation)}
045: * method (which is called from <code>handle()</code>), the
046: * <code>doHandle()</code> method (if you wish to redirect the handling of the
047: * asynchronous calls somewhere else) and the
048: * {@link #doHandleException(Invocation)} method (if you wish to handle
049: * exceptions thrown from applying <code>Invocation</code>s gracefully).</p>
050: *
051: * @author <a href="lsimons at jicarilla dot org">Leo Simons</a>
052: * @version $Id: AbstractAsyncEnabled.java,v 1.3 2003/11/17 21:10:23 lsimons
053: * Exp $
054: */
055: public abstract class AbstractAsyncEnabled extends AbstractExecutable
056: implements AsyncEnabled {
057: /** The recipient of incoming calls. */
058: protected final Channel m_incoming;
059:
060: /**
061: * Create an instance using a custom executor.
062: *
063: * @param executor the <code>Executor</code> that will be used in
064: * {@link AbstractExecutable} to do the work
065: */
066: public AbstractAsyncEnabled(final Executor executor) {
067: super (executor);
068:
069: m_incoming = new LinkedQueue();
070: }
071:
072: /**
073: * Create an instance using a custom executor and an exception listener.
074: *
075: * @param executor the <code>Executor</code> that will be used in
076: * {@link AbstractExecutable} to do the work
077: * @param listener the listener that will be notified of any abnomral
078: * problems occuring during the calls to {@link #work()}. Note that
079: * any exceptions resulting from applying an <code>Invocation</code>
080: * are <b>not</b> sent to this listener.
081: */
082: public AbstractAsyncEnabled(final Executor executor,
083: final ExceptionListener listener) {
084: super (executor, listener);
085:
086: m_incoming = new LinkedQueue();
087: }
088:
089: /**
090: * Enqueue the invocation on the asynchronous call stack.
091: *
092: * @param invocation the invocation to enqueue
093: * @return whatever {@link #getImmediateResult(Invocation)} returns
094: * @throws InterruptedException if the current thread has been
095: * {@link java.lang.Thread#interrupt()}ed
096: */
097: public Object handle(final Invocation invocation)
098: throws InterruptedException {
099: Assert.assertNotNull(invocation);
100:
101: m_incoming.put(invocation);
102: return getImmediateResult(invocation);
103: }
104:
105: /**
106: * Override this to specify what the handle() method should return after
107: * enqueuing an invocation. The default implementation simply returns
108: * <code>null</code>.
109: *
110: * @return null, but subclasses may change that behaviour
111: * @param invocation the invocation that has just been enqueued
112: */
113: protected Object getImmediateResult(final Invocation invocation) {
114: return null;
115: }
116:
117: /**
118: * This method will be called from the worker thread and you should
119: * implement whatever behaviour neccessary to complete the invocation. The
120: * default implementation simply runs the invocation.
121: *
122: * @param invocation the invocation that has just been dequeued and should
123: * now be applied or redirected somewhere else
124: */
125: protected void doHandle(final Invocation invocation) {
126: try {
127: final Object result = invocation.getMethod().invoke(
128: invocation.getTarget(), invocation.getArgs());
129: invocation.setResult(result);
130: } catch (InvocationTargetException ite) {
131: invocation.setThrowable(ite.getTargetException());
132: doHandleException(invocation);
133: } catch (IllegalAccessException e) {
134: invocation.setThrowable(e);
135: doHandleException(invocation);
136: }
137: }
138:
139: /**
140: * This method is called by the default doHandle() implementation if an
141: * exception occurs making the invocation. The default implementation
142: * silently ignores the problem, which is arguably a bad idea, but
143: * acceptable if subclasses never throw exceptions.
144: *
145: * @param invocation the invocation that was applied and caused an
146: * exception
147: */
148: protected void doHandleException(final Invocation invocation) {
149: // bummer! Ignore...
150: }
151:
152: /**
153: * Implements the {@link super#work() superclass method} by dequeuing an
154: * invocation (possibly blocking until one is added to the queue), then
155: * feeding it to the {@link #doHandle(Invocation)} method.
156: *
157: * @throws InterruptedException if the current thread has been
158: * {@link java.lang.Thread#interrupt()}ed
159: */
160: protected void work() throws InterruptedException, Throwable {
161: final Invocation invocation = (Invocation) m_incoming.take();
162: doHandle(invocation);
163: }
164: }
|