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]>

Reply via email to