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