Skip to content

Commit

Permalink
Redesigned proxies to use only interfaces where possible and fixed se…
Browse files Browse the repository at this point in the history
…rialization issues
  • Loading branch information
drallen committed May 26, 2010
1 parent dd7e773 commit 32b3978
Show file tree
Hide file tree
Showing 10 changed files with 119 additions and 100 deletions.
Expand Up @@ -200,7 +200,7 @@ protected T applyDecorators(T instance, CreationalContext<T> creationalContext,
{
T proxy = null;
TargetBeanInstance beanInstance = new TargetBeanInstance(this, instance);
ProxyFactory<T> proxyFactory = new ProxyFactory<T>(beanInstance);
ProxyFactory<T> proxyFactory = new ProxyFactory<T>(getType(), getTypes());
DecorationHelper<T> decorationHelper = new DecorationHelper<T>(beanInstance, proxyFactory.getProxyClass(), beanManager, decorators);

DecorationHelper.getHelperStack().push(decorationHelper);
Expand Down
2 changes: 1 addition & 1 deletion impl/src/main/java/org/jboss/weld/bean/ManagedBean.java
Expand Up @@ -585,7 +585,7 @@ protected T applyInterceptors(T instance, final CreationalContext<T> creationalC
MethodHandler methodHandler = interceptorProxyCreator.createMethodHandler(instance, getType(), getBeanManager().getServices().get(InterceptionMetadataService.class).getInterceptorMetadataRegistry().getInterceptorClassMetadata(WeldClassReference.of(getWeldAnnotated()), true));
TargetBeanInstance targetInstance = new TargetBeanInstance(this, instance);
targetInstance.setInterceptorsHandler(methodHandler);
instance = new ProxyFactory<T>(targetInstance).create(targetInstance);
instance = new ProxyFactory<T>(getType(), getTypes()).create(targetInstance);
}

}
Expand Down
Expand Up @@ -43,7 +43,7 @@ protected AbstractEEBean(Class<T> type, Callable<T> callable, BeanManagerImpl be
this.types = new HashSet<Type>();
this.types.add(Object.class);
this.types.add(type);
this.proxy = new ProxyFactory<T>(type).create(new EnterpriseTargetBeanInstance(type, new CallableMethodHandler(callable)));
this.proxy = new ProxyFactory<T>(type, types).create(new EnterpriseTargetBeanInstance(type, new CallableMethodHandler(callable)));
}

public T create(CreationalContext<T> creationalContext)
Expand Down
Expand Up @@ -140,7 +140,7 @@ public T create(CreationalContext<T> creationalContext)
else
{
BeanInstance proxyBeanInstance = new EnterpriseTargetBeanInstance(getTypes(), new CallableMethodHandler(new EEResourceCallable<T>(getBeanManager(), this, creationalContext)));
return new ProxyFactory<T>(proxyBeanInstance).create(proxyBeanInstance);
return new ProxyFactory<T>(getType(), getTypes()).create(proxyBeanInstance);
}
}

Expand Down
Expand Up @@ -84,28 +84,7 @@ public ClientProxyProvider()
private static <T> T createClientProxy(Bean<T> bean, String id) throws RuntimeException
{
ContextBeanInstance<T> beanInstance = new ContextBeanInstance<T>(bean, id);
return new ProxyFactory<T>(beanInstance).create(beanInstance);
// try
// {
// TypeInfo typeInfo;
// if ((bean instanceof AbstractClassBean) && ((AbstractClassBean)bean).hasInterceptors())
// {
// typeInfo = TypeInfo.of(bean.getTypes()).add(Serializable.class).add(LifecycleMixin.class);
// }
// else
// {
// typeInfo = TypeInfo.of(bean.getTypes()).add(Serializable.class);
// }
// return Proxies.<T>createProxy(new ClientProxyMethodHandler(bean, id), typeInfo);
// }
// catch (InstantiationException e)
// {
// throw new WeldException(PROXY_INSTANTIATION_FAILED, e, bean);
// }
// catch (IllegalAccessException e)
// {
// throw new WeldException(PROXY_INSTANTIATION_BEAN_ACCESS_FAILED, e, bean);
// }
return new ProxyFactory<T>(bean.getBeanClass(), bean.getTypes()).create(beanInstance);
}

/**
Expand Down
Expand Up @@ -20,6 +20,7 @@
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Collections;

import javassist.CtClass;
import javassist.CtConstructor;
Expand Down Expand Up @@ -52,7 +53,7 @@ public class DecoratorProxyFactory<T> extends ProxyFactory<T>

public DecoratorProxyFactory(Class<T> proxyType, WeldInjectionPoint<?, ?> delegateInjectionPoint)
{
super(proxyType);
super(proxyType, Collections.EMPTY_SET);
this.delegateInjectionPoint = delegateInjectionPoint;
try
{
Expand Down
Expand Up @@ -25,49 +25,31 @@
import javassist.CtNewMethod;

import org.jboss.weld.exceptions.WeldException;
import org.jboss.weld.util.reflection.Reflections;

/**
* This factory produces proxies specific for enterprise beans, in particular
* session beans. It adds the interface {@link EnterpriseBeanInstance} to
* each proxy class.
* This factory produces client proxies specific for enterprise beans, in
* particular session beans. It adds the interface
* {@link EnterpriseBeanInstance} on the proxy.
*
* @author David Allen
*/
public class EnterpriseProxyFactory<T> extends ProxyFactory<T>
{
public static final String PROXY_SUFFIX = "EnterpriseProxy";

/**
* Produces a factory for a specific bean implementation.
*
* @param proxiedBeanType the actual enterprise bean
*/
public EnterpriseProxyFactory(Class<T> proxiedBeanType, Set<Type> localBusinessInterfaces)
{
super(proxiedBeanType);
for (Type type : localBusinessInterfaces)
{
Class<?> c = Reflections.getRawType(type);
// Ignore no-interface views, they are dealt with proxiedBeanType (pending redesign)
if (c.isInterface())
{
addInterface(c);
}
}
}

@Override
protected String getProxyNameSuffix()
{
return PROXY_SUFFIX;
super(proxiedBeanType, localBusinessInterfaces);
}

@Override
protected void addSpecialMethods(CtClass proxyClassType)
{
super.addSpecialMethods(proxyClassType);

// Add methods for the EnterpriseBeanInstance interface
try
{
Expand All @@ -83,6 +65,6 @@ protected void addSpecialMethods(CtClass proxyClassType)
{
throw new WeldException(e);
}

}
}
122 changes: 77 additions & 45 deletions impl/src/main/java/org/jboss/weld/bean/proxy/ProxyFactory.java
Expand Up @@ -27,9 +27,11 @@
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

import javassist.ClassPool;
import javassist.CtClass;
Expand All @@ -47,6 +49,9 @@
import org.jboss.weld.exceptions.DefinitionException;
import org.jboss.weld.exceptions.WeldException;
import org.jboss.weld.serialization.spi.ProxyServices;
import org.jboss.weld.util.Proxies.TypeInfo;
import org.jboss.weld.util.collections.ArraySet;
import org.jboss.weld.util.reflection.Reflections;
import org.jboss.weld.util.reflection.SecureReflections;
import org.jboss.weld.util.reflection.instantiation.InstantiatorFactory;
import org.slf4j.cal10n.LocLogger;
Expand All @@ -61,41 +66,55 @@
public class ProxyFactory<T>
{
// The log provider
protected static final LocLogger log = loggerFactory().getLogger(BEAN);
protected static final LocLogger log = loggerFactory().getLogger(BEAN);
// Default proxy class name suffix
public static final String PROXY_SUFFIX = "Proxy";
public static final String PROXY_SUFFIX = "Proxy";

private final Class<?> beanType;
private final ArrayList<Class<?>> additionalInterfaces = new ArrayList<Class<?>>();
private final ClassLoader classLoader;
private final ProtectionDomain protectionDomain;
private final ClassPool classPool;

/**
* Creates a new proxy factory from any type of BeanInstance. This bean
* instance is only used for initialization information and is not associated
* with this factory once created.
*
* @param instance a bean instance that will be used with the proxy
*/
public ProxyFactory(BeanInstance beanInstance)
{
this(beanInstance.getInstanceType());
}
private final Class<?> beanType;
private final Set<Class<?>> additionalInterfaces = new HashSet<Class<?>>();
private final ClassLoader classLoader;
private final ProtectionDomain protectionDomain;
private final ClassPool classPool;
private final String baseProxyName;

/**
* Creates a new proxy factory with only the type of proxy specified.
*
* @param proxiedBeanType the super-class for this proxy class
*/
public ProxyFactory(Class<?> proxiedBeanType)
public ProxyFactory(Class<?> proxiedBeanType, Set<Type> businessInterfaces)
{
this.beanType = proxiedBeanType;
this.classLoader = Container.instance().services().get(ProxyServices.class).getClassLoader(beanType);
for (Type type : businessInterfaces)
{
Class<?> c = Reflections.getRawType(type);
// Ignore no-interface views, they are dealt with proxiedBeanType
// (pending redesign)
if (c.isInterface())
{
addInterface(c);
}
}
Class<?> superClass = TypeInfo.of(businessInterfaces).getSuperClass();
superClass = superClass == null ? Object.class : superClass;
if (superClass.equals(Object.class))
{
if (additionalInterfaces.isEmpty())
{
// No interface beans must use the bean impl as superclass
superClass = proxiedBeanType;
}
this.classLoader = Container.instance().services().get(ProxyServices.class).getClassLoader(proxiedBeanType);
}
else
{
this.classLoader = Container.instance().services().get(ProxyServices.class).getClassLoader(superClass);
}
this.beanType = superClass;
this.protectionDomain = Container.instance().services().get(ProxyServices.class).getProtectionDomain(beanType);
this.classPool = new ClassPool();
this.classPool.appendClassPath(new ClassloaderClassPath(classLoader));
addDefaultAdditionalInterfaces();
baseProxyName = proxiedBeanType.getName();
}

/**
Expand Down Expand Up @@ -153,7 +172,7 @@ public T create(BeanInstance beanInstance)
@SuppressWarnings("unchecked")
public Class<T> getProxyClass()
{
String proxyClassName = beanType.getName() + "_$$_Weld" + getProxyNameSuffix();
String proxyClassName = getBaseProxyName() + "_$$_Weld" + getProxyNameSuffix();
if (proxyClassName.startsWith("java"))
{
proxyClassName = proxyClassName.replaceFirst("java", "org.jboss.weld");
Expand All @@ -180,6 +199,16 @@ public Class<T> getProxyClass()
return proxyClass;
}

/**
* Returns the package and base name for the proxy class.
*
* @return base name without suffixes
*/
protected String getBaseProxyName()
{
return baseProxyName;
}

/**
* Convenience method to determine if an object is a proxy generated by this
* factory or any derived factory.
Expand Down Expand Up @@ -227,6 +256,13 @@ private void addDefaultAdditionalInterfaces()
@SuppressWarnings("unchecked")
private Class<T> createProxyClass(String proxyClassName) throws Exception
{
ArraySet<Class<?>> specialInterfaces = new ArraySet<Class<?>>(3);
specialInterfaces.add(Proxy.class);
specialInterfaces.add(LifecycleMixin.class);
specialInterfaces.add(TargetInstanceProxy.class);
// Remove special interfaces from main set (deserialization scenario)
additionalInterfaces.removeAll(specialInterfaces);

CtClass instanceType = classPool.get(beanType.getName());
CtClass proxyClassType = null;
if (instanceType.isInterface())
Expand All @@ -249,9 +285,10 @@ private Class<T> createProxyClass(String proxyClassName) throws Exception
addMethods(proxyClassType);

// Additional interfaces whose methods require special handling
proxyClassType.addInterface(classPool.get(Proxy.class.getName()));
proxyClassType.addInterface(classPool.get(LifecycleMixin.class.getName()));
proxyClassType.addInterface(classPool.get(TargetInstanceProxy.class.getName()));
for (Class<?> specialInterface : specialInterfaces)
{
proxyClassType.addInterface(classPool.get(specialInterface.getName()));
}

Class<T> proxyClass = proxyClassType.toClass(classLoader, protectionDomain);
proxyClassType.detach();
Expand Down Expand Up @@ -318,10 +355,10 @@ private void addMethods(CtClass proxyClassType)

/**
* Adds special serialization code by 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}.
* The next call will receive the proxy object itself permitting the substitute
* object to serialize the proxy.
* the proxy. This method when first called will substitute the proxy object
* with an instance of {@link org.jboss.weld.proxy.util.SerializableProxy}.
* The next call will receive the proxy object itself permitting the
* substitute object to serialize the proxy.
*
* @param proxyClassType the Javassist class for the proxy class
*/
Expand All @@ -333,23 +370,18 @@ protected void addSerializationSupport(CtClass proxyClassType)
// replacement object and the subsequent call get the proxy object.
CtClass exception = classPool.get(ObjectStreamException.class.getName());
CtClass objectClass = classPool.get(Object.class.getName());
String writeReplaceBody = "{ " +
" if (firstSerializationPhaseComplete) {" +
" firstSerializationPhaseComplete = false; " +
" 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);" +
" } }";
String writeReplaceBody = "{ " + " if (firstSerializationPhaseComplete) {" + " firstSerializationPhaseComplete = false; " + " 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));

// Also add a static method that can be used to deserialize a proxy object.
// This causes the OO input stream to use the class loader from this class.

// Also add a static method that can be used to deserialize a proxy
// object.
// This causes the OO input stream to use the class loader from this
// class.
CtClass objectInputStreamClass = classPool.get(ObjectInputStream.class.getName());
CtClass cnfe = classPool.get(ClassNotFoundException.class.getName());
CtClass ioe = classPool.get(IOException.class.getName());
String deserializeProxyBody = "{ return $1.readObject(); }";
proxyClassType.addMethod(CtNewMethod.make(Modifier.STATIC | Modifier.PUBLIC, objectClass, "deserializeProxy", new CtClass[]{objectInputStreamClass}, new CtClass[]{cnfe, ioe}, deserializeProxyBody, proxyClassType));
proxyClassType.addMethod(CtNewMethod.make(Modifier.STATIC | Modifier.PUBLIC, objectClass, "deserializeProxy", new CtClass[] { objectInputStreamClass }, new CtClass[] { cnfe, ioe }, deserializeProxyBody, proxyClassType));
}
catch (Exception e)
{
Expand Down Expand Up @@ -402,14 +434,14 @@ protected String createInterceptorBody(CtMethod method) throws NotFoundException
}

bodyString.append("beanInstance.invoke(");
bodyString.append(method.getDeclaringClass().getName());
if (Modifier.isPublic(method.getModifiers()))
{
bodyString.append("beanInstance.getInstanceType().getMethod(\"");
bodyString.append(".class.getMethod(\"");
log.trace("Using getMethod in proxy for method " + method.getLongName());
}
else
{
bodyString.append(method.getDeclaringClass().getName());
bodyString.append(".class.getDeclaredMethod(\"");
log.trace("Using getDeclaredMethod in proxy for method " + method.getLongName());
}
Expand Down

0 comments on commit 32b3978

Please sign in to comment.