Class RestChildren

java.lang.Object
org.apache.juneau.rest.server.RestChildren

public class RestChildren extends Object
Implements the child resources of a Rest-annotated class.

Holds a registry of RestContext instances keyed by composed path. Reads (request routing via findMatch(RestSession.Builder) and the asMap() accessor) are lock-free against a volatile copy-on-write snapshot; mutations (addChild / removeChild) synchronize on an internal write lock and atomically replace the snapshot. This makes runtime child management safe even while requests are in flight on other threads.

Supports lazy-init children registered via RestChildren.Builder.addLazy(Class, String) — these children have their RestContext constructed on the first matching request rather than at parent startup. The routing entry (path prefix matcher) is always populated at startup; only the full context build is deferred.

See Also:
  • Constructor Details

    • RestChildren

      Constructor.
      Parameters:
      builder - The builder containing the settings for this object. Must not be null.
  • Method Details

    • create

      public static RestChildren.Builder create(RestContext parent, BeanStore beanStore, jakarta.servlet.ServletConfig servletConfig)
      Static creator.
      Parameters:
      parent - The parent RestContext. Required for runtime addChild support (may be null otherwise).
      beanStore - The bean store used for child instantiation.
      servletConfig - The ServletConfig propagated to dynamically added children. May be null.
      Returns:
      A new builder for this object.
    • asMap

      Returns the children in this object as a map.

      The keys are the paths of the child contexts. The returned map is an unmodifiable snapshot taken at the time of the call; subsequent addChild / removeChild calls do not affect this view.

      Returns:
      The children as an unmodifiable map.
    • destroy

      public void destroy()
      Called during servlet destruction on all children to invoke all RestDestroy and Servlet.destroy() methods.

      Lazy children that were never materialized are silently skipped (no context was ever built for them).

    • findMatch

      public Optional<RestChildMatch> findMatch(RestSession.Builder builder) throws jakarta.servlet.ServletException
      Looks through the registered children of this object and returns the best match.

      Eager children are checked first (lock-free volatile read), then lazy entries. A matching lazy entry triggers RestChildren.LazyChildEntry.materialize() which builds the full RestContext on first call (blocking concurrent first-requests until construction completes) and caches the result.

      Parameters:
      builder - The HTTP call builder. Must not be null.
      Returns:
      The child that best matches the call, or an empty Optional if a match could not be made.
      Throws:
      jakarta.servlet.ServletException - If a lazy child fails to materialize.
    • postInit

      public void postInit() throws jakarta.servlet.ServletException
      Called during servlet initialization on all eager children to invoke all RestPostInit child-last methods.

      Lazy children are intentionally excluded — they are initialized on first invocation, not at startup.

      Throws:
      jakarta.servlet.ServletException - Error occurred.
    • postInitChildFirst

      public void postInitChildFirst() throws jakarta.servlet.ServletException
      Called during servlet initialization on all eager children to invoke all RestPostInit child-first methods.

      Lazy children are intentionally excluded — they are initialized on first invocation, not at startup.

      Throws:
      jakarta.servlet.ServletException - Error occurred.
    • getLazyEntries

      public Map<String,org.apache.juneau.rest.server.RestChildren.LazyChildEntry> getLazyEntries()
      Returns the lazy child entries registered on this object.

      Each entry carries the path prefix and materialization state. Primarily used for testing.

      Returns:
      An unmodifiable map of path-to-lazy-entry. Never null.
    • addChild

      public RestContext addChild(Class<?> resourceClass) throws jakarta.servlet.ServletException
      Dynamically registers a child REST resource by class, instantiating it via the parent's BeanStore.

      The path under which the child is registered is determined by the @Rest(path) annotation on the resource class composed against the parent's full path.

      The new child's RestContext.postInit() and RestContext.postInitChildFirst() lifecycle hooks are invoked before this method returns, mirroring the eager-init behavior of @Rest(children = ...).

      Parameters:
      resourceClass - The @Rest-annotated resource class. Must not be null.
      Returns:
      The newly-built child RestContext.
      Throws:
      jakarta.servlet.ServletException - If construction or lifecycle initialization of the child fails.
      IllegalStateException - If a child is already registered at the resolved path.
    • addChild

      public RestContext addChild(Object resource) throws jakarta.servlet.ServletException
      Dynamically registers a pre-instantiated child REST resource.

      The path under which the child is registered is determined by the @Rest(path) annotation on the resource's class composed against the parent's full path.

      Parameters:
      resource - The @Rest-annotated resource instance. Must not be null.
      Returns:
      The newly-built child RestContext.
      Throws:
      jakarta.servlet.ServletException - If construction or lifecycle initialization of the child fails.
      IllegalStateException - If a child is already registered at the resolved path.
    • addChild

      public RestContext addChild(Object resource, boolean replace) throws jakarta.servlet.ServletException
      Dynamically registers a pre-instantiated child REST resource, optionally replacing any existing child at the same resolved path.
      Parameters:
      resource - The @Rest-annotated resource instance. Must not be null.
      replace - If true, an existing child at the same path is destroyed and removed before the new child is added. If false, an existing child causes an IllegalStateException.
      Returns:
      The newly-built child RestContext.
      Throws:
      jakarta.servlet.ServletException - If construction or lifecycle initialization of the child fails.
    • addChild

      public RestContext addChild(String path, Object resource) throws jakarta.servlet.ServletException
      Dynamically registers a pre-instantiated child REST resource at an explicit path.

      The supplied path overrides whatever @Rest(path) would normally provide. Useful for mounting the same servlet class at multiple paths, or for test fixtures that compose paths programmatically.

      Parameters:
      path - The path segment under the parent at which to mount this child. Leading slashes are trimmed.
      resource - The @Rest-annotated resource instance. Must not be null.
      Returns:
      The newly-built child RestContext.
      Throws:
      jakarta.servlet.ServletException - If construction or lifecycle initialization of the child fails.
      IllegalStateException - If a child is already registered at the resolved path.
    • addChild

      public RestContext addChild(String path, Object resource, boolean replace) throws jakarta.servlet.ServletException
      Dynamically registers a pre-instantiated child REST resource at an explicit path, optionally replacing any existing child at the same path.
      Parameters:
      path - The path segment under the parent at which to mount this child. Leading slashes are trimmed.
      resource - The @Rest-annotated resource instance. Must not be null.
      replace - If true, an existing child at the same path is destroyed and removed before the new child is added. If false, an existing child causes an IllegalStateException.
      Returns:
      The newly-built child RestContext.
      Throws:
      jakarta.servlet.ServletException - If construction or lifecycle initialization of the child fails.
    • removeChild

      Removes the child registered at the given composed path.

      The removed child has RestContext.destroy() invoked (which runs @RestDestroy hooks and recursively destroys any grandchildren), followed by Servlet.destroy() if the underlying resource is a Servlet.

      Parameters:
      path - The composed path key (as returned by RestContext.getPath()) of the child to remove.
      Returns:
      The removed and destroyed RestContext, or null if no child was registered at the given path.
    • removeChild

      public RestContext removeChild(Class<?> resourceClass)
      Removes the first child whose resource class matches the given type.
      Parameters:
      resourceClass - The resource class to match. Matching is performed via RestContext.getResourceClass().
      Returns:
      The removed and destroyed RestContext, or null if no matching child was found.