avalon-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From leosu...@apache.org
Subject cvs commit: jakarta-avalon-excalibur/util/src/java/org/apache/excalibur/util MultiDelegateFactory.java MultiDelegate.java
Date Thu, 03 Oct 2002 16:59:40 GMT
leosutic    2002/10/03 09:59:40

  Added:       util/src/java/org/apache/excalibur/util
                        MultiDelegateFactory.java MultiDelegate.java
  Log:
  Multicast delegates. Initial checkin.
  
  Revision  Changes    Path
  1.1                  jakarta-avalon-excalibur/util/src/java/org/apache/excalibur/util/MultiDelegateFactory.java
  
  Index: MultiDelegateFactory.java
  ===================================================================
  /*
  
  ============================================================================
  The Apache Software License, Version 1.1
  ============================================================================
  
  Copyright (C) @year@ The Apache Software Foundation. All rights reserved.
  
  Redistribution and use in source and binary forms, with or without modifica-
  tion, are permitted provided that the following conditions are met:
  
  1. Redistributions of  source code must  retain the above copyright  notice,
  this list of conditions and the following disclaimer.
  
  2. Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.
  
  3. The end-user documentation included with the redistribution, if any, must
  include  the following  acknowledgment:  "This product includes  software
  developed  by the  Apache Software Foundation  (http://www.apache.org/)."
  Alternately, this  acknowledgment may  appear in the software itself,  if
  and wherever such third-party acknowledgments normally appear.
  
  4. The names "Jakarta", "Avalon", "Excalibur" and "Apache Software Foundation"
  must not be used to endorse or promote products derived from this  software
  without  prior written permission. For written permission, please contact
  apache@apache.org.
  
  5. Products  derived from this software may not  be called "Apache", nor may
  "Apache" appear  in their name,  without prior written permission  of the
  Apache Software Foundation.
  
  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
  APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
  INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
  DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
  OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
  ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
  (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  
  This software  consists of voluntary contributions made  by many individuals
  on  behalf of the Apache Software  Foundation. For more  information on the
  Apache Software Foundation, please see <http://www.apache.org/>.
  
  */
  package org.apache.excalibur.util;
  
  import java.lang.reflect.InvocationHandler;
  import java.lang.reflect.Method;
  import java.lang.reflect.Proxy;
  
  import java.util.ArrayList;
  import java.util.Iterator;
  import java.util.List;
  
  /**
   * A factory for MultiDelegates. Please see the MultiDelegate interface for
   * examples of use.
   * 
   * @see MultiDelegate
   * @author <a href="mailto:bloritsch@apache.org">Berin Loritsch</a>
   * @author <a href="mailto:leo.sutic@inspireinfrastructure.com">Leo Sutic</a>
   */
  public class MultiDelegateFactory 
  {
      
      static private final class MultiDelegateHandler implements InvocationHandler 
      {
          
          private        final Class  delegateClass;
          private        final List   handlers = new ArrayList ();
          private static final Method addMethod;
          private static final Method removeMethod;
          
          /*
           * Static initializer. Finds the add and remove methods in the MultiDelegate interface.
           */
          static 
          {
              try 
              {
                  addMethod = MultiDelegate.class.getDeclaredMethod( "add", new Class[]{ Object.class
} );
                  removeMethod = MultiDelegate.class.getDeclaredMethod( "remove", new Class[]{
Object.class } );
              } 
              catch (Exception e) 
              {
                  throw new LinkageError( "Unable to find MultiDelegate.add and MultiDelegate.remove
in the MultiDelegate interface." );
              }
          }
          
          /**
           * Creates a new MultiDelegateHandler. The handler's add and remove methods will
only accept
           * objects that implements the interface given in delegateClass.
           */
          public MultiDelegateHandler( Class delegateClass ) 
          {
              this.delegateClass = delegateClass;
          }
          
          /**
           * Handles invocations. If the call is made through the MultiDelegate interface,
           * the appropriate methods are called. Otherwise the delegate methods are called.
           */
          public Object invoke(Object proxy, Method method, Object[] args) throws Throwable

          {
              if (method.equals (addMethod)) 
              {
                  if( args[0] == null )
                  {
                      throw new NullPointerException( "Argument to MultiDelegate.add(Object)
is null." );
                  }
                  
                  if( !delegateClass.isAssignableFrom(args[0].getClass()) )
                  {
                      throw new ClassCastException( "The argument to MultiDelegate.add(Object)
does not have the " +
                          "correct delegate interface, which is " + delegateClass.getName
() + ". Instead, it is a " + 
                          args[0].getClass().getName () + ".");
                  }
                  
                  synchronized( handlers )  
                  {
                      if( !handlers.contains( args[0] ) )
                      {
                          handlers.add (args[0]);
                      }
                  }
                  return null;
              } 
              else if (method.equals (removeMethod)) 
              {
                  synchronized( handlers ) 
                  {
                      handlers.remove (args[0]);
                  }
                  return null;
              } 
              else 
              {
                  List activeList = new ArrayList ();
                  synchronized( handlers )
                  {
                      // Copy the list of handlers to allow for updates to 
                      // the list during invocation.
                      
                      activeList.addAll( handlers );
                  }
                  
                  Iterator iter = activeList.iterator ();
                  while (iter.hasNext ()) 
                  {
                      method.invoke (iter.next (), args);
                  }
                  
                  // As MultiDelegates are multicast, the only allowed return value is void.
                  
                  return null;
              }
          }
      }
      
      /**
       * Creates a new MultiDelegate.
       * 
       * @param delegateInterface the delegate interface. The multiDelegate's add and remove
       *                          methods will only accept Objects that implement this interface.
       *                          The interface may only contain a single method that must
have a 
       *                          return type of void. The rationale behind the return type
is this:
       *                          Since the MultiDelegate will in turn invoke many delegates,
there
       *                          is no good way of determining which return value to give
back to the
       *                          caller.
       * 
       * @return the MultiDelegate instance.  You have to cast it to the interface
       *         you passed in (<code>delegateInterface</code>) to invoke it.
       */
      public static MultiDelegate newMultiDelegate( Class delegateInterface )
      {
          Method[] declaredMethods = delegateInterface.getDeclaredMethods();
          
          if( declaredMethods.length != 1 )
          {
              throw new IllegalArgumentException("The delegate interface must have one (1)
and only one method.");
          }
          
          Class methodReturnType = declaredMethods[0].getReturnType();
          
          if( !methodReturnType.equals(Void.TYPE) )
          {
              throw new IllegalArgumentException("The delegate interface's only method must
return void. (was: " + 
                  methodReturnType.getName () + ")");
          }
          
          ClassLoader proxyClassLoader = Thread.currentThread ().getContextClassLoader ();
          
          if (proxyClassLoader == null) 
          {
              proxyClassLoader = delegateInterface.getClassLoader ();
          }
          
          return (MultiDelegate) Proxy.newProxyInstance( 
              proxyClassLoader,
              new Class[]{ MultiDelegate.class, delegateInterface }, 
              new MultiDelegateHandler( delegateInterface ));
      }
      
  }
  
  
  1.1                  jakarta-avalon-excalibur/util/src/java/org/apache/excalibur/util/MultiDelegate.java
  
  Index: MultiDelegate.java
  ===================================================================
  /*
  
  ============================================================================
  The Apache Software License, Version 1.1
  ============================================================================
  
  Copyright (C) @year@ The Apache Software Foundation. All rights reserved.
  
  Redistribution and use in source and binary forms, with or without modifica-
  tion, are permitted provided that the following conditions are met:
  
  1. Redistributions of  source code must  retain the above copyright  notice,
  this list of conditions and the following disclaimer.
  
  2. Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.
  
  3. The end-user documentation included with the redistribution, if any, must
  include  the following  acknowledgment:  "This product includes  software
  developed  by the  Apache Software Foundation  (http://www.apache.org/)."
  Alternately, this  acknowledgment may  appear in the software itself,  if
  and wherever such third-party acknowledgments normally appear.
  
  4. The names "Jakarta", "Avalon", "Excalibur" and "Apache Software Foundation"
  must not be used to endorse or promote products derived from this  software
  without  prior written permission. For written permission, please contact
  apache@apache.org.
  
  5. Products  derived from this software may not  be called "Apache", nor may
  "Apache" appear  in their name,  without prior written permission  of the
  Apache Software Foundation.
  
  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
  APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
  INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
  DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
  OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
  ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
  (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  
  This software  consists of voluntary contributions made  by many individuals
  on  behalf of the Apache Software  Foundation. For more  information on the
  Apache Software Foundation, please see <http://www.apache.org/>.
  
  */
  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:
   * 
   * <p>
   * <pre><code>
   * public static class Publisher {
   *
   *     public static interface Listener 
   *     {
   *         public void onEvent ();
   *     }
   *     
   *     public MultiDelegate event = MultiDelegateFactory.newMultiDelegate( Listener.class
);
   *
   *     public void fireEvent () 
   *     {
   *         ((Listener) event).onEvent ();
   *     }
   * }
   * </code></pre>
   * <p>
   *
   * Note the following: We can cast the MultiDelegate instance to the interface given to
   * the MultiDelegateFactory.newMultiDelegate method.
   * Subscribers/Listeners to the Publisher above can register themselves with:
   *
   * <p>
   * <pre><code>
   * public void myEventHandler () {
   *    ...
   * }
   *
   * public void registerWithPublisher( Publisher publisher )  
   * {
   *    publisher.event.add( 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>
   *
   * All MultiDelegates are thread-safe, provided that the delegates they in turn call
   * are thread-safe. For example, if you invoke a MultiDelegate while some other thread
   * modifies the MultiDelegate (via add or remove), those changes will not affect the
   * current invocation.
   * 
   * It is also legal for delegates to remove themselves from the MultiDelegate when invoked,
   * or perform operations on it.
   *
   * @author <a href="mailto:bloritsch@apache.org">Berin Loritsch</a>
   * @author <a href="mailto:leo.sutic@inspireinfrastructure.com">Leo Sutic</a>
   */
  public interface MultiDelegate 
  {
      
      /**
       * Adds a new delegate to the MultiDelegate's list. The Delegate is only added
       * if it does not yet exist in the list.
       */
      public void add (Object o);
      
      /**
       * Removes a delegate from the MultiDelegate's list.
       */    
      public void remove (Object o);
  }
  
  

--
To unsubscribe, e-mail:   <mailto:avalon-cvs-unsubscribe@jakarta.apache.org>
For additional commands, e-mail: <mailto:avalon-cvs-help@jakarta.apache.org>


Mime
View raw message