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

Gavin King gavin.king at jboss.com
Wed Jun 20 04:23:17 EDT 2007


  User: gavin   
  Date: 07/06/20 04:23:17

  Modified:    src/main/org/jboss/seam/contexts          Contexts.java
                        ContextualHttpServletRequest.java Lifecycle.java
                        PageContext.java ServerConversationContext.java
                        SessionContext.java
  Added:       src/main/org/jboss/seam/contexts         
                        FacesLifecycle.java ServletLifecycle.java
                        TestLifecycle.java
  Log:
  split up Lifecycle, much better
  
  Revision  Changes    Path
  1.52      +191 -8    jboss-seam/src/main/org/jboss/seam/contexts/Contexts.java
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: Contexts.java
  ===================================================================
  RCS file: /cvsroot/jboss/jboss-seam/src/main/org/jboss/seam/contexts/Contexts.java,v
  retrieving revision 1.51
  retrieving revision 1.52
  diff -u -b -r1.51 -r1.52
  --- Contexts.java	20 Jun 2007 05:06:40 -0000	1.51
  +++ Contexts.java	20 Jun 2007 08:23:17 -0000	1.52
  @@ -1,23 +1,31 @@
   /*
  - * JBoss, Home of Professional Open Source
  - *
  - * Distributable under LGPL license.
  - * See terms of license at gnu.org.
  - */
  + * JBoss, Home of Professional Open Source
  + *
  + * Distributable under LGPL license.
  + * See terms of license at gnu.org.
  + */
   package org.jboss.seam.contexts;
   
   import static org.jboss.seam.InterceptionType.NEVER;
   import static org.jboss.seam.annotations.Install.BUILT_IN;
   
  -import org.jboss.seam.log.LogProvider;
  -import org.jboss.seam.log.Logging;
  +import java.util.Map;
  +
   import org.jboss.seam.Component;
   import org.jboss.seam.ScopeType;
   import org.jboss.seam.annotations.Install;
   import org.jboss.seam.annotations.Intercept;
   import org.jboss.seam.annotations.Name;
   import org.jboss.seam.annotations.Scope;
  +import org.jboss.seam.bpm.BusinessProcess;
   import org.jboss.seam.core.Events;
  +import org.jboss.seam.core.Init;
  +import org.jboss.seam.core.Manager;
  +import org.jboss.seam.core.Mutable;
  +import org.jboss.seam.core.ServletSession;
  +import org.jboss.seam.log.LogProvider;
  +import org.jboss.seam.log.Logging;
  +import org.jboss.seam.transaction.Transaction;
   
   /**
    * Provides access to the current contexts associated with the thread.
  @@ -112,6 +120,9 @@
           return businessProcessContext.get() != null;
       }
      
  +    /**
  +     * Remove the named component from all contexts.
  +     */
      public static void removeFromAllContexts(String name)
      {
         log.debug("removing from all contexts: " + name);
  @@ -145,6 +156,13 @@
         }
      }
   
  +   /**
  +    * Search for a named attribute in all contexts, in the
  +    * following order: method, event, page, conversation,
  +    * session, business process, application.
  +    * 
  +    * @return the first component found, or null
  +    */
      public static Object lookupInStatefulContexts(String name)
      {
         if (isMethodContextActive())
  @@ -167,7 +185,7 @@
            }
         }
         
  -      if ( isPageContextActive() && Lifecycle.getPhaseId()!=null ) // phase id is null when third-party phase listeners try to do stuff
  +      if ( isPageContextActive() )
         {
            Object result = getPageContext().get(name);
            if (result!=null)
  @@ -221,6 +239,9 @@
         
      }
      
  +   /**
  +    * Destroy all components in the given context
  +    */
      public static void destroy(Context context)
      {
         if ( Events.exists() ) Events.instance().raiseEvent("org.jboss.seam.preDestroyContext." + context.getType().toString());
  @@ -251,4 +272,166 @@
         if ( Events.exists() ) Events.instance().raiseEvent("org.jboss.seam.postDestroyContext." + context.getType().toString());
      }
      
  +   /**
  +    * Startup all @Startup components in the given scope
  +    */
  +   static void startup(ScopeType scopeType)
  +   {
  +      Context context = Contexts.getApplicationContext();
  +      for ( String name: context.getNames() )
  +      {
  +         Object object = context.get(name);
  +         if ( object!=null && (object instanceof Component) )
  +         {
  +            Component component = (Component) object;
  +            if ( component.isStartup() && component.getScope()==scopeType )
  +            {
  +               startup(component);
  +            }
  +         }
  +      }
  +   }
  +
  +   /**
  +    * Startup a component and all its dependencies
  +    */
  +   static void startup(Component component)
  +   {
  +      if ( component.isStartup() )
  +      {
  +         for ( String dependency: component.getDependencies() )
  +         {
  +            Component dependentComponent = Component.forName(dependency);
  +            if (dependentComponent!=null)
  +            {
  +               startup(dependentComponent);
  +            }
  +         }
  +      }
  +
  +      if ( !component.getScope().getContext().isSet( component.getName() ) ) 
  +      {
  +         log.info( "starting up: " + component.getName() );
  +         component.newInstance();
  +      }
  +   }
  +
  +   /**
  +    * Does this context attribute need to be force-replicated?
  +    */
  +   static boolean isAttributeDirty(Object attribute)
  +   {
  +      return attribute instanceof Mutable && ( (Mutable) attribute ).clearDirty();
  +   }
  +
  +   /**
  +    * At the end of a request, flush all contexts to their underlying
  +    * persistent stores, or destroy their attributes (one or the other!).
  +    */
  +   static void flushAndDestroyContexts()
  +   {
  +   
  +      if ( isConversationContextActive() )
  +      {
  +   
  +         if ( isBusinessProcessContextActive() )
  +         {
  +            boolean transactionActive = false;
  +            try
  +            {
  +               transactionActive = Transaction.instance().isActive();
  +            }
  +            catch (Exception e)
  +            {
  +               log.error("could not discover transaction status");
  +            }
  +            if (transactionActive)
  +            {
  +               //in calls to MDBs and remote calls to SBs, the 
  +               //transaction doesn't commit until after contexts
  +               //are destroyed, so pre-emptively flush here:
  +               getBusinessProcessContext().flush();
  +            }
  +            
  +            //TODO: it would be nice if BP context spanned redirects along with the conversation
  +            //      this would also require changes to BusinessProcessContext
  +            boolean destroyBusinessProcessContext = !Init.instance().isJbpmInstalled() ||
  +                  !BusinessProcess.instance().hasActiveProcess();
  +            if (destroyBusinessProcessContext)
  +            {
  +               //TODO: note that this occurs from Lifecycle.endRequest(), after
  +               //      the Seam-managed txn was committed, but Contexts.destroy()
  +               //      calls BusinessProcessContext.getNames(), which hits the
  +               //      database!
  +               log.debug("destroying business process context");
  +               destroy( getBusinessProcessContext() );
  +            }
  +         }
  +   
  +         if ( !Manager.instance().isLongRunningConversation() )
  +         {
  +            log.debug("destroying conversation context");
  +            destroy( getConversationContext() );
  +         }
  +         if ( !Init.instance().isClientSideConversations() )
  +         {
  +            //note that we need to flush even if the session is
  +            //about to be invalidated, since we still need
  +            //to destroy the conversation context in endSession()
  +            log.debug("flushing server-side conversation context");
  +            getConversationContext().flush();
  +         }
  +   
  +         //uses the event and session contexts
  +         if ( ServletSession.getInstance()!=null )
  +         {
  +            Manager.instance().unlockConversation();
  +         }
  +   
  +      }
  +      
  +      if ( isSessionContextActive() )
  +      {
  +         log.debug("flushing session context");
  +         getSessionContext().flush();
  +      }
  +      
  +      //destroy the event context after the
  +      //conversation context, since we need
  +      //the manager to flush() conversation
  +      if ( isEventContextActive() )
  +      {
  +         log.debug("destroying event context");
  +         destroy( getEventContext() );
  +      }
  +   
  +   }
  +
  +   /**
  +    * Destroy a conversation context that is not currently bound to the request, called 
  +    * due to a timeout.
  +    * 
  +    * @param session the current session, to which both current and destroyed conversation belong
  +    * @param conversationId the conversation id of the conversation to be destroyed
  +    */
  +   static void destroyConversationContext(Map<String, Object> session, String conversationId)
  +   {
  +      Context current = getConversationContext();
  +      ServerConversationContext temp = new ServerConversationContext(session, conversationId);
  +      conversationContext.set(temp);
  +      try
  +      {
  +         destroy(temp);
  +         if ( !ServletSession.instance().isInvalid() ) //its also unnecessary during a session timeout
  +         {
  +            temp.clear();
  +            temp.flush();
  +         }
  +      }
  +      finally
  +      {
  +         conversationContext.set(current);
  +      }
  +   }
  +
   }
  
  
  
  1.3       +4 -7      jboss-seam/src/main/org/jboss/seam/contexts/ContextualHttpServletRequest.java
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: ContextualHttpServletRequest.java
  ===================================================================
  RCS file: /cvsroot/jboss/jboss-seam/src/main/org/jboss/seam/contexts/ContextualHttpServletRequest.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -b -r1.2 -r1.3
  --- ContextualHttpServletRequest.java	19 Jun 2007 19:02:31 -0000	1.2
  +++ ContextualHttpServletRequest.java	20 Jun 2007 08:23:17 -0000	1.3
  @@ -2,7 +2,6 @@
   
   import java.io.IOException;
   
  -import javax.servlet.ServletContext;
   import javax.servlet.ServletException;
   import javax.servlet.http.HttpServletRequest;
   
  @@ -18,12 +17,10 @@
      private static final LogProvider log = Logging.getLogProvider(ContextualHttpServletRequest.class);
   
      private final HttpServletRequest request;
  -   private final ServletContext servletContext;
      
  -   public ContextualHttpServletRequest(HttpServletRequest request, ServletContext servletContext)
  +   public ContextualHttpServletRequest(HttpServletRequest request)
      {
         this.request = request;
  -      this.servletContext = servletContext;
      }
      
      public abstract void process() throws Exception;
  @@ -31,18 +28,18 @@
      public void run() throws ServletException, IOException
      {
         log.debug("beginning request");
  -      Lifecycle.beginRequest(servletContext, request);
  +      ServletLifecycle.beginRequest(request);
         ServletContexts.instance().setRequest(request);
         restoreConversationId();
         Manager.instance().restoreConversation();
  -      Lifecycle.resumeConversation(request);
  +      ServletLifecycle.resumeConversation(request);
         handleConversationPropagation();
         try
         {
            process();
            //TODO: conversation timeout
            Manager.instance().endRequest( new ServletRequestSessionMap(request)  );
  -         Lifecycle.endRequest(request);
  +         ServletLifecycle.endRequest(request);
         }
         catch (IOException ioe)
         {
  
  
  
  1.101     +82 -416   jboss-seam/src/main/org/jboss/seam/contexts/Lifecycle.java
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: Lifecycle.java
  ===================================================================
  RCS file: /cvsroot/jboss/jboss-seam/src/main/org/jboss/seam/contexts/Lifecycle.java,v
  retrieving revision 1.100
  retrieving revision 1.101
  diff -u -b -r1.100 -r1.101
  --- Lifecycle.java	19 Jun 2007 19:02:31 -0000	1.100
  +++ Lifecycle.java	20 Jun 2007 08:23:17 -0000	1.101
  @@ -9,27 +9,11 @@
   import java.util.Map;
   import java.util.Set;
   
  -import javax.faces.context.ExternalContext;
  -import javax.faces.context.FacesContext;
  -import javax.servlet.ServletContext;
  -import javax.servlet.http.HttpServletRequest;
  -
  -import org.jboss.seam.Component;
   import org.jboss.seam.ScopeType;
  -import org.jboss.seam.bpm.BusinessProcess;
   import org.jboss.seam.core.ConversationEntries;
  -import org.jboss.seam.core.Events;
  -import org.jboss.seam.core.Init;
   import org.jboss.seam.core.Manager;
  -import org.jboss.seam.core.Mutable;
  -import org.jboss.seam.core.ServletSession;
   import org.jboss.seam.log.LogProvider;
   import org.jboss.seam.log.Logging;
  -import org.jboss.seam.navigation.Pages;
  -import org.jboss.seam.servlet.ServletApplicationMap;
  -import org.jboss.seam.servlet.ServletRequestMap;
  -import org.jboss.seam.servlet.ServletRequestSessionMap;
  -import org.jboss.seam.transaction.Transaction;
   
   /**
    * @author Gavin King
  @@ -38,30 +22,65 @@
   public class Lifecycle
   {
   
  -   private static final LogProvider log = Logging.getLogProvider(Lifecycle.class);
  +   static final LogProvider log = Logging.getLogProvider(Lifecycle.class);
  +
  +   private static ThreadLocal<Boolean> destroying = new ThreadLocal<Boolean>();
  +   private static Map<String, Object> application;
  +   private static ThreadLocal phaseId = new ThreadLocal();
  +
  +   public static Object getPhaseId()
  +   {
  +      return phaseId.get();
  +   }
   
  -   public static void beginRequest(ExternalContext externalContext) 
  +   static void setPhaseId(Object phase)
      {
  -      log.debug( ">>> Begin JSF request" );
  -      Contexts.eventContext.set( new EventContext( externalContext.getRequestMap() ) );
  -      Contexts.applicationContext.set( new ApplicationContext( externalContext.getApplicationMap() ) );
  -      Contexts.sessionContext.set( new SessionContext( externalContext.getSessionMap() ) );
  -      ServletSession servletSession = ServletSession.getInstance();
  -      if ( servletSession!=null && servletSession.isInvalidDueToNewScheme( Pages.getRequestScheme( FacesContext.getCurrentInstance() ) ) )
  +      phaseId.set(phase);
  +   }
  +   
  +   public static Map<String, Object> getApplication() 
  +   {
  +      if (application==null)
  +      {
  +         throw new IllegalStateException("Attempted to invoke a Seam component outside the an initialized application");
  +      }
  +      return application;
  +   }
  +
  +   public static void beginApplication(Map<String, Object> app) 
         {
  -         invalidateSession(externalContext);
  +      application = app;
         }
  -      Contexts.conversationContext.set(null); //in case endRequest() was never called
  -      //Events.instance(); //TODO: only for now, until we have a way to do EL outside of JSF!
  +   
  +   public static void endApplication()
  +   {
  +      log.debug("Undeploying, destroying application context");
  +
  +      Context tempApplicationContext = new ApplicationContext( getApplication() );
  +      Contexts.applicationContext.set(tempApplicationContext);
  +      Contexts.destroy(tempApplicationContext);
  +      Contexts.applicationContext.set(null);
  +      Contexts.eventContext.set(null);
  +      Contexts.sessionContext.set(null);
  +      Contexts.conversationContext.set(null);
  +      
  +      application = null;
      }
   
  -   public static void beginRequest(ServletContext servletContext, HttpServletRequest request) 
  +   public static void startDestroying()
      {
  -      log.debug( ">>> Begin web request" );
  -      Contexts.eventContext.set( new EventContext( new ServletRequestMap(request) ) );
  -      Contexts.sessionContext.set( new SessionContext( new ServletRequestSessionMap(request) ) );
  -      Contexts.applicationContext.set(new ApplicationContext( new ServletApplicationMap(servletContext) ) );
  -      Contexts.conversationContext.set(null); //in case endRequest() was never called
  +      destroying.set(true);
  +   }
  +
  +   public static void stopDestroying()
  +   {
  +      destroying.set(false);
  +   }
  +
  +   public static boolean isDestroying()
  +   {
  +      Boolean value = destroying.get();
  +      return value!=null && value.booleanValue();
      }
   
      public static void beginCall()
  @@ -71,7 +90,7 @@
         Contexts.sessionContext.set( new BasicContext(ScopeType.SESSION) );
         Contexts.conversationContext.set( new BasicContext(ScopeType.CONVERSATION) );
         Contexts.businessProcessContext.set( new BusinessProcessContext() );
  -      Contexts.applicationContext.set( new ApplicationContext( new ServletApplicationMap( getServletContext() ) ) );
  +      Contexts.applicationContext.set( new ApplicationContext(application) );
      }
   
      public static void endCall()
  @@ -79,7 +98,7 @@
         try
         {
            Contexts.destroy( Contexts.getSessionContext() );
  -         flushAndDestroyContexts();
  +         Contexts.flushAndDestroyContexts();
            if ( Manager.instance().isLongRunningConversation() )
            {
               throw new IllegalStateException("Do not start long-running conversations in direct calls to EJBs");
  @@ -92,25 +111,9 @@
         }
      }
   
  -   public static void beginTest(ServletContext context, Map<String, Object> session)
  -   {
  -      log.debug( ">>> Begin test" );
  -      Contexts.eventContext.set( new BasicContext(ScopeType.EVENT) );
  -      Contexts.conversationContext.set( new BasicContext(ScopeType.CONVERSATION) );
  -      Contexts.businessProcessContext.set( new BusinessProcessContext() );
  -      Contexts.sessionContext.set( new SessionContext(session) );
  -      Contexts.applicationContext.set( new ApplicationContext( new ServletApplicationMap(context) ) );
  -   }
  -
  -   public static void endTest()
  -   {
  -      clearThreadlocals();
  -      log.debug( "<<< End test" );
  -   }
  -
      public static void mockApplication()
      {
  -      Contexts.applicationContext.set( new ApplicationContext( new ServletApplicationMap( getServletContext() ) ) );
  +      Contexts.applicationContext.set( new ApplicationContext(application) );
      }
   
      public static void unmockApplication()
  @@ -130,107 +133,36 @@
         Contexts.methodContext.set(context);
      }
   
  -   public static void beginInitialization(ServletContext servletContext)
  +   public static void endRequest() 
      {
  -      log.debug(">>> Begin initialization");
  -      Contexts.applicationContext.set( new ApplicationContext( new ServletApplicationMap(servletContext) ) );
  -      Contexts.eventContext.set( new BasicContext(ScopeType.EVENT) );
  -      Contexts.conversationContext.set( new BasicContext(ScopeType.CONVERSATION) );
  -   }
  -
  -   public static void beginReinitialization(ServletContext servletContext, HttpServletRequest request)
  +      log.debug("After request, destroying contexts");  
  +      try
      {
  -      log.debug(">>> Begin re-initialization");
  -      Contexts.applicationContext.set( new ApplicationContext( new ServletApplicationMap(servletContext) ) );
  -      Contexts.eventContext.set( new BasicContext(ScopeType.EVENT) );
  -      Contexts.sessionContext.set( new SessionContext( new ServletRequestSessionMap(request) ) );
  -      Contexts.conversationContext.set( new BasicContext(ScopeType.CONVERSATION) );
  +         Contexts.flushAndDestroyContexts();
      }
  -
  -   public static void beginExceptionRecovery(ExternalContext externalContext)
  +      finally
      {
  -      log.debug(">>> Begin exception recovery");
  -      Contexts.applicationContext.set( new ApplicationContext( externalContext.getApplicationMap() ) );
  -      Contexts.eventContext.set( new EventContext( externalContext.getRequestMap() ) );
  -      Contexts.sessionContext.set( new SessionContext( externalContext.getSessionMap() ) );
  -      Contexts.conversationContext.set( new ServerConversationContext( externalContext.getSessionMap() ) );
  -      Contexts.pageContext.set(null);
  -      Contexts.businessProcessContext.set(null); //TODO: is this really correct?
  +         clearThreadlocals();
  +         log.debug( "<<< End web request" );
  +      }
      }
   
  -   public static void endInitialization()
  +   static void clearThreadlocals() 
      {
  -      startup(ScopeType.APPLICATION);
  -      
  -      Events.instance().raiseEvent("org.jboss.seam.postInitialization");
  -      
  -      // Clean up contexts used during initialization
  -      Contexts.destroy( Contexts.getConversationContext() );
  -      Contexts.conversationContext.set(null);
  -      Contexts.destroy( Contexts.getEventContext() );
         Contexts.eventContext.set(null);
  +      Contexts.pageContext.set(null);
         Contexts.sessionContext.set(null);
  +      Contexts.conversationContext.set(null);
  +      Contexts.businessProcessContext.set(null);
         Contexts.applicationContext.set(null);
  -      
  -      log.debug("<<< End initialization");
  -   }
  -   
  -   private static void startup(ScopeType scopeType)
  -   {
  -      // instantiate all components in the given scope
  -      Context context = Contexts.getApplicationContext();
  -      for ( String name: context.getNames() )
  -      {
  -         Object object = context.get(name);
  -         if ( object!=null && (object instanceof Component) )
  -         {
  -            Component component = (Component) object;
  -            if ( component.isStartup() && component.getScope()==scopeType )
  -            {
  -               startup(component);
  -            }
  -         }
  -      }
  -   }
  -
  -   private static void startup(Component component)
  -   {
  -      if ( component.isStartup() )
  -      {
  -         for ( String dependency: component.getDependencies() )
  -         {
  -            Component dependentComponent = Component.forName(dependency);
  -            if (dependentComponent!=null)
  -            {
  -               startup(dependentComponent);
  -            }
  -         }
         }
   
  -      if ( !component.getScope().getContext().isSet( component.getName() ) ) 
  +   public static void destroyConversationContext(Map<String, Object> session, String conversationId)
         {
  -         log.info( "starting up: " + component.getName() );
  -         component.newInstance();
  -      }
  +      Contexts.destroyConversationContext(session, conversationId);
      }
   
  -   public static void endApplication(ServletContext servletContext)
  -   {
  -      log.debug("Undeploying, destroying application context");
  -
  -      Context tempApplicationContext = new ApplicationContext( new ServletApplicationMap(servletContext) );
  -      Contexts.applicationContext.set(tempApplicationContext);
  -      Contexts.destroy(tempApplicationContext);
  -      Contexts.applicationContext.set(null);
  -      Contexts.eventContext.set(null);
  -      Contexts.sessionContext.set(null);
  -      Contexts.conversationContext.set(null);
  -   }
  -
  -  /***
  -    * Instantiate @Startup components for session scoped component
  -    */
  -   public static void beginSession(ServletContext servletContext, Map<String, Object> session)
  +   public static void beginSession(Map<String, Object> session)
      {
         log.debug("Session started");
         
  @@ -243,7 +175,7 @@
   
         if ( !applicationContextActive )
         {
  -         Context tempApplicationContext = new ApplicationContext( new ServletApplicationMap(servletContext) );
  +         Context tempApplicationContext = new ApplicationContext( getApplication() );
            Contexts.applicationContext.set(tempApplicationContext);
         }
         Context oldSessionContext = Contexts.sessionContext.get();
  @@ -261,7 +193,7 @@
            Contexts.conversationContext.set(tempConversationContext);
         }
   
  -      startup(ScopeType.SESSION);
  +      Contexts.startup(ScopeType.SESSION);
         
         if ( !conversationContextActive )
         {
  @@ -281,7 +213,7 @@
         
      }
   
  -   public static void endSession(ServletContext servletContext, Map<String, Object> session)
  +   public static void endSession(Map<String, Object> session)
      {
         log.debug("End of session, destroying contexts");
         
  @@ -294,7 +226,7 @@
            throw new IllegalStateException("Please end the HttpSession via Seam.invalidateSession()");
         }
         
  -      Context tempApplicationContext = new ApplicationContext( new ServletApplicationMap(servletContext) );
  +      Context tempApplicationContext = new ApplicationContext( getApplication() );
         Contexts.applicationContext.set(tempApplicationContext);
   
         //this is used just as a place to stick the ConversationManager
  @@ -310,7 +242,7 @@
         log.debug("destroying conversation contexts: " + conversationIds);
         for (String conversationId: conversationIds)
         {
  -         destroyConversationContext(session, conversationId);
  +         Contexts.destroyConversationContext(session, conversationId);
         }
         
         //we need some conversation-scope components for destroying
  @@ -331,270 +263,4 @@
         Contexts.applicationContext.set(null);
      }
   
  -   public static void endRequest(ExternalContext externalContext) 
  -   {
  -      log.debug("After render response, destroying contexts");
  -      try
  -      {
  -         ServletSession servletSession = ServletSession.getInstance();
  -         boolean sessionInvalid = servletSession!=null && servletSession.isInvalid();
  -         
  -         flushAndDestroyContexts();
  -
  -         if (sessionInvalid)
  -         {
  -            clearThreadlocals();
  -            Lifecycle.setPhaseId(null);
  -            invalidateSession(externalContext);
  -            //actual session context will be destroyed from the listener
  -         }
  -      }
  -      finally
  -      {
  -         clearThreadlocals();
  -         log.debug( "<<< End JSF request" );
  -      }
  -   }
  -   
  -   /**
  -    * Invalidate the session, no matter what kind of session it is
  -    * (portlet or servlet). Why is this method not on ExternalContext?!
  -    * Oh boy, those crazy rascals in the JSF EG...
  -    */
  -   public static void invalidateSession(ExternalContext externalContext)
  -   {
  -      Object session = externalContext.getSession(false);
  -      if (session!=null)
  -      {
  -         try
  -         {
  -            session.getClass().getMethod("invalidate").invoke(session);
  -         }
  -         catch (Exception e)
  -         {
  -            throw new RuntimeException(e);
  -         }
  -      }
  -   }
  -
  -   public static void endRequest() 
  -   {
  -      log.debug("After request, destroying contexts");  
  -      try
  -      {
  -         flushAndDestroyContexts();
  -      }
  -      finally
  -      {
  -         clearThreadlocals();
  -         log.debug( "<<< End web request" );
  -      }
  -   }
  -
  -   public static void endRequest(HttpServletRequest request) 
  -   {
  -      log.debug("After request, destroying contexts");
  -      try
  -      {
  -         ServletSession servletSession = ServletSession.getInstance();
  -         boolean sessionInvalid = servletSession!=null && servletSession.isInvalid();
  -         
  -         flushAndDestroyContexts();
  -
  -         if (sessionInvalid)
  -         {
  -            clearThreadlocals();
  -            request.getSession().invalidate();
  -            //actual session context will be destroyed from the listener
  -         }
  -      }
  -      finally
  -      {
  -         clearThreadlocals();
  -         log.debug( "<<< End web request" );
  -      }
  -   }
  -
  -   private static void clearThreadlocals() 
  -   {
  -      Contexts.eventContext.set(null);
  -      Contexts.pageContext.set(null);
  -      Contexts.sessionContext.set(null);
  -      Contexts.conversationContext.set(null);
  -      Contexts.businessProcessContext.set(null);
  -      Contexts.applicationContext.set(null);
  -   }
  -
  -   private static void flushAndDestroyContexts()
  -   {
  -
  -      if ( Contexts.isConversationContextActive() )
  -      {
  -
  -         if ( Contexts.isBusinessProcessContextActive() )
  -         {
  -            boolean transactionActive = false;
  -            try
  -            {
  -               transactionActive = Transaction.instance().isActive();
  -            }
  -            catch (Exception e)
  -            {
  -               log.error("could not discover transaction status");
  -            }
  -            if (transactionActive)
  -            {
  -               //in calls to MDBs and remote calls to SBs, the 
  -               //transaction doesn't commit until after contexts
  -               //are destroyed, so pre-emptively flush here:
  -               Contexts.getBusinessProcessContext().flush();
  -            }
  -            
  -            //TODO: it would be nice if BP context spanned redirects along with the conversation
  -            //      this would also require changes to BusinessProcessContext
  -            boolean destroyBusinessProcessContext = !Init.instance().isJbpmInstalled() ||
  -                  !BusinessProcess.instance().hasActiveProcess();
  -            if (destroyBusinessProcessContext)
  -            {
  -               //TODO: note that this occurs from Lifecycle.endRequest(), after
  -               //      the Seam-managed txn was committed, but Contexts.destroy()
  -               //      calls BusinessProcessContext.getNames(), which hits the
  -               //      database!
  -               log.debug("destroying business process context");
  -               Contexts.destroy( Contexts.getBusinessProcessContext() );
  -            }
  -         }
  -
  -         if ( !Manager.instance().isLongRunningConversation() )
  -         {
  -            log.debug("destroying conversation context");
  -            Contexts.destroy( Contexts.getConversationContext() );
  -         }
  -         if ( !Init.instance().isClientSideConversations() )
  -         {
  -            //note that we need to flush even if the session is
  -            //about to be invalidated, since we still need
  -            //to destroy the conversation context in endSession()
  -            log.debug("flushing server-side conversation context");
  -            Contexts.getConversationContext().flush();
  -         }
  -
  -         //uses the event and session contexts
  -         if ( ServletSession.getInstance()!=null )
  -         {
  -            Manager.instance().unlockConversation();
  -         }
  -
  -      }
  -      
  -      if ( Contexts.isSessionContextActive() )
  -      {
  -         log.debug("flushing session context");
  -         Contexts.getSessionContext().flush();
  -      }
  -      
  -      //destroy the event context after the
  -      //conversation context, since we need
  -      //the manager to flush() conversation
  -      if ( Contexts.isEventContextActive() )
  -      {
  -         log.debug("destroying event context");
  -         Contexts.destroy( Contexts.getEventContext() );
  -      }
  -
  -   }
  -
  -   public static void resumePage()
  -   {
  -      Contexts.pageContext.set( new PageContext() );
  -   }
  -
  -   public static void resumeConversation(ExternalContext externalContext)
  -   {
  -      Init init = Init.instance();
  -      Context conversationContext = init.isClientSideConversations() ?
  -            (Context) new ClientConversationContext() :
  -            (Context) new ServerConversationContext( externalContext.getSessionMap() );
  -      Contexts.conversationContext.set( conversationContext );
  -      Contexts.businessProcessContext.set( new BusinessProcessContext() );
  -   }
  -
  -   public static void resumeConversation(HttpServletRequest request)
  -   {
  -      Context conversationContext = new ServerConversationContext( new ServletRequestSessionMap(request) );
  -      Contexts.conversationContext.set( conversationContext );
  -      Contexts.businessProcessContext.set( new BusinessProcessContext() );
  -   }
  -
  -   private static ThreadLocal phaseId = new ThreadLocal();
  -
  -   public static Object getPhaseId()
  -   {
  -      return phaseId.get();
  -   }
  -
  -   public static void setPhaseId(Object phase)
  -   {
  -      phaseId.set(phase);
  -   }
  -
  -   private static ServletContext servletContext;
  -
  -   public static ServletContext getServletContext() 
  -   {
  -      if (servletContext==null)
  -      {
  -         throw new IllegalStateException("Attempted to invoke a Seam component outside the context of a web application");
  -      }
  -      return servletContext;
  -   }
  -
  -   public static void setServletContext(ServletContext servletContext) 
  -   {
  -      Lifecycle.servletContext = servletContext;
  -   }
  -
  -   private static ThreadLocal<Boolean> destroying = new ThreadLocal<Boolean>();
  -
  -   public static void startDestroying()
  -   {
  -      destroying.set(true);
  -   }
  -
  -   public static void stopDestroying()
  -   {
  -      destroying.set(false);
  -   }
  -
  -   public static boolean isDestroying()
  -   {
  -      Boolean value = destroying.get();
  -      return value!=null && value.booleanValue();
  -   }
  -
  -   public static boolean isAttributeDirty(Object attribute)
  -   {
  -      return attribute instanceof Mutable && ( (Mutable) attribute ).clearDirty();
  -   }
  -
  -   public static void destroyConversationContext(Map<String, Object> session, String conversationId)
  -   {
  -      ServerConversationContext conversationContext = new ServerConversationContext(session, conversationId);
  -      Context old = Contexts.getConversationContext();
  -      Contexts.conversationContext.set(conversationContext);
  -      try
  -      {
  -         Contexts.destroy(conversationContext);
  -         if ( !ServletSession.instance().isInvalid() ) //its also unnecessary during a session timeout
  -         {
  -            conversationContext.clear();
  -            conversationContext.flush();
  -         }
  -      }
  -      finally
  -      {
  -         Contexts.conversationContext.set(old);
  -      }
  -   }
  -
   }
  
  
  
  1.17      +17 -4     jboss-seam/src/main/org/jboss/seam/contexts/PageContext.java
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: PageContext.java
  ===================================================================
  RCS file: /cvsroot/jboss/jboss-seam/src/main/org/jboss/seam/contexts/PageContext.java,v
  retrieving revision 1.16
  retrieving revision 1.17
  diff -u -b -r1.16 -r1.17
  --- PageContext.java	19 Jun 2007 19:02:31 -0000	1.16
  +++ PageContext.java	20 Jun 2007 08:23:17 -0000	1.17
  @@ -7,6 +7,7 @@
   package org.jboss.seam.contexts;
   
   import java.util.ArrayList;
  +import java.util.Collections;
   import java.util.HashMap;
   import java.util.List;
   import java.util.Map;
  @@ -73,9 +74,16 @@
      
      private Map<String, Object> getCurrentReadableMap()
      {
  +      if ( !isInPhase() )
  +      {
  +         return Collections.EMPTY_MAP;
  +      }
  +      else
  +      {
         return isRenderResponsePhase() ?
               nextPageMap : previousPageMap;
      }
  +   }
   
      private Map<String, Object> getCurrentWritableMap()
      {
  @@ -148,12 +156,17 @@
   
      private static PhaseId getPhaseId()
      {
  -      Object phaseId = Lifecycle.getPhaseId();
  +      PhaseId phaseId = FacesLifecycle.getPhaseId();
         if (phaseId==null)
         {
            throw new IllegalStateException("No phase id bound to current thread (make sure you do not have two SeamPhaseListener instances installed)");
         }
  -      return (PhaseId) phaseId;
  +      return phaseId;
  +   }
  +   
  +   private static boolean isInPhase()
  +   {
  +      return FacesLifecycle.getPhaseId()!=null;
      }
   
      private static boolean isBeforeInvokeApplicationPhase()
  
  
  
  1.29      +1 -1      jboss-seam/src/main/org/jboss/seam/contexts/ServerConversationContext.java
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: ServerConversationContext.java
  ===================================================================
  RCS file: /cvsroot/jboss/jboss-seam/src/main/org/jboss/seam/contexts/ServerConversationContext.java,v
  retrieving revision 1.28
  retrieving revision 1.29
  diff -u -b -r1.28 -r1.29
  --- ServerConversationContext.java	17 Jun 2007 05:46:57 -0000	1.28
  +++ ServerConversationContext.java	20 Jun 2007 08:23:17 -0000	1.29
  @@ -239,7 +239,7 @@
            {
               String key = getKey(name);
               Object attribute = session.get(key);
  -            if ( attribute!=null && Lifecycle.isAttributeDirty(attribute) )
  +            if ( attribute!=null && Contexts.isAttributeDirty(attribute) )
               {
                  session.put(key, attribute);
               }
  
  
  
  1.4       +1 -1      jboss-seam/src/main/org/jboss/seam/contexts/SessionContext.java
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: SessionContext.java
  ===================================================================
  RCS file: /cvsroot/jboss/jboss-seam/src/main/org/jboss/seam/contexts/SessionContext.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -b -r1.3 -r1.4
  --- SessionContext.java	20 Jun 2007 05:06:40 -0000	1.3
  +++ SessionContext.java	20 Jun 2007 08:23:17 -0000	1.4
  @@ -45,7 +45,7 @@
         {
            Object attribute = get(name);
            boolean dirty = attribute!=null && 
  -               ( Lifecycle.isAttributeDirty(attribute) || Seam.isEntityClass( attribute.getClass() ) );
  +               ( Contexts.isAttributeDirty(attribute) || Seam.isEntityClass( attribute.getClass() ) );
            if ( dirty )
            {
               set(name, attribute);
  
  
  
  1.1      date: 2007/06/20 08:23:17;  author: gavin;  state: Exp;jboss-seam/src/main/org/jboss/seam/contexts/FacesLifecycle.java
  
  Index: FacesLifecycle.java
  ===================================================================
  /*
   * JBoss, Home of Professional Open Source
   *
   * Distributable under LGPL license.
   * See terms of license at gnu.org.
   */
  package org.jboss.seam.contexts;
  
  import javax.faces.context.ExternalContext;
  import javax.faces.context.FacesContext;
  import javax.faces.event.PhaseId;
  
  import org.jboss.seam.core.Init;
  import org.jboss.seam.core.ServletSession;
  import org.jboss.seam.log.LogProvider;
  import org.jboss.seam.log.Logging;
  import org.jboss.seam.navigation.Pages;
  
  /**
   * @author Gavin King
   * @author <a href="mailto:theute at jboss.org">Thomas Heute</a>
   */
  public class FacesLifecycle
  {
  
     private static final LogProvider log = Logging.getLogProvider(FacesLifecycle.class);
     
     public static void setPhaseId(PhaseId phase)
     {
        Lifecycle.setPhaseId(phase);
     }
     
     public static PhaseId getPhaseId()
     {
        return (PhaseId) Lifecycle.getPhaseId();
     }
  
     public static void clearPhaseId()
     {
        Lifecycle.setPhaseId(null);
     }
  
     public static void beginRequest(ExternalContext externalContext) 
     {
        log.debug( ">>> Begin JSF request" );
        Contexts.eventContext.set( new EventContext( externalContext.getRequestMap() ) );
        Contexts.applicationContext.set( new ApplicationContext( externalContext.getApplicationMap() ) );
        Contexts.sessionContext.set( new SessionContext( externalContext.getSessionMap() ) );
        ServletSession servletSession = ServletSession.getInstance();
        if ( servletSession!=null && servletSession.isInvalidDueToNewScheme( Pages.getRequestScheme( FacesContext.getCurrentInstance() ) ) )
        {
           invalidateSession(externalContext);
        }
        Contexts.conversationContext.set(null); //in case endRequest() was never called
        //Events.instance(); //TODO: only for now, until we have a way to do EL outside of JSF!
     }
  
     public static void beginExceptionRecovery(ExternalContext externalContext)
     {
        log.debug(">>> Begin exception recovery");
        Contexts.applicationContext.set( new ApplicationContext( externalContext.getApplicationMap() ) );
        Contexts.eventContext.set( new EventContext( externalContext.getRequestMap() ) );
        Contexts.sessionContext.set( new SessionContext( externalContext.getSessionMap() ) );
        Contexts.conversationContext.set( new ServerConversationContext( externalContext.getSessionMap() ) );
        Contexts.pageContext.set(null);
        Contexts.businessProcessContext.set(null); //TODO: is this really correct?
     }
  
     public static void endRequest(ExternalContext externalContext) 
     {
        log.debug("After render response, destroying contexts");
        try
        {
           ServletSession servletSession = ServletSession.getInstance();
           boolean sessionInvalid = servletSession!=null && servletSession.isInvalid();
           
           Contexts.flushAndDestroyContexts();
  
           if (sessionInvalid)
           {
              Lifecycle.clearThreadlocals();
              Lifecycle.setPhaseId(null);
              invalidateSession(externalContext);
              //actual session context will be destroyed from the listener
           }
        }
        finally
        {
           Lifecycle.clearThreadlocals();
           log.debug( "<<< End JSF request" );
        }
     }
     
     /**
      * Invalidate the session, no matter what kind of session it is
      * (portlet or servlet). Why is this method not on ExternalContext?!
      * Oh boy, those crazy rascals in the JSF EG...
      */
     public static void invalidateSession(ExternalContext externalContext)
     {
        Object session = externalContext.getSession(false);
        if (session!=null)
        {
           try
           {
              session.getClass().getMethod("invalidate").invoke(session);
           }
           catch (Exception e)
           {
              throw new RuntimeException(e);
           }
        }
     }
  
     public static void resumeConversation(ExternalContext externalContext)
     {
        Init init = Init.instance();
        Context conversationContext = init.isClientSideConversations() ?
              (Context) new ClientConversationContext() :
              (Context) new ServerConversationContext( externalContext.getSessionMap() );
        Contexts.conversationContext.set( conversationContext );
        Contexts.businessProcessContext.set( new BusinessProcessContext() );
     }
  
     public static void resumePage()
     {
        Contexts.pageContext.set( new PageContext() );
     }
  
  }
  
  
  
  1.1      date: 2007/06/20 08:23:17;  author: gavin;  state: Exp;jboss-seam/src/main/org/jboss/seam/contexts/ServletLifecycle.java
  
  Index: ServletLifecycle.java
  ===================================================================
  /*
   * JBoss, Home of Professional Open Source
   *
   * Distributable under LGPL license.
   * See terms of license at gnu.org.
   */
  package org.jboss.seam.contexts;
  
  import javax.servlet.ServletContext;
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpSession;
  
  import org.jboss.seam.ScopeType;
  import org.jboss.seam.core.Events;
  import org.jboss.seam.core.ServletSession;
  import org.jboss.seam.log.LogProvider;
  import org.jboss.seam.log.Logging;
  import org.jboss.seam.servlet.ServletApplicationMap;
  import org.jboss.seam.servlet.ServletRequestMap;
  import org.jboss.seam.servlet.ServletRequestSessionMap;
  import org.jboss.seam.servlet.ServletSessionMap;
  
  /**
   * @author Gavin King
   * @author <a href="mailto:theute at jboss.org">Thomas Heute</a>
   */
  public class ServletLifecycle
  {
  
     private static final LogProvider log = Logging.getLogProvider(ServletLifecycle.class);
  
     private static ServletContext servletContext;
  
     public static ServletContext getServletContext() 
     {
        if (servletContext==null)
        {
           throw new IllegalStateException("Attempted to invoke a Seam component outside the context of a web application");
        }
        return servletContext;
     }
  
     public static void beginRequest(HttpServletRequest request) 
     {
        log.debug( ">>> Begin web request" );
        Contexts.eventContext.set( new EventContext( new ServletRequestMap(request) ) );
        Contexts.sessionContext.set( new SessionContext( new ServletRequestSessionMap(request) ) );
        Contexts.applicationContext.set(new ApplicationContext( Lifecycle.getApplication() ) );
        Contexts.conversationContext.set(null); //in case endRequest() was never called
     }
  
     public static void endRequest(HttpServletRequest request) 
     {
        log.debug("After request, destroying contexts");
        try
        {
           ServletSession servletSession = ServletSession.getInstance();
           boolean sessionInvalid = servletSession!=null && servletSession.isInvalid();
           
           Contexts.flushAndDestroyContexts();
  
           if (sessionInvalid)
           {
              Lifecycle.clearThreadlocals();
              request.getSession().invalidate();
              //actual session context will be destroyed from the listener
           }
        }
        finally
        {
           Lifecycle.clearThreadlocals();
           log.debug( "<<< End web request" );
        }
     }
  
     public static void beginInitialization()
     {
        log.debug(">>> Begin initialization");
        Contexts.applicationContext.set( new ApplicationContext( Lifecycle.getApplication() ) );
        Contexts.eventContext.set( new BasicContext(ScopeType.EVENT) );
        Contexts.conversationContext.set( new BasicContext(ScopeType.CONVERSATION) );
     }
  
     public static void beginReinitialization(HttpServletRequest request)
     {
        log.debug(">>> Begin re-initialization");
        Contexts.applicationContext.set( new ApplicationContext( Lifecycle.getApplication() ) );
        Contexts.eventContext.set( new BasicContext(ScopeType.EVENT) );
        Contexts.sessionContext.set( new SessionContext( new ServletRequestSessionMap(request) ) );
        Contexts.conversationContext.set( new BasicContext(ScopeType.CONVERSATION) );
     }
  
     public static void endInitialization()
     {
        Contexts.startup(ScopeType.APPLICATION);
        
        Events.instance().raiseEvent("org.jboss.seam.postInitialization");
        
        // Clean up contexts used during initialization
        Contexts.destroy( Contexts.getConversationContext() );
        Contexts.conversationContext.set(null);
        Contexts.destroy( Contexts.getEventContext() );
        Contexts.eventContext.set(null);
        Contexts.sessionContext.set(null);
        Contexts.applicationContext.set(null);
        
        log.debug("<<< End initialization");
     }
  
     public static void beginApplication(ServletContext context) 
     {
        servletContext = context;
        Lifecycle.beginApplication( new ServletApplicationMap(context) );
     }
  
     public static void endApplication()
     {
        Lifecycle.endApplication();
        servletContext=null;
     }
  
     public static void beginSession(HttpSession session)
     {
        Lifecycle.beginSession( new ServletSessionMap(session) );
     }
  
     public static void endSession(HttpSession session)
     {
        Lifecycle.endSession( new ServletSessionMap(session) );
     }
  
     public static void resumeConversation(HttpServletRequest request)
     {
        Context conversationContext = new ServerConversationContext( new ServletRequestSessionMap(request) );
        Contexts.conversationContext.set( conversationContext );
        Contexts.businessProcessContext.set( new BusinessProcessContext() );
     }
  
  }
  
  
  
  1.1      date: 2007/06/20 08:23:17;  author: gavin;  state: Exp;jboss-seam/src/main/org/jboss/seam/contexts/TestLifecycle.java
  
  Index: TestLifecycle.java
  ===================================================================
  /*
   * JBoss, Home of Professional Open Source
   *
   * Distributable under LGPL license.
   * See terms of license at gnu.org.
   */
  package org.jboss.seam.contexts;
  
  import java.util.Map;
  
  import javax.servlet.ServletContext;
  
  import org.jboss.seam.ScopeType;
  import org.jboss.seam.log.LogProvider;
  import org.jboss.seam.log.Logging;
  import org.jboss.seam.servlet.ServletApplicationMap;
  
  /**
   * @author Gavin King
   */
  public class TestLifecycle
  {
  
     private static final LogProvider log = Logging.getLogProvider(TestLifecycle.class);
  
     public static void beginTest(ServletContext context, Map<String, Object> session)
     {
        log.debug( ">>> Begin test" );
        Contexts.eventContext.set( new BasicContext(ScopeType.EVENT) );
        Contexts.conversationContext.set( new BasicContext(ScopeType.CONVERSATION) );
        Contexts.businessProcessContext.set( new BusinessProcessContext() );
        Contexts.sessionContext.set( new SessionContext(session) );
        Contexts.applicationContext.set( new ApplicationContext( new ServletApplicationMap(context) ) );
     }
  
     public static void endTest()
     {
        Lifecycle.clearThreadlocals();
        log.debug( "<<< End test" );
     }
  
  }
  
  
  



More information about the jboss-cvs-commits mailing list