Package org.jboss.seam.contexts

Source Code of org.jboss.seam.contexts.Lifecycle

/*
* 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.Set;

import javax.faces.context.ExternalContext;
import javax.faces.event.PhaseId;
import javax.servlet.ServletContext;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpSession;

import org.jboss.seam.Component;
import org.jboss.seam.ScopeType;
import org.jboss.seam.Seam;
import org.jboss.seam.core.BusinessProcess;
import org.jboss.seam.core.ConversationEntries;
import org.jboss.seam.core.Init;
import org.jboss.seam.core.Manager;
import org.jboss.seam.core.Mutable;
import org.jboss.seam.log.LogProvider;
import org.jboss.seam.log.Logging;

/**
* @author Gavin King
* @author <a href="mailto:theute@jboss.org">Thomas Heute</a>
* @version $Revision: 1.85 $
*/
public class Lifecycle
{

   private static final LogProvider log = Logging.getLogProvider(Lifecycle.class);

   public static void beginRequest(ExternalContext externalContext)
   {
      log.debug( ">>> Begin web request" );
      Contexts.eventContext.set( new WebRequestContext( ContextAdaptor.getRequest(externalContext) ) );
      Contexts.sessionContext.set( new WebSessionContext( ContextAdaptor.getSession(externalContext) ) );
      Contexts.applicationContext.set( new FacesApplicationContext(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 beginRequest(ServletContext servletContext, HttpSession session, ServletRequest request)
   {
      log.debug( ">>> Begin web request" );
      Contexts.eventContext.set( new WebRequestContext( ContextAdaptor.getRequest(request) ) );
      Contexts.sessionContext.set( new WebSessionContext( ContextAdaptor.getSession(session) ) );
      Contexts.applicationContext.set( new WebApplicationContext(servletContext) );
      Contexts.conversationContext.set(null); //in case endRequest() was never called
   }

   public static void beginCall()
   {
      log.debug( ">>> Begin call" );
      Contexts.eventContext.set( new MapContext(ScopeType.EVENT) );
      Contexts.sessionContext.set( new MapContext(ScopeType.SESSION) );
      Contexts.conversationContext.set( new MapContext(ScopeType.CONVERSATION) );
      Contexts.businessProcessContext.set( new BusinessProcessContext() );
      Contexts.applicationContext.set( new WebApplicationContext( getServletContext() ) );
   }

   public static void endCall()
   {
      try
      {
         Contexts.destroy( Contexts.getSessionContext() );
         flushAndDestroyContexts();
         if ( Manager.instance().isLongRunningConversation() )
         {
            throw new IllegalStateException("Do not start long-running conversations in direct calls to EJBs");
         }
      }
      finally
      {
         clearThreadlocals();
         log.debug( "<<< End call" );
      }

   }

   public static void mockApplication()
   {
      Contexts.applicationContext.set( new WebApplicationContext( getServletContext() ) );
   }

   public static void unmockApplication()
   {
      Contexts.applicationContext.set(null);
   }

   public static Context beginMethod()
   {
      Context result = Contexts.methodContext.get();
      Contexts.methodContext.set( new MapContext(ScopeType.METHOD) );
      return result;
   }

   public static void endMethod(Context context)
   {
      Contexts.methodContext.set(context);
   }

   public static void beginInitialization(ServletContext servletContext)
   {
      Contexts.applicationContext.set( new WebApplicationContext(servletContext) );
      Contexts.eventContext.set( new MapContext(ScopeType.EVENT) );
      Contexts.conversationContext.set( new MapContext(ScopeType.CONVERSATION) );
   }

   public static void beginReinitialization(ServletContext servletContext, HttpSession session)
   {
      Contexts.applicationContext.set( new WebApplicationContext(servletContext) );
      Contexts.eventContext.set( new MapContext(ScopeType.EVENT) );
      Contexts.sessionContext.set( new WebSessionContext( ContextAdaptor.getSession(session) ) );
      Contexts.conversationContext.set( new MapContext(ScopeType.CONVERSATION) );
   }

   public static void beginExceptionRecovery(ExternalContext externalContext)
   {
      Contexts.applicationContext.set( new FacesApplicationContext(externalContext) );
      Contexts.eventContext.set( new WebRequestContext( ContextAdaptor.getRequest(externalContext) ) );
      Contexts.sessionContext.set( new WebSessionContext( ContextAdaptor.getSession(externalContext) ) );
      Contexts.conversationContext.set( new ServerConversationContext( ContextAdaptor.getSession(externalContext) ) );
      Contexts.pageContext.set(null);
      Contexts.businessProcessContext.set(null); //TODO: is this really correct?
   }

   public static void endInitialization()
   {
     //instantiate all application-scoped @Startup components
      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.APPLICATION )
           {
               startup(component);
           }
         }
      }

      Contexts.destroy( Contexts.getConversationContext() );
      Contexts.conversationContext.set(null);
      Contexts.destroy( Contexts.getEventContext() );
      Contexts.eventContext.set(null);
      Contexts.sessionContext.set(null);
      Contexts.applicationContext.set(null);
   }

   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() ) )
      {
         log.info("starting up: " + component.getName());
         component.newInstance();
      }
   }

   public static void endApplication(ServletContext servletContext)
   {
      log.debug("Undeploying, destroying application context");

      Context tempApplicationContext = new WebApplicationContext(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, ContextAdaptor session)
   {
      log.debug("Session started");
     
      //Normally called synchronously with a JSF request, but there are some
      //special cases!

      boolean applicationContextActive = Contexts.isApplicationContextActive();
      boolean eventContextActive = Contexts.isEventContextActive();
      boolean conversationContextActive = Contexts.isConversationContextActive();
      if ( !applicationContextActive )
      {
         Context tempApplicationContext = new WebApplicationContext(servletContext);
         Contexts.applicationContext.set(tempApplicationContext);
      }
      Context tempEventContext = null;
      if ( !eventContextActive )
      {
         tempEventContext = new MapContext(ScopeType.EVENT);
         Contexts.eventContext.set(tempEventContext);
      }
      Context tempConversationContext = null;
      if ( !conversationContextActive )
      {
         tempConversationContext = new MapContext(ScopeType.CONVERSATION);
         Contexts.conversationContext.set(tempConversationContext);
      }

      Context tempSessionContext = new WebSessionContext(session);
      Contexts.sessionContext.set(tempSessionContext);

      //instantiate all session-scoped @Startup components
      for ( String name : Contexts.getApplicationContext().getNames() )
      {
         Object object = Contexts.getApplicationContext().get(name);
         if ( object!=null && (object instanceof Component) )
         {
            Component component = (Component) object;
            if ( component.isStartup() && component.getScope() == ScopeType.SESSION )
            {
               startup(component);
            }
         }
      }

      Contexts.sessionContext.set(null);
     
      if ( !conversationContextActive )
      {
         Contexts.destroy(tempConversationContext);
         Contexts.conversationContext.set(null);
      }
      if ( !eventContextActive )
      {
         Contexts.destroy(tempEventContext);
         Contexts.eventContext.set(null);
      }
      if ( !applicationContextActive )
      {
         Contexts.applicationContext.set(null);
      }
     
   }

   public static void endSession(ServletContext servletContext, ContextAdaptor session)
   {
      log.debug("End of session, destroying contexts");
     
      //This code assumes that sessions are only destroyed at the very end of a 
      //web request, after the request-bound context objects have been destroyed,
      //or during session timeout, when there are no request-bound contexts.
     
      if ( Contexts.isEventContextActive() || Contexts.isApplicationContextActive() )
      {
         throw new IllegalStateException("Please end the HttpSession via Seam.invalidateSession()");
      }
     
      Context tempApplicationContext = new WebApplicationContext(servletContext);
      Contexts.applicationContext.set(tempApplicationContext);

      //this is used just as a place to stick the ConversationManager
      Context tempEventContext = new MapContext(ScopeType.EVENT);
      Contexts.eventContext.set(tempEventContext);

      //this is used (a) for destroying session-scoped components
      //and is also used (b) by the ConversationManager
      Context tempSessionContext = new WebSessionContext(session);
      Contexts.sessionContext.set(tempSessionContext);

      Set<String> conversationIds = ConversationEntries.instance().getConversationIds();
      log.debug("destroying conversation contexts: " + conversationIds);
      for (String conversationId: conversationIds)
      {
         destroyConversationContext(session, conversationId);
      }
     
      //we need some conversation-scope components for destroying
      //the session context...
      Context tempConversationContext = new MapContext(ScopeType.CONVERSATION);
      Contexts.conversationContext.set(tempConversationContext);

      log.debug("destroying session context");
      Contexts.destroy(tempSessionContext);
      Contexts.sessionContext.set(null);
     
      Contexts.destroy(tempConversationContext);
      Contexts.conversationContext.set(null);

      Contexts.destroy(tempEventContext);
      Contexts.eventContext.set(null);

      Contexts.applicationContext.set(null);
   }

   public static void endRequest(ExternalContext externalContext)
   {

      log.debug("After render response, destroying contexts");
      try
      {
         flushAndDestroyContexts();

         if ( Seam.isSessionInvalid() )
         {
            clearThreadlocals();
            Lifecycle.setPhaseId(null);
            ContextAdaptor.getSession(externalContext).invalidate(); //huh? we create a session just to invalidate it?
            //actual session context will be destroyed from the listener
         }
      }
      finally
      {
         clearThreadlocals();
      }

      log.debug( "<<< End web request" );
   }

   public static void endRequest()
   {

      log.debug("After request, destroying contexts");
     
      try
      {
         flushAndDestroyContexts();
      }
      finally
      {
         clearThreadlocals();
      }

      log.debug( "<<< End web request" );
   }

   public static void endRequest(HttpSession session)
   {

      log.debug("After request, destroying contexts");

      try
      {
         flushAndDestroyContexts();

         if ( Seam.isSessionInvalid() )
         {
            clearThreadlocals();
            ContextAdaptor.getSession(session).invalidate(); //huh? we create a session just to invalidate it?
            //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() )
         {
            //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
         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( ContextAdaptor.getSession(externalContext) );
      Contexts.conversationContext.set( conversationContext );
      Contexts.businessProcessContext.set( new BusinessProcessContext() );
   }

   public static void resumeConversation(HttpSession session)
   {
      Context conversationContext = new ServerConversationContext( ContextAdaptor.getSession(session) );
      Contexts.conversationContext.set( conversationContext );
      Contexts.businessProcessContext.set( new BusinessProcessContext() );
   }

   private static ThreadLocal<PhaseId> phaseId = new ThreadLocal<PhaseId>();

   public static PhaseId getPhaseId()
   {
      return phaseId.get();
   }

   public static void setPhaseId(PhaseId phase)
   {
      phaseId.set(phase);
   }

   private static ThreadLocal<ServletRequest> servletRequest = new ThreadLocal<ServletRequest>();
   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;
   }

   public static ServletRequest getServletRequest()
   {
      return servletRequest.get();
   }

   public static void setServletRequest(ServletRequest servletRequest)
   {
      Lifecycle.servletRequest.set(servletRequest);
   }

   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(ContextAdaptor session, String conversationId)
   {
      ServerConversationContext conversationContext = new ServerConversationContext(session, conversationId);
      Context old = Contexts.getConversationContext();
      Contexts.conversationContext.set(conversationContext);
      try
      {
         Contexts.destroy(conversationContext);
         if ( !Seam.isSessionInvalid() ) //its also unnecessary during a session timeout
         {
            conversationContext.clear();
            conversationContext.flush();
         }
      }
      finally
      {
         Contexts.conversationContext.set(old);
      }
   }

}
TOP

Related Classes of org.jboss.seam.contexts.Lifecycle

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.