Added: commons/proper/proxy/branches/version-2.0-work/core/src/test/java/org/apache/commons/proxy/util/QuoteService.java URL: http://svn.apache.org/viewvc/commons/proper/proxy/branches/version-2.0-work/core/src/test/java/org/apache/commons/proxy/util/QuoteService.java?rev=964636&view=auto ============================================================================== --- commons/proper/proxy/branches/version-2.0-work/core/src/test/java/org/apache/commons/proxy/util/QuoteService.java (added) +++ commons/proper/proxy/branches/version-2.0-work/core/src/test/java/org/apache/commons/proxy/util/QuoteService.java Thu Jul 15 23:10:43 2010 @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.proxy.util; + +import java.rmi.Remote; +import java.rmi.RemoteException; + +/** + * @author James Carman + * @since 1.0 + */ +public interface QuoteService extends Remote +{ +//********************************************************************************************************************** +// Other Methods +//********************************************************************************************************************** + + public float getQuote( String symbol ) throws RemoteException; +}
Added: commons/proper/proxy/branches/version-2.0-work/core/src/test/java/org/apache/commons/proxy/util/SuffixInterceptor.java URL: http://svn.apache.org/viewvc/commons/proper/proxy/branches/version-2.0-work/core/src/test/java/org/apache/commons/proxy/util/SuffixInterceptor.java?rev=964636&view=auto ============================================================================== --- commons/proper/proxy/branches/version-2.0-work/core/src/test/java/org/apache/commons/proxy/util/SuffixInterceptor.java (added) +++ commons/proper/proxy/branches/version-2.0-work/core/src/test/java/org/apache/commons/proxy/util/SuffixInterceptor.java Thu Jul 15 23:10:43 2010 @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.proxy.util; + +import org.apache.commons.proxy.Interceptor; +import org.apache.commons.proxy.Invocation; + +/** + * @author James Carman + * @since 1.0 + */ +public class SuffixInterceptor implements Interceptor +{ +//********************************************************************************************************************** +// Fields +//********************************************************************************************************************** + + private final String suffix; + +//********************************************************************************************************************** +// Constructors +//********************************************************************************************************************** + + public SuffixInterceptor( String suffix ) + { + this.suffix = suffix; + } + +//********************************************************************************************************************** +// Interceptor Implementation +//********************************************************************************************************************** + + + public Object intercept( Invocation methodInvocation ) throws Throwable + { + return methodInvocation.proceed() + suffix; + } +} Added: commons/proper/proxy/branches/version-2.0-work/javassist/pom.xml URL: http://svn.apache.org/viewvc/commons/proper/proxy/branches/version-2.0-work/javassist/pom.xml?rev=964636&view=auto ============================================================================== --- commons/proper/proxy/branches/version-2.0-work/javassist/pom.xml (added) +++ commons/proper/proxy/branches/version-2.0-work/javassist/pom.xml Thu Jul 15 23:10:43 2010 @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <artifactId>commons-proxy</artifactId> + <groupId>org.apache.commons</groupId> + <version>2.0-SNAPSHOT</version> + </parent> + <modelVersion>4.0.0</modelVersion> + + <artifactId>commons-proxy-javassist</artifactId> + + <dependencies> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>commons-proxy-core</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>jboss</groupId> + <artifactId>javassist</artifactId> + <version>3.0</version> + </dependency> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>commons-proxy-core</artifactId> + <version>${project.version}</version> + <type>test-jar</type> + <scope>test</scope> + </dependency> + <dependency> + <groupId>commons-lang</groupId> + <artifactId>commons-lang</artifactId> + <version>2.3</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>3.8.1</version> + <scope>test</scope> + </dependency> + </dependencies> +</project> Added: commons/proper/proxy/branches/version-2.0-work/javassist/src/main/java/org/apache/commons/proxy/javassist/JavassistInvocation.java URL: http://svn.apache.org/viewvc/commons/proper/proxy/branches/version-2.0-work/javassist/src/main/java/org/apache/commons/proxy/javassist/JavassistInvocation.java?rev=964636&view=auto ============================================================================== --- commons/proper/proxy/branches/version-2.0-work/javassist/src/main/java/org/apache/commons/proxy/javassist/JavassistInvocation.java (added) +++ commons/proper/proxy/branches/version-2.0-work/javassist/src/main/java/org/apache/commons/proxy/javassist/JavassistInvocation.java Thu Jul 15 23:10:43 2010 @@ -0,0 +1,222 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.proxy.javassist; + +import javassist.CannotCompileException; +import javassist.CtClass; +import javassist.CtConstructor; +import javassist.CtMethod; +import org.apache.commons.proxy.Invocation; +import org.apache.commons.proxy.ProxyUtils; + +import java.lang.ref.WeakReference; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; +import java.util.WeakHashMap; + +/** + * A <a href="http://www.jboss.org/products/javassist">Javassist</a>-based {...@link Invocation} implementation. This + * class actually serves as the superclass for all <a href="http://www.jboss.org/products/javassist">Javassist</a>-based + * method invocations. Subclasses are dynamically created to deal with specific interface methods (they're hard-wired). + * + * @author James Carman + * @since 1.0 + */ +public abstract class JavassistInvocation implements Invocation +{ +//********************************************************************************************************************** +// Fields +//********************************************************************************************************************** + + private static WeakHashMap loaderToClassCache = new WeakHashMap(); + protected final Method method; + protected final Object target; + protected final Object[] arguments; + +//********************************************************************************************************************** +// Static Methods +//********************************************************************************************************************** + + private static String createCastExpression( Class type, String objectToCast ) + { + if( !type.isPrimitive() ) + { + return "( " + ProxyUtils.getJavaClassName(type) + " )" + objectToCast; + } + else + { + return "( ( " + ProxyUtils.getWrapperClass(type).getName() + " )" + objectToCast + " )." + + type.getName() + "Value()"; + } + } + + private static Class createInvocationClass( ClassLoader classLoader, Method interfaceMethod ) + throws CannotCompileException + { + Class invocationClass; + final CtClass ctClass = JavassistUtils.createClass( + getSimpleName(interfaceMethod.getDeclaringClass()) + "_" + interfaceMethod.getName() + + "_invocation", + JavassistInvocation.class); + final CtConstructor constructor = new CtConstructor( + JavassistUtils.resolve(new Class[] {Method.class, Object.class, Object[].class}), + ctClass); + constructor.setBody("{\n\tsuper($$);\n}"); + ctClass.addConstructor(constructor); + final CtMethod proceedMethod = new CtMethod(JavassistUtils.resolve(Object.class), "proceed", + JavassistUtils.resolve(new Class[0]), ctClass); + final Class[] argumentTypes = interfaceMethod.getParameterTypes(); + final StringBuffer proceedBody = new StringBuffer("{\n"); + if( !Void.TYPE.equals(interfaceMethod.getReturnType()) ) + { + proceedBody.append("\treturn "); + if( interfaceMethod.getReturnType().isPrimitive() ) + { + proceedBody.append("new "); + proceedBody.append(ProxyUtils.getWrapperClass(interfaceMethod.getReturnType()).getName()); + proceedBody.append("( "); + } + } + else + { + proceedBody.append("\t"); + } + proceedBody.append("( ("); + proceedBody.append(ProxyUtils.getJavaClassName(interfaceMethod.getDeclaringClass())); + proceedBody.append(" )target )."); + proceedBody.append(interfaceMethod.getName()); + proceedBody.append("("); + for( int i = 0; i < argumentTypes.length; ++i ) + { + final Class argumentType = argumentTypes[i]; + proceedBody.append(createCastExpression(argumentType, "arguments[" + i + "]")); + if( i != argumentTypes.length - 1 ) + { + proceedBody.append(", "); + } + } + if( !Void.TYPE.equals(interfaceMethod.getReturnType()) && interfaceMethod.getReturnType().isPrimitive() ) + { + proceedBody.append(") );\n"); + } + else + { + proceedBody.append(");\n"); + } + if( Void.TYPE.equals(interfaceMethod.getReturnType()) ) + { + proceedBody.append("\treturn null;\n"); + } + proceedBody.append("}"); + final String body = proceedBody.toString(); + proceedMethod.setBody(body); + ctClass.addMethod(proceedMethod); + invocationClass = ctClass.toClass(classLoader); + return invocationClass; + } + + private static Map getClassCache( ClassLoader classLoader ) + { + Map cache = ( Map ) loaderToClassCache.get(classLoader); + if( cache == null ) + { + cache = new HashMap(); + loaderToClassCache.put(classLoader, cache); + } + return cache; + } + + /** + * Returns a method invocation class specifically coded to invoke the supplied interface method. + * + * @param classLoader the classloader to use + * @param interfaceMethod the interface method + * @return a method invocation class specifically coded to invoke the supplied interface method + * @throws CannotCompileException if a compilation error occurs + */ + synchronized static Class getMethodInvocationClass( ClassLoader classLoader, + Method interfaceMethod ) + throws CannotCompileException + { + final Map classCache = getClassCache(classLoader); + final String key = toClassCacheKey(interfaceMethod); + final WeakReference invocationClassRef = ( WeakReference ) classCache.get(key); + Class invocationClass; + if( invocationClassRef == null ) + { + invocationClass = createInvocationClass(classLoader, interfaceMethod); + classCache.put(key, new WeakReference(invocationClass)); + } + else + { + synchronized( invocationClassRef ) + { + invocationClass = ( Class ) invocationClassRef.get(); + if( invocationClass == null ) + { + invocationClass = createInvocationClass(classLoader, interfaceMethod); + classCache.put(key, new WeakReference(invocationClass)); + } + } + } + return invocationClass; + } + + private static String getSimpleName( Class c ) + { + final String name = c.getName(); + final int ndx = name.lastIndexOf('.'); + return ndx == -1 ? name : name.substring(ndx + 1); + } + + private static String toClassCacheKey( Method method ) + { + return String.valueOf(method); + } + +//********************************************************************************************************************** +// Constructors +//********************************************************************************************************************** + + public JavassistInvocation( Method method, Object target, Object[] arguments ) + { + this.method = method; + this.target = target; + this.arguments = arguments; + } + +//********************************************************************************************************************** +// Invocation Implementation +//********************************************************************************************************************** + + public Object[] getArguments() + { + return arguments; + } + + public Method getMethod() + { + return method; + } + + public Object getProxy() + { + return target; + } +} Added: commons/proper/proxy/branches/version-2.0-work/javassist/src/main/java/org/apache/commons/proxy/javassist/JavassistProxyFactory.java URL: http://svn.apache.org/viewvc/commons/proper/proxy/branches/version-2.0-work/javassist/src/main/java/org/apache/commons/proxy/javassist/JavassistProxyFactory.java?rev=964636&view=auto ============================================================================== --- commons/proper/proxy/branches/version-2.0-work/javassist/src/main/java/org/apache/commons/proxy/javassist/JavassistProxyFactory.java (added) +++ commons/proper/proxy/branches/version-2.0-work/javassist/src/main/java/org/apache/commons/proxy/javassist/JavassistProxyFactory.java Thu Jul 15 23:10:43 2010 @@ -0,0 +1,255 @@ +package org.apache.commons.proxy.javassist; + +import javassist.CannotCompileException; +import javassist.CtClass; +import javassist.CtConstructor; +import javassist.CtMethod; +import org.apache.commons.proxy.Interceptor; +import org.apache.commons.proxy.Invoker; +import org.apache.commons.proxy.ObjectProvider; +import org.apache.commons.proxy.exception.ProxyFactoryException; +import org.apache.commons.proxy.impl.AbstractProxyClassGenerator; +import org.apache.commons.proxy.impl.AbstractSubclassingProxyFactory; +import org.apache.commons.proxy.impl.ProxyClassCache; + +import java.lang.reflect.Method; + +public class JavassistProxyFactory extends AbstractSubclassingProxyFactory +{ + //********************************************************************************************************************** +// Fields +//********************************************************************************************************************** + + private static final String GET_METHOD_METHOD_NAME = "_javassistGetMethod"; + + private static final ProxyClassCache delegatingProxyClassCache = new ProxyClassCache( + new DelegatingProxyClassGenerator()); + private static final ProxyClassCache interceptorProxyClassCache = new ProxyClassCache( + new InterceptorProxyClassGenerator()); + private static final ProxyClassCache invocationHandlerProxyClassCache = new ProxyClassCache( + new InvokerProxyClassGenerator()); + +//********************************************************************************************************************** +// Static Methods +//********************************************************************************************************************** + + private static void addGetMethodMethod(CtClass proxyClass) throws CannotCompileException + { + final CtMethod method = new CtMethod(JavassistUtils.resolve(Method.class), GET_METHOD_METHOD_NAME, + JavassistUtils.resolve(new Class[]{String.class, String.class, Class[].class}), proxyClass); + final String body = "try { return Class.forName($1).getMethod($2, $3); } catch( Exception e ) " + + "{ throw new RuntimeException(\"Unable to look up method.\", e); }"; + method.setBody(body); + proxyClass.addMethod(method); + } + +//********************************************************************************************************************** +// Other Methods +//********************************************************************************************************************** + + public Object createDelegatorProxy(ClassLoader classLoader, ObjectProvider targetProvider, + Class... proxyClasses) + { + try + { + final Class clazz = delegatingProxyClassCache.getProxyClass(classLoader, proxyClasses); + return clazz.getConstructor(ObjectProvider.class) + .newInstance(targetProvider); + } + catch (Exception e) + { + throw new ProxyFactoryException("Unable to instantiate proxy from generated proxy class.", e); + } + } + + public Object createInterceptorProxy(ClassLoader classLoader, Object target, Interceptor interceptor, + Class... proxyClasses) + { + try + { + final Class clazz = interceptorProxyClassCache.getProxyClass(classLoader, proxyClasses); + return clazz.getConstructor(Object.class, Interceptor.class) + .newInstance(target, interceptor); + } + catch (Exception e) + { + throw new ProxyFactoryException("Unable to instantiate proxy class instance.", e); + } + } + + public Object createInvokerProxy(ClassLoader classLoader, Invoker invoker, + Class... proxyClasses) + { + try + { + final Class clazz = invocationHandlerProxyClassCache.getProxyClass(classLoader, proxyClasses); + return clazz.getConstructor(Invoker.class) + .newInstance(invoker); + } + catch (Exception e) + { + throw new ProxyFactoryException("Unable to instantiate proxy from generated proxy class.", e); + } + } + +//********************************************************************************************************************** +// Inner Classes +//********************************************************************************************************************** + + private static class DelegatingProxyClassGenerator extends AbstractProxyClassGenerator + { + public Class generateProxyClass(ClassLoader classLoader, Class[] proxyClasses) + { + try + { + final CtClass proxyClass = JavassistUtils.createClass(getSuperclass(proxyClasses)); + JavassistUtils.addField(ObjectProvider.class, "provider", proxyClass); + final CtConstructor proxyConstructor = new CtConstructor( + JavassistUtils.resolve(new Class[]{ObjectProvider.class}), + proxyClass); + proxyConstructor.setBody("{ this.provider = $1; }"); + proxyClass.addConstructor(proxyConstructor); + JavassistUtils.addInterfaces(proxyClass, toInterfaces(proxyClasses)); + addHashCodeMethod(proxyClass); + addEqualsMethod(proxyClass); + final Method[] methods = getImplementationMethods(proxyClasses); + for (int i = 0; i < methods.length; ++i) + { + if (!isEqualsMethod(methods[i]) && !isHashCode(methods[i])) + { + final Method method = methods[i]; + final CtMethod ctMethod = new CtMethod(JavassistUtils.resolve(method.getReturnType()), + method.getName(), + JavassistUtils.resolve(method.getParameterTypes()), + proxyClass); + final String body = "{ return ( $r ) ( ( " + method.getDeclaringClass().getName() + + " )provider.getObject() )." + + method.getName() + "($$); }"; + ctMethod.setBody(body); + proxyClass.addMethod(ctMethod); + } + } + return proxyClass.toClass(classLoader); + } + catch (CannotCompileException e) + { + throw new ProxyFactoryException("Could not compile class.", e); + } + } + } + + private static class InterceptorProxyClassGenerator extends AbstractProxyClassGenerator + { + public Class generateProxyClass(ClassLoader classLoader, Class[] proxyClasses) + { + try + { + final CtClass proxyClass = JavassistUtils.createClass(getSuperclass(proxyClasses)); + final Method[] methods = getImplementationMethods(proxyClasses); + JavassistUtils.addInterfaces(proxyClass, toInterfaces(proxyClasses)); + JavassistUtils.addField(Object.class, "target", proxyClass); + JavassistUtils.addField(Interceptor.class, "interceptor", proxyClass); + addGetMethodMethod(proxyClass); + addHashCodeMethod(proxyClass); + addEqualsMethod(proxyClass); + final CtConstructor proxyConstructor = new CtConstructor( + JavassistUtils.resolve( + new Class[]{Object.class, Interceptor.class}), + proxyClass); + proxyConstructor + .setBody( + "{\n\tthis.target = $1;\n\tthis.interceptor = $2; }"); + proxyClass.addConstructor(proxyConstructor); + for (int i = 0; i < methods.length; ++i) + { + if (!isEqualsMethod(methods[i]) && !isHashCode(methods[i])) + { + final CtMethod method = new CtMethod(JavassistUtils.resolve(methods[i].getReturnType()), + methods[i].getName(), + JavassistUtils.resolve(methods[i].getParameterTypes()), + proxyClass); + final Class invocationClass = JavassistInvocation + .getMethodInvocationClass(classLoader, methods[i]); + + final String body = "{\n\t return ( $r ) interceptor.intercept( new " + invocationClass.getName() + + "( " + GET_METHOD_METHOD_NAME + "(\"" + methods[i].getDeclaringClass().getName() + + "\", \"" + methods[i].getName() + "\", $sig), target, $args ) );\n }"; + method.setBody(body); + proxyClass.addMethod(method); + } + + } + return proxyClass.toClass(classLoader); + } + catch (CannotCompileException e) + { + throw new ProxyFactoryException("Could not compile class.", e); + } + } + + + } + + private static void addEqualsMethod(CtClass proxyClass) + throws CannotCompileException + { + final CtMethod equalsMethod = new CtMethod(JavassistUtils.resolve(Boolean.TYPE), "equals", + JavassistUtils.resolve(new Class[]{Object.class}), proxyClass); + final String body = "{\n\treturn this == $1;\n}"; + equalsMethod.setBody(body); + proxyClass.addMethod(equalsMethod); + } + + private static void addHashCodeMethod(CtClass proxyClass) + throws CannotCompileException + { + final CtMethod hashCodeMethod = new CtMethod(JavassistUtils.resolve(Integer.TYPE), "hashCode", + new CtClass[0], proxyClass); + hashCodeMethod.setBody("{\n\treturn System.identityHashCode(this);\n}"); + proxyClass.addMethod(hashCodeMethod); + } + + private static class InvokerProxyClassGenerator extends AbstractProxyClassGenerator + { + public Class generateProxyClass(ClassLoader classLoader, Class[] proxyClasses) + { + try + { + final CtClass proxyClass = JavassistUtils.createClass(getSuperclass(proxyClasses)); + final Method[] methods = getImplementationMethods(proxyClasses); + JavassistUtils.addInterfaces(proxyClass, toInterfaces(proxyClasses)); + JavassistUtils.addField(Invoker.class, "invoker", proxyClass); + final CtConstructor proxyConstructor = new CtConstructor( + JavassistUtils.resolve( + new Class[]{Invoker.class}), + proxyClass); + proxyConstructor + .setBody("{\n\tthis.invoker = $1; }"); + proxyClass.addConstructor(proxyConstructor); + addGetMethodMethod(proxyClass); + addHashCodeMethod(proxyClass); + addEqualsMethod(proxyClass); + for (int i = 0; i < methods.length; ++i) + { + if (!isEqualsMethod(methods[i]) && !isHashCode(methods[i])) + { + final CtMethod method = new CtMethod(JavassistUtils.resolve(methods[i].getReturnType()), + methods[i].getName(), + JavassistUtils.resolve(methods[i].getParameterTypes()), + proxyClass); + final String body = "{\n\t return ( $r ) invoker.invoke( this, " + GET_METHOD_METHOD_NAME + "(\"" + + methods[i].getDeclaringClass().getName() + + "\", \"" + methods[i].getName() + "\", $sig), $args );\n }"; + method.setBody(body); + proxyClass.addMethod(method); + } + } + return proxyClass.toClass(classLoader); + } + catch (CannotCompileException e) + { + throw new ProxyFactoryException("Could not compile class.", e); + } + } + } +} Added: commons/proper/proxy/branches/version-2.0-work/javassist/src/main/java/org/apache/commons/proxy/javassist/JavassistUtils.java URL: http://svn.apache.org/viewvc/commons/proper/proxy/branches/version-2.0-work/javassist/src/main/java/org/apache/commons/proxy/javassist/JavassistUtils.java?rev=964636&view=auto ============================================================================== --- commons/proper/proxy/branches/version-2.0-work/javassist/src/main/java/org/apache/commons/proxy/javassist/JavassistUtils.java (added) +++ commons/proper/proxy/branches/version-2.0-work/javassist/src/main/java/org/apache/commons/proxy/javassist/JavassistUtils.java Thu Jul 15 23:10:43 2010 @@ -0,0 +1,154 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.proxy.javassist; + +import javassist.CannotCompileException; +import javassist.ClassPool; +import javassist.CtClass; +import javassist.CtField; +import javassist.LoaderClassPath; +import javassist.NotFoundException; +import org.apache.commons.proxy.ProxyUtils; +import org.apache.commons.proxy.exception.ObjectProviderException; + +import java.util.HashSet; +import java.util.Set; + +/** + * Some utility methods for dealing with Javassist. This class is not part of the public API! + * + * @author James Carman + * @since 1.0 + */ +class JavassistUtils +{ +//********************************************************************************************************************** +// Fields +//********************************************************************************************************************** + + public static final String DEFAULT_BASE_NAME = "JavassistUtilsGenerated"; + private static int classNumber = 0; + private static final ClassPool classPool = new ClassPool(); + + private static final Set classLoaders = new HashSet(); + +//********************************************************************************************************************** +// Static Methods +//********************************************************************************************************************** + + static + { + classPool.appendClassPath(new LoaderClassPath(ClassLoader.getSystemClassLoader())); + } + + /** + * Adds a field to a class. + * + * @param fieldType the field's type + * @param fieldName the field name + * @param enclosingClass the class receiving the new field + * @throws CannotCompileException if a compilation problem occurs + */ + public static void addField( Class fieldType, String fieldName, CtClass enclosingClass ) + throws CannotCompileException + { + enclosingClass.addField(new CtField(resolve(fieldType), fieldName, enclosingClass)); + } + + /** + * Adds interfaces to a {...@link CtClass} + * + * @param ctClass the {...@link CtClass} + * @param proxyClasses the interfaces + */ + public static void addInterfaces( CtClass ctClass, Class[] proxyClasses ) + { + for( int i = 0; i < proxyClasses.length; i++ ) + { + Class proxyInterface = proxyClasses[i]; + ctClass.addInterface(resolve(proxyInterface)); + } + } + + /** + * Creates a new {...@link CtClass} derived from the Java {...@link Class} using the default base name. + * + * @param superclass the superclass + * @return the new derived {...@link CtClass} + */ + public static CtClass createClass( Class superclass ) + { + return createClass(DEFAULT_BASE_NAME, superclass); + } + + /** + * Creates a new {...@link CtClass} derived from the Java {...@link Class} using the supplied base name. + * + * @param baseName the base name + * @param superclass the superclass + * @return the new derived {...@link CtClass} + */ + public synchronized static CtClass createClass( String baseName, Class superclass ) + { + return classPool.makeClass(baseName + "_" + classNumber++, resolve(superclass)); + } + + /** + * Finds the {...@link CtClass} corresponding to the Java {...@link Class} passed in. + * + * @param clazz the Java {...@link Class} + * @return the {...@link CtClass} + */ + public static CtClass resolve( Class clazz ) + { + synchronized( classLoaders ) + { + try + { + final ClassLoader loader = clazz.getClassLoader(); + if( loader != null && !classLoaders.contains(loader) ) + { + classLoaders.add(loader); + classPool.appendClassPath(new LoaderClassPath(loader)); + } + return classPool.get(ProxyUtils.getJavaClassName(clazz)); + } + catch( NotFoundException e ) + { + throw new ObjectProviderException( + "Unable to find class " + clazz.getName() + " in default Javassist class pool.", e); + } + } + } + + /** + * Resolves an array of Java {...@link Class}es to an array of their corresponding {...@link CtClass}es. + * + * @param classes the Java {...@link Class}es + * @return the corresponding {...@link CtClass}es + */ + public static CtClass[] resolve( Class[] classes ) + { + final CtClass[] ctClasses = new CtClass[classes.length]; + for( int i = 0; i < ctClasses.length; ++i ) + { + ctClasses[i] = resolve(classes[i]); + } + return ctClasses; + } +} Added: commons/proper/proxy/branches/version-2.0-work/javassist/src/test/java/org/apache/commons/proxy/javassist/TestJavassistProxyFactory.java URL: http://svn.apache.org/viewvc/commons/proper/proxy/branches/version-2.0-work/javassist/src/test/java/org/apache/commons/proxy/javassist/TestJavassistProxyFactory.java?rev=964636&view=auto ============================================================================== --- commons/proper/proxy/branches/version-2.0-work/javassist/src/test/java/org/apache/commons/proxy/javassist/TestJavassistProxyFactory.java (added) +++ commons/proper/proxy/branches/version-2.0-work/javassist/src/test/java/org/apache/commons/proxy/javassist/TestJavassistProxyFactory.java Thu Jul 15 23:10:43 2010 @@ -0,0 +1,16 @@ +package org.apache.commons.proxy.javassist; + +import org.apache.commons.proxy.AbstractSubclassingProxyFactoryTestCase; +import org.apache.commons.proxy.ProxyFactory; + +public class TestJavassistProxyFactory extends AbstractSubclassingProxyFactoryTestCase +{ +//********************************************************************************************************************** +// Constructors +//********************************************************************************************************************** + + public TestJavassistProxyFactory() + { + super(new JavassistProxyFactory()); + } +} Added: commons/proper/proxy/branches/version-2.0-work/jdk/pom.xml URL: http://svn.apache.org/viewvc/commons/proper/proxy/branches/version-2.0-work/jdk/pom.xml?rev=964636&view=auto ============================================================================== --- commons/proper/proxy/branches/version-2.0-work/jdk/pom.xml (added) +++ commons/proper/proxy/branches/version-2.0-work/jdk/pom.xml Thu Jul 15 23:10:43 2010 @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <artifactId>commons-proxy</artifactId> + <groupId>org.apache.commons</groupId> + <version>2.0-SNAPSHOT</version> + </parent> + <modelVersion>4.0.0</modelVersion> + + <artifactId>commons-proxy-jdk</artifactId> + + <dependencies> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>commons-proxy-core</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>commons-proxy-core</artifactId> + <version>${project.version}</version> + <type>test-jar</type> + <scope>test</scope> + </dependency> + <dependency> + <groupId>commons-lang</groupId> + <artifactId>commons-lang</artifactId> + <version>2.3</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>3.8.1</version> + <scope>test</scope> + </dependency> + </dependencies> +</project> Added: commons/proper/proxy/branches/version-2.0-work/jdk/src/main/java/org/apache/commons/proxy/jdk/JdkProxyFactory.java URL: http://svn.apache.org/viewvc/commons/proper/proxy/branches/version-2.0-work/jdk/src/main/java/org/apache/commons/proxy/jdk/JdkProxyFactory.java?rev=964636&view=auto ============================================================================== --- commons/proper/proxy/branches/version-2.0-work/jdk/src/main/java/org/apache/commons/proxy/jdk/JdkProxyFactory.java (added) +++ commons/proper/proxy/branches/version-2.0-work/jdk/src/main/java/org/apache/commons/proxy/jdk/JdkProxyFactory.java Thu Jul 15 23:10:43 2010 @@ -0,0 +1,190 @@ +package org.apache.commons.proxy.jdk; + +import org.apache.commons.proxy.Interceptor; +import org.apache.commons.proxy.Invocation; +import org.apache.commons.proxy.Invoker; +import org.apache.commons.proxy.ObjectProvider; +import org.apache.commons.proxy.ProxyUtils; +import org.apache.commons.proxy.impl.AbstractProxyFactory; + +import java.io.Serializable; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; + +public class JdkProxyFactory extends AbstractProxyFactory +{ +//********************************************************************************************************************** +// ProxyFactory Implementation +//********************************************************************************************************************** + + + /** + * Creates a proxy which delegates to the object provided by <code>delegateProvider</code>. + * + * @param classLoader the class loader to use when generating the proxy + * @param delegateProvider the delegate provider + * @param proxyClasses the interfaces that the proxy should implement + * @return a proxy which delegates to the object provided by the target <code>delegateProvider> + */ + public Object createDelegatorProxy( ClassLoader classLoader, ObjectProvider delegateProvider, + Class... proxyClasses ) + { + return Proxy.newProxyInstance(classLoader, proxyClasses, + new DelegatorInvocationHandler(delegateProvider)); + } + + /** + * Creates a proxy which passes through a {...@link Interceptor interceptor} before eventually reaching the + * <code>target</code> object. + * + * @param classLoader the class loader to use when generating the proxy + * @param target the target object + * @param interceptor the method interceptor + * @param proxyClasses the interfaces that the proxy should implement. + * @return a proxy which passes through a {...@link Interceptor interceptor} before eventually reaching the + * <code>target</code> object. + */ + public Object createInterceptorProxy( ClassLoader classLoader, Object target, Interceptor interceptor, + Class... proxyClasses ) + { + return Proxy + .newProxyInstance(classLoader, proxyClasses, new InterceptorInvocationHandler(target, interceptor)); + } + + /** + * Creates a proxy which uses the provided {...@link Invoker} to handle all method invocations. + * + * @param classLoader the class loader to use when generating the proxy + * @param invoker the invoker + * @param proxyClasses the interfaces that the proxy should implement + * @return a proxy which uses the provided {...@link Invoker} to handle all method invocations + */ + public Object createInvokerProxy( ClassLoader classLoader, Invoker invoker, + Class... proxyClasses ) + { + return Proxy.newProxyInstance(classLoader, proxyClasses, new InvokerInvocationHandler(invoker)); + } + +//********************************************************************************************************************** +// Inner Classes +//********************************************************************************************************************** + + private abstract static class AbstractInvocationHandler implements InvocationHandler, Serializable + { + public Object invoke( Object proxy, Method method, Object[] args ) throws Throwable + { + if( isHashCode(method) ) + { + return System.identityHashCode(proxy); + } + else if( isEqualsMethod(method) ) + { + return proxy == args[0]; + } + else + { + return invokeImpl(proxy, method, args); + } + } + + protected abstract Object invokeImpl( Object proxy, Method method, Object[] args ) throws Throwable; + } + + private static class DelegatorInvocationHandler extends AbstractInvocationHandler + { + private final ObjectProvider delegateProvider; + + protected DelegatorInvocationHandler( ObjectProvider delegateProvider ) + { + this.delegateProvider = delegateProvider; + } + + public Object invokeImpl( Object proxy, Method method, Object[] args ) throws Throwable + { + try + { + return method.invoke(delegateProvider.getObject(), args); + } + catch( InvocationTargetException e ) + { + throw e.getTargetException(); + } + } + } + + private static class InterceptorInvocationHandler extends AbstractInvocationHandler + { + private final Object target; + private final Interceptor methodInterceptor; + + public InterceptorInvocationHandler( Object target, Interceptor methodInterceptor ) + { + this.target = target; + this.methodInterceptor = methodInterceptor; + } + + public Object invokeImpl( Object proxy, Method method, Object[] args ) throws Throwable + { + final ReflectionInvocation invocation = new ReflectionInvocation(target, method, args); + return methodInterceptor.intercept(invocation); + } + } + + private static class InvokerInvocationHandler extends AbstractInvocationHandler + { + private final Invoker invoker; + + public InvokerInvocationHandler( Invoker invoker ) + { + this.invoker = invoker; + } + + public Object invokeImpl( Object proxy, Method method, Object[] args ) throws Throwable + { + return invoker.invoke(proxy, method, args); + } + } + + private static class ReflectionInvocation implements Invocation, Serializable + { + private final Method method; + private final Object[] arguments; + private final Object target; + + public ReflectionInvocation( Object target, Method method, Object[] arguments ) + { + this.method = method; + this.arguments = ( arguments == null ? ProxyUtils.EMPTY_ARGUMENTS : arguments ); + this.target = target; + } + + public Object[] getArguments() + { + return arguments; + } + + public Method getMethod() + { + return method; + } + + public Object getProxy() + { + return target; + } + + public Object proceed() throws Throwable + { + try + { + return method.invoke(target, arguments); + } + catch( InvocationTargetException e ) + { + throw e.getTargetException(); + } + } + } +} Added: commons/proper/proxy/branches/version-2.0-work/jdk/src/test/java/org/apache/commons/proxy/jdk/TestJdkProxyFactory.java URL: http://svn.apache.org/viewvc/commons/proper/proxy/branches/version-2.0-work/jdk/src/test/java/org/apache/commons/proxy/jdk/TestJdkProxyFactory.java?rev=964636&view=auto ============================================================================== --- commons/proper/proxy/branches/version-2.0-work/jdk/src/test/java/org/apache/commons/proxy/jdk/TestJdkProxyFactory.java (added) +++ commons/proper/proxy/branches/version-2.0-work/jdk/src/test/java/org/apache/commons/proxy/jdk/TestJdkProxyFactory.java Thu Jul 15 23:10:43 2010 @@ -0,0 +1,12 @@ +package org.apache.commons.proxy.jdk; + +import org.apache.commons.proxy.AbstractProxyFactoryTestCase; +import org.apache.commons.proxy.AbstractSubclassingProxyFactoryTestCase; + +public class TestJdkProxyFactory extends AbstractProxyFactoryTestCase +{ + public TestJdkProxyFactory() + { + super(new JdkProxyFactory()); + } +} Modified: commons/proper/proxy/branches/version-2.0-work/pom.xml URL: http://svn.apache.org/viewvc/commons/proper/proxy/branches/version-2.0-work/pom.xml?rev=964636&r1=964635&r2=964636&view=diff ============================================================================== --- commons/proper/proxy/branches/version-2.0-work/pom.xml (original) +++ commons/proper/proxy/branches/version-2.0-work/pom.xml Thu Jul 15 23:10:43 2010 @@ -20,6 +20,13 @@ <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> + <packaging>pom</packaging> + <modules> + <module>core</module> + <module>jdk</module> + <module>javassist</module> + <module>cglib</module> + </modules> <parent> <groupId>org.apache.commons</groupId> <artifactId>commons-parent</artifactId> @@ -81,7 +88,6 @@ <roles> <role>advisor</role> </roles> - <url></url> </contributor> <contributor> <name>Howard M. Lewis Ship</name> @@ -115,93 +121,6 @@ </plugins> </build> - <dependencies> - <dependency> - <groupId>cglib</groupId> - <artifactId>cglib-nodep</artifactId> - <version>2.1_3</version> - <optional>true</optional> - </dependency> - <dependency> - <groupId>jboss</groupId> - <artifactId>javassist</artifactId> - <version>3.0</version> - <optional>true</optional> - </dependency> - <dependency> - <groupId>aopalliance</groupId> - <artifactId>aopalliance</artifactId> - <version>1.0</version> - <optional>true</optional> - </dependency> - <dependency> - <groupId>axis</groupId> - <artifactId>axis-jaxrpc</artifactId> - <version>1.2.1</version> - <optional>true</optional> - </dependency> - <dependency> - <groupId>hessian</groupId> - <artifactId>hessian</artifactId> - <version>3.0.1</version> - <optional>true</optional> - </dependency> - <dependency> - <groupId>burlap</groupId> - <artifactId>burlap</artifactId> - <version>2.1.7</version> - <optional>true</optional> - </dependency> - <dependency> - <groupId>commons-logging</groupId> - <artifactId>commons-logging</artifactId> - <version>1.0.4</version> - <optional>true</optional> - </dependency> - <dependency> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-api</artifactId> - <version>[1.4.0,)</version> - <optional>true</optional> - </dependency> - <dependency> - <groupId>commons-collections</groupId> - <artifactId>commons-collections</artifactId> - <version>3.1</version> - <optional>true</optional> - </dependency> - <dependency> - <groupId>concurrent</groupId> - <artifactId>concurrent</artifactId> - <version>1.3.4</version> - <optional>true</optional> - </dependency> - <dependency> - <groupId>jmock</groupId> - <artifactId>jmock</artifactId> - <version>1.0.1</version> - <scope>test</scope> - </dependency> - <dependency> - <groupId>xmlrpc</groupId> - <artifactId>xmlrpc</artifactId> - <version>2.0</version> - <optional>true</optional> - </dependency> - <dependency> - <groupId>commons-codec</groupId> - <artifactId>commons-codec</artifactId> - <version>1.3</version> - <optional>true</optional> - </dependency> - <dependency> - <groupId>commons-lang</groupId> - <artifactId>commons-lang</artifactId> - <version>2.3</version> - <scope>test</scope> - </dependency> - </dependencies> - <reporting> <plugins> <plugin>