bloritsch 2002/10/03 19:57:47
Modified: util/src/java/org/apache/excalibur/util Delegate.java
MultiDelegate.java
util/src/test/org/apache/excalibur/util/test
MultiDelegateTestCase.java
Log:
update the javadocs so they are top notch, and fix the testcase
Revision Changes Path
1.9 +93 -13
jakarta-avalon-excalibur/util/src/java/org/apache/excalibur/util/Delegate.java
Index: Delegate.java
===================================================================
RCS file:
/home/cvs/jakarta-avalon-excalibur/util/src/java/org/apache/excalibur/util/Delegate.java,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -r1.8 -r1.9
--- Delegate.java 3 Oct 2002 18:10:26 -0000 1.8
+++ Delegate.java 4 Oct 2002 02:57:47 -0000 1.9
@@ -60,25 +60,105 @@
/**
- * Used to create a proxy for a method. It is supposed to be as close to the
- * C# delegate as possible. The Delegate is only allowed to have one method,
- * and all instances of it will call that one method. You must also realize
- * that only public methods on public classes can be turned into a Delegate.
- *
- * <p>Two delegates are considered equal if and only if:
- *
- * <ul>
- * <li>They both refer to the same instance. That is, the <code>instance</code>
- * parameter passed to the newDelegate method was the same for both. The
- * instances are compared with the identity equality operator, <code>==</code>.
- * <li>They refer to the same method as resolved by <code>Method.equals</code>.
- * </ul>
+ * Delegates are a typesafe pointer to another method. Since Java does not
+ * have language support for such a construct, this utility will construct
+ * a proxy that forwards method calls to any method with the same signature.
+ * This utility is inspired in part by the C# delegate mechanism. We
+ * implemented it in a Java-centric manner.
+ *
+ * <h2>Delegate</h2>
+ * <p>
+ * Any interface with one method can become the interface for a delegate.
+ * Consider the example below:
+ * </p>
+ *
+ * <pre>
+ * public interface MainDelegate
+ * {
+ * int main(String[] args);
+ * }
+ * </pre>
+ *
+ * <p>
+ * The interface above is an example of an interface that can become a
+ * delegate. It has only one method, and the interface is public. In
+ * order to create a delegate for that method, all we have to do is
+ * call <code>Delegate.newDelegate( this, "alternateMain", MainDelegate.class
)</code>.
+ * The following program will show how to use it:
+ * </p>
+ *
+ * <pre>
+ * public class Main
+ * {
+ * public static int main( String[] args )
+ * {
+ * Main newMain = new Main();
+ *
+ * MainDelegate start = (MainDelegate)
+ * Delegate.newDelegate( newMain, "alternateMain",
MainDelegate.class );
+ *
+ * return start.main( args );
+ * }
+ *
+ * public int alternateMain( String[] args )
+ * {
+ * for ( int i = 0; i < args.length; i++ )
+ * {
+ * System.out.println( args[i] );
+ * }
+ *
+ * return args.length;
+ * }
+ * }
+ * </pre>
+ *
+ * <p>
+ * By themselves, delegates don't do much. Their true power lies in the fact that
+ * they can be treated like objects, and passed to other methods. In fact that is
+ * one of the key building blocks of building Intelligent Agents which in tern are
+ * the foundation of artificial intelligence. In the above program, we could have
+ * easily created the delegate to match the static <code>main</code> method by
+ * substituting the delegate creation call with this:
+ * <code>Delegate.newDelegate( getClass(), "main", MainDelegate.class )</code>.
+ * You create delegates to static methods by passing in their class in the first
+ * parameter instead of an object instance. The only problem with doing what we
+ * just described is we would have created an infinite loop.
+ * </p>
+ * <p>
+ * Another key use for Delegates is to register event listeners. It is much
easier
+ * to have all the code for your events separated out into methods instead of
individual
+ * classes. One of the ways Java gets around that is to create anonymous classes.
+ * They are particularly troublesome because many Debuggers do not know what to do
+ * with them. Anonymous classes tend to duplicate alot of code as well. We can
+ * use any interface with one declared method to forward events to any method that
+ * matches the signature (although the method name can be different).
+ * </p>
+ *
+ * <h2>MultiDelegates</h2>
+ * <p>
+ * The full text on <code>MultiDelegate</code> is with the {@link MultiDelegate}
+ * JavaDocs. MultiDelegates will invoke a whole <em>set</em> of Delegates (or
+ * objects that implement the delegate's interface). The criteria that we use
+ * to test if two delegates are equal are:
+ *
+ * <ul>
+ * <li>
+ * They both refer to the same instance. That is, the <code>instance</code>
+ * parameter passed to the newDelegate method was the same for both. The
+ * instances are compared with the identity equality operator,
<code>==</code>.
+ * </li>
+ * <li>They refer to the same method as resolved by
<code>Method.equals</code>.</li>
+ * </ul>
+ * </p>
*
* @author <a href="mailto:[EMAIL PROTECTED]">Berin Loritsch</a>
* @author <a href="mailto:[EMAIL PROTECTED]">Leo Sutic</a>
*/
public final class Delegate
{
+ /** Private constructor to prevent instantiation */
+ private Delegate() {}
+
/**
* Create a new delegate instance. We use the instance with the specified
* method name to forward requests to the delegate interface--which can
1.5 +81 -37
jakarta-avalon-excalibur/util/src/java/org/apache/excalibur/util/MultiDelegate.java
Index: MultiDelegate.java
===================================================================
RCS file:
/home/cvs/jakarta-avalon-excalibur/util/src/java/org/apache/excalibur/util/MultiDelegate.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- MultiDelegate.java 3 Oct 2002 18:35:04 -0000 1.4
+++ MultiDelegate.java 4 Oct 2002 02:57:47 -0000 1.5
@@ -50,13 +50,15 @@
package org.apache.excalibur.util;
/**
- * A multicast-type delegate interface. While a delegate is a pointer
- * to a method, a MultiDelegate is intended for the times when you want
- * to send an event to several delegates. This is best illustrated
- * with a code example:
+ * The interface used to add and remove delegates to this multicast delegate.
+ * A normal delegate is a pointer to one method. A <code>MultiDelegate</code>
+ * is a pointer to a set of methods, and they are all called when the
+ * <code>MultiDelegate</code> is called. The <code>MultiDelegate</code>
+ * interface is never implemented directly, but the {@link
Delegate#newMultiDelegate}
+ * method generates a proxy that implements both this interface and the
+ * interface you interact with. This is best illustrated with a code example:
*
- * <p>
- * <pre><code>
+ * <pre>
* public class Publisher {
*
* public static interface Listener
@@ -64,7 +66,8 @@
* public void onEvent ();
* }
*
- * private final MultiDelegate event = Delegate.newMultiDelegate(
Listener.class );
+ * private final MultiDelegate event =
+ * Delegate.newMultiDelegate( Listener.class );
*
* public void registerListener( Listener listener )
* {
@@ -76,40 +79,81 @@
* ((Listener) event).onEvent ();
* }
* }
- * </code></pre>
+ * </pre>
+
* <p>
+ * The Listener interface is what we use to interact with. We can add new
Listener
+ * instances to the <code>MultiDelegate</code> through the
<code>registerListener</code>
+ * method. Those Listener instances can be delegates, concrete implementations,
or
+ * even another <code>MultiDelegate</code>. Once we call <code>fireEvent</code>,
every
+ * registered Listener will have the onEvent() method called.
+ * </p>
+ *
+ * <p>
+ * Note the following:
+ * <ul>
+ * <li>
+ * We can cast the <code>MultiDelegate</code> instance to the interface given
to
+ * the <code>Delegate.newMultiDelegate</code> method.
+ * </li>
+ * <li>
+ * Just as with any class that implements two interfaces, any code can cast
the
+ * <code>MultiDelegate</code> to the interface (in our example,
<code>Listener</code).
+ * Take the normal precautions you would when you only want to expose one of
the
+ * interfaces.
+ * </li>
+ * <li>
+ * If you expose the <code>MultiDelegate</code> directly, then client code can
+ * cast it to the implementation interface (e.g. <code>Listener</code>) and
invoke
+ * the event. The code would looke like the contents of the
+ * <code>Publisher.fireEvent</code> method.
+ * </li>
+ * </ul>
+ * </p>
*
- * Note the following:
- * <ul>
- * <li>We can cast the <code>MultiDelegate</code> instance to the interface given to
- * the <code>MultiDelegateFactory.newMultiDelegate</code> method.
- * </ul>
* <p>
- * Subscribers/Listeners to the Publisher above can register themselves with:
+ * Subscribers/Listeners to the Publisher above can register themselves with:
+ * </p>
*
- * <p>
- * <pre><code>
+ * <pre>
* public void myEventHandler () {
- * ...
+ * // ... actual code ...
* }
*
* public void registerWithPublisher( Publisher publisher )
* {
- * publisher.registerListener( (Listener) Delegate.newDelegate (this,
"myEventHandler", Publisher.Listener.class) );
+ * publisher.registerListener(
+ * (Listener) Delegate.newDelegate (this,
+ * "myEventHandler",
+ * Publisher.Listener.class)
+ * );
* }
- * </code></pre>
- * <p>
- *
- * <b>Note that the add and remove methods have Set-like behavior. Adding a
delegate twice has
- * the same effect as only adding it once.</b>
- * <p>
- * All <code>MultiDelegates</code> are thread-safe, provided that the delegates
they in turn call
- * are thread-safe. For example, if you invoke a <code>MultiDelegate</code> while
some other thread
- * modifies the <code>MultiDelegate</code> (via <code>add</code> or
<code>remove</code>), those changes
- * will not affect the current invocation.
+ * </pre>
+ *
+ * <h3>Notes:</h3>
* <p>
- * It is also legal for delegates to remove themselves from the
<code>MultiDelegate</code> when invoked,
- * or perform operations on it.
+ * <ul>
+ * <li>
+ * <strong>Note that the add and remove methods
+ * have Set-like behavior. Adding a delegate twice has
+ * the same effect as only adding it once.</strong>
+ * </li>
+ * <li>
+ * All <code>MultiDelegates</code> are thread-safe,
+ * provided that the delegates they in turn call
+ * are thread-safe. For example, if you invoke a
+ * <code>MultiDelegate</code> while some other thread
+ * modifies the <code>MultiDelegate</code> (via
+ * <code>add</code> or <code>remove</code>), those changes
+ * will not affect the current invocation.
+ * </li>
+ * <li>
+ * It is also legal for delegates to remove themselves
+ * from the <code>MultiDelegate</code> when invoked,
+ * or perform operations on it.
+ * </li>
+ * </ul>
+ * </p>
*
* @author <a href="mailto:[EMAIL PROTECTED]">Berin Loritsch</a>
* @author <a href="mailto:[EMAIL PROTECTED]">Leo Sutic</a>
@@ -118,18 +162,18 @@
{
/**
- * Adds a new delegate to the MultiDelegate's list. The delegate is only added
- * if it does not yet exist in the list.
+ * Adds a new delegate to the <code>MultiDelegate</code>'s set. The delegate is
only added
+ * if it does not yet exist in the set.
*
- * @param o The delegate we are adding to this MultiDelegate. The delegate
+ * @param delegate The delegate we are adding to this MultiDelegate. The
delegate
* must use the same interface this MultiDelegate is using.
*/
- public void add (Object o);
+ public void add (Object delegate);
/**
- * Removes a delegate from the MultiDelegate's list.
+ * Removes a delegate from the <code>MultiDelegate</code>'s set.
*
- * @param o The delegate we are removing from this MultiDelegate.
+ * @param delegate The delegate we are removing from this MultiDelegate.
*/
- public void remove (Object o);
+ public void remove (Object delegate);
}
1.2 +1 -3
jakarta-avalon-excalibur/util/src/test/org/apache/excalibur/util/test/MultiDelegateTestCase.java
Index: MultiDelegateTestCase.java
===================================================================
RCS file:
/home/cvs/jakarta-avalon-excalibur/util/src/test/org/apache/excalibur/util/test/MultiDelegateTestCase.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- MultiDelegateTestCase.java 3 Oct 2002 16:59:22 -0000 1.1
+++ MultiDelegateTestCase.java 4 Oct 2002 02:57:47 -0000 1.2
@@ -75,9 +75,7 @@
public void onEvent ();
}
- private String result;
-
- public MultiDelegate event = MultiDelegateFactory.newMultiDelegate(
Listener.class );
+ public MultiDelegate event = Delegate.newMultiDelegate( Listener.class );
public void fireEvent ()
{
--
To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>