package org.jboss.seam.wicket.ioc;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
import org.jboss.seam.wicket.WicketComponent;
public class WicketHandler implements Serializable
{
public static WicketHandler create(Object bean)
{
WicketHandler handler = new WicketHandler(bean.getClass());
return handler;
}
public WicketHandler(Class<?> type)
{
this.type = type;
}
private Class<?> type;
private transient WicketComponent component;
private int reentrant = 0;
private WicketComponent getComponent()
{
if (component == null)
{
component = WicketComponent.getInstance(type);
}
return component;
}
public void beforeInvoke(Object target, Method calledMethod)
{
doBeforeInvoke(new InvocationContext(calledMethod, target, getComponent()));
}
public Object afterInvoke(Object target, Method calledMethod, Object result)
{
return doAfterInvoke(new InvocationContext(calledMethod, target, getComponent()), result);
}
public void beforeInvoke(Object target, Constructor constructor)
{
getComponent().initialize(target);
doBeforeInvoke(new InvocationContext(constructor, target, getComponent()));
}
public void afterInvoke(Object target, Constructor constructor)
{
doAfterInvoke(new InvocationContext(constructor, target, getComponent()), null);
}
private void doBeforeInvoke(InvocationContext invocationContext)
{
if (reentrant == 0)
{
for (StatelessInterceptor interceptor : (List<StatelessInterceptor>) getComponent().getInterceptors())
{
interceptor.beforeInvoke(invocationContext);
}
}
reentrant++;
InstrumentedComponent enclosing = getEnclosingInstance(invocationContext.getBean());
if (enclosing != null && enclosing.getHandler() != null)
{
enclosing.getHandler().injectEnclosingInstance(enclosing);
}
}
protected void injectEnclosingInstance(InstrumentedComponent instance)
{
if (reentrant == 0)
{
getComponent().inject(instance);
}
reentrant++;
instance = instance.getEnclosingInstance();
if (instance != null)
{
instance.getHandler().injectEnclosingInstance(instance);
}
}
public Exception handleException(Object target, Method method, Exception exception)
{
return doHandleException(new InvocationContext(method, target, getComponent()), exception);
}
public Exception handleException(Object target, Constructor constructor, Exception exception)
{
return doHandleException(new InvocationContext(constructor, target, getComponent()), exception);
}
private Exception doHandleException(InvocationContext invocationContext, Exception exception)
{
reentrant--;
if (reentrant == 0)
{
for (StatelessInterceptor interceptor : (List<StatelessInterceptor>) getComponent().getInterceptors())
{
exception = interceptor.handleException(invocationContext, exception);
}
}
return exception;
}
private Object doAfterInvoke(InvocationContext invocationContext, Object result)
{
reentrant--;
if (reentrant == 0)
{
for (int i = getComponent().getInterceptors().size() - 1; i >= 0; i--)
{
result = ((StatelessInterceptor) getComponent().getInterceptors().get(i)).afterInvoke(invocationContext, result);
}
}
InstrumentedComponent enclosing = getEnclosingInstance(invocationContext.getBean());
if (enclosing != null && enclosing.getHandler() != null)
{
enclosing.getHandler().disinjectEnclosingInstance(enclosing);
}
return result;
}
protected void disinjectEnclosingInstance(InstrumentedComponent instance)
{
reentrant--;
if (reentrant == 0)
{
getComponent().disinject(instance);
}
instance = instance.getEnclosingInstance();
if (instance != null)
{
instance.getHandler().disinjectEnclosingInstance(instance);
}
}
public boolean isReentrant()
{
return reentrant > 0;
}
public InstrumentedComponent getEnclosingInstance(Object bean)
{
Class enclosingType = getComponent().getClass();
if (enclosingType != null)
{
try
{
Field enclosingField = bean.getClass().getDeclaredField(getComponent().getEnclosingInstanceVariableName());
enclosingField.setAccessible(true);
Object enclosingInstance = enclosingField.get(bean);
if (enclosingInstance instanceof InstrumentedComponent)
{
return (InstrumentedComponent) enclosingInstance;
}
}
catch (Exception e) {}
}
return null;
}
}