You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openwebbeans.apache.org by st...@apache.org on 2012/12/30 18:52:57 UTC

svn commit: r1426968 - in /openwebbeans/trunk/webbeans-impl: ./ src/main/java/org/apache/webbeans/proxy/asm/ src/test/java/org/apache/webbeans/newtests/interceptors/factory/ src/test/java/org/apache/webbeans/newtests/interceptors/factory/beans/

Author: struberg
Date: Sun Dec 30 17:52:56 2012
New Revision: 1426968

URL: http://svn.apache.org/viewvc?rev=1426968&view=rev
Log:
OWB-344 start with an easy ASM proxy implementation

Added:
    openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/asm/InterceptorDecoratorProxyFactory.java
    openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/newtests/interceptors/factory/
    openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/newtests/interceptors/factory/InterceptorDecoratorProxyFactoryTest.java
    openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/newtests/interceptors/factory/beans/
    openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/newtests/interceptors/factory/beans/ClassInterceptedClass.java
    openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/newtests/interceptors/factory/beans/NonInterceptedClass.java
Modified:
    openwebbeans/trunk/webbeans-impl/pom.xml
    openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/asm/AsmProxyFactory.java

Modified: openwebbeans/trunk/webbeans-impl/pom.xml
URL: http://svn.apache.org/viewvc/openwebbeans/trunk/webbeans-impl/pom.xml?rev=1426968&r1=1426967&r2=1426968&view=diff
==============================================================================
--- openwebbeans/trunk/webbeans-impl/pom.xml (original)
+++ openwebbeans/trunk/webbeans-impl/pom.xml Sun Dec 30 17:52:56 2012
@@ -48,11 +48,19 @@
         </dependency>
 
         <dependency>
+            <groupId>org.ow2.asm</groupId>
+            <artifactId>asm-all</artifactId>
+            <version>4.1</version>
+            <optional>true</optional>
+        </dependency>
+<!-- TODO this is the old version
+        <dependency>
             <groupId>asm</groupId>
             <artifactId>asm</artifactId>
             <version>3.3.1</version>
             <optional>true</optional>
         </dependency>
+-->
 
         <dependency>
             <groupId>org.apache.geronimo.specs</groupId>

Modified: openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/asm/AsmProxyFactory.java
URL: http://svn.apache.org/viewvc/openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/asm/AsmProxyFactory.java?rev=1426968&r1=1426967&r2=1426968&view=diff
==============================================================================
--- openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/asm/AsmProxyFactory.java (original)
+++ openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/asm/AsmProxyFactory.java Sun Dec 30 17:52:56 2012
@@ -48,8 +48,7 @@ import org.objectweb.asm.MethodVisitor;
 import org.objectweb.asm.Opcodes;
 import org.objectweb.asm.Type;
 
-public class AsmProxyFactory
-    implements Opcodes
+public class AsmProxyFactory implements Opcodes
 {
 
     private static final AtomicInteger ID = new AtomicInteger(1);

Added: openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/asm/InterceptorDecoratorProxyFactory.java
URL: http://svn.apache.org/viewvc/openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/asm/InterceptorDecoratorProxyFactory.java?rev=1426968&view=auto
==============================================================================
--- openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/asm/InterceptorDecoratorProxyFactory.java (added)
+++ openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/asm/InterceptorDecoratorProxyFactory.java Sun Dec 30 17:52:56 2012
@@ -0,0 +1,165 @@
+/*
+ * 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.webbeans.proxy.asm;
+
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import org.apache.webbeans.proxy.ProxyGenerationException;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+
+/**
+ * WORK IN PROGRESS
+ *
+ * Generate a dynamic subclass which has exactly 1 delegation point instance
+ * which get's set in the Constructor of the proxy.
+ * Any non-intercepted or decorated method will get delegated natively,
+ * All intercepted and decorated methods will get invoked via an InvocationHandler chain.
+ *
+ * This factory will create and cache the proxy classes for a given type.
+ */
+public class InterceptorDecoratorProxyFactory
+{
+
+    /**
+     * Create a decorator and interceptor proxy for the given type.
+     *
+     * TODO: we also need to pass in the decorator and interceptor stack definition
+     *       plus the list of methods which are intercepted
+     *
+     * TODO: create a way to access the internal delegation point for invoking private methods later.
+     *
+     * @param classLoader to use for creating the class in
+     * @param classToProxy
+     * @param <T>
+     * @return the proxy class
+     */
+    public synchronized <T> Class<T> createInterceptorDecoratorProxyClass(ClassLoader classLoader, Class<T> classToProxy)
+    {
+        String proxyName = classToProxy.getName() + "$OwbInterceptProxy";
+        String proxyClassFileName = proxyName.replace('.', '/');
+
+        try
+        {
+            final byte[] proxyBytes = generateProxy(classToProxy, proxyName, proxyClassFileName);
+            return defineAndLoadClass(classLoader, proxyName, proxyBytes);
+        }
+        catch (Exception e)
+        {
+            final InternalError internalError = new InternalError();
+            internalError.initCause(e);
+            throw internalError;
+        }
+    }
+
+
+    private byte[] generateProxy(Class<?> classToProxy, String proxyName, String proxyClassFileName)
+            throws ProxyGenerationException
+    {
+        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
+        String classFileName = classToProxy.getName().replace('.', '/');
+
+        String[] interfaceNames = new String[0]; //X TODO there might be some more in the future
+
+        cw.visit(Opcodes.V1_5, Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER + Opcodes.ACC_SYNTHETIC, proxyClassFileName, null, classFileName, interfaceNames);
+        cw.visitSource(classFileName + ".java", null);
+
+        propagateDefaultConstructor(cw, classToProxy, classFileName);
+
+        //X TODO continue;
+
+        return cw.toByteArray();
+    }
+
+    private void propagateDefaultConstructor(ClassWriter cw, Class<?> classToProxy, String classFileName)
+            throws ProxyGenerationException
+    {
+        try
+        {
+            Constructor superDefaultCt = classToProxy.getConstructor(null);
+
+            final String descriptor = Type.getConstructorDescriptor(superDefaultCt);
+            final MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", descriptor, null, null);
+            mv.visitCode();
+            mv.visitVarInsn(Opcodes.ALOAD, 0);
+
+            mv.visitMethodInsn(Opcodes.INVOKESPECIAL, classFileName, "<init>", descriptor);
+            mv.visitInsn(Opcodes.RETURN);
+            mv.visitMaxs(-1, -1);
+            mv.visitEnd();
+        }
+        catch (NoSuchMethodException e)
+        {
+            throw new ProxyGenerationException(e);
+        }
+    }
+
+    /**
+     * The 'defineClass' method on the ClassLoader is protected, thus we need to invoke it via reflection.
+     * @return the Class which got loaded in the classloader
+     */
+    private <T> Class<T> defineAndLoadClass(ClassLoader classLoader, String proxyName, byte[] proxyBytes)
+            throws ProxyGenerationException
+    {
+        Class<?> clazz = classLoader.getClass();
+
+        Method defineClassMethod = null;
+        do
+        {
+            try
+            {
+                defineClassMethod = clazz.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class);
+            }
+            catch (NoSuchMethodException e)
+            {
+                // do nothing, we need to search the superclass
+            }
+
+            clazz = clazz.getSuperclass();
+        } while (defineClassMethod == null && clazz != Object.class);
+
+        if (defineClassMethod == null)
+        {
+            throw new ProxyGenerationException("could not find 'defineClass' method in the ClassLoader!");
+        }
+
+        defineClassMethod.setAccessible(true);
+        try
+        {
+            Class<T> definedClass = (Class<T>) defineClassMethod.invoke(classLoader, proxyName, proxyBytes, 0, proxyBytes.length);
+
+            return definedClass;
+        }
+        catch (IllegalAccessException e)
+        {
+            throw new ProxyGenerationException(e);
+        }
+        catch (InvocationTargetException e)
+        {
+            throw new ProxyGenerationException(e);
+        }
+    }
+
+}

Added: openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/newtests/interceptors/factory/InterceptorDecoratorProxyFactoryTest.java
URL: http://svn.apache.org/viewvc/openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/newtests/interceptors/factory/InterceptorDecoratorProxyFactoryTest.java?rev=1426968&view=auto
==============================================================================
--- openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/newtests/interceptors/factory/InterceptorDecoratorProxyFactoryTest.java (added)
+++ openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/newtests/interceptors/factory/InterceptorDecoratorProxyFactoryTest.java Sun Dec 30 17:52:56 2012
@@ -0,0 +1,52 @@
+/*
+ * 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.webbeans.newtests.interceptors.factory;
+
+import org.apache.webbeans.newtests.interceptors.factory.beans.ClassInterceptedClass;
+import org.apache.webbeans.proxy.asm.InterceptorDecoratorProxyFactory;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+
+/**
+ * Test the {@link org.apache.webbeans.proxy.asm.InterceptorDecoratorProxyFactory}
+ */
+public class InterceptorDecoratorProxyFactoryTest
+{
+
+    @Test
+    public void textSimpleProxyCreation() throws Exception
+    {
+        InterceptorDecoratorProxyFactory pf = new InterceptorDecoratorProxyFactory();
+
+        ClassLoader classLoader = this.getClass().getClassLoader();
+
+        Class<ClassInterceptedClass> proxyClass = pf.createInterceptorDecoratorProxyClass(classLoader, ClassInterceptedClass.class);
+        Assert.assertNotNull(proxyClass);
+
+        ClassInterceptedClass instance = proxyClass.newInstance();
+        Assert.assertNotNull(instance);
+        Assert.assertTrue(instance.defaultCtInvoked);
+
+        instance.setMeaningOfLife(42);
+
+        Assert.assertEquals(42, instance.getMeaningOfLife());
+    }
+}

Added: openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/newtests/interceptors/factory/beans/ClassInterceptedClass.java
URL: http://svn.apache.org/viewvc/openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/newtests/interceptors/factory/beans/ClassInterceptedClass.java?rev=1426968&view=auto
==============================================================================
--- openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/newtests/interceptors/factory/beans/ClassInterceptedClass.java (added)
+++ openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/newtests/interceptors/factory/beans/ClassInterceptedClass.java Sun Dec 30 17:52:56 2012
@@ -0,0 +1,47 @@
+/*
+ * 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.webbeans.newtests.interceptors.factory.beans;
+
+import org.apache.webbeans.test.component.intercept.webbeans.bindings.Transactional;
+
+/**
+ * A simple class which is not intercepted
+ */
+@Transactional
+public class ClassInterceptedClass
+{
+    public boolean defaultCtInvoked = false;
+
+    private int meaningOfLife;
+
+    public ClassInterceptedClass()
+    {
+        defaultCtInvoked = true;
+    }
+
+    public int getMeaningOfLife()
+    {
+        return meaningOfLife;
+    }
+
+    public void setMeaningOfLife(int meaningOfLife)
+    {
+        this.meaningOfLife = meaningOfLife;
+    }
+}

Added: openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/newtests/interceptors/factory/beans/NonInterceptedClass.java
URL: http://svn.apache.org/viewvc/openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/newtests/interceptors/factory/beans/NonInterceptedClass.java?rev=1426968&view=auto
==============================================================================
--- openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/newtests/interceptors/factory/beans/NonInterceptedClass.java (added)
+++ openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/newtests/interceptors/factory/beans/NonInterceptedClass.java Sun Dec 30 17:52:56 2012
@@ -0,0 +1,30 @@
+/*
+ * 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.webbeans.newtests.interceptors.factory.beans;
+
+/**
+ * A simple class which is not intercepted
+ */
+public class NonInterceptedClass
+{
+    public int getMeaningOfLife()
+    {
+        return 42;
+    }
+}