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 2013/01/20 23:54:03 UTC

svn commit: r1435993 - in /openwebbeans/trunk/webbeans-impl/src: main/java/org/apache/webbeans/component/ main/java/org/apache/webbeans/intercept/ main/java/org/apache/webbeans/proxy/ test/java/org/apache/webbeans/newtests/contexts/

Author: struberg
Date: Sun Jan 20 22:54:02 2013
New Revision: 1435993

URL: http://svn.apache.org/viewvc?rev=1435993&view=rev
Log:
OWB-344 add serialisation support for NormalScoped bean proxies

Modified:
    openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/component/AbstractProducerBean.java
    openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/component/ManagedBean.java
    openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/intercept/NormalScopedBeanInterceptorHandler.java
    openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/AbstractProxyFactory.java
    openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/InterceptorDecoratorProxyFactory.java
    openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/NormalScopeProxyFactory.java
    openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/SubclassProxyFactory.java
    openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/newtests/contexts/SerializationTest.java

Modified: openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/component/AbstractProducerBean.java
URL: http://svn.apache.org/viewvc/openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/component/AbstractProducerBean.java?rev=1435993&r1=1435992&r2=1435993&view=diff
==============================================================================
--- openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/component/AbstractProducerBean.java (original)
+++ openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/component/AbstractProducerBean.java Sun Jan 20 22:54:02 2013
@@ -26,6 +26,7 @@ import java.util.Set;
 
 import javax.enterprise.context.spi.CreationalContext;
 import javax.enterprise.inject.spi.Bean;
+import javax.enterprise.inject.spi.PassivationCapable;
 
 
 /**
@@ -34,7 +35,7 @@ import javax.enterprise.inject.spi.Bean;
  * @version $Rev$ $Date$
  * @param <T> bean type info
  */
-public abstract class AbstractProducerBean<T> extends AbstractOwbBean<T> implements IBeanHasParent<T>
+public abstract class AbstractProducerBean<T> extends AbstractOwbBean<T> implements IBeanHasParent<T>, PassivationCapable
 {
     /** Owner of the producer field component */
     protected InjectionTargetBean<?> ownerComponent;

Modified: openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/component/ManagedBean.java
URL: http://svn.apache.org/viewvc/openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/component/ManagedBean.java?rev=1435993&r1=1435992&r2=1435993&view=diff
==============================================================================
--- openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/component/ManagedBean.java (original)
+++ openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/component/ManagedBean.java Sun Jan 20 22:54:02 2013
@@ -25,6 +25,7 @@ import java.lang.reflect.Type;
 import java.util.Set;
 
 import javax.enterprise.inject.spi.AnnotatedType;
+import javax.enterprise.inject.spi.PassivationCapable;
 
 import org.apache.webbeans.config.WebBeansContext;
 
@@ -33,7 +34,7 @@ import org.apache.webbeans.config.WebBea
  * 
  * @version $Rev$ $Date$
  */
-public class ManagedBean<T> extends InjectionTargetBean<T> implements InterceptedMarker
+public class ManagedBean<T> extends InjectionTargetBean<T> implements InterceptedMarker, PassivationCapable
 {
     /** Constructor of the web bean component */
     private Constructor<T> constructor;

Modified: openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/intercept/NormalScopedBeanInterceptorHandler.java
URL: http://svn.apache.org/viewvc/openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/intercept/NormalScopedBeanInterceptorHandler.java?rev=1435993&r1=1435992&r2=1435993&view=diff
==============================================================================
--- openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/intercept/NormalScopedBeanInterceptorHandler.java (original)
+++ openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/intercept/NormalScopedBeanInterceptorHandler.java Sun Jan 20 22:54:02 2013
@@ -23,20 +23,42 @@ import javax.enterprise.context.spi.Crea
 import javax.enterprise.inject.UnproxyableResolutionException;
 import javax.enterprise.inject.spi.Bean;
 import javax.enterprise.inject.spi.BeanManager;
+import javax.enterprise.inject.spi.PassivationCapable;
 import javax.inject.Provider;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+
+import org.apache.webbeans.config.WebBeansContext;
 
 /**
- * TODO add serialisation
+ * <p>A Provider which handles all NormalScoped proxying.
+ * It's two main responsibilities are to provide the one active
+ * Contextual Instance, the second is to provide serialisation.</p>
+ *
+ * <p>The generated proxy will writeReplace() with this class and any
+ * NormalScopedBean provider must readResolve() and regenerate the
+ * proxy class from the {@link org.apache.webbeans.proxy.NormalScopeProxyFactory}
+ * again.
+ * </p>
+ * <p>Any subclass should either declare all their fields <code>transient</code>
+ * or handle the serialisation properly!</p>
  */
-public class NormalScopedBeanInterceptorHandler implements Provider
+public class NormalScopedBeanInterceptorHandler implements Provider, Serializable
 {
     private transient BeanManager beanManager;
     protected transient Bean<?> bean;
 
+    // we just keep this field for serializing it away
+    private String beanPassivationId;
+
     public NormalScopedBeanInterceptorHandler(BeanManager beanManager, Bean<?> bean)
     {
         this.beanManager = beanManager;
         this.bean = bean;
+        if (bean instanceof PassivationCapable)
+        {
+            beanPassivationId = ((PassivationCapable) bean).getId();
+        }
     }
 
     @Override
@@ -76,4 +98,22 @@ public class NormalScopedBeanInterceptor
         return webbeansInstance;
     }
 
+    /**
+     * The following code gets generated into the proxy:
+     *
+     * <pre>
+     * Object writeReplace() throws ObjectStreamException
+     * {
+     *     return provider;
+     * }
+     * </pre>
+    */
+    Object readResolve() throws ObjectStreamException
+    {
+        WebBeansContext webBeansContext = WebBeansContext.getInstance();
+        this.beanManager = webBeansContext.getBeanManagerImpl();
+        this.bean = beanManager.getPassivationCapableBean(beanPassivationId);
+
+        return webBeansContext.getNormalScopeProxyFactory().createNormalScopeProxy(bean);
+    }
 }

Modified: openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/AbstractProxyFactory.java
URL: http://svn.apache.org/viewvc/openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/AbstractProxyFactory.java?rev=1435993&r1=1435992&r2=1435993&view=diff
==============================================================================
--- openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/AbstractProxyFactory.java (original)
+++ openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/AbstractProxyFactory.java Sun Jan 20 22:54:02 2013
@@ -62,6 +62,11 @@ public abstract class AbstractProxyFacto
     protected abstract void createInstanceVariables(ClassWriter cw, Class<?> classToProxy, String classFileName);
 
     /**
+     * generate the bytecode for serialization.
+     */
+    protected abstract void createSerialisation(ClassWriter cw, String proxyClassFileName, Class<?> classToProxy, String classFileName);
+
+    /**
      * Each of our interceptor/decorator proxies has exactly 1 constructor
      * which invokes the super ct + sets the delegation field.
      *
@@ -182,6 +187,8 @@ public abstract class AbstractProxyFacto
         cw.visitSource(classFileName + ".java", null);
 
         createInstanceVariables(cw, classToProxy, classFileName);
+        createSerialisation(cw, proxyClassFileName, classToProxy, classFileName);
+
 
 
         // create a static String Field which contains the passivationId of the Bean or null if not PassivationCapable
@@ -205,8 +212,6 @@ public abstract class AbstractProxyFacto
     }
 
 
-
-
     /**
      * 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

Modified: openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/InterceptorDecoratorProxyFactory.java
URL: http://svn.apache.org/viewvc/openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/InterceptorDecoratorProxyFactory.java?rev=1435993&r1=1435992&r2=1435993&view=diff
==============================================================================
--- openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/InterceptorDecoratorProxyFactory.java (original)
+++ openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/InterceptorDecoratorProxyFactory.java Sun Jan 20 22:54:02 2013
@@ -44,7 +44,6 @@ import org.objectweb.asm.Type;
  * This factory will create and cache the proxy classes for a given type.
  *
  */
-//X TODO: clarify how serialisation works! The proxy classes might need to get created on deserialisation!
 public class InterceptorDecoratorProxyFactory extends AbstractProxyFactory
 {
 
@@ -133,6 +132,11 @@ public class InterceptorDecoratorProxyFa
         return null;
     }
 
+    @Override
+    protected void createSerialisation(ClassWriter cw, String proxyClassFileName, Class<?> classToProxy, String classFileName)
+    {
+        // nothing to do ;)
+    }
 
     /**
      * <p>Create a decorator and interceptor proxy for the given type. A single instance

Modified: openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/NormalScopeProxyFactory.java
URL: http://svn.apache.org/viewvc/openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/NormalScopeProxyFactory.java?rev=1435993&r1=1435992&r2=1435993&view=diff
==============================================================================
--- openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/NormalScopeProxyFactory.java (original)
+++ openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/NormalScopeProxyFactory.java Sun Jan 20 22:54:02 2013
@@ -21,12 +21,14 @@ package org.apache.webbeans.proxy;
 import javax.enterprise.inject.spi.Bean;
 import javax.enterprise.inject.spi.BeanManager;
 import javax.inject.Provider;
+import java.io.ObjectStreamException;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
 
 import org.apache.webbeans.component.OwbBean;
 import org.apache.webbeans.config.OpenWebBeansConfiguration;
@@ -50,6 +52,8 @@ public class NormalScopeProxyFactory ext
     /** the name of the field which stores the {@link Provider} for the Contextual Instance */
     public static final String FIELD_INSTANCE_PROVIDER = "owbContextualInstanceProvider";
 
+    private ConcurrentHashMap<Bean<?>, Class<?>> cachedProxyClasses = new ConcurrentHashMap<Bean<?>, Class<?>>();
+
 
     public NormalScopeProxyFactory(WebBeansContext webBeansContext)
     {
@@ -95,7 +99,14 @@ public class NormalScopeProxyFactory ext
             classToProxy = (Class<T>) bean.getBeanClass();
         }
 
-        Class<? extends T> proxyClass = createProxyClass(classLoader, classToProxy);
+
+
+        Class<? extends T> proxyClass = (Class<? extends T>) cachedProxyClasses.get(bean);
+
+        if (proxyClass == null)
+        {
+            proxyClass = createProxyClass(bean, classLoader, classToProxy);
+        }
 
         return createProxyInstance(proxyClass, getInstanceProvider(classLoader, bean));
     }
@@ -141,15 +152,45 @@ public class NormalScopeProxyFactory ext
         return null;
     }
 
+    public synchronized <T> Class<T> createProxyClass(Bean<T> bean, ClassLoader classLoader, Class<T> classToProxy)
+    {
+        Class<T> proxyClass = (Class<T>) cachedProxyClasses.get(bean);
+
+        if (proxyClass == null)
+        {
+            proxyClass = createProxyClass(classLoader, classToProxy);
+            cachedProxyClasses.putIfAbsent(bean, proxyClass);
+        }
+
+        return proxyClass;
+    }
+
+    @Override
+    protected void createSerialisation(ClassWriter cw, String proxyClassFileName, Class<?> classToProxy, String classFileName)
+    {
+        String[] exceptionTypeNames = {Type.getType(ObjectStreamException.class).getInternalName()};
+        MethodVisitor mv = cw.visitMethod(Modifier.PUBLIC, "writeReplace", "()Ljava/lang/Object;", null, exceptionTypeNames);
+
+        // fill method body
+        mv.visitCode();
+
+        // load the contextual instance Provider
+        mv.visitVarInsn(Opcodes.ALOAD, 0);
+        mv.visitFieldInsn(Opcodes.GETFIELD, proxyClassFileName, FIELD_INSTANCE_PROVIDER, Type.getDescriptor(Provider.class));
+
+        mv.visitInsn(Opcodes.ARETURN);
+
+        mv.visitMaxs(-1, -1);
+        mv.visitEnd();
+    }
 
     /**
      * @param classLoader to use for creating the class in
      * @param classToProxy the class for which a subclass will get generated
      * @param <T>
      * @return the proxy class
-     * //X TODO for serialisation reasons this probably needs the Bean it serves.
      */
-    public synchronized <T> Class<T> createProxyClass(ClassLoader classLoader, Class<T> classToProxy)
+    public <T> Class<T> createProxyClass(ClassLoader classLoader, Class<T> classToProxy)
             throws ProxyGenerationException
     {
         String proxyClassName = getUnusedProxyClassName(classLoader, classToProxy.getName() + "$OwbNormalScopeProxy");

Modified: openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/SubclassProxyFactory.java
URL: http://svn.apache.org/viewvc/openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/SubclassProxyFactory.java?rev=1435993&r1=1435992&r2=1435993&view=diff
==============================================================================
--- openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/SubclassProxyFactory.java (original)
+++ openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/SubclassProxyFactory.java Sun Jan 20 22:54:02 2013
@@ -158,6 +158,11 @@ public class SubclassProxyFactory extend
     @Override
     protected void delegateInterceptedMethods(ClassWriter cw, String proxyClassFileName, Class<?> classToProxy, Method[] interceptedMethods) throws ProxyGenerationException
     {
+    }
+
+    @Override
+    protected void createSerialisation(ClassWriter cw, String proxyClassFileName, Class<?> classToProxy, String classFileName)
+    {
         // nothing to do ;)
     }
 

Modified: openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/newtests/contexts/SerializationTest.java
URL: http://svn.apache.org/viewvc/openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/newtests/contexts/SerializationTest.java?rev=1435993&r1=1435992&r2=1435993&view=diff
==============================================================================
--- openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/newtests/contexts/SerializationTest.java (original)
+++ openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/newtests/contexts/SerializationTest.java Sun Jan 20 22:54:02 2013
@@ -32,6 +32,7 @@ import org.apache.webbeans.newtests.inje
 import org.apache.webbeans.newtests.injection.circular.beans.CircularConstructorOrProducerMethodParameterBean;
 import org.apache.webbeans.newtests.injection.circular.beans.CircularDependentScopedBean;
 import org.apache.webbeans.newtests.injection.circular.beans.CircularNormalInConstructor;
+import org.apache.webbeans.proxy.OwbNormalScopeProxy;
 import org.apache.webbeans.test.component.CheckWithCheckPayment;
 import org.apache.webbeans.test.component.CheckWithMoneyPayment;
 import org.apache.webbeans.test.component.IPayment;
@@ -43,10 +44,8 @@ import org.apache.webbeans.util.WebBeans
 
 import junit.framework.Assert;
 
-import org.junit.Ignore;
 import org.junit.Test;
 
-import javassist.util.proxy.ProxyObject;
 
 import javax.enterprise.context.SessionScoped;
 import javax.enterprise.context.spi.Context;
@@ -91,7 +90,6 @@ public class SerializationTest extends A
         Assert.assertNotNull(cc2);
     }
 
-    @Ignore // TODO Make this work!!! XXX
     @Test
     public void testPersonalDataBean() throws ClassNotFoundException, IOException
     {
@@ -150,8 +148,8 @@ public class SerializationTest extends A
         Context sessContext2 = (Context) deSerializeObject(ba);
         Assert.assertNotNull(sessContext2);
     }
-    
-    //X TODO this will work after JASSIST-97 got fixed @Test
+
+    @Test
     public void testProxySerialization() throws Exception
     {
         Collection<Class<?>> classes = new ArrayList<Class<?>>();
@@ -173,7 +171,7 @@ public class SerializationTest extends A
         
         SessScopedBean reference = (SessScopedBean) getBeanManager().getReference(bean, SessScopedBean.class, ssbCreational);
         Assert.assertNotNull(reference);
-        Assert.assertTrue(reference instanceof ProxyObject);
+        Assert.assertTrue(reference instanceof OwbNormalScopeProxy);
         
         reference.getApp().setI(4711);