[Proxool-cvs] proxool/src/java/org/logicalcobwebs/cglib/reflect ConstructorDelegate.java,NONE,1.1 Fa
UNMAINTAINED!
Brought to you by:
billhorsman
|
From: <bil...@us...> - 2003-12-12 19:28:17
|
Update of /cvsroot/proxool/proxool/src/java/org/logicalcobwebs/cglib/reflect In directory sc8-pr-cvs1:/tmp/cvs-serv25673/src/java/org/logicalcobwebs/cglib/reflect Added Files: ConstructorDelegate.java FastClass.java FastClassEmitter.java FastConstructor.java FastMember.java FastMethod.java MethodDelegate.java MulticastDelegate.java Log Message: Repackaged Cglib project --- NEW FILE: ConstructorDelegate.java --- /* * The Apache Software License, Version 1.1 * * Copyright (c) 2002 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, 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 "Apache" 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 ap...@ap.... * * 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 (INCLUDING, 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.logicalcobwebs.cglib.reflect; import java.lang.reflect.*; import org.logicalcobwebs.cglib.core.*; import org.logicalcobwebs.asm.ClassVisitor; import org.logicalcobwebs.asm.Type; /** * @author Chris Nokleberg * @version $Id: ConstructorDelegate.java,v 1.1 2003/12/12 19:28:13 billhorsman Exp $ */ abstract public class ConstructorDelegate { private static final ConstructorKey KEY_FACTORY = (ConstructorKey)KeyFactory.create(ConstructorKey.class, KeyFactory.CLASS_BY_NAME); interface ConstructorKey { public Object newInstance(Class declaring, Class iface); } protected ConstructorDelegate() { } public static ConstructorDelegate create(Class targetClass, Class iface) { Generator gen = new Generator(); gen.setTargetClass(targetClass); gen.setInterface(iface); return gen.create(); } public static class Generator extends AbstractClassGenerator { private static final Source SOURCE = new Source(ConstructorDelegate.class.getName()); private static final Type CONSTRUCTOR_DELEGATE = TypeUtils.parseType("org.logicalcobwebs.cglib.reflect.ConstructorDelegate"); private Class iface; private Class targetClass; public Generator() { super(SOURCE); } public void setInterface(Class iface) { this.iface = iface; } public void setTargetClass(Class targetClass) { this.targetClass = targetClass; } public ConstructorDelegate create() { setNamePrefix(targetClass.getName()); Object key = KEY_FACTORY.newInstance(iface, targetClass); return (ConstructorDelegate)super.create(key); } protected ClassLoader getDefaultClassLoader() { return targetClass.getClassLoader(); } public void generateClass(ClassVisitor v) { setNamePrefix(targetClass.getName()); final Method newInstance = ReflectUtils.findNewInstance(iface); if (!newInstance.getReturnType().isAssignableFrom(targetClass)) { throw new IllegalArgumentException("incompatible return type"); } final Constructor constructor; try { constructor = targetClass.getDeclaredConstructor(newInstance.getParameterTypes()); } catch (NoSuchMethodException e) { throw new IllegalArgumentException("interface does not match any known constructor"); } ClassEmitter ce = new ClassEmitter(v); ce.begin_class(Constants.ACC_PUBLIC, getClassName(), CONSTRUCTOR_DELEGATE, new Type[]{ Type.getType(iface) }, Constants.SOURCE_FILE); Type declaring = Type.getType(constructor.getDeclaringClass()); EmitUtils.null_constructor(ce); CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, ReflectUtils.getSignature(newInstance), ReflectUtils.getExceptionTypes(newInstance), null); e.new_instance(declaring); e.dup(); e.load_args(); e.invoke_constructor(declaring, ReflectUtils.getSignature(constructor)); e.return_value(); e.end_method(); ce.end_class(); } protected Object firstInstance(Class type) { return ReflectUtils.newInstance(type); } protected Object nextInstance(Object instance) { return instance; } } } --- NEW FILE: FastClass.java --- /* * The Apache Software License, Version 1.1 * * Copyright (c) 2002 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, 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 "Apache" 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 ap...@ap.... * * 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 (INCLUDING, 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.logicalcobwebs.cglib.reflect; import org.logicalcobwebs.cglib.core.*; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import org.logicalcobwebs.asm.ClassVisitor; import org.logicalcobwebs.asm.Type; abstract public class FastClass { private Class type; protected FastClass(Class type) { this.type = type; } public static FastClass create(Class type) { Generator gen = new Generator(); gen.setType(type); return gen.create(); } public static class Generator extends AbstractClassGenerator { private static final Source SOURCE = new Source(FastClass.class.getName()); private Class type; public Generator() { super(SOURCE); } public void setType(Class type) { this.type = type; } public FastClass create() { setNamePrefix(type.getName()); return (FastClass)super.create(type.getName()); } protected ClassLoader getDefaultClassLoader() { return type.getClassLoader(); } public void generateClass(ClassVisitor v) throws Exception { new FastClassEmitter(v, getClassName(), type); } protected Object firstInstance(Class type) { return ReflectUtils.newInstance(type, new Class[]{ Class.class }, new Object[]{ this.type }); } protected Object nextInstance(Object instance) { return instance; } } public Object invoke(String name, Class[] parameterTypes, Object obj, Object[] args) throws InvocationTargetException { return invoke(getIndex(name, parameterTypes), obj, args); } public Object newInstance() throws InvocationTargetException { return newInstance(getIndex(Constants.EMPTY_CLASS_ARRAY), null); } public Object newInstance(Class[] parameterTypes, Object[] args) throws InvocationTargetException { return newInstance(getIndex(parameterTypes), args); } public FastMethod getMethod(Method method) { return new FastMethod(this, method); } public FastConstructor getConstructor(Constructor constructor) { return new FastConstructor(this, constructor); } public FastMethod getMethod(String name, Class[] parameterTypes) { try { return getMethod(type.getMethod(name, parameterTypes)); } catch (NoSuchMethodException e) { throw new NoSuchMethodError(e.getMessage()); } } public FastConstructor getConstructor(Class[] parameterTypes) { try { return getConstructor(type.getConstructor(parameterTypes)); } catch (NoSuchMethodException e) { throw new NoSuchMethodError(e.getMessage()); } } public String getName() { return type.getName(); } public Class getJavaClass() { return type; } public String toString() { return type.toString(); } public int hashCode() { return type.hashCode(); } public boolean equals(Object o) { if (o == null || !(o instanceof FastClass)) { return false; } return type.equals(((FastClass)o).type); } /** * Return the index of the matching method. The index may be used * later to invoke the method with less overhead. If more than one * method matches (i.e. they differ by return type only), one is * chosen arbitrarily. * @see #invoke(int, Object, Object[]) * @param name the method name * @param parameterTypes the parameter array * @return the index, or <code>-1</code> if none is found. */ abstract public int getIndex(String name, Class[] parameterTypes); /** * Return the index of the matching constructor. The index may be used * later to create a new instance with less overhead. * @see #newInstance(int, Object[]) * @param parameterTypes the parameter array * @return the constructor index, or <code>-1</code> if none is found. */ abstract public int getIndex(Class[] parameterTypes); /** * Invoke the method with the specified index. * @see getIndex(name, Class[]) * @param index the method index * @param obj the object the underlying method is invoked from * @param args the arguments used for the method call * @throws java.lang.reflect.InvocationTargetException if the underlying method throws an exception */ abstract public Object invoke(int index, Object obj, Object[] args) throws InvocationTargetException; /** * Create a new instance using the specified constructor index and arguments. * @see getIndex(Class[]) * @param index the constructor index * @param args the arguments passed to the constructor * @throws java.lang.reflect.InvocationTargetException if the constructor throws an exception */ abstract public Object newInstance(int index, Object[] args) throws InvocationTargetException; abstract public int getIndex(Signature sig); /** * Returns the maximum method index for this class. */ abstract public int getMaxIndex(); protected static String getSignatureWithoutReturnType(String name, Class[] parameterTypes) { StringBuffer sb = new StringBuffer(); sb.append(name); sb.append('('); for (int i = 0; i < parameterTypes.length; i++) { sb.append(Type.getDescriptor(parameterTypes[i])); } sb.append(')'); return sb.toString(); } } --- NEW FILE: FastClassEmitter.java --- /* * The Apache Software License, Version 1.1 * * Copyright (c) 2002 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, 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 "Apache" 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 ap...@ap.... * * 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 (INCLUDING, 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.logicalcobwebs.cglib.reflect; import java.lang.reflect.*; import java.util.*; import org.logicalcobwebs.cglib.core.*; import org.logicalcobwebs.asm.ClassVisitor; import org.logicalcobwebs.asm.Label; import org.logicalcobwebs.asm.Type; class FastClassEmitter extends ClassEmitter { private static final Signature CSTRUCT_CLASS = TypeUtils.parseConstructor("Class"); private static final Signature METHOD_GET_INDEX = TypeUtils.parseSignature("int getIndex(String, Class[])"); private static final Signature SIGNATURE_GET_INDEX = TypeUtils.parseSignature("int getIndex(org.logicalcobwebs.cglib.core.Signature)"); private static final Signature TO_STRING = TypeUtils.parseSignature("String toString()"); private static final Signature CONSTRUCTOR_GET_INDEX = TypeUtils.parseSignature("int getIndex(Class[])"); private static final Signature INVOKE = TypeUtils.parseSignature("Object invoke(int, Object, Object[])"); private static final Signature NEW_INSTANCE = TypeUtils.parseSignature("Object newInstance(int, Object[])"); private static final Signature GET_MAX_INDEX = TypeUtils.parseSignature("int getMaxIndex()"); private static final Signature GET_SIGNATURE_WITHOUT_RETURN_TYPE = TypeUtils.parseSignature("String getSignatureWithoutReturnType(String, Class[])"); private static final Type FAST_CLASS = TypeUtils.parseType("org.logicalcobwebs.cglib.reflect.FastClass"); private static final Type ILLEGAL_ARGUMENT_EXCEPTION = TypeUtils.parseType("IllegalArgumentException"); private static final Type INVOCATION_TARGET_EXCEPTION = TypeUtils.parseType("java.lang.reflect.InvocationTargetException"); private static final Type[] INVOCATION_TARGET_EXCEPTION_ARRAY = { INVOCATION_TARGET_EXCEPTION }; public FastClassEmitter(ClassVisitor v, String className, Class type) { super(v); begin_class(Constants.ACC_PUBLIC, className, FAST_CLASS, null, Constants.SOURCE_FILE); // constructor CodeEmitter e = begin_method(Constants.ACC_PUBLIC, CSTRUCT_CLASS, null, null); e.load_this(); e.load_args(); e.super_invoke_constructor(CSTRUCT_CLASS); e.return_value(); e.end_method(); VisibilityPredicate vp = new VisibilityPredicate(type, false); List methodList = ReflectUtils.addAllMethods(type, new ArrayList()); CollectionUtils.filter(methodList, vp); CollectionUtils.filter(methodList, new DuplicatesPredicate()); final Method[] methods = (Method[])methodList.toArray(new Method[methodList.size()]); final Constructor[] constructors = (Constructor[])CollectionUtils.filter(type.getDeclaredConstructors(), vp); // getIndex(String) emitIndexBySignature(methods); // getIndex(String, Class[]) emitIndexByClassArray(methods); // getIndex(Class[]) e = begin_method(Constants.ACC_PUBLIC, CONSTRUCTOR_GET_INDEX, null, null); e.load_args(); EmitUtils.constructor_switch(e, constructors, new GetIndexCallback(e, constructors)); e.end_method(); // invoke(int, Object, Object[]) e = begin_method(Constants.ACC_PUBLIC, INVOKE, INVOCATION_TARGET_EXCEPTION_ARRAY, null); e.load_arg(1); e.checkcast(Type.getType(type)); e.load_arg(0); invokeSwitchHelper(e, methods, 2); e.end_method(); // newInstance(int, Object[]) e = begin_method(Constants.ACC_PUBLIC, NEW_INSTANCE, INVOCATION_TARGET_EXCEPTION_ARRAY, null); e.new_instance(Type.getType(type)); e.dup(); e.load_arg(0); invokeSwitchHelper(e, constructors, 1); e.end_method(); // getMaxIndex() e = begin_method(Constants.ACC_PUBLIC, GET_MAX_INDEX, null, null); e.push(methods.length - 1); e.return_value(); e.end_method(); end_class(); } // TODO: support constructor indices ("<init>") private void emitIndexBySignature(Method[] methods) { CodeEmitter e = begin_method(Constants.ACC_PUBLIC, SIGNATURE_GET_INDEX, null, null); List signatures = CollectionUtils.transform(Arrays.asList(methods), new Transformer() { public Object transform(Object obj) { return ReflectUtils.getSignature((Method)obj).toString(); } }); e.load_arg(0); e.invoke_virtual(Constants.TYPE_OBJECT, TO_STRING); signatureSwitchHelper(e, signatures); e.end_method(); } private static final int TOO_MANY_METHODS = 100; // TODO private void emitIndexByClassArray(Method[] methods) { CodeEmitter e = begin_method(Constants.ACC_PUBLIC, METHOD_GET_INDEX, null, null); if (methods.length > TOO_MANY_METHODS) { // hack for big classes List signatures = CollectionUtils.transform(Arrays.asList(methods), new Transformer() { public Object transform(Object obj) { String s = ReflectUtils.getSignature((Method)obj).toString(); return s.substring(0, s.lastIndexOf(')') + 1); } }); e.load_args(); e.invoke_static(FAST_CLASS, GET_SIGNATURE_WITHOUT_RETURN_TYPE); signatureSwitchHelper(e, signatures); } else { e.load_args(); EmitUtils.method_switch(e, methods, new GetIndexCallback(e, methods)); } e.end_method(); } private void signatureSwitchHelper(final CodeEmitter e, final List signatures) { ObjectSwitchCallback callback = new ObjectSwitchCallback() { public void processCase(Object key, Label end) { // TODO: remove linear indexOf e.push(signatures.indexOf(key)); e.return_value(); } public void processDefault() { e.push(-1); e.return_value(); } }; EmitUtils.string_switch(e, (String[])signatures.toArray(new String[signatures.size()]), Constants.SWITCH_STYLE_HASH, callback); } private static void invokeSwitchHelper(final CodeEmitter e, final Object[] members, final int arg) { final Label illegalArg = e.make_label(); Block block = e.begin_block(); e.process_switch(getIntRange(members.length), new ProcessSwitchCallback() { public void processCase(int key, Label end) { Member member = (Member)members[key]; Signature sig = ReflectUtils.getSignature(member); Type[] types = sig.getArgumentTypes(); for (int i = 0; i < types.length; i++) { e.load_arg(arg); e.aaload(i); e.unbox(types[i]); } if (member instanceof Method) { e.invoke((Method)member); e.box(Type.getType(((Method)member).getReturnType())); } else { e.invoke_constructor(Type.getType(member.getDeclaringClass()), sig); } e.return_value(); } public void processDefault() { e.goTo(illegalArg); } }); block.end(); EmitUtils.wrap_throwable(block, INVOCATION_TARGET_EXCEPTION); e.mark(illegalArg); e.throw_exception(ILLEGAL_ARGUMENT_EXCEPTION, "Cannot find matching method/constructor"); } private static class GetIndexCallback implements ObjectSwitchCallback { private CodeEmitter e; private Map indexes = new HashMap(); public GetIndexCallback(CodeEmitter e, Object[] members) { this.e = e; for (int i = 0; i < members.length; i++) { indexes.put(members[i], new Integer(i)); } } public void processCase(Object key, Label end) { e.push(((Integer)indexes.get(key)).intValue()); e.return_value(); } public void processDefault() { e.push(-1); e.return_value(); } } private static int[] getIntRange(int length) { int[] range = new int[length]; for (int i = 0; i < length; i++) { range[i] = i; } return range; } } --- NEW FILE: FastConstructor.java --- /* * The Apache Software License, Version 1.1 * * Copyright (c) 2002 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, 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 "Apache" 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 ap...@ap.... * * 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 (INCLUDING, 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.logicalcobwebs.cglib.reflect; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; public class FastConstructor extends FastMember { FastConstructor(FastClass fc, Constructor constructor) { super(fc, constructor, fc.getIndex(constructor.getParameterTypes())); } public Class[] getParameterTypes() { return ((Constructor)member).getParameterTypes(); } public Class[] getExceptionTypes() { return ((Constructor)member).getExceptionTypes(); } public Object newInstance() throws InvocationTargetException { return fc.newInstance(index, null); } public Object newInstance(Object[] args) throws InvocationTargetException { return fc.newInstance(index, args); } public Constructor getJavaConstructor() { return (Constructor)member; } } --- NEW FILE: FastMember.java --- /* * The Apache Software License, Version 1.1 * * Copyright (c) 2002 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, 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 "Apache" 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 ap...@ap.... * * 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 (INCLUDING, 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.logicalcobwebs.cglib.reflect; import java.lang.reflect.Member; abstract public class FastMember { protected FastClass fc; protected Member member; protected int index; protected FastMember(FastClass fc, Member member, int index) { this.fc = fc; this.member = member; this.index = index; } abstract public Class[] getParameterTypes(); abstract public Class[] getExceptionTypes(); public int getIndex() { return index; } public String getName() { return member.getName(); } public Class getDeclaringClass() { return fc.getJavaClass(); } public int getModifiers() { return member.getModifiers(); } public String toString() { return member.toString(); } public int hashCode() { return member.hashCode(); } public boolean equals(Object o) { if (o == null || !(o instanceof FastMember)) { return false; } return member.equals(((FastMember)o).member); } } --- NEW FILE: FastMethod.java --- /* * The Apache Software License, Version 1.1 * * Copyright (c) 2002 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, 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 "Apache" 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 ap...@ap.... * * 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 (INCLUDING, 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.logicalcobwebs.cglib.reflect; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class FastMethod extends FastMember { FastMethod(FastClass fc, Method method) { super(fc, method, helper(fc, method)); } private static int helper(FastClass fc, Method method) { try { return fc.getIndex(method.getName(), method.getParameterTypes()); } catch (Error e) { System.err.println("Caught error " + e + " LOOKING UP INDEX name=" + method.getName() + " types=" + java.util.Arrays.asList(method.getParameterTypes()) + " in class " + fc.getClass().getName()); throw e; } } public Class getReturnType() { return ((Method)member).getReturnType(); } public Class[] getParameterTypes() { return ((Method)member).getParameterTypes(); } public Class[] getExceptionTypes() { return ((Method)member).getExceptionTypes(); } public Object invoke(Object obj, Object[] args) throws InvocationTargetException { return fc.invoke(index, obj, args); } public Method getJavaMethod() { return (Method)member; } } --- NEW FILE: MethodDelegate.java --- /* * The Apache Software License, Version 1.1 * * Copyright (c) 2002 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, 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 "Apache" 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 ap...@ap.... * * 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 (INCLUDING, 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.logicalcobwebs.cglib.reflect; import java.lang.reflect.*; import org.logicalcobwebs.cglib.*; import org.logicalcobwebs.cglib.core.*; import org.logicalcobwebs.asm.ClassVisitor; import org.logicalcobwebs.asm.Type; // TODO: don't require exact match for return type /** * <b>DOCUMENTATION FROM APACHE AVALON DELEGATE CLASS</b> * * <p> * 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. * </p> * * <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>MethodDelegate.create(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) * MethodDelegate.create(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>MethodDelegate.createStatic(getClass(), "main", MainDelegate.class)</code>. * </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> * * <h3>Equality</h3> * 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> * * @version $Id: MethodDelegate.java,v 1.1 2003/12/12 19:28:13 billhorsman Exp $ */ abstract public class MethodDelegate { private static final MethodDelegateKey KEY_FACTORY = (MethodDelegateKey)KeyFactory.create(MethodDelegateKey.class, KeyFactory.CLASS_BY_NAME); protected Object target; protected String eqMethod; interface MethodDelegateKey { Object newInstance(Class delegateClass, String methodName, Class iface); } public static MethodDelegate createStatic(Class targetClass, String methodName, Class iface) { Generator gen = new Generator(); gen.setTargetClass(targetClass); gen.setMethodName(methodName); gen.setInterface(iface); return gen.create(); } public static MethodDelegate create(Object target, String methodName, Class iface) { Generator gen = new Generator(); gen.setTarget(target); gen.setMethodName(methodName); gen.setInterface(iface); return gen.create(); } public boolean equals(Object obj) { MethodDelegate other = (MethodDelegate)obj; return target == other.target && eqMethod.equals(other.eqMethod); } public int hashCode() { return target.hashCode() ^ eqMethod.hashCode(); } public Object getTarget() { return target; } abstract public MethodDelegate newInstance(Object target); public static class Generator extends AbstractClassGenerator { private static final Source SOURCE = new Source(MethodDelegate.class.getName()); private static final Signature NEW_INSTANCE = TypeUtils.parseSignature("org.logicalcobwebs.cglib.reflect.MethodDelegate newInstance(Object)"); private static final Type METHOD_DELEGATE = TypeUtils.parseType("org.logicalcobwebs.cglib.reflect.MethodDelegate"); private Object target; private Class targetClass; private String methodName; private Class iface; public Generator() { super(SOURCE); } public void setTarget(Object target) { this.target = target; this.targetClass = target.getClass(); } public void setTargetClass(Class targetClass) { this.targetClass = targetClass; } public void setMethodName(String methodName) { this.methodName = methodName; } public void setInterface(Class iface) { this.iface = iface; } protected ClassLoader getDefaultClassLoader() { return targetClass.getClassLoader(); } public MethodDelegate create() { setNamePrefix(targetClass.getName()); Object key = KEY_FACTORY.newInstance(targetClass, methodName, iface); return (MethodDelegate)super.create(key); } protected Object firstInstance(Class type) { return ((MethodDelegate)ReflectUtils.newInstance(type)).newInstance(target); } protected Object nextInstance(Object instance) { return ((MethodDelegate)instance).newInstance(target); } public void generateClass(ClassVisitor v) throws NoSuchMethodException { Method proxy = ReflectUtils.findInterfaceMethod(iface); final Method method = targetClass.getMethod(methodName, proxy.getParameterTypes()); if (!proxy.getReturnType().isAssignableFrom(method.getReturnType())) { throw new IllegalArgumentException("incompatible return types"); } boolean isStatic = Modifier.isStatic(method.getModifiers()); if ((target == null) ^ isStatic) { throw new IllegalArgumentException("Static method " + (isStatic ? "not " : "") + "expected"); } ClassEmitter ce = new ClassEmitter(v); CodeEmitter e; ce.begin_class(Constants.ACC_PUBLIC, getClassName(), METHOD_DELEGATE, new Type[]{ Type.getType(iface) }, Constants.SOURCE_FILE); ce.declare_field(Constants.PRIVATE_FINAL_STATIC, "eqMethod", Constants.TYPE_STRING, null, null); EmitUtils.null_constructor(ce); // generate proxied method Method proxied = iface.getDeclaredMethods()[0]; e = ce.begin_method(Constants.ACC_PUBLIC, ReflectUtils.getSignature(proxied), ReflectUtils.getExceptionTypes(proxied), null); e.load_this(); e.super_getfield("target", Constants.TYPE_OBJECT); e.checkcast(Type.getType(method.getDeclaringClass())); e.load_args(); e.invoke(method); e.return_value(); e.end_method(); // newInstance e = ce.begin_method(Constants.ACC_PUBLIC, NEW_INSTANCE, null, null); e.new_instance_this(); e.dup(); e.dup2(); e.invoke_constructor_this(); e.getfield("eqMethod"); e.super_putfield("eqMethod", Constants.TYPE_STRING); e.load_arg(0); e.super_putfield("target", Constants.TYPE_OBJECT); e.return_value(); e.end_method(); // static initializer e = ce.begin_static(); Signature sig = ReflectUtils.getSignature(method); e.push(sig.getName() + sig.getDescriptor()); e.putfield("eqMethod"); e.return_value(); e.end_method(); ce.end_class(); } } } --- NEW FILE: MulticastDelegate.java --- /* * The Apache Software License, Version 1.1 * * Copyright (c) 2002 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, 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 "Apache" 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 ap...@ap.... * * 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 (INCLUDING, 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.logicalcobwebs.cglib.reflect; import java.lang.reflect.*; import java.util.*; import org.logicalcobwebs.cglib.core.*; import org.logicalcobwebs.asm.ClassVisitor; import org.logicalcobwebs.asm.CodeVisitor; import org.logicalcobwebs.asm.Type; abstract public class MulticastDelegate implements Cloneable { protected Object[] targets = {}; protected MulticastDelegate() { } public List getTargets() { return new ArrayList(Arrays.asList(targets)); } abstract public MulticastDelegate add(Object target); protected MulticastDelegate addHelper(Object target) { MulticastDelegate copy = newInstance(); copy.targets = new Object[targets.length + 1]; System.arraycopy(targets, 0, copy.targets, 0, targets.length); copy.targets[targets.length] = target; return copy; } public MulticastDelegate remove(Object target) { for (int i = targets.length - 1; i >= 0; i--) { if (targets[i].equals(target)) { MulticastDelegate copy = newInstance(); copy.targets = new Object[targets.length - 1]; System.arraycopy(targets, 0, copy.targets, 0, i); System.arraycopy(targets, i + 1, copy.targets, i, targets.length - i - 1); return copy; } } return this; } abstract public MulticastDelegate newInstance(); public static MulticastDelegate create(Class iface) { Generator gen = new Generator(); gen.setInterface(iface); return gen.create(); } public static class Generator extends AbstractClassGenerator { private static final Source SOURCE = new Source(MulticastDelegate.class.getName()); private static final Signature NEW_INSTANCE = TypeUtils.parseSignature("org.logicalcobwebs.cglib.reflect.MulticastDelegate newInstance()"); private static final Signature ADD_DELEGATE = TypeUtils.parseSignature("org.logicalcobwebs.cglib.reflect.MulticastDelegate add(Object)"); private static final Signature ADD_HELPER = TypeUtils.parseSignature("org.logicalcobwebs.cglib.reflect.MulticastDelegate addHelper(Object)"); private static final Type MULTICAST_DELEGATE = TypeUtils.parseType("org.logicalcobwebs.cglib.reflect.MulticastDelegate"); private Class iface; public Generator() { super(SOURCE); } protected ClassLoader getDefaultClassLoader() { return iface.getClassLoader(); } public void setInterface(Class iface) { this.iface = iface; } public MulticastDelegate create() { setNamePrefix(MulticastDelegate.class.getName()); return (MulticastDelegate)super.create(iface.getName()); } public void generateClass(ClassVisitor cv) { final Method method = ReflectUtils.findInterfaceMethod(iface); ClassEmitter ce = new ClassEmitter(cv); ce.begin_class(Constants.ACC_PUBLIC, getClassName(), MULTICAST_DELEGATE, new Type[]{ Type.getType(iface) }, Constants.SOURCE_FILE); EmitUtils.null_constructor(ce); // generate proxied method emitProxy(ce, method); // newInstance CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, NEW_INSTANCE, null, null); e.new_instance_this(); e.dup(); e.invoke_constructor_this(); e.return_value(); e.end_method(); // add e = ce.begin_method(Constants.ACC_PUBLIC, ADD_DELEGATE, null, null); e.load_this(); e.load_arg(0); e.checkcast(Type.getType(iface)); e.invoke_virtual_this(ADD_HELPER); e.return_value(); e.end_method(); ce.end_class(); } private void emitProxy(ClassEmitter ce, final Method method) { final CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, ReflectUtils.getSignature(method), ReflectUtils.getExceptionTypes(method), null); Type returnType = e.getReturnType(); final boolean returns = returnType != Type.VOID_TYPE; Local result = null; if (returns) { result = e.make_local(returnType); e.zero_or_null(returnType); e.store_local(result); } e.load_this(); e.super_getfield("targets", Constants.TYPE_OBJECT_ARRAY); final Local result2 = result; EmitUtils.process_array(e, Constants.TYPE_OBJECT_ARRAY, new ProcessArrayCallback() { public void processElement(Type type) { e.checkcast(Type.getType(iface)); e.load_args(); e.invoke(method); if (returns) { e.store_local(result2); } } }); if (returns) { e.load_local(result); } e.return_value(); e.end_method(); } protected Object firstInstance(Class type) { // make a new instance in case first object is used with a long list of targets return ((MulticastDelegate)ReflectUtils.newInstance(type)).newInstance(); } protected Object nextInstance(Object instance) { return ((MulticastDelegate)instance).newInstance(); } } } |