Package dyntabs.scope

Class TabScopedContextHolder

java.lang.Object
dyntabs.scope.TabScopedContextHolder

public class TabScopedContextHolder extends Object
Singleton class that stores all @TabScoped bean instances organized by HTTP session and by tab ID.

IMPORTANT: Bean instances are isolated per session! Each HTTP session has its own independent map of tabs and beans. This prevents cross-session data leaks (user A cannot see user B's beans).

Data structure:

 sessionTabBeans (Map)
   └── "session_abc" (HTTP session ID)
         └── "r0" (tab ID)
               └── Map<Contextual, BeanInstance>
                     ├── MyBean.class -> instance1
                     └── OtherBean.class -> instance2
         └── "r1" (tab ID)
               └── Map<Contextual, BeanInstance>
                     ├── MyBean.class -> instance3
                     └── ...
   └── "session_xyz" (another session)
         └── "r0" (tab ID - same as first session, but DIFFERENT beans!)
               └── ...
 
Author:
DynTabs
See Also:
  • Method Details

    • getInstance

      public static TabScopedContextHolder getInstance()
      Returns the singleton instance of the holder.
      Returns:
      the singleton instance
    • setCurrentTabId

      public static void setCurrentTabId(String tabId)
      Sets the ID of the currently active tab. Called before accessing a @TabScoped bean so the CDI Context knows which tab scope to look up/create the bean in.
      Parameters:
      tabId - the tab ID (e.g. "r0", "r1")
    • getCurrentTabId

      public static String getCurrentTabId()
      Returns the ID of the currently active tab.
      Returns:
      the tab ID, or null if not set
    • clearCurrentTabId

      public static void clearCurrentTabId()
      Clears the currently active tab ID. Called after tab processing is complete.
    • getBeansForTab

      public Map<jakarta.enterprise.context.spi.Contextual<?>,TabScopedContextHolder.BeanInstance<?>> getBeansForTab(String tabId)
      Returns the bean map for the given tab in the current session. If no map exists, creates a new empty one.
      Parameters:
      tabId - the tab ID
      Returns:
      the bean map for that tab
    • getBean

      public <T> TabScopedContextHolder.BeanInstance<T> getBean(String tabId, jakarta.enterprise.context.spi.Contextual<T> contextual)
      Returns the bean instance for the given tab and bean type in the current session.
      Parameters:
      tabId - the tab ID
      contextual - the bean type (Contextual)
      Returns:
      BeanInstance, or null if not found
    • putBean

      public <T> void putBean(String tabId, jakarta.enterprise.context.spi.Contextual<T> contextual, T instance, jakarta.enterprise.context.spi.CreationalContext<T> creationalContext)
      Stores a bean instance for the given tab in the current session.
      Parameters:
      tabId - the tab ID
      contextual - the bean type (Contextual)
      instance - the bean instance
      creationalContext - the CDI creational context
    • destroyBeansForTab

      public void destroyBeansForTab(String tabId)
      Destroys all beans associated with the given tab in the current session. Called when a tab is being closed.

      For each bean, calls destroy() which triggers @PreDestroy methods.

      Parameters:
      tabId - the ID of the tab being closed
    • hasTab

      public boolean hasTab(String tabId)
      Checks whether a scope exists for the given tab in the current session.
      Parameters:
      tabId - the tab ID
      Returns:
      true if at least one bean exists for that tab
    • destroyAllBeansForSession

      public void destroyAllBeansForSession(String sessionId)
      Destroys ALL beans for the given HTTP session.

      Called from TabScopeSessionListener when a session expires or is invalidated. This prevents memory leaks - without this, beans would remain in the map forever even after the session no longer exists.

      IMPORTANT: This method is called OUTSIDE a JSF request (from HttpSessionListener), so it does NOT use FacesContext. Instead, it receives sessionId as a parameter.

      Parameters:
      sessionId - the ID of the HTTP session being destroyed
    • migrateSession

      public static void migrateSession(String oldSessionId, String newSessionId)
      Migrates all beans from the old session ID to the new one.

      Called from TabScopeSessionListener.sessionIdChanged(jakarta.servlet.http.HttpSessionEvent, java.lang.String) when the servlet container changes the session ID (session fixation protection during login, or explicit changeSessionId() call).

      Without this, beans would remain "trapped" under the old session ID and would never be cleaned up or accessible under the new ID.

      Parameters:
      oldSessionId - the previous session ID
      newSessionId - the new session ID
    • getActiveSessionCount

      public static int getActiveSessionCount()
      Returns the number of active sessions with @TabScoped beans. Useful for monitoring and debugging.
      Returns:
      the number of sessions