Skip to content

Epic: Support concurrent multi-tab / multi-iframe ZK navigation #107

Description

@marioserrano09

Goal

Prepare tools.dynamia.navigation / ZK navigation so a single HTTP session can reliably drive multiple independent ZK desktops at once — real browser tabs opened concurrently, and (the primary near-term target) a non-ZK front-end shell embedding several <iframe>s, each loading its own ZK page via /page-embed/**.

Current state

  • ZKNavigationManager is @Scope("zk-desktop"), so each ZK Desktop (tab/iframe) already gets its own instance — the "one current page per manager" model is correct for this use case and does not need to change.
  • Page events (sendEvent/onPageEvent) already use EventQueues.DESKTOP scope — already isolated per tab/iframe.

Root problem

NavigationManagerSession (platform/core/navigation/.../NavigationManagerSession.java) is @Scope("session"): a single shared slot (page, pageParams, runLaterQueue) per HTTP session used to hand off the initial page to whichever ZKNavigationManager desktop bean is constructed next (ZKNavigationManager.init() → NavigationManagerSession.getInstance().updateNavManager(this)).

PageNavigationController.navigate() and PageEmbedController (platform/core/web/.../navigation/, already built for iframe embedding from non-ZK fronts) call NavigationManager.setPageLater(page, params) on every HTTP request, writing into that same shared session slot.

With a single tab this works because at most one desktop init is pending at a time. With multiple tabs/iframes opened concurrently in the same session, each /page-embed/.../pageX request overwrites the previous one's pending page/params before the corresponding desktop's @PostConstruct consumes it — a race condition where iframes can end up showing the wrong page, duplicate pages, or silently drop one of the requested pages. Same risk applies to runLaterQueue.

There is also no stable identifier correlating a NavigationManager instance to "which tab/iframe" it belongs to, and no session-level registry of active navigation manager instances — needed later if a host shell wants to enumerate/target a specific iframe's navigation.

Key design insight

PageNavigationController/PageEmbedController resolve their ModelAndView through InternalResourceView, which renders via a servlet forward (same thread, same request) into the .zul view — ZK's Desktop/ZKNavigationManager bootstrap for that tab/iframe happens on that same thread. So the fix doesn't need a correlation token threaded through URLs: replacing the @Scope("session") bean with a ThreadLocal isolates each concurrent request naturally, with zero changes to the web controllers. See #108.

Scope of changes

  1. Replace NavigationManagerSession session-scope with ThreadLocal #108 — Replace NavigationManagerSession's session scope with ThreadLocal, with a request-lifecycle filter to clear it. This is the blocking fix; no token/URL/controller changes needed.
  2. Add stable instance identity to NavigationManager #109 — Stable instance identity on NavigationManager — a framework-agnostic id per manager instance, for correlation/debugging and the registry below.
  3. Session-level registry of active NavigationManager instances #110 — Session-level registry of active NavigationManager instances (phase 2) — enumerate/target open tabs/iframes for a session, needed for a host shell orchestrating multiple iframes.
  4. Propagate a token through PageNavigationController/PageEmbedController — not needed, see key design insight above (was Propagate navigation token through PageNavigationController / PageEmbedController #111, closed as superseded).
  5. Docs: document the contract — NavigationManager.getCurrent() keeps resolving "the manager for the current desktop/iframe" (via zk-desktop scope, unchanged); setPageLater/runLater must be called on the same thread that forwards into the target ZK desktop (not across a redirect).

Out of scope (for this Epic)

  • The single-current-page-per-NavigationManager model itself — correct for 1 desktop = 1 active page; not a blocker for real tabs/iframes (each already gets its own manager instance).
  • Intra-desktop multi-tab UI (TabPanel/WorkspaceViewBuilder, ZK tabs within one browser tab) — separate, already-working concern, not required for this goal.

Affected modules

  • platform/core/navigation (NavigationManager, NavigationManagerSession, BaseNavigationManager)
  • platform/core/web (request-lifecycle filter only; PageNavigationController/PageEmbedController unchanged)
  • platform/ui/zk (ZKNavigationManager)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions