/* * 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 java.util.Set; import org.jboss.seam.ScopeType; import org.jboss.seam.core.ConversationEntries; import org.jboss.seam.core.Manager; import org.jboss.seam.log.LogProvider; import org.jboss.seam.log.Logging; /** * Methods for setup and teardown of Seam contexts. * * @author Gavin King * @author <a href="mailto:theute@jboss.org">Thomas Heute</a> */ public class Lifecycle { private static final LogProvider log = Logging.getLogProvider(Lifecycle.class); private static ThreadLocal<Boolean> destroying = new ThreadLocal<Boolean>(); private static Map<String, Object> application; public static Map<String, Object> getApplication() { if (!isApplicationInitialized()) { throw new IllegalStateException("Attempted to invoke a Seam component outside an initialized application"); } return application; } public static boolean isApplicationInitialized() { return application!=null; } public static void beginApplication(Map<String, Object> app) { application = app; } public static void endApplication() { endApplication(application); } public static void endApplication(Map<String,Object> app) { log.debug("Shutting down application and destroying contexts"); Context tempApplicationContext = new ApplicationContext( app ); 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 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 void beginCall() { log.debug( ">>> Begin call" ); Contexts.applicationContext.set( new ApplicationContext(getApplication()) ); Contexts.eventContext.set( new BasicContext(ScopeType.EVENT) ); Contexts.sessionContext.set( new BasicContext(ScopeType.SESSION) ); Contexts.conversationContext.set( new BasicContext(ScopeType.CONVERSATION) ); Contexts.businessProcessContext.set( new BusinessProcessContext() ); } public static void endCall() { try { Contexts.destroy( Contexts.getSessionContext() ); Contexts.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" ); } } /** * @deprecated Use {@link Lifecycle#setupApplication()} */ @Deprecated public static void mockApplication() { setupApplication(null); } /** * @deprecated Use {@link Lifecycle#cleanupApplication()} */ @Deprecated public static void unmockApplication() { cleanupApplication(); } public static void setupApplication() { Contexts.applicationContext.set( new ApplicationContext(getApplication()) ); } public static void setupApplication(Map<String, Object> appCtx) { Contexts.applicationContext.set(new ApplicationContext(appCtx)); } public static void cleanupApplication() { Contexts.applicationContext.set(null); } public static Context beginMethod() { Context result = Contexts.methodContext.get(); Contexts.methodContext.set( new BasicContext(ScopeType.METHOD) ); return result; } public static void endMethod(Context context) { Contexts.methodContext.set(context); } public static void endRequest() { log.debug("After request, destroying contexts"); try { Contexts.flushAndDestroyContexts(); } finally { clearThreadlocals(); log.debug( "<<< End web request" ); } } 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); } public static void destroyConversationContext(Map<String, Object> session, String conversationId) { Contexts.destroyConversationContext(session, conversationId); } @Deprecated public static void beginSession(Map<String, Object> session) { beginSession(session,null); } public static void beginSession(Map<String, Object> session, Map<String,Object> appCtx) { 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 = null; if(appCtx == null) { tempApplicationContext= new ApplicationContext( getApplication() ); } else { tempApplicationContext = new ApplicationContext(appCtx); } Contexts.applicationContext.set(tempApplicationContext); } Context oldSessionContext = Contexts.sessionContext.get(); Contexts.sessionContext.set( new SessionContext(session) ); //we have to use the session object that came in the sessionCreated() event Context tempEventContext = null; if ( !eventContextActive ) { tempEventContext = new BasicContext(ScopeType.EVENT); Contexts.eventContext.set(tempEventContext); } Context tempConversationContext = null; if ( !conversationContextActive ) { tempConversationContext = new BasicContext(ScopeType.CONVERSATION); Contexts.conversationContext.set(tempConversationContext); } Contexts.startup(ScopeType.SESSION); if ( !conversationContextActive ) { Contexts.destroy(tempConversationContext); Contexts.conversationContext.set(null); } if ( !eventContextActive ) { Contexts.destroy(tempEventContext); Contexts.eventContext.set(null); } Contexts.sessionContext.set(oldSessionContext); //replace the one from sessionCreated() with the one from JSF, or null if ( !applicationContextActive ) { Contexts.applicationContext.set(null); } } public static void endSession(Map<String, Object> session) { endSession(session, application); } public static void endSession(Map<String, Object> session, Map<String,Object> app) { 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 org.jboss.seam.web.Session.instance().invalidate()"); } Context tempApplicationContext = new ApplicationContext( app ); Contexts.applicationContext.set(tempApplicationContext); //this is used just as a place to stick the ConversationManager Context tempEventContext = new BasicContext(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 SessionContext(session); Contexts.sessionContext.set(tempSessionContext); Set<String> conversationIds = ConversationEntries.instance().getConversationIds(); log.debug("destroying conversation contexts: " + conversationIds); for (String conversationId: conversationIds) { Contexts.destroyConversationContext(session, conversationId); } //we need some conversation-scope components for destroying //the session context... Context tempConversationContext = new BasicContext(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); } }