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

Gavin King gavin.king at jboss.com
Mon Jun 25 19:59:31 EDT 2007


  User: gavin   
  Date: 07/06/25 19:59:31

  Added:       src/main/org/jboss/seam/core       BijectionInterceptor.java
                        ConversationInterceptor.java
                        ConversationalInterceptor.java
                        EventInterceptor.java MethodContextInterceptor.java
                        SynchronizationInterceptor.java
  Log:
  move builtin interceptors to the packages they relate to
  
  Revision  Changes    Path
  1.1      date: 2007/06/25 23:59:30;  author: gavin;  state: Exp;jboss-seam/src/main/org/jboss/seam/core/BijectionInterceptor.java
  
  Index: BijectionInterceptor.java
  ===================================================================
  //$Id: BijectionInterceptor.java,v 1.1 2007/06/25 23:59:30 gavin Exp $
  package org.jboss.seam.core;
  
  import org.jboss.seam.Component;
  import org.jboss.seam.annotations.intercept.AroundInvoke;
  import org.jboss.seam.annotations.intercept.Interceptor;
  import org.jboss.seam.intercept.AbstractInterceptor;
  import org.jboss.seam.intercept.InvocationContext;
  import org.jboss.seam.log.LogProvider;
  import org.jboss.seam.log.Logging;
  
  /**
   * Before invoking the component, inject all dependencies. After
   * invoking, outject dependencies back into their context.
   * 
   * @author Gavin King
   */
  @Interceptor
  public class BijectionInterceptor extends AbstractInterceptor
  {
     private static final long serialVersionUID = 4686458105931528659L;
     
     private static final LogProvider log = Logging.getLogProvider(BijectionInterceptor.class);
     
     private boolean reentrant; //OK, since all Seam components are single-threaded
     
     @AroundInvoke
     public Object aroundInvoke(InvocationContext invocation) throws Exception
     {
        if (reentrant)
        {
           if ( log.isTraceEnabled() )
           {
              log.trace("reentrant call to component: " + getComponent().getName() );
           }
           return invocation.proceed();
        }
        else
        {
           reentrant = true;
           try
           {
              Component component = getComponent();
              boolean enforceRequired = !component.isLifecycleMethod( invocation.getMethod() );
              component.inject( invocation.getTarget(), enforceRequired );
              Object result = invocation.proceed();            
              component.outject( invocation.getTarget(), enforceRequired );
              component.disinject( invocation.getTarget() );
              return result;
              
           }
           finally
           {
              reentrant = false;
           }
        }
     }
  
  }
  
  
  
  1.1      date: 2007/06/25 23:59:30;  author: gavin;  state: Exp;jboss-seam/src/main/org/jboss/seam/core/ConversationInterceptor.java
  
  Index: ConversationInterceptor.java
  ===================================================================
  //$Id: ConversationInterceptor.java,v 1.1 2007/06/25 23:59:30 gavin Exp $
  package org.jboss.seam.core;
  
  import java.lang.reflect.Method;
  import java.util.Arrays;
  
  import org.jboss.seam.annotations.ApplicationException;
  import org.jboss.seam.annotations.Begin;
  import org.jboss.seam.annotations.End;
  import org.jboss.seam.annotations.FlushModeType;
  import org.jboss.seam.annotations.bpm.BeginTask;
  import org.jboss.seam.annotations.bpm.EndTask;
  import org.jboss.seam.annotations.bpm.StartTask;
  import org.jboss.seam.annotations.intercept.AroundInvoke;
  import org.jboss.seam.annotations.intercept.Interceptor;
  import org.jboss.seam.bpm.BusinessProcessInterceptor;
  import org.jboss.seam.intercept.AbstractInterceptor;
  import org.jboss.seam.intercept.InvocationContext;
  import org.jboss.seam.pageflow.Pageflow;
  import org.jboss.seam.persistence.PersistenceContexts;
  
  /**
   * Implements annotation-based conversation demarcation.
   * 
   * @author Gavin King
   */
  @Interceptor(stateless=true,
               around=BijectionInterceptor.class,
               within=BusinessProcessInterceptor.class)
  public class ConversationInterceptor extends AbstractInterceptor
  {
     private static final long serialVersionUID = -5405533438107796414L;
  
     @AroundInvoke
     public Object aroundInvoke(InvocationContext invocation) throws Exception
     {
        try
        {
           Method method = invocation.getMethod();
           if ( getComponent().isConversationManagementMethod(method) ) //performance optimization 
           {
        
              if ( isMissingJoin(method) )
              {
                 throw new IllegalStateException("begin method invoked from a long running conversation, try using @Begin(join=true) on method: " + method.getName());
              }
              
              if ( redirectToExistingConversation(method) ) 
              {
                 return null;
              }
              else
              {
                 Object result = invocation.proceed();   
                 beginConversationIfNecessary(method, result);
                 endConversationIfNecessary(method, result);
                 return result;
              }
              
           }
           else
           {
              return invocation.proceed();
           }
        }
        catch (Exception e)
        {
           if ( isEndConversationRequired(e) )
           {
              endConversation(false);
           }
           throw e;
        }
     }
  
     private boolean isEndConversationRequired(Exception e)
     {
        Class<? extends Exception> clazz = e.getClass();
        return clazz.isAnnotationPresent(ApplicationException.class)
              && clazz.getAnnotation(ApplicationException.class).end();
     }
     
     @SuppressWarnings("deprecation")
     public boolean redirectToExistingConversation(Method method)
     {
        if ( !Manager.instance().isLongRunningConversation() )
        {
           String id = null;
           if ( method.isAnnotationPresent(Begin.class) )
           {
              id = method.getAnnotation(Begin.class).id();
           }
           else if ( method.isAnnotationPresent(BeginTask.class) )
           {
              id = method.getAnnotation(BeginTask.class).id();
           }
           else if ( method.isAnnotationPresent(StartTask.class) )
           {
              id = method.getAnnotation(StartTask.class).id();
           }
           
           if ( id!=null && !"".equals(id) )
           {
              id = Interpolator.instance().interpolate(id);
              ConversationEntry ce = ConversationEntries.instance().getConversationEntry(id);
              if (ce==null) 
              {
                 Manager.instance().updateCurrentConversationId(id);
              }
              else
              {
                 return ce.redirect();
              }
           }
        }
        
        return false;
     }
  
     private boolean isMissingJoin(Method method) {
        return Manager.instance().isLongRunningOrNestedConversation() && ( 
              ( 
                    method.isAnnotationPresent(Begin.class) && 
                    !method.getAnnotation(Begin.class).join() && 
                    !method.getAnnotation(Begin.class).nested() 
              ) ||
              method.isAnnotationPresent(BeginTask.class) ||
              method.isAnnotationPresent(StartTask.class) 
           );
     }
  
     @SuppressWarnings("deprecation")
     private void beginConversationIfNecessary(Method method, Object result)
     {
        
        boolean simpleBegin = 
              method.isAnnotationPresent(StartTask.class) || 
              method.isAnnotationPresent(BeginTask.class) ||
              ( method.isAnnotationPresent(Begin.class) && method.getAnnotation(Begin.class).ifOutcome().length==0 );
        if ( simpleBegin )
        {
           if ( result!=null || method.getReturnType().equals(void.class) )
           {
              boolean nested = false;
              if ( method.isAnnotationPresent(Begin.class) )
              {
                 nested = method.getAnnotation(Begin.class).nested();
              }
              beginConversation( nested, getProcessDefinitionName(method) );
              setFlushMode(method); //TODO: what if conversation already exists? Or a nested conversation?
           }
        }
        else if ( method.isAnnotationPresent(Begin.class) )
        {
           String[] outcomes = method.getAnnotation(Begin.class).ifOutcome();
           if ( outcomes.length==0 || Arrays.asList(outcomes).contains(result) )
           {
              beginConversation( 
                    method.getAnnotation(Begin.class).nested(), 
                    getProcessDefinitionName(method) 
                 );
              setFlushMode(method); //TODO: what if conversation already exists? Or a nested conversation?
           }
        }
        
     }
     
     private void setFlushMode(Method method)
     {
        FlushModeType flushMode;
        if (method.isAnnotationPresent(Begin.class))
        {
           flushMode = method.getAnnotation(Begin.class).flushMode();
        }
        else if (method.isAnnotationPresent(BeginTask.class))
        {
           flushMode = method.getAnnotation(BeginTask.class).flushMode();
        }
        else if (method.isAnnotationPresent(StartTask.class))
        {
           flushMode = method.getAnnotation(StartTask.class).flushMode();
        }
        else
        {
           return;
        }
        
        PersistenceContexts.instance().changeFlushMode(flushMode);
     }
  
     private String getProcessDefinitionName(Method method) {
        if ( method.isAnnotationPresent(Begin.class) )
        {
           return method.getAnnotation(Begin.class).pageflow();
        }
        if ( method.isAnnotationPresent(BeginTask.class) )
        {
           return method.getAnnotation(BeginTask.class).pageflow();
        }
        if ( method.isAnnotationPresent(StartTask.class) )
        {
           return method.getAnnotation(StartTask.class).pageflow();
        }
        //TODO: let them pass a pageflow name as a request parameter
        return "";
     }
  
     private void beginConversation(boolean nested, String pageflowName)
     {
        if ( !Manager.instance().isLongRunningOrNestedConversation() )
        {
           Manager.instance().beginConversation( );
           beginNavigation(pageflowName);
        }
        else if (nested)
        {
           Manager.instance().beginNestedConversation( );
           beginNavigation(pageflowName);
        }
     }
     
     private void beginNavigation(String pageflowName)
     {
        if ( !pageflowName.equals("") )
        {
           Pageflow.instance().begin(pageflowName);
        }
     }
  
     @SuppressWarnings("deprecation")
     private void endConversationIfNecessary(Method method, Object result)
     {
        boolean isEndAnnotation = method.isAnnotationPresent(End.class);
        boolean isEndTaskAnnotation = method.isAnnotationPresent(EndTask.class);
        
        boolean beforeRedirect = ( isEndAnnotation && method.getAnnotation(End.class).beforeRedirect() ) ||
              ( isEndTaskAnnotation && method.getAnnotation(EndTask.class).beforeRedirect() );
        
        boolean simpleEnd = 
              ( isEndAnnotation && method.getAnnotation(End.class).ifOutcome().length==0 ) || 
              ( isEndTaskAnnotation && method.getAnnotation(EndTask.class).ifOutcome().length==0 );
        if ( simpleEnd )
        {
           if ( result!=null || method.getReturnType().equals(void.class) ) //null outcome interpreted as redisplay
           {
              endConversation(beforeRedirect);
           }
        }
        else if ( isEndAnnotation )
        {
           String[] outcomes = method.getAnnotation(End.class).ifOutcome();
           if ( Arrays.asList(outcomes).contains(result) )
           {
              endConversation(beforeRedirect);
           }
        }
        else if ( isEndTaskAnnotation )
        {
           //TODO: fix minor code duplication
           String[] outcomes = method.getAnnotation(EndTask.class).ifOutcome();
           if ( Arrays.asList(outcomes).contains(result) )
           {
              endConversation(beforeRedirect);
           }
        }
     }
  
     private void endConversation(boolean beforeRedirect)
     {
        Manager.instance().endConversation(beforeRedirect);
     }
  
  }
  
  
  
  1.1      date: 2007/06/25 23:59:30;  author: gavin;  state: Exp;jboss-seam/src/main/org/jboss/seam/core/ConversationalInterceptor.java
  
  Index: ConversationalInterceptor.java
  ===================================================================
  //$Id: ConversationalInterceptor.java,v 1.1 2007/06/25 23:59:30 gavin Exp $
  package org.jboss.seam.core;
  
  import java.lang.reflect.Method;
  
  import org.jboss.seam.NoConversationException;
  import org.jboss.seam.annotations.Begin;
  import org.jboss.seam.annotations.Conversational;
  import org.jboss.seam.annotations.Create;
  import org.jboss.seam.annotations.Destroy;
  import org.jboss.seam.annotations.bpm.BeginTask;
  import org.jboss.seam.annotations.bpm.StartTask;
  import org.jboss.seam.annotations.intercept.AroundInvoke;
  import org.jboss.seam.annotations.intercept.Interceptor;
  import org.jboss.seam.bpm.BusinessProcessInterceptor;
  import org.jboss.seam.intercept.AbstractInterceptor;
  import org.jboss.seam.intercept.InvocationContext;
  
  /**
   * Check that a conversational bean is not being invoked
   * outside the scope of a long-running conversation. If
   * it is, throw an exception.
   * 
   * @author Gavin King
   */
  @Interceptor(stateless=true,
               around={BijectionInterceptor.class, BusinessProcessInterceptor.class})
  public class ConversationalInterceptor extends AbstractInterceptor
  {
     private static final long serialVersionUID = 1127583515811479385L;
  
     @AroundInvoke
     public Object aroundInvoke(InvocationContext invocation) throws Exception
     {
        Method method = invocation.getMethod();
  
        if ( isNoConversationForConversationalBean(method) )
        {
           Events.instance().raiseEvent("org.jboss.seam.noConversation");
           throw new NoConversationException( "no long-running conversation for @Conversational bean: " + getComponent().getName() );         
        }
  
        return invocation.proceed();
     
     }
     
     private boolean isNoConversationForConversationalBean(Method method)
     {
        boolean classlevelViolation = componentIsConversational() && 
              !Manager.instance().isLongRunningOrNestedConversation()  &&
              !method.isAnnotationPresent(Begin.class) &&
              !method.isAnnotationPresent(StartTask.class) &&
              !method.isAnnotationPresent(BeginTask.class) &&
              !method.isAnnotationPresent(Destroy.class) && 
              !method.isAnnotationPresent(Create.class); //probably superfluous
        
        if (classlevelViolation) return true;
        
        boolean methodlevelViolation = methodIsConversational(method) &&
              !Manager.instance().isLongRunningOrNestedConversation();
        
        return methodlevelViolation;
        
     }
  
     private boolean methodIsConversational(Method method) 
     {
        return method.isAnnotationPresent(Conversational.class);
     }
  
     private boolean componentIsConversational() 
     {
        return getComponent().getBeanClass().isAnnotationPresent(Conversational.class);
     }
  
  }
  
  
  
  1.1      date: 2007/06/25 23:59:30;  author: gavin;  state: Exp;jboss-seam/src/main/org/jboss/seam/core/EventInterceptor.java
  
  Index: EventInterceptor.java
  ===================================================================
  package org.jboss.seam.core;
  
  import java.lang.reflect.Method;
  import org.jboss.seam.annotations.RaiseEvent;
  import org.jboss.seam.annotations.intercept.AroundInvoke;
  import org.jboss.seam.annotations.intercept.Interceptor;
  import org.jboss.seam.bpm.BusinessProcessInterceptor;
  import org.jboss.seam.intercept.AbstractInterceptor;
  import org.jboss.seam.intercept.InvocationContext;
  import org.jboss.seam.transaction.RollbackInterceptor;
  import org.jboss.seam.transaction.TransactionInterceptor;
  
  /**
   * Raises Seam events connected with a bean lifecycle.
   * 
   * @author Gavin King
   *
   */
  @Interceptor(stateless=true,
               around={BijectionInterceptor.class, ConversationInterceptor.class, 
                       TransactionInterceptor.class, BusinessProcessInterceptor.class, 
                       RollbackInterceptor.class})
  public class EventInterceptor extends AbstractInterceptor
  {
     private static final long serialVersionUID = -136300200838134612L;
     
     /*@PostConstruct
     public void postConstruct(InvocationContext ctx)
     {
        Events.instance().raiseEvent("org.jboss.seam.postConstruct." + component.getName());
     }
     @PreDestroy
     public void preDestroy(InvocationContext ctx)
     {
        Events.instance().raiseEvent("org.jboss.seam.preDestroy." + component.getName());
     }
     @PrePassivate
     public void prePassivate(InvocationContext ctx)
     {
        Events.instance().raiseEvent("org.jboss.seam.prePassivate." + component.getName());
     }
     
     @PostActivate
     public void postActivate(InvocationContext ctx)
     {
        Events.instance().raiseEvent("org.jboss.seam.postActivate." + component.getName());
     }*/
     @AroundInvoke
     public Object aroundInvoke(InvocationContext ctx) throws Exception
     {
        Object result = ctx.proceed();
        Method method = ctx.getMethod();
        if ( result!=null || method.getReturnType().equals(void.class) )
        {
           if ( method.isAnnotationPresent(RaiseEvent.class) )
           {
              String[] types = method.getAnnotation(RaiseEvent.class).value();
              if ( types.length==0 )
              {
                 Events.instance().raiseEvent( method.getName() );
              }
              else
              {
                 for (String type: types )
                 {
                    Events.instance().raiseEvent(type);
                 }
              }
           }
        }
        return result;
     }
  }
  
  
  
  1.1      date: 2007/06/25 23:59:30;  author: gavin;  state: Exp;jboss-seam/src/main/org/jboss/seam/core/MethodContextInterceptor.java
  
  Index: MethodContextInterceptor.java
  ===================================================================
  package org.jboss.seam.core;
  
  import java.lang.reflect.Method;
  
  import org.jboss.seam.Component;
  import org.jboss.seam.annotations.intercept.AroundInvoke;
  import org.jboss.seam.annotations.intercept.Interceptor;
  import org.jboss.seam.contexts.Context;
  import org.jboss.seam.contexts.Contexts;
  import org.jboss.seam.contexts.Lifecycle;
  import org.jboss.seam.intercept.AbstractInterceptor;
  import org.jboss.seam.intercept.InvocationContext;
  import org.jboss.seam.security.SecurityInterceptor;
  
  /**
   * Sets up the METHOD context and unproxies the SFSB 
   * for the duration of the call.
   * 
   * @author Gavin King
   *
   */
  @Interceptor(stateless=true, around={BijectionInterceptor.class, EventInterceptor.class, SecurityInterceptor.class})
  public class MethodContextInterceptor extends AbstractInterceptor
  {
     private static final long serialVersionUID = 6833040683938889232L;
     @AroundInvoke
     public Object aroundInvoke(InvocationContext ctx) throws Exception
     {
        Component comp = getComponent();
        String name = comp.getName();
        Object target = ctx.getTarget();
        Method method = ctx.getMethod();
        Object[] parameters = ctx.getParameters();
        Context outerMethodContext = Lifecycle.beginMethod();
        try
        {
           Contexts.getMethodContext().set(name, target);
           Contexts.getMethodContext().set("org.jboss.seam.this", target);
           Contexts.getMethodContext().set("org.jboss.seam.method", method);
           Contexts.getMethodContext().set("org.jboss.seam.parameters", parameters);
           Contexts.getMethodContext().set("org.jboss.seam.component", comp);
           return ctx.proceed();
        }
        finally
        {
           Lifecycle.endMethod(outerMethodContext);
        }
     }
  }
  
  
  
  1.1      date: 2007/06/25 23:59:30;  author: gavin;  state: Exp;jboss-seam/src/main/org/jboss/seam/core/SynchronizationInterceptor.java
  
  Index: SynchronizationInterceptor.java
  ===================================================================
  //$Id: SynchronizationInterceptor.java,v 1.1 2007/06/25 23:59:30 gavin Exp $
  package org.jboss.seam.core;
  
  import java.util.concurrent.TimeUnit;
  import java.util.concurrent.locks.ReentrantLock;
  
  import org.jboss.seam.annotations.intercept.AroundInvoke;
  import org.jboss.seam.annotations.intercept.Interceptor;
  import org.jboss.seam.annotations.intercept.InterceptorType;
  import org.jboss.seam.intercept.AbstractInterceptor;
  import org.jboss.seam.intercept.InvocationContext;
  
  /**
   * Serializes calls to a component.
   * 
   * @author Gavin King
   */
  @Interceptor(type=InterceptorType.CLIENT)
  public class SynchronizationInterceptor extends AbstractInterceptor
  {
     private static final long serialVersionUID = -4173880108889358566L;
     
     private ReentrantLock lock = new ReentrantLock(true);
     
     @AroundInvoke
     public Object aroundInvoke(InvocationContext invocation) throws Exception
     {
        if ( lock.tryLock( getComponent().getTimeout(), TimeUnit.MILLISECONDS ) )
        {
           try
           {
              return invocation.proceed();
           }
           finally
           {
              lock.unlock();
           }
        }
        else
        {
           throw new IllegalStateException("could not acquire lock on @Synchronized component: " + getComponent().getName());
        }
     }
  
  }
  
  
  



More information about the jboss-cvs-commits mailing list