[jboss-cvs] jboss-seam/src/main/org/jboss/seam/intercept ...

Gavin King gavin.king at jboss.com
Tue Oct 10 02:43:16 EDT 2006


  User: gavin   
  Date: 06/10/10 02:43:16

  Added:       src/main/org/jboss/seam/intercept        
                        ClientSideInterceptor.java EventType.java
                        Interceptor.java JavaBeanInterceptor.java
                        JavaBeanInvocationContext.java RootInterceptor.java
                        SeamInvocationContext.java
                        SessionBeanInterceptor.java
  Log:
  refactored interceptor fwk, fixed serialization problems
  
  Revision  Changes    Path
  1.1      date: 2006/10/10 06:43:16;  author: gavin;  state: Exp;jboss-seam/src/main/org/jboss/seam/intercept/ClientSideInterceptor.java
  
  Index: ClientSideInterceptor.java
  ===================================================================
  //$Id: ClientSideInterceptor.java,v 1.1 2006/10/10 06:43:16 gavin Exp $
  package org.jboss.seam.intercept;
  
  import java.io.Serializable;
  import java.lang.reflect.Method;
  
  
  import net.sf.cglib.proxy.MethodInterceptor;
  import net.sf.cglib.proxy.MethodProxy;
  
  import org.jboss.seam.Component;
  import org.jboss.seam.InterceptorType;
  import org.jboss.seam.ejb.SeamInterceptor;
  
  /**
   * Controller interceptor for client-side interceptors of
   * EJB3 session bean components
   * 
   * @author Gavin King
   */
  public class ClientSideInterceptor extends RootInterceptor 
        implements MethodInterceptor, Serializable
  {
     
     private final Object bean;
  
     public ClientSideInterceptor(Object bean, Component component)
     {
        super(InterceptorType.CLIENT);
        this.bean = bean;
        init(component);
     }
     
     public Object intercept(final Object proxy, final Method method, final Object[] params,
           final MethodProxy methodProxy) throws Throwable
     {
        return aroundInvoke( new JavaBeanInvocationContext(bean, method, params)
        {
           public Object proceed() throws Exception
           {
              SeamInterceptor.COMPONENT.set( getComponent() );
              try
              {
                 return methodProxy.invoke(bean, params);
              }
              catch (Error e)
              {
                 throw e;
              }
              catch (Exception e)
              {
                 throw e;
              }
              catch (Throwable t)
              {
                 //only extremely wierd stuff!
                 throw new Exception(t);
              }
              finally
              {
                 SeamInterceptor.COMPONENT.set(null);
              }
           }
        
        });
     }
  
  }
  
  
  
  1.1      date: 2006/10/10 06:43:16;  author: gavin;  state: Exp;jboss-seam/src/main/org/jboss/seam/intercept/EventType.java
  
  Index: EventType.java
  ===================================================================
  package org.jboss.seam.intercept;
  
  public enum EventType
  {
     AROUND_INVOKE,
     PRE_DESTORY,
     POST_CONSTRUCT,
     PRE_PASSIVATE,
     POST_ACTIVATE
  }
  
  
  
  1.1      date: 2006/10/10 06:43:16;  author: gavin;  state: Exp;jboss-seam/src/main/org/jboss/seam/intercept/Interceptor.java
  
  Index: Interceptor.java
  ===================================================================
  //$Id: Interceptor.java,v 1.1 2006/10/10 06:43:16 gavin Exp $
  package org.jboss.seam.intercept;
  
  import java.lang.annotation.Annotation;
  import java.lang.reflect.Method;
  
  import javax.annotation.PostConstruct;
  import javax.annotation.PreDestroy;
  import javax.ejb.PostActivate;
  import javax.ejb.PrePassivate;
  import javax.interceptor.AroundInvoke;
  import javax.interceptor.Interceptors;
  import javax.interceptor.InvocationContext;
  
  import org.jboss.seam.Component;
  import org.jboss.seam.InterceptorType;
  import org.jboss.seam.util.Reflections;
  
  /**
   * Wraps and delegates to a Seam interceptor.
   * 
   * @author Gavin King
   */
  public final class Interceptor extends Reflections
  {
     private Class<?> userInterceptorClass;
     private Object statelessUserInterceptorInstance;
     private Method aroundInvokeMethod;
     private Method postConstructMethod;
     private Method preDestroyMethod;
     private Method postActivateMethod;
     private Method prePassivateMethod;
     private Method componentInjectorMethod;
     private Method annotationInjectorMethod;
     private InterceptorType type;
     private Annotation annotation;
     private Component component;
  
     private boolean isStateless()
     {
        return userInterceptorClass.isAnnotationPresent(org.jboss.seam.annotations.Interceptor.class) &&
              userInterceptorClass.getAnnotation(org.jboss.seam.annotations.Interceptor.class).stateless();
     }
     
     public Object createUserInterceptor()
     {
        if ( isStateless() )
        {
           return statelessUserInterceptorInstance;
        }
        else
        {
           try
           {
              Object userInterceptor = userInterceptorClass.newInstance();
              if (componentInjectorMethod!=null)
              {
                 Reflections.invokeAndWrap(componentInjectorMethod, userInterceptor, component);
              }
              if (annotationInjectorMethod!=null) 
              {
                 Reflections.invokeAndWrap(annotationInjectorMethod, userInterceptor, annotation);
              }
              return userInterceptor;
           }
           catch (Exception e)
           {
              throw new RuntimeException(e);
           }
        }
     }
  
     public Class getUserInterceptorClass()
     {
        return userInterceptorClass;
     }
     
     public InterceptorType getType()
     {
        return type;
     }
     
     public String toString()
     {
        return "Interceptor(" + userInterceptorClass.getName() + ")";
     }
     
     public Interceptor(Object interceptor, Component component)
     {
        userInterceptorClass = interceptor.getClass();
        statelessUserInterceptorInstance = interceptor;
        this.component = component;
        init();
     }
     
     public Interceptor(Annotation annotation, Component component) 
     {
        Interceptors interceptorAnnotation = annotation.annotationType()
              .getAnnotation(Interceptors.class);
        Class[] classes = interceptorAnnotation.value();
        if (classes.length!=1)
        {
           //TODO: remove this silly restriction!
           throw new IllegalArgumentException("Must be exactly one interceptor when used as a meta-annotation");
        }
        userInterceptorClass = classes[0];
        
        try
        {
           statelessUserInterceptorInstance = userInterceptorClass.newInstance();
        }
        catch (Exception e)
        {
           throw new IllegalArgumentException("could not instantiate interceptor", e);
        }
        
        this.annotation = annotation;
        this.component = component;
        
        init();
     }
     
  
     private void init()
     {
        for (Method method : userInterceptorClass.getMethods())
        {
           if ( !method.isAccessible() ) method.setAccessible(true);
           if ( method.isAnnotationPresent(AroundInvoke.class) )
           {
              aroundInvokeMethod = method;
           }
           if ( method.isAnnotationPresent(PostConstruct.class) )
           {
              postConstructMethod = method;
           }
           if ( method.isAnnotationPresent(PreDestroy.class) )
           {
              preDestroyMethod = method;
           }
           if ( method.isAnnotationPresent(PrePassivate.class) )
           {
              prePassivateMethod = method;
           }
           if ( method.isAnnotationPresent(PostActivate.class) )
           {
              postActivateMethod = method;
           }
  
           Class[] params = method.getParameterTypes();
           //if there is a method that takes the annotation, call it, to pass initialization info
           if ( annotation!=null && params.length==1 && params[0]==annotation.annotationType() )
           {
              annotationInjectorMethod = method;
              Reflections.invokeAndWrap(method, userInterceptorClass, annotation);
           }
           //if there is a method that takes the component, call it
           if ( params.length==1 && params[0]==Component.class )
           {
              componentInjectorMethod = method;
              Reflections.invokeAndWrap(method, statelessUserInterceptorInstance, component);
           }
        }
  
        type = userInterceptorClass.isAnnotationPresent(org.jboss.seam.annotations.Interceptor.class) ?
              userInterceptorClass.getAnnotation(org.jboss.seam.annotations.Interceptor.class).type() :
              InterceptorType.SERVER;
     }
     
     public Object aroundInvoke(InvocationContext invocation, Object userInterceptor) throws Exception
     {
        return aroundInvokeMethod==null ?
              invocation.proceed() :
              Reflections.invoke( aroundInvokeMethod, userInterceptor, invocation );
     }
     
     public Object postConstruct(InvocationContext invocation, Object userInterceptor) throws Exception
     {
        return postConstructMethod==null ?
              invocation.proceed() :
              Reflections.invoke( postConstructMethod, userInterceptor, invocation );
     }
     
     public Object preDestroy(InvocationContext invocation, Object userInterceptor) throws Exception
     {
        return preDestroyMethod==null ?
              invocation.proceed() :
              Reflections.invoke( preDestroyMethod, userInterceptor, invocation );
     }
     
     public Object prePassivate(InvocationContext invocation, Object userInterceptor) throws Exception
     {
        return prePassivateMethod==null ?
              invocation.proceed() :
              Reflections.invoke( prePassivateMethod, userInterceptor, invocation );
     }
     
     public Object postActivate(InvocationContext invocation, Object userInterceptor) throws Exception
     {
        return postActivateMethod==null ?
              invocation.proceed() :
              Reflections.invoke( postActivateMethod, userInterceptor, invocation );
     }
     
  }
  
  
  
  1.1      date: 2006/10/10 06:43:16;  author: gavin;  state: Exp;jboss-seam/src/main/org/jboss/seam/intercept/JavaBeanInterceptor.java
  
  Index: JavaBeanInterceptor.java
  ===================================================================
  //$Id: JavaBeanInterceptor.java,v 1.1 2006/10/10 06:43:16 gavin Exp $
  package org.jboss.seam.intercept;
  
  import java.io.Serializable;
  import java.lang.reflect.Method;
  
  import net.sf.cglib.proxy.MethodInterceptor;
  import net.sf.cglib.proxy.MethodProxy;
  
  import org.jboss.seam.Component;
  import org.jboss.seam.InterceptorType;
  
  /**
   * Controller interceptor for JavaBean components
   * 
   * @author Gavin King
   */
  public class JavaBeanInterceptor extends RootInterceptor
        implements MethodInterceptor, Serializable
  {
     
     private boolean recursive = false;
     
     public JavaBeanInterceptor(Component component)
     {
        super(InterceptorType.ANY);
        init(component);
     }
  
     public Object intercept(final Object target, final Method method, final Object[] params,
           final MethodProxy methodProxy) throws Throwable
     {
        if (recursive) 
        {
           return methodProxy.invokeSuper(target, params);
        }
        
        recursive = true;
        try
        {
           String methodName = method.getName();
           if ( "finalize".equals(methodName) ) 
           {
              return methodProxy.invokeSuper(target, params);
           }
           else if ( "sessionDidActivate".equals(methodName) )
           {
              callPostActivate(target);
              return null;
           }
           else if ( "sessionWillPassivate".equals(methodName) )
           {
              callPrePassivate(target);
              return null;
           }
           else
           {
              return interceptInvocation(target, method, params, methodProxy);
           }
        }
        finally
        {
           recursive = false;
        }
     }
  
     private void callPrePassivate(final Object target)
     {
        prePassivate( new JavaBeanInvocationContext(target, getComponent().getPrePassivateMethod(), new Object[0])
        {
           public Object proceed() throws Exception
           {
              getComponent().callPrePassivateMethod(target);
              return null;
           }
           
        } );
     }
  
     private void callPostActivate( final Object target)
     {
        postActivate( new JavaBeanInvocationContext(target, getComponent().getPostActivateMethod(), new Object[0])
        {
           public Object proceed() throws Exception
           {
              getComponent().callPostActivateMethod(target);
              return null;
           }
           
        } );
     }
  
     private Object interceptInvocation(final Object target, final Method method, final Object[] params, 
           final MethodProxy methodProxy) throws Exception
     {
        return aroundInvoke( new JavaBeanInvocationContext(target, method, params)
        {
           
           public Object proceed() throws Exception
           {
              try
              {
                 return methodProxy.invokeSuper(target, params);
              }
              catch (Error e)
              {
                 throw e;
              }
              catch (Exception e)
              {
                 throw e;
              }
              catch (Throwable t)
              {
                 //only extremely wierd stuff!
                 throw new Exception(t);
              }
           }
           
        } );
     }
  
  }
  
  
  
  1.1      date: 2006/10/10 06:43:16;  author: gavin;  state: Exp;jboss-seam/src/main/org/jboss/seam/intercept/JavaBeanInvocationContext.java
  
  Index: JavaBeanInvocationContext.java
  ===================================================================
  package org.jboss.seam.intercept;
  
  import java.lang.reflect.Method;
  import java.util.HashMap;
  import java.util.Map;
  
  import javax.interceptor.InvocationContext;
  
  /**
   * InvocationContext for use with CGLIB-based interceptors.
   * 
   * @author Gavin King
   *
   */
  public abstract class JavaBeanInvocationContext implements InvocationContext
  {
     private final Object bean;
     private final Method method;
     private Object[] params;
     private final Map contextData = new HashMap();
  
     public JavaBeanInvocationContext(Object bean, Method method, Object[] params)
     {
        this.bean = bean;
        this.method = method;
        this.params = params;
     }
     
     public abstract Object proceed() throws Exception;
  
     public Object getTarget()
     {
        return bean;
     }
  
     public Map getContextData()
     {
        return contextData;
     }
  
     public Method getMethod()
     {
        return method;
     }
  
     public Object[] getParameters()
     {
        return params;
     }
  
     public void setParameters(Object[] newParams)
     {
        params = newParams;
     }
  }
  
  
  1.1      date: 2006/10/10 06:43:16;  author: gavin;  state: Exp;jboss-seam/src/main/org/jboss/seam/intercept/RootInterceptor.java
  
  Index: RootInterceptor.java
  ===================================================================
  /*
   * 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.util.List;
  
  import javax.annotation.PostConstruct;
  import javax.annotation.PreDestroy;
  import javax.ejb.PostActivate;
  import javax.ejb.PrePassivate;
  import javax.interceptor.AroundInvoke;
  import javax.interceptor.InvocationContext;
  
  import org.apache.commons.logging.Log;
  import org.apache.commons.logging.LogFactory;
  import org.jboss.seam.Component;
  import org.jboss.seam.InterceptorType;
  import org.jboss.seam.Seam;
  import org.jboss.seam.contexts.Contexts;
  import org.jboss.seam.contexts.Lifecycle;
  
  /**
   * Abstract superclass of all controller interceptors
   * 
   * @author Gavin King
   */
  public class RootInterceptor implements Serializable
  {
     
     private static final Log log = LogFactory.getLog(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
  
     /**
      * Called when instatiated by EJB container.
      * (In this case it might be a Seam component,
      * but we won't know until postConstruct() is
      * called.)
      */
     public 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;
     }
     
     @PostConstruct
     public void postConstruct(InvocationContext invocation)
     {
        // initialize the bean instance
        if (isSeamComponent)
        {
           try
           {
              getComponent().initialize( invocation.getTarget() );
           }
           catch (RuntimeException e)
           {
              throw e;
           }
           catch (Exception e)
           {
              throw new RuntimeException("exception initializing EJB component", e);
           }
        }
        
        invokeAndHandle(invocation, EventType.POST_CONSTRUCT);
     }
  
     @PreDestroy
     public void preDestroy(InvocationContext invocation)
     {
        invokeAndHandle(invocation, EventType.PRE_DESTORY);
     }
     
     @PrePassivate
     public void prePassivate(InvocationContext invocation)
     {
        invokeAndHandle(invocation, EventType.PRE_PASSIVATE);
     }
     
     @PostActivate
     public void postActivate(InvocationContext invocation)
     {
        invokeAndHandle(invocation, EventType.POST_ACTIVATE);
     }
     
     private 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);
        }
     }
     
     @AroundInvoke
     public Object aroundInvoke(InvocationContext invocation) throws Exception
     {
        return invoke(invocation, EventType.AROUND_INVOKE);
     }
     
     private Object invoke(InvocationContext invocation, EventType invocationType) throws Exception
     {
        if ( !isSeamComponent )
        {
           //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 invokeInContexts(invocation, invocationType);
        }
        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 invokeInContexts(invocation, invocationType);
           }
           finally
           {
              Lifecycle.endCall();
           }
        }
     }
  
     private Object invokeInContexts(InvocationContext invocation, EventType eventType) throws Exception
     {
        if ( isProcessInterceptors(getComponent()) )
        {
           if ( log.isTraceEnabled() ) 
           {
              log.trace("intercepted: " + getComponent().getName() + '.' + invocation.getMethod().getName());
           }
           return new SeamInvocationContext( invocation, eventType, userInterceptors, getComponent().getInterceptors(type) ).proceed();
        }
        else {
           if ( log.isTraceEnabled() ) 
           {
              log.trace("not intercepted: " + getComponent().getName() + '.' + invocation.getMethod().getName());
           }
           return invocation.proceed();
        }
     }
  
     private boolean isProcessInterceptors(final Component component)
     {
        return component!=null && component.getInterceptionType().isActive();
     }
     
     protected Component getComponent()
     {
        if (isSeamComponent && component==null) 
        {
           component = Seam.componentForName(componentName);
        }
        return component;
     }
     
  }
  
  
  
  1.1      date: 2006/10/10 06:43:16;  author: gavin;  state: Exp;jboss-seam/src/main/org/jboss/seam/intercept/SeamInvocationContext.java
  
  Index: SeamInvocationContext.java
  ===================================================================
  //$Id: SeamInvocationContext.java,v 1.1 2006/10/10 06:43:16 gavin Exp $
  package org.jboss.seam.intercept;
  
  import java.lang.reflect.Method;
  import java.util.List;
  import java.util.Map;
  
  import javax.interceptor.InvocationContext;
  
  
  /**
   * Adapts from EJB interception to Seam component interceptors
   * 
   * @author Gavin King
   */
  public class SeamInvocationContext implements InvocationContext
  {
     
     private final EventType eventType;
     private final InvocationContext ejbInvocationContext;
     private final List<Interceptor> interceptors;
     private final List<Object> userInterceptors;
     int location = 0;
  
     public SeamInvocationContext(InvocationContext ejbInvocationContext, EventType type, List<Object> userInterceptors, List<Interceptor> interceptors)
     {
        this.ejbInvocationContext = ejbInvocationContext;
        this.interceptors = interceptors;
        this.userInterceptors = userInterceptors;
        this.eventType = type;
     }
     
     public Object getTarget()
     {
        return ejbInvocationContext.getTarget();
     }
  
     public Map getContextData()
     {
        return ejbInvocationContext.getContextData();
     }
  
     public Method getMethod()
     {
        return ejbInvocationContext.getMethod();
     }
  
     public Object[] getParameters()
     {
        return ejbInvocationContext.getParameters();
     }
  
     public Object proceed() throws Exception
     {
        if ( location==interceptors.size() )
        {
           return ejbInvocationContext.proceed();
        }
        else
        {
           Object userInterceptor = userInterceptors.get(location);
           Interceptor interceptor = interceptors.get(location);
           location++;
           switch(eventType)
           {
              case AROUND_INVOKE: return interceptor.aroundInvoke(this, userInterceptor);
              case POST_CONSTRUCT: return interceptor.postConstruct(this, userInterceptor);
              case PRE_DESTORY: return interceptor.preDestroy(this, userInterceptor);
              case PRE_PASSIVATE: return interceptor.prePassivate(this, userInterceptor);
              case POST_ACTIVATE: return interceptor.postActivate(this, userInterceptor);
              default: throw new IllegalArgumentException("no InvocationType");
           }
        }
     }
  
     public void setParameters(Object[] params)
     {
        ejbInvocationContext.setParameters(params);
     }
  
  }
  
  
  
  1.1      date: 2006/10/10 06:43:16;  author: gavin;  state: Exp;jboss-seam/src/main/org/jboss/seam/intercept/SessionBeanInterceptor.java
  
  Index: SessionBeanInterceptor.java
  ===================================================================
  /*
   * JBoss, Home of Professional Open Source
   *
   * Distributable under LGPL license.
   * See terms of license at gnu.org.
   */
  package org.jboss.seam.intercept;
  
  import javax.annotation.PostConstruct;
  import javax.interceptor.InvocationContext;
  
  import org.jboss.seam.Component;
  import org.jboss.seam.InterceptorType;
  import org.jboss.seam.Seam;
  import org.jboss.seam.annotations.Name;
  import org.jboss.seam.intercept.RootInterceptor;
  
  /**
   * Controller interceptor for server-side interceptors of
   * EJB3 session bean components.
   * 
   * @author Gavin King
   */
  public class SessionBeanInterceptor extends RootInterceptor
  {
     
     public static ThreadLocal<Component> COMPONENT = new ThreadLocal<Component>();
  
     /**
      * Called when instatiated by EJB container.
      * (In this case it might be a Seam component,
      * but we won't know until postConstruct() is
      * called.)
      */
     public SessionBeanInterceptor()
     {
        super(InterceptorType.SERVER);
     }
     
     @PostConstruct
     public void postConstruct(InvocationContext invocation)
     {
        Component invokingComponent = SessionBeanInterceptor.COMPONENT.get();
        if ( invokingComponent!=null )
        {
           //the session bean was obtained by the application by
           //calling Component.getInstance(), could be a role
           //other than the default role
           init(invokingComponent);
        }
        else if ( invocation.getTarget().getClass().isAnnotationPresent(Name.class) )
        {
           //the session bean was obtained by the application from
           //JNDI, so assume the default role
           String defaultComponentName = invocation.getTarget().getClass().getAnnotation(Name.class).value();
           init( Seam.componentForName( defaultComponentName ) );
        }
        else
        {
           initNonSeamComponent();
        }
        
        super.postConstruct(invocation);
     }
  
     
  }
  
  
  



More information about the jboss-cvs-commits mailing list