/*
* JBoss, Home of Professional Open Source
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.seam.intercept;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.List;
import org.jboss.seam.log.LogProvider;
import org.jboss.seam.log.Logging;
import org.jboss.seam.Component;
import org.jboss.seam.Seam;
import org.jboss.seam.annotations.intercept.BypassInterceptors;
import org.jboss.seam.annotations.intercept.InterceptorType;
import org.jboss.seam.contexts.Contexts;
import org.jboss.seam.contexts.Lifecycle;
import org.jboss.seam.core.Mutable;
import org.jboss.seam.util.EJB;
/**
* Abstract superclass of all controller interceptors
*
* @author Gavin King
*/
public class RootInterceptor implements Serializable
{
private static final long serialVersionUID = 8041533870186694663L;
private static final LogProvider log = Logging.getLogProvider(RootInterceptor.class);
private final InterceptorType type;
private boolean isSeamComponent;
private String componentName;
private List<Object> userInterceptors;
private transient Component component; //a cache of the Component reference for performance
protected RootInterceptor(InterceptorType type)
{
this.type = type;
}
protected void init(Component component)
{
isSeamComponent = true;
componentName = component.getName();
userInterceptors = component.createUserInterceptors(type);
this.component = component;
}
protected void initNonSeamComponent()
{
isSeamComponent = false;
}
protected void postConstruct(Object bean)
{
// initialize the bean instance
if (isSeamComponent)
{
try
{
getComponent().initialize(bean);
}
catch (RuntimeException e)
{
throw e;
}
catch (Exception e)
{
throw new RuntimeException("exception initializing EJB component", e);
}
}
}
protected void invokeAndHandle(InvocationContext invocation, EventType invocationType)
{
try
{
invoke(invocation, invocationType);
}
catch (RuntimeException e)
{
throw e;
}
catch (Exception e)
{
throw new RuntimeException("exception in EJB lifecycle callback", e);
}
}
protected Object invoke(InvocationContext invocation, EventType invocationType) throws Exception
{
if ( !isSeamComponent || !Lifecycle.isApplicationInitialized())
{
//not a Seam component
return invocation.proceed();
}
else if ( Contexts.isEventContextActive() || Contexts.isApplicationContextActive() ) //not sure about the second bit (only needed at init time!)
{
// a Seam component, and Seam contexts exist
return createInvocationContext(invocation, invocationType).proceed();
}
else
{
//if invoked outside of a set of Seam contexts,
//set up temporary Seam EVENT and APPLICATION
//contexts just for this call
Lifecycle.beginCall();
try
{
return createInvocationContext(invocation, invocationType).proceed();
}
finally
{
Lifecycle.endCall();
}
}
}
private InvocationContext createInvocationContext(InvocationContext invocation, EventType eventType) throws Exception
{
if ( isProcessInterceptors( invocation.getMethod(), invocation.getTarget() ) )
{
if ( log.isTraceEnabled() )
{
log.trace( "intercepted: " + getInterceptionMessage(invocation, eventType) );
}
return createSeamInvocationContext(invocation, eventType);
}
else
{
if ( log.isTraceEnabled() )
{
log.trace( "not intercepted: " + getInterceptionMessage(invocation, eventType) );
}
return invocation;
}
}
private SeamInvocationContext createSeamInvocationContext(InvocationContext invocation, EventType eventType) throws Exception
{
return EJB.INVOCATION_CONTEXT_AVAILABLE ?
createEE5SeamInvocationContext(invocation, eventType) :
createNonEE5SeamInvocationContext(invocation, eventType);
}
private SeamInvocationContext createNonEE5SeamInvocationContext(InvocationContext invocation, EventType eventType)
{
return new SeamInvocationContext( invocation, eventType, userInterceptors, getComponent().getInterceptors(type) );
}
private static final Constructor CONSTRUCTOR;
static
{
if ( EJB.INVOCATION_CONTEXT_AVAILABLE )
{
try
{
Class[] paramTypes = {InvocationContext.class, EventType.class, List.class, List.class};
CONSTRUCTOR = Class.forName("org.jboss.seam.intercept.EE5SeamInvocationContext").getConstructor(paramTypes);
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}
else
{
CONSTRUCTOR = null;
}
}
private SeamInvocationContext createEE5SeamInvocationContext(InvocationContext invocation, EventType eventType)
{
try
{
return (SeamInvocationContext) CONSTRUCTOR.newInstance( invocation, eventType, userInterceptors, getComponent().getInterceptors(type) );
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}
private String getInterceptionMessage(InvocationContext invocation, EventType eventType)
{
return getComponent().getName() + '.' +
( eventType==EventType.AROUND_INVOKE ? invocation.getMethod().getName() : eventType );
}
private boolean isProcessInterceptors(Method method, Object bean)
{
boolean res = isSeamComponent &&
getComponent().isInterceptionEnabled() &&
!isBypassed(method) &&
!isClearDirtyMethod(method, bean);
return res;
}
private boolean isBypassed(Method method)
{
return method!=null && method.isAnnotationPresent(BypassInterceptors.class);
}
private boolean isClearDirtyMethod(Method method, Object bean)
{
return bean instanceof Mutable &&
method!=null &&
method.getName().equals("clearDirty") &&
method.getParameterTypes().length==0;
}
protected Component getComponent()
{
if (isSeamComponent && component==null)
{
component = Seam.componentForName(componentName);
}
return component;
}
protected boolean isSeamComponent()
{
return isSeamComponent;
}
protected String getComponentName()
{
return componentName;
}
}