leosutic 2002/10/03 09:58:48 Modified: util/src/java/org/apache/excalibur/util Delegate.java Log: Changed the default classloader for proxies to be the context classloader instead of the interface classloader. Added an equals() method on the proxy (required for MultiDelegates). Revision Changes Path 1.7 +277 -233 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.6 retrieving revision 1.7 diff -u -r1.6 -r1.7 --- Delegate.java 3 Oct 2002 15:12:45 -0000 1.6 +++ Delegate.java 3 Oct 2002 16:58:48 -0000 1.7 @@ -1,233 +1,277 @@ -/* - - ============================================================================ - 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 - [EMAIL PROTECTED] - - 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.*; - - -/** - * 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. - * - * @author <a href="mailto:[EMAIL PROTECTED]">Berin Loritsch</a> - * @author <a href="mailto:[EMAIL PROTECTED]">Leo Sutic</a> - */ -public final class Delegate -{ - /** - * Create a new delegate instance. We use the instance with the specified - * method name to forward requests to the delegate interface--which can - * only have one method declared. - * - * @param instance The object that has the method - * @param methodName The method name that implements the signature - * @param delegateInterface The interface that the delegate uses. - * - * @return the Delegate instance. You have to cast it to the interface - * you passed in (<code>delegateInterface</code>). - */ - public static Object newDelegate( Object instance, String methodName, Class delegateInterface) - { - ClassLoader loader = delegateInterface.getClassLoader(); - Class[] publicInterface = new Class[] { delegateInterface }; - Method[] interfaceMethods = delegateInterface.getDeclaredMethods(); - - if ( interfaceMethods.length != 1 ) - { - throw new IllegalArgumentException("The delegate interface must have one (1) and only one method."); - } - - Class[] signature = interfaceMethods[0].getParameterTypes(); - InvocationHandler handler = new DelegateHandler( instance, methodName, signature ); - - return Proxy.newProxyInstance( loader, publicInterface, handler ); - } - - /** - * Create a new delegate instance for a static method. We use the instance - * with the specified method name to forward requests to the delegate - * interface--which can only have one method declared. We do not require an instance - * - * @param klass The class that has the static method - * @param methodName The method name that implements the signature - * @param delegateInterface The interface that the delegate uses. - * - * @return the Delegate instance. You have to cast it to the interface - * you passed in (<code>delegateInterface</code>). - */ - public static Object newDelegate( Class klass, String methodName, Class delegateInterface) - { - ClassLoader loader = delegateInterface.getClassLoader(); - Class[] publicInterface = new Class[] { delegateInterface }; - Method[] interfaceMethods = delegateInterface.getDeclaredMethods(); - - if ( interfaceMethods.length != 1 ) - { - throw new IllegalArgumentException("The delegate interface must have one (1) and only one method."); - } - - Class[] signature = interfaceMethods[0].getParameterTypes(); - InvocationHandler handler = new DelegateHandler( klass, methodName, signature ); - - return Proxy.newProxyInstance( loader, publicInterface, handler ); - } - - /** - * The invocation handler for all delegates. - */ - private static final class DelegateHandler implements InvocationHandler - { - private final Object m_instance; - private final Method m_delegateMethod; - - /** - * Create a new InvocationHandler for the delegate we manufactured, - * this version is used to delegate to objects. - * - * @param instance The object instance that has the method - * @param methodName The method name that we forward messages to. - * @param signature The method signature used to ensure we have - * a good delegate. - */ - public DelegateHandler ( Object instance, String methodName, Class[] signature ) - { - m_instance = instance; - m_delegateMethod = extractMethod( m_instance.getClass(), methodName, signature ); - } - - /** - * Create a new InvocationHandler for the delegate we manufactured, - * this version is used to delegate to static methods. - * - * @param klass The class of the object containing the method - * @param methodName The method name that we forward messages to. - * @param signature The method signature used to ensure we have - * a good delegate. - */ - public DelegateHandler ( Class klass, String methodName, Class[] signature ) - { - m_instance = null; - m_delegateMethod = extractMethod( klass, methodName, signature ); - } - - /** - * Extract the Method instance we need for this delegate. We examine - * the instance class passed in for the method with the requested name. - * When we find it, we save and use it every time we have a method call - * on the delegate. - * - * @param klass The class of the object containing the method - * @param methodName The method name that we forward messages to. - * @param signature The method signature used to ensure we have - * a good delegate. - */ - public Method extractMethod ( Class klass, String methodName, Class[] signature ) - { - Method[] methods = klass.getDeclaredMethods(); - Method delegate = null; - - for ( int i = 0; i < methods.length; i++ ) - { - if ( methods[i].getName().equals( methodName ) ) - { - Class[] parameters = methods[i].getParameterTypes(); - - if ( parameters.length == signature.length ) - { - boolean signatureOk = true; - - for ( int m = 0; m < signature.length; m++ ) - { - if ( ! ( signature[m].equals( parameters[m] ) ) ) - { - signatureOk = false; - } - } - - if ( signatureOk ) - { - delegate = methods[i]; - } - } - } - } - - if ( delegate == null ) - { - throw new IllegalArgumentException( "There is no valid method with the required interface" ); - } - - return delegate; - } - - /** - * Call the proxied delegate method. - * - * @param proxy The original object we are forwarding calls to. - * @param m The method we are ignoring( the delegated method - * may not have the same name ) - * @param args The arguments passed to the method - * - * @return the results of the invocation in the form of an Object - * - * @throws IllegalAccessException When the method or proxy object - * is not accessible - * @throws InvocationTargetException When the method throws an - * exception - */ - public Object invoke( Object proxy, Method m, Object[] args ) - throws IllegalAccessException, InvocationTargetException - { - return m_delegateMethod.invoke( m_instance, args ); - } - } -} +/* + + ============================================================================ + 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 + [EMAIL PROTECTED] + + 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.*; + + +/** + * 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> + * + * @author <a href="mailto:[EMAIL PROTECTED]">Berin Loritsch</a> + * @author <a href="mailto:[EMAIL PROTECTED]">Leo Sutic</a> + */ +public final class Delegate +{ + /** + * Create a new delegate instance. We use the instance with the specified + * method name to forward requests to the delegate interface--which can + * only have one method declared. + * + * @param instance The object that has the method + * @param methodName The method name that implements the signature + * @param delegateInterface The interface that the delegate uses. + * + * @return the Delegate instance. You have to cast it to the interface + * you passed in (<code>delegateInterface</code>). + */ + public static Object newDelegate( Object instance, String methodName, Class delegateInterface ) + { + ClassLoader loader = Thread.currentThread ().getContextClassLoader (); + if( loader == null ) + { + loader = delegateInterface.getClassLoader(); + } + + Class[] publicInterface = new Class[] { delegateInterface }; + Method[] interfaceMethods = delegateInterface.getDeclaredMethods(); + + if ( interfaceMethods.length != 1 ) + { + throw new IllegalArgumentException("The delegate interface must have one (1) and only one method."); + } + + Class[] signature = interfaceMethods[0].getParameterTypes(); + InvocationHandler handler = new DelegateHandler( instance, methodName, signature ); + + return Proxy.newProxyInstance( loader, publicInterface, handler ); + } + + /** + * Create a new delegate instance for a static method. We use the instance + * with the specified method name to forward requests to the delegate + * interface--which can only have one method declared. We do not require an instance + * + * @param klass The class that has the static method + * @param methodName The method name that implements the signature + * @param delegateInterface The interface that the delegate uses. + * + * @return the Delegate instance. You have to cast it to the interface + * you passed in (<code>delegateInterface</code>). + */ + public static Object newDelegate( Class klass, String methodName, Class delegateInterface) + { + ClassLoader loader = Thread.currentThread ().getContextClassLoader (); + if( loader == null ) + { + loader = delegateInterface.getClassLoader(); + } + + Class[] publicInterface = new Class[] { delegateInterface }; + Method[] interfaceMethods = delegateInterface.getDeclaredMethods(); + + if ( interfaceMethods.length != 1 ) + { + throw new IllegalArgumentException("The delegate interface must have one (1) and only one method."); + } + + Class[] signature = interfaceMethods[0].getParameterTypes(); + InvocationHandler handler = new DelegateHandler( klass, methodName, signature ); + + return Proxy.newProxyInstance( loader, publicInterface, handler ); + } + + /** + * The invocation handler for all delegates. + */ + private static final class DelegateHandler implements InvocationHandler + { + private final Object m_instance; + private final Method m_delegateMethod; + + /** + * Create a new InvocationHandler for the delegate we manufactured, + * this version is used to delegate to objects. + * + * @param instance The object instance that has the method + * @param methodName The method name that we forward messages to. + * @param signature The method signature used to ensure we have + * a good delegate. + */ + public DelegateHandler ( Object instance, String methodName, Class[] signature ) + { + m_instance = instance; + m_delegateMethod = extractMethod( m_instance.getClass(), methodName, signature ); + } + + /** + * Create a new InvocationHandler for the delegate we manufactured, + * this version is used to delegate to static methods. + * + * @param klass The class of the object containing the method + * @param methodName The method name that we forward messages to. + * @param signature The method signature used to ensure we have + * a good delegate. + */ + public DelegateHandler ( Class klass, String methodName, Class[] signature ) + { + m_instance = null; + m_delegateMethod = extractMethod( klass, methodName, signature ); + } + + /** + * Extract the Method instance we need for this delegate. We examine + * the instance class passed in for the method with the requested name. + * When we find it, we save and use it every time we have a method call + * on the delegate. + * + * @param klass The class of the object containing the method + * @param methodName The method name that we forward messages to. + * @param signature The method signature used to ensure we have + * a good delegate. + */ + public Method extractMethod ( Class klass, String methodName, Class[] signature ) + { + Method[] methods = klass.getDeclaredMethods(); + Method delegate = null; + + for ( int i = 0; i < methods.length; i++ ) + { + if ( methods[i].getName().equals( methodName ) ) + { + Class[] parameters = methods[i].getParameterTypes(); + + if ( parameters.length == signature.length ) + { + boolean signatureOk = true; + + for ( int m = 0; m < signature.length; m++ ) + { + if ( ! ( signature[m].equals( parameters[m] ) ) ) + { + signatureOk = false; + } + } + + if ( signatureOk ) + { + delegate = methods[i]; + } + } + } + } + + if ( delegate == null ) + { + throw new IllegalArgumentException( "There is no valid method with the required interface" ); + } + + return delegate; + } + + /** + * Call the proxied delegate method. + * + * @param proxy The original object we are forwarding calls to. + * @param m The method we are ignoring( the delegated method + * may not have the same name ) + * @param args The arguments passed to the method + * + * @return the results of the invocation in the form of an Object + * + * @throws IllegalAccessException When the method or proxy object + * is not accessible + * @throws InvocationTargetException When the method throws an + * exception + */ + public Object invoke( Object proxy, Method m, Object[] args ) + throws IllegalAccessException, InvocationTargetException + { + if( m.getName().equals( "equals" ) && args.length == 1 ) + { + Object other = args[0]; + + if( other instanceof Proxy ) + { + DelegateHandler otherHandler = (DelegateHandler) Proxy.getInvocationHandler( other ); + if ( otherHandler.m_instance == m_instance && + otherHandler.m_delegateMethod.equals( m_delegateMethod ) ) + { + return Boolean.TRUE; + } + else + { + return Boolean.FALSE; + } + } + else + { + return Boolean.FALSE; + } + } + else + { + return m_delegateMethod.invoke( m_instance, args ); + } + } + } +}
-- To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>
