//$Id: JavaBeanInterceptor.java 9715 2008-12-04 08:00:42Z dan.j.allen $
package org.jboss.seam.intercept;
import java.lang.reflect.Method;
import javassist.util.proxy.MethodHandler;
import javassist.util.proxy.ProxyObject;
import javax.servlet.http.HttpSessionActivationListener;
import javax.servlet.http.HttpSessionEvent;
import org.jboss.seam.Component;
import org.jboss.seam.ComponentType;
import org.jboss.seam.annotations.ReadOnly;
import org.jboss.seam.annotations.intercept.InterceptorType;
import org.jboss.seam.core.Mutable;
/**
* Controller interceptor for JavaBean components
*
* @author Gavin King
*/
public class JavaBeanInterceptor extends RootInterceptor
implements MethodHandler
{
private static final long serialVersionUID = -771725005103740533L;
private final Object bean;
private final Class beanClass;
private transient boolean dirty;
public JavaBeanInterceptor(Object bean, Component component)
{
super(InterceptorType.ANY);
this.bean = bean;
this.beanClass = component.getBeanClass();
init(component);
}
public Object invoke(final Object proxy, final Method method, final Method proceed, final Object[] params) throws Throwable
{
if ( params!=null )
{
if ( params.length==0 )
{
String methodName = method.getName();
if ( "finalize".equals(methodName) )
{
return proceed.invoke (proxy, params);
}
else if ( "writeReplace".equals(methodName) )
{
return this;
}
else if ( "clearDirty".equals(methodName) && !(bean instanceof Mutable) )
{
//clear and return the dirty flag
boolean result = dirty;
dirty = false;
return result;
}
else if ( "getComponent".equals(methodName) )
{
return getComponent();
}
}
else if ( params.length==1 && (params[0] instanceof HttpSessionEvent) )
{
String methodName = method.getName();
if ( "sessionDidActivate".equals(methodName) )
{
callPostActivate();
return (bean instanceof HttpSessionActivationListener) ? method.invoke(bean, params) : null;
}
else if ( "sessionWillPassivate".equals(methodName) )
{
callPrePassivate();
return (bean instanceof HttpSessionActivationListener) ? method.invoke(bean, params) : null;
}
}
}
if ( markDirty(method) )
{
//mark it dirty each time it gets called
//this flag will be ignored if the bean
//implements Mutable
dirty = true;
}
//make default equals() method return true when called on itself
//by unwrapping the proxy
if ( method.getName().equals("equals")
&& method.getParameterTypes().length == 1
&& method.getParameterTypes()[0] == Object.class
&& params[0] == proxy)
{
return interceptInvocation(method, new Object[]{bean});
}
Object result = interceptInvocation(method, params);
return result==bean ? proxy : result;
}
private boolean markDirty(Method method)
{
return !getComponent().getBeanClass().isAnnotationPresent(ReadOnly.class) &&
!method.isAnnotationPresent(ReadOnly.class);
}
public void postConstruct()
{
super.postConstruct(bean);
callPostConstruct();
}
private void callPostConstruct()
{
final Component component = getComponent();
if (!component.hasPostConstructMethod())
{
return;
}
InvocationContext context = new RootInvocationContext( bean, component.getPostConstructMethod(), new Object[0] )
{
@Override
public Object proceed() throws Exception
{
component.callPostConstructMethod(bean);
return null;
}
};
invokeAndHandle(context, EventType.POST_CONSTRUCT);
}
private void callPrePassivate()
{
final Component component = getComponent();
if (!component.hasPrePassivateMethod())
{
return;
}
InvocationContext context = new RootInvocationContext( bean, component.getPrePassivateMethod(), new Object[0] )
{
@Override
public Object proceed() throws Exception
{
component.callPrePassivateMethod(bean);
return null;
}
};
invokeAndHandle(context, EventType.PRE_PASSIVATE);
}
private void callPostActivate()
{
final Component component = getComponent();
if (!component.hasPostActivateMethod())
{
return;
}
RootInvocationContext context = new RootInvocationContext(bean, component.getPostActivateMethod(), new Object[0])
{
@Override
public Object proceed() throws Exception
{
component.callPostActivateMethod(bean);
return null;
}
};
invokeAndHandle(context, EventType.POST_ACTIVATE);
}
private Object interceptInvocation(final Method method, final Object[] params) throws Exception
{
return invoke( new RootInvocationContext(bean, method, params), EventType.AROUND_INVOKE );
}
// TODO: copy/paste from ClientSide interceptor
Object readResolve()
{
Component comp = null;
try
{
comp = getComponent();
}
catch (IllegalStateException ise) {
//this can occur when tomcat deserializes persistent sessions
}
try
{
if (comp==null)
{
ProxyObject proxy = Component.createProxyFactory(
ComponentType.JAVA_BEAN,
beanClass,
Component.getBusinessInterfaces(beanClass)
).newInstance();
proxy.setHandler(this);
return proxy;
}
else
{
return comp.wrap(bean, this);
}
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}
}