You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by jc...@apache.org on 2005/08/25 16:51:14 UTC

svn commit: r240082 - in /jakarta/commons/sandbox/proxy/trunk/src: java/org/apache/commons/proxy/exception/ java/org/apache/commons/proxy/factory/javassist/ test/org/apache/commons/proxy/factory/javassist/

Author: jcarman
Date: Thu Aug 25 07:51:10 2005
New Revision: 240082

URL: http://svn.apache.org/viewcvs?rev=240082&view=rev
Log:
Completed JavassistProxyFactory.

Added:
    jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/exception/ProxyFactoryException.java
Modified:
    jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/javassist/JavassistProxyFactory.java
    jakarta/commons/sandbox/proxy/trunk/src/test/org/apache/commons/proxy/factory/javassist/TestJavassistProxyFactory.java

Added: jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/exception/ProxyFactoryException.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/exception/ProxyFactoryException.java?rev=240082&view=auto
==============================================================================
--- jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/exception/ProxyFactoryException.java (added)
+++ jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/exception/ProxyFactoryException.java Thu Aug 25 07:51:10 2005
@@ -0,0 +1,45 @@
+/*
+ *  Copyright 2005 The Apache Software Foundation
+ *
+ *  Licensed 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.exception;
+
+/**
+ * A runtime exception type to be used by {@link org.apache.commons.proxy.ProxyFactory proxy factories} when a
+ * problem occurs.
+ * 
+ * @author James Carman
+ * @version 1.0
+ */
+public class ProxyFactoryException extends RuntimeException
+{
+    public ProxyFactoryException()
+    {
+    }
+
+    public ProxyFactoryException( String message )
+    {
+        super( message );
+    }
+
+    public ProxyFactoryException( String message, Throwable cause )
+    {
+        super( message, cause );
+    }
+
+    public ProxyFactoryException( Throwable cause )
+    {
+        super( cause );
+    }
+}

Modified: jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/javassist/JavassistProxyFactory.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/javassist/JavassistProxyFactory.java?rev=240082&r1=240081&r2=240082&view=diff
==============================================================================
--- jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/javassist/JavassistProxyFactory.java (original)
+++ jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/javassist/JavassistProxyFactory.java Thu Aug 25 07:51:10 2005
@@ -23,8 +23,12 @@
 import javassist.CtMethod;
 import javassist.NotFoundException;
 import org.aopalliance.intercept.MethodInterceptor;
+import org.aopalliance.intercept.MethodInvocation;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 import org.apache.commons.proxy.ObjectProvider;
 import org.apache.commons.proxy.exception.ObjectProviderException;
+import org.apache.commons.proxy.exception.ProxyFactoryException;
 import org.apache.commons.proxy.factory.AbstractProxyFactory;
 
 import java.lang.reflect.Method;
@@ -32,17 +36,132 @@
 /**
  * A <a href="http://www.jboss.org/products/javassist">Javassist</a>-based {@link org.apache.commons.proxy.ProxyFactory}
  * implementation.
+ *
  * @author James Carman
  * @version 1.0
  */
 public class JavassistProxyFactory extends AbstractProxyFactory
 {
+    private static final Log log = LogFactory.getLog( JavassistProxyFactory.class );
+
     private static int classNumber = 0;
     private static final ClassPool classPool = ClassPool.getDefault();
 
+    private void addField( Class fieldType, String fieldName, CtClass enclosingClass )
+    {
+        try
+        {
+            enclosingClass.addField( new CtField( resolve( fieldType ), fieldName, enclosingClass )  );
+        }
+        catch( CannotCompileException e )
+        {
+            throw new ProxyFactoryException( "Unable to add field named " + fieldName + " of type " + fieldType.getName() + " to class " + enclosingClass.getName(), e );
+        }
+    }
+
     public Object createInterceptorProxy( ClassLoader classLoader, Object target, MethodInterceptor interceptor, Class... proxyInterfaces )
     {
-        return null;
+        try
+        {
+            final CtClass proxyClass = createClass();
+            addField( target.getClass(), "target", proxyClass );
+            addField( MethodInterceptor.class, "interceptor", proxyClass );
+            final CtConstructor proxyConstructor = new CtConstructor( resolve( new Class[]{target.getClass(), MethodInterceptor.class} ), proxyClass );
+            proxyConstructor.setBody( "{ this.target = $1;\nthis.interceptor = $2; }" );
+            proxyClass.addConstructor( proxyConstructor );
+            for( Class proxyInterface : proxyInterfaces )
+            {
+                proxyClass.addInterface( resolve( proxyInterface ) );
+                final Method[] methods = proxyInterface.getMethods();
+                for( int i = 0; i < methods.length; ++i )
+                {
+                    final CtMethod method = new CtMethod( resolve( methods[i].getReturnType() ), methods[i].getName(), resolve( methods[i].getParameterTypes() ), proxyClass );
+                    final Class invocationClass = createMethodInvocationClass( methods[i], target.getClass(), classLoader );
+                    final String body = "{\n\t return ( $r ) interceptor.invoke( new " + invocationClass.getName() + "( target, $$ ) );\n }";
+                    log.debug( method.getName() + "() method body:\n" + body );
+                    method.setBody( body );
+                    proxyClass.addMethod( method );
+                }
+            }
+            final Class clazz = proxyClass.toClass( classLoader );
+            return clazz.getConstructor( target.getClass(), MethodInterceptor.class ).newInstance( target, interceptor );
+        }
+        catch( CannotCompileException e )
+        {
+            throw new ObjectProviderException( "Could not compile class.", e );
+        }
+        catch( NoSuchMethodException e )
+        {
+            throw new ObjectProviderException( "Could not find constructor in generated proxy class.", e );
+        }
+        catch( Exception e )
+        {
+            throw new ObjectProviderException( "Unable to instantiate proxy from generated proxy class.", e );
+        }
+    }
+
+    private Class createMethodInvocationClass( Method method, Class targetClass, ClassLoader classLoader )
+    {
+        try
+        {
+            final CtClass invocationClass = createClass();
+            invocationClass.addInterface( resolve( MethodInvocation.class ) );
+            addField( targetClass, "target", invocationClass );
+            final Class[] argumentTypes = method.getParameterTypes();
+            final Class[] constructorArgs = new Class[argumentTypes.length + 1];
+            constructorArgs[0] = targetClass;
+            for( int i = 0; i < argumentTypes.length; i++ )
+            {
+                Class argumentType = argumentTypes[i];
+                final CtField argumentField = new CtField( resolve( argumentType ), "argument" + i, invocationClass );
+                invocationClass.addField( argumentField );
+                constructorArgs[i + 1] = argumentType;
+            }
+            final CtConstructor constructor = new CtConstructor( resolve( constructorArgs ), invocationClass );
+            final StringBuffer constructorBody = new StringBuffer( "{\n" );
+            constructorBody.append( "\tthis.target = $1;\n" );
+            for( int i = 0; i < argumentTypes.length; i++ )
+            {
+                constructorBody.append( "\tthis.argument" + i + " = $" + ( 2 + i ) + ";\n" );
+
+            }
+            constructorBody.append( "}" );
+            log.debug( "Constructor body:\n" + constructorBody );
+            constructor.setBody( constructorBody.toString() );
+            invocationClass.addConstructor( constructor );
+            // proceed()...
+            final CtMethod proceedMethod = new CtMethod( resolve( Object.class ), "proceed", new CtClass[0], invocationClass );
+            final String proceedBody = generateProceedBody( method, argumentTypes );
+            log.debug( "Proceed method body:\n" + proceedBody );
+            proceedMethod.setBody( proceedBody.toString() );
+            invocationClass.addMethod( proceedMethod );
+            return invocationClass.toClass( classLoader );
+        }
+        catch( CannotCompileException e )
+        {
+            throw new RuntimeException( "Oops!", e );
+        }
+    }
+
+    private String generateProceedBody( Method method, Class[] argumentTypes )
+    {
+        final StringBuffer proceedBody = new StringBuffer( "{\n" );
+        if( !Void.TYPE.equals( method.getReturnType() ) )
+        {
+            proceedBody.append( "\treturn ( $r )" );
+        }
+        proceedBody.append( "target." + method.getName() + "(" );
+        for( int i = 0; i < argumentTypes.length; ++i )
+        {
+            proceedBody.append( "argument" + i );
+            if( i != argumentTypes.length - 1 )
+            {
+                proceedBody.append( ", " );
+            }
+        }
+        proceedBody.append( ");\n" );
+        proceedBody.append( "}" );
+        return proceedBody.toString();
     }
 
     public Object createProxy( ClassLoader classLoader, ObjectProvider targetProvider, Class... proxyInterfaces )
@@ -112,6 +231,6 @@
 
     public static CtClass createClass( Class superclass )
     {
-        return classPool.makeClass( "JavassistUtilsGenerated_" + ( ++classNumber ), resolve( superclass ) );
+        return classPool.makeClass( "JavassistProxyFactoryGenerated_" + ( ++classNumber ), resolve( superclass ) );
     }
 }

Modified: jakarta/commons/sandbox/proxy/trunk/src/test/org/apache/commons/proxy/factory/javassist/TestJavassistProxyFactory.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/sandbox/proxy/trunk/src/test/org/apache/commons/proxy/factory/javassist/TestJavassistProxyFactory.java?rev=240082&r1=240081&r2=240082&view=diff
==============================================================================
--- jakarta/commons/sandbox/proxy/trunk/src/test/org/apache/commons/proxy/factory/javassist/TestJavassistProxyFactory.java (original)
+++ jakarta/commons/sandbox/proxy/trunk/src/test/org/apache/commons/proxy/factory/javassist/TestJavassistProxyFactory.java Thu Aug 25 07:51:10 2005
@@ -16,7 +16,6 @@
 package org.apache.commons.proxy.factory.javassist;
 
 import org.apache.commons.proxy.factory.AbstractProxyFactoryTestCase;
-import org.apache.commons.proxy.ProxyFactory;
 
 /**
  * @author James Carman



---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org