[weld-commits] Weld SVN: r6209 - in core/trunk/impl/src/main: java/org/jboss/weld/bean/proxy/util and 2 other directories.

weld-commits at lists.jboss.org weld-commits at lists.jboss.org
Mon May 3 03:43:14 EDT 2010


Author: dallen6
Date: 2010-05-03 03:43:13 -0400 (Mon, 03 May 2010)
New Revision: 6209

Added:
   core/trunk/impl/src/main/java/org/jboss/weld/bean/proxy/util/SerializableProxy.java
Modified:
   core/trunk/impl/src/main/java/org/jboss/weld/bean/proxy/DecoratorProxyFactory.java
   core/trunk/impl/src/main/java/org/jboss/weld/bean/proxy/EnterpriseProxyFactory.java
   core/trunk/impl/src/main/java/org/jboss/weld/bean/proxy/ProxyFactory.java
   core/trunk/impl/src/main/java/org/jboss/weld/bean/proxy/util/SimpleProxyServices.java
   core/trunk/impl/src/main/java/org/jboss/weld/logging/messages/BeanMessage.java
   core/trunk/impl/src/main/resources/org/jboss/weld/messages/bean_en.properties
Log:
Added serialization of proxies

Modified: core/trunk/impl/src/main/java/org/jboss/weld/bean/proxy/DecoratorProxyFactory.java
===================================================================
--- core/trunk/impl/src/main/java/org/jboss/weld/bean/proxy/DecoratorProxyFactory.java	2010-05-03 07:42:35 UTC (rev 6208)
+++ core/trunk/impl/src/main/java/org/jboss/weld/bean/proxy/DecoratorProxyFactory.java	2010-05-03 07:43:13 UTC (rev 6209)
@@ -36,16 +36,16 @@
 import org.jboss.weld.injection.WeldInjectionPoint;
 
 /**
- * This special proxy factory is mostly used for abstract decorators.  When
- * a delegate field is injected, the abstract methods directly invoke the
- * corresponding method on the delegate.  All other cases forward the calls
- * to the {@link BeanInstance} for further processing.
+ * This special proxy factory is mostly used for abstract decorators. When a
+ * delegate field is injected, the abstract methods directly invoke the
+ * corresponding method on the delegate. All other cases forward the calls to
+ * the {@link BeanInstance} for further processing.
  * 
  * @author David Allen
  */
 public class DecoratorProxyFactory<T> extends ProxyFactory<T>
 {
-   private static final String            PROXY_SUFFIX = "DecoratorProxy";
+   public static final String             PROXY_SUFFIX = "DecoratorProxy";
    private final WeldInjectionPoint<?, ?> delegateInjectionPoint;
    private final CtClass                  delegateClass;
    private final Field                    delegateField;

Modified: core/trunk/impl/src/main/java/org/jboss/weld/bean/proxy/EnterpriseProxyFactory.java
===================================================================
--- core/trunk/impl/src/main/java/org/jboss/weld/bean/proxy/EnterpriseProxyFactory.java	2010-05-03 07:42:35 UTC (rev 6208)
+++ core/trunk/impl/src/main/java/org/jboss/weld/bean/proxy/EnterpriseProxyFactory.java	2010-05-03 07:43:13 UTC (rev 6209)
@@ -34,7 +34,7 @@
  */
 public class EnterpriseProxyFactory<T> extends ProxyFactory<T>
 {
-   private static final String PROXY_SUFFIX = "EnterpriseProxy";
+   public static final String PROXY_SUFFIX = "EnterpriseProxy";
 
    /**
     * Produces a factory for a specific bean implementation.

Modified: core/trunk/impl/src/main/java/org/jboss/weld/bean/proxy/ProxyFactory.java
===================================================================
--- core/trunk/impl/src/main/java/org/jboss/weld/bean/proxy/ProxyFactory.java	2010-05-03 07:42:35 UTC (rev 6208)
+++ core/trunk/impl/src/main/java/org/jboss/weld/bean/proxy/ProxyFactory.java	2010-05-03 07:43:13 UTC (rev 6209)
@@ -22,6 +22,7 @@
 import static org.jboss.weld.logging.messages.BeanMessage.PROXY_INSTANTIATION_BEAN_ACCESS_FAILED;
 import static org.jboss.weld.logging.messages.BeanMessage.PROXY_INSTANTIATION_FAILED;
 
+import java.io.ObjectStreamException;
 import java.io.Serializable;
 import java.lang.reflect.Modifier;
 import java.security.ProtectionDomain;
@@ -58,13 +59,13 @@
    // The log provider
    protected static final LocLogger    log                  = loggerFactory().getLogger(BEAN);
    // Default proxy class name suffix
-   private static final String         PROXY_SUFFIX         = "Proxy";
+   public static final String          PROXY_SUFFIX         = "Proxy";
 
    protected final Class<?>            beanType;
    protected final ArrayList<Class<?>> additionalInterfaces = new ArrayList<Class<?>>();
-   protected final ClassLoader               classLoader;
-   protected final ProtectionDomain          protectionDomain;
-   protected final ClassPool                 classPool;
+   protected final ClassLoader         classLoader;
+   protected final ProtectionDomain    protectionDomain;
+   protected final ClassPool           classPool;
 
    /**
     * Creates a new proxy factory from any type of BeanInstance. This bean
@@ -169,6 +170,18 @@
    }
 
    /**
+    * Convenience method to determine if an object is a proxy generated by this
+    * factory or any derived factory.
+    * 
+    * @param proxySuspect the object suspected of being a proxy
+    * @return true only if it is a proxy object
+    */
+   public static boolean isProxy(Object proxySuspect)
+   {
+      return proxySuspect instanceof Proxy;
+   }
+
+   /**
     * Convenience method to set the underlying bean instance for a proxy.
     * 
     * @param proxy the proxy instance
@@ -236,8 +249,8 @@
    }
 
    /**
-    * Adds a constructor for the proxy for each constructor declared
-    * by the base bean type.
+    * Adds a constructor for the proxy for each constructor declared by the base
+    * bean type.
     * 
     * @param proxyClassType the Javassist class for the proxy
     */
@@ -264,12 +277,15 @@
       }
    }
 
-   private void addFields(CtClass proxyClassType)
+   protected void addFields(CtClass proxyClassType)
    {
-      // The field for the instance locator
       try
       {
+         // The field representing the underlying instance or special method
+         // handling
          proxyClassType.addField(new CtField(classPool.get("org.jboss.weld.bean.proxy.BeanInstance"), "beanInstance", proxyClassType));
+         // Special field used during serialization of a proxy
+         proxyClassType.addField(new CtField(CtClass.booleanType, "firstSerializationPhaseComplete", proxyClassType), "false");
       }
       catch (Exception e)
       {
@@ -284,8 +300,44 @@
 
       // Add special proxy methods
       addSpecialMethods(proxyClassType);
+
+      // Add serialization support methods
+      addSerializationSupport(proxyClassType);
    }
 
+   /**
+    * Adds special serialization code be providing a writeReplace() method on
+    * the proxy.  This method when first called will substitute the proxy
+    * object with an instance of {@link org.jboss.weld.proxy.util.SerializableProxy}.
+    * Subsequent calls will receive the proxy object itself permitting the substitute
+    * object to serialize the proxy.
+    * 
+    * @param proxyClassType the Javassist class for the proxy class
+    */
+   protected void addSerializationSupport(CtClass proxyClassType)
+   {
+      try
+      {
+         // Create a two phase writeReplace where the first call uses a
+         // replacement object and subsequent calls get the proxy object.
+         CtClass exception = classPool.get(ObjectStreamException.class.getName());
+         CtClass objectClass = classPool.get(Object.class.getName());
+         String writeReplaceBody = "{ " + 
+         " if (firstSerializationPhaseComplete)" +
+         "    return $0; " +
+         " else {" +
+         " firstSerializationPhaseComplete = true; " +
+         " return ((org.jboss.weld.serialization.spi.ProxyServices)org.jboss.weld.Container.instance().services().get(org.jboss.weld.serialization.spi.ProxyServices.class)).wrapForSerialization($0);" +
+         " } }";
+         proxyClassType.addMethod(CtNewMethod.make(objectClass, "writeReplace", null, new CtClass[] { exception }, writeReplaceBody, proxyClassType));
+      }
+      catch (Exception e)
+      {
+         throw new WeldException(e);
+      }
+
+   }
+
    protected void addMethodsFromClass(CtClass proxyClassType)
    {
       try
@@ -387,7 +439,8 @@
    }
 
    /**
-    * Adds methods requiring special implementations rather than just delegation.
+    * Adds methods requiring special implementations rather than just
+    * delegation.
     * 
     * @param proxyClassType the Javassist class description for the proxy type
     */
@@ -419,9 +472,9 @@
    }
 
    /**
-    * Creates the method body code for methods which forward the calls
-    * directly to the bean instance.  These methods are not considered
-    * to be implemented by any superclass of the proxy.
+    * Creates the method body code for methods which forward the calls directly
+    * to the bean instance. These methods are not considered to be implemented
+    * by any superclass of the proxy.
     * 
     * @param method a method
     * @return code for the body of the method to be compiled

Added: core/trunk/impl/src/main/java/org/jboss/weld/bean/proxy/util/SerializableProxy.java
===================================================================
--- core/trunk/impl/src/main/java/org/jboss/weld/bean/proxy/util/SerializableProxy.java	                        (rev 0)
+++ core/trunk/impl/src/main/java/org/jboss/weld/bean/proxy/util/SerializableProxy.java	2010-05-03 07:43:13 UTC (rev 6209)
@@ -0,0 +1,116 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2008, Red Hat, Inc. and/or its affiliates, and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * 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.jboss.weld.bean.proxy.util;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+
+import org.jboss.weld.Container;
+import org.jboss.weld.bean.proxy.ProxyFactory;
+import org.jboss.weld.exceptions.ForbiddenStateException;
+import org.jboss.weld.logging.messages.BeanMessage;
+import org.jboss.weld.serialization.spi.ProxyServices;
+
+/**
+ * A wrapper mostly for client proxies which provides header information
+ * useful to generate the client proxy class in a VM before the proxy
+ * object is deserialized.  Only client proxies really need this
+ * extra step for serialization and deserialization since the other
+ * proxy classes are generated during bean archive deployment.
+ * 
+ * @author David Allen
+ */
+public class SerializableProxy implements Serializable
+{
+
+   private static final long serialVersionUID = -7682006876407447753L;
+
+   // Information required to generate client proxy classes
+   private final String proxyClassName;
+   private final String proxySuperClassName;
+
+   // The wrapped proxy object not serialized by default actions
+   private transient Object proxyObject;
+
+   public SerializableProxy(Object proxyObject)
+   {
+      if (!ProxyFactory.isProxy(proxyObject))
+      {
+         throw new ForbiddenStateException(BeanMessage.PROXY_REQUIRED);
+      }
+      this.proxyClassName = proxyObject.getClass().getName();
+      this.proxySuperClassName = proxyObject.getClass().getSuperclass().getName();
+      this.proxyObject = proxyObject;
+   }
+
+   /**
+    * Writes this object to the stream and also appends the serialization of
+    * the proxy object afterwards.  This allows this wrapper to later recover
+    * the proxy class before trying to deserialize the proxy object.
+    * 
+    * @param out the output stream of objects
+    * @throws IOException
+    */
+   private void writeObject(ObjectOutputStream out) throws IOException
+   {
+      out.defaultWriteObject();
+      // Must use another OO stream since the proxy was replaced in the original
+      ObjectOutputStream out2 = new ObjectOutputStream(out);
+      out2.writeObject(proxyObject);
+   }
+
+   /**
+    * First reads the state of this object from the stream, then generates the
+    * proxy class if needed, and then deserializes the proxy object.
+    * 
+    * @param in the object input stream
+    * @throws IOException
+    * @throws ClassNotFoundException
+    */
+   private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException
+   {
+      in.defaultReadObject();
+      // Must use another OO stream per writeObject() above
+      ObjectInputStream in2 = new ObjectInputStream(in);
+      Class<?> proxyBeanType = Container.instance().services().get(ProxyServices.class).loadProxySuperClass(proxySuperClassName);
+      if (proxyClassName.endsWith(ProxyFactory.PROXY_SUFFIX))
+      {
+         generateClientProxyClass(proxyBeanType);
+      }
+      proxyObject = in2.readObject();
+   }
+
+   /**
+    * Always returns the original proxy object that was serialized.
+    * 
+    * @return the proxy object
+    * @throws ObjectStreamException
+    */
+   Object readResolve() throws ObjectStreamException
+   {
+      return proxyObject;
+   }
+   
+   private <T> void generateClientProxyClass(Class<T> beanType)
+   {
+      new ProxyFactory<T>(beanType).getProxyClass();
+   }
+}


Property changes on: core/trunk/impl/src/main/java/org/jboss/weld/bean/proxy/util/SerializableProxy.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain

Modified: core/trunk/impl/src/main/java/org/jboss/weld/bean/proxy/util/SimpleProxyServices.java
===================================================================
--- core/trunk/impl/src/main/java/org/jboss/weld/bean/proxy/util/SimpleProxyServices.java	2010-05-03 07:42:35 UTC (rev 6208)
+++ core/trunk/impl/src/main/java/org/jboss/weld/bean/proxy/util/SimpleProxyServices.java	2010-05-03 07:43:13 UTC (rev 6209)
@@ -17,25 +17,26 @@
 
 package org.jboss.weld.bean.proxy.util;
 
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
 import java.security.ProtectionDomain;
 
+import org.jboss.weld.exceptions.WeldException;
+import org.jboss.weld.logging.messages.BeanMessage;
 import org.jboss.weld.serialization.spi.ProxyServices;
 
 /**
  * A default implementation of the {@link ProxyServices} which simply use the
- * corresponding information from the proxy type.  An exception is made for
- * {@code java.*} and {@code javax.*} packages which are often associated
- * with the system classloader and a more privileged ProtectionDomain.
+ * corresponding information from the proxy type. An exception is made for
+ * {@code java.*} and {@code javax.*} packages which are often associated with
+ * the system classloader and a more privileged ProtectionDomain.
  * 
  * @author David Allen
- *
  */
 public class SimpleProxyServices implements ProxyServices
 {
 
-   /* (non-Javadoc)
-    * @see org.jboss.weld.serialization.spi.ProxyServices#getClassLoader(java.lang.Class)
-    */
    public ClassLoader getClassLoader(Class<?> type)
    {
       if (type.getName().startsWith("java"))
@@ -48,9 +49,6 @@
       }
    }
 
-   /* (non-Javadoc)
-    * @see org.jboss.weld.serialization.spi.ProxyServices#getProtectionDomain(java.lang.Class)
-    */
    public ProtectionDomain getProtectionDomain(Class<?> type)
    {
       if (type.getName().startsWith("java"))
@@ -63,13 +61,35 @@
       }
    }
 
-   /* (non-Javadoc)
-    * @see org.jboss.weld.bootstrap.api.Service#cleanup()
-    */
    public void cleanup()
    {
       // This implementation requires no cleanup
 
    }
 
+   public Object wrapForSerialization(Object proxyObject)
+   {
+      // Simply use our own replacement object for proxies
+      return new SerializableProxy(proxyObject);
+   }
+
+   public Class<?> loadProxySuperClass(final String className)
+   {
+      try
+      {
+         return (Class<?>) AccessController.doPrivileged(new PrivilegedExceptionAction<Object>()
+         {
+            public Object run() throws Exception
+            {
+               ClassLoader cl = Thread.currentThread().getContextClassLoader();
+               return Class.forName(className, true, cl);
+            }
+         });
+      }
+      catch (PrivilegedActionException pae)
+      {
+         throw new WeldException(BeanMessage.CANNOT_LOAD_CLASS, className, pae.getException());
+      }
+   }
+
 }

Modified: core/trunk/impl/src/main/java/org/jboss/weld/logging/messages/BeanMessage.java
===================================================================
--- core/trunk/impl/src/main/java/org/jboss/weld/logging/messages/BeanMessage.java	2010-05-03 07:42:35 UTC (rev 6208)
+++ core/trunk/impl/src/main/java/org/jboss/weld/logging/messages/BeanMessage.java	2010-05-03 07:43:13 UTC (rev 6209)
@@ -132,6 +132,7 @@
    @MessageId("000095") GENERIC_SESSION_BEAN_MUST_BE_DEPENDENT,
    @MessageId("000096") PRODUCER_FIELD_ON_SESSION_BEAN_MUST_BE_STATIC,
    @MessageId("000097") PRODUCER_METHOD_WITH_TYPE_VARIABLE_RETURN_TYPE_MUST_BE_DEPENDENT,
-   @MessageId("000098") PRODUCER_METHOD_WITH_WILDCARD_RETURN_TYPE_MUST_BE_DEPENDENT;
+   @MessageId("000098") PRODUCER_METHOD_WITH_WILDCARD_RETURN_TYPE_MUST_BE_DEPENDENT,
+   @MessageId("000099") CANNOT_LOAD_CLASS;
    
 }

Modified: core/trunk/impl/src/main/resources/org/jboss/weld/messages/bean_en.properties
===================================================================
--- core/trunk/impl/src/main/resources/org/jboss/weld/messages/bean_en.properties	2010-05-03 07:42:35 UTC (rev 6208)
+++ core/trunk/impl/src/main/resources/org/jboss/weld/messages/bean_en.properties	2010-05-03 07:43:13 UTC (rev 6209)
@@ -97,3 +97,4 @@
 PRODUCER_FIELD_ON_SESSION_BEAN_MUST_BE_STATIC=Producer fields on session beans must be static. Field {0} declared on {1}
 PRODUCER_METHOD_WITH_TYPE_VARIABLE_RETURN_TYPE_MUST_BE_DEPENDENT=A producer method with a parameterized return type with a type variable must be declared @Dependent scoped. Method {0}
 PRODUCER_METHOD_WITH_WILDCARD_RETURN_TYPE_MUST_BE_DEPENDENT=A producer method with a parameterized return type with a wildcard must be declared @Dependent scoped. Method {0}  
+CANNOT_LOAD_CLASS=Cannot load class {0} during deserialization of proxy



More information about the weld-commits mailing list