Class ServerStartupWaiter

java.lang.Object
org.exoplatform.container.monitor.jvm.ServerStartupWaiter

public final class ServerStartupWaiter extends Object
Holds a caller until the full server startup: the given ExoContainer started, then a JMX-managed HTTP connector in STARTED state. Tomcat starts its connectors only once every webapp is deployed and every container is started, and their 'stateName' JMX attribute switches to STARTED as the last server startup step — so that state is the one signal that the server can answer the HTTP requests startup-time work may need to send to itself (OAuth/OIDC discovery, token issuance, MCP, REST).

Degrades to the container-startup-only wait when no JMX-managed HTTP connector exists (unit tests, embedded runs, AJP-only servers) or when the JMX read fails, escapes with a warning when every HTTP connector reached a terminal state without starting (e.g. port already bound), and gives up with a warning past "exo.server.startup.wait.timeoutSeconds" seconds (600L by default) — the timeout is the safety net for any thread the server startup transitively depends on that this class cannot recognize (see below), turning a potential boot deadlock into a bounded delay.

The server startup thread itself is refused with an IllegalStateException: the connector starts only after that thread finishes the startup, so waiting there can never end. That detection is by thread name ("main") — the reliable signal for the standard Tomcat bootstrap, but blind to renamed bootstrap threads and to the catalina-utility-* threads Tomcat uses when startStopThreads > 1; those cases are what the timeout bounds instead.

  • Method Details

    • awaitServerStartup

      public static void awaitServerStartup(ExoContainer container, String subject) throws InterruptedException
      Waits until the container is started and one HTTP connector is up, per the class contract above.
      Parameters:
      container - the container whose startup ends the first wait phase
      subject - what is being held, for the wait logs and the startup-thread error message (e.g. "Quartz scheduled jobs", "MCP client OAuth registrations")
      Throws:
      InterruptedException - when the wait is interrupted (server shutdown)
      IllegalStateException - when called on the server startup thread while a wait is actually needed — waiting there would deadlock the boot, the work must move to an async-init or request thread
    • isHttpConnectorPending

      public static boolean isHttpConnectorPending(ExoContainer container, String subject)
      Whether an HTTP connector exists and has not started yet — i.e. whether awaitServerStartup(org.exoplatform.container.ExoContainer, java.lang.String) would actually have something to wait for beyond the container startup. Lets a caller keep its legacy synchronous path when there is nothing observable to wait for (unit tests, embedded runs, AJP-only servers) and pay the asynchronous wait only when the wait is real.
      Parameters:
      container - the container providing the JMX server
      subject - what would be held, for the degrade-path logs
      Returns:
      true when an HTTP connector is observable and not STARTED