java.lang.Object
jakarta.servlet.GenericServlet
jakarta.servlet.http.HttpServlet
de.aristaflow.adept2.base.servletcontainer.demux.DemuxServlet
All Implemented Interfaces:
DynamicServlet, jakarta.servlet.Servlet, jakarta.servlet.ServletConfig, Serializable

public class DemuxServlet extends jakarta.servlet.http.HttpServlet implements DynamicServlet
This servlet allows to register sub servlets at runtime, i. e. even after the servlet context has been initialised. It is closely coupled with a corresponding servlet context. This servlet demultiplexes requests to the registered sub servlets, i. e. it resolves paths and forwards the requests to the corresponding sub servlet.

This servlet can be used in two ways:

  • Let the servlet container instantiate it (or a subclass) via web.xml.
    The servlet will then instantiate the corresponding DeferredServletContext in init(ServletConfig) providing the servlet config (and context). This allows the DeferredServletContext to parse the URL mapping of this servlet as defined in web.xml.
  • The DeferredServletContext is created programmatically.
    This requires init parameters for the URL mapping and optionally async support for this servlet. The DeferredServletContext will then create and register this servlet. Async support will be required if any sub servlets should use async behaviour.
In both cases the URL mapping needs to end with /* to allow for the paths of sub servlets to be handled correctly. That is, the sub servlets are "registered" below this servlet at the DeferredServletContext. However, the parent servlet context and the servlet container do not know about them. So requests need to be handled by this demultiplexing servlet which forwards them appropriately.

Subclasses needing to perform their HTTP request handling, i. e. HttpServlet.doGet(HttpServletRequest, jakarta.servlet.http.HttpServletResponse), HttpServlet.doPost(HttpServletRequest, jakarta.servlet.http.HttpServletResponse), ..., simply need to register themselves with the corresponding path mapping. If the demultiplexing target is this, the request will be forwarded to HttpServlet.service(ServletRequest, ServletResponse). Just make sure not to use /* for the mapping since this is required for demultiplexing sub servlets.

The implementation is heavily inspired by ServletHandler.

See Also:
  • Field Summary

    Fields
    Modifier and Type
    Field
    Description
    protected jakarta.servlet.ServletConfig
    The config of this servlet.
    protected String
    The (inner) context path, i.
    protected final DynamicServlet
    The default 404 servlet used in case no other servlet has been found for a specific path/target.
    The DeferredServletContext, i.
    protected final org.eclipse.jetty.http.pathmap.PathMappings<DynamicServlet>
    All path mappings known by this demultiplexing servlet.
    protected final Map<String,Collection<String>>
    The paths for each servlet; key is the corresponding servlet name.
    protected String
    The name of this demultiplexing servlet for logging purpose.
    protected final Map<String,Pair<DynamicServlet,String>>
    All sub servlets registered at this servlet (or rather the corresponding servlet context).

    Fields inherited from class jakarta.servlet.http.HttpServlet

    LEGACY_DO_HEAD
  • Constructor Summary

    Constructors
    Modifier
    Constructor
    Description
     
    Creates a new DemuxServlet usually called by a servlet container directly.
    protected
    Creates a new DemuxServlet usually called by the designated DeferredServletContext which is explicitly created by some code.
    The calling DeferredServletContext is responsible for registering this servlet (in the outer servlet context).
  • Method Summary

    Modifier and Type
    Method
    Description
    protected Collection<String>
    Adds the designated servlet with the designated path specifications.
    void
    Removes the mapping for and calls destroy() on all known sub servlets.
    static String
    Gets a default name for this demultiplexing servlet.
    protected Collection<String>
    Gets the paths for the servlet with the designated name or null if no corresponding paths are known.
    jakarta.servlet.ServletConfig
     
    Gets the servlet for the designated (request) target.
     
    void
    init(jakarta.servlet.ServletConfig initConfig)
    Sets the designated config.
    protected void
    Remove all previously added URL mappings for the designated servlet.
    void
    service(jakarta.servlet.ServletRequest req, jakarta.servlet.ServletResponse res)
    Determines the target servlet for the designated request, wraps the request (to adapt the context and servlet paths appropriately, i.
    void
    servletDeployed(jakarta.servlet.ServletContext context, Collection<String> urlPatterns)
    Notifies the servlet that it has been deployed with the designated context and the designated patterns.
    final void
    servletUndeployed(jakarta.servlet.ServletContext context)
    Notifies the servlet that it has been undeployed.
    protected void
    subServletDeployed(DynamicServlet servlet, String servletContext)
    Signals that the designated sub servlet has been deployed now.

    Methods inherited from class jakarta.servlet.http.HttpServlet

    doDelete, doGet, doHead, doOptions, doPatch, doPost, doPut, doTrace, getLastModified, isSensitiveHeader, service

    Methods inherited from class jakarta.servlet.GenericServlet

    getInitParameter, getInitParameterNames, getServletContext, getServletName, init, log, log

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

    Methods inherited from interface de.aristaflow.adept2.base.servletcontainer.DynamicServlet

    getServletName
  • Field Details

    • default404

      protected final DynamicServlet default404
      The default 404 servlet used in case no other servlet has been found for a specific path/target.
    • servletName

      protected String servletName
      The name of this demultiplexing servlet for logging purpose.
    • config

      protected jakarta.servlet.ServletConfig config
      The config of this servlet. This is the outer servlet config. It will not be used directly by sub servlets.
    • dsc

      protected DeferredServletContext dsc
      The DeferredServletContext, i. e. the inner servlet context used by the sub servlets.
    • contextPath

      protected String contextPath
      The (inner) context path, i. e. the path of the deferred servlet context. This is required to adapt the paths of incoming requests for the sub servlets. The demultiplexing servlet has to be hidden from them.
    • servlets

      protected final Map<String,Pair<DynamicServlet,String>> servlets
      All sub servlets registered at this servlet (or rather the corresponding servlet context). Key of the map is the corresponding servlet name, values are the servlet as well as the hierarchical servlet context, i. e. more or less the main URL mapping of the servlet. The servlet hierchical servlet context is required to resolve the servlet path correctly within the demultiplexing request.
      This map only contains fully initialised servlets. Before this, paths and pathMappings may already contain the mappings for a servlet.

      When accessing servlets or paths synchronise on the field. If both locks are required, make sure to get servlets before paths! This is especially critical when calling methods internally.

    • paths

      protected final Map<String,Collection<String>> paths
      The paths for each servlet; key is the corresponding servlet name. Each servlet mapping may contain several paths, i. e. each servlet may have several URL mappings.
      Paths are added before initialising a servlet so this map may contain a servlet path for which no servlet is in servlets.

      When accessing servlets or paths synchronise on the field. If both locks are required, make sure to get servlets before paths! This is especially critical when calling methods internally.

    • pathMappings

      protected final org.eclipse.jetty.http.pathmap.PathMappings<DynamicServlet> pathMappings
      All path mappings known by this demultiplexing servlet. This allows to demultiplex incoming requests to the corresponding servlet. It also allows to track already known paths and prevents several servlets having the same mapping. The first registered path/servlet wins, later servlets will be refused.
      Access to this map is synchronised via paths.
      See Also:
      • ServletRegistration.addMapping(String...)
  • Constructor Details

    • DemuxServlet

      public DemuxServlet()
      Creates a new DemuxServlet usually called by a servlet container directly. The missing field values will be set when initialising. Also the accompanying DeferredServletContext will be created there.
    • DemuxServlet

      protected DemuxServlet(String servletName, DeferredServletContext dsc)
      Creates a new DemuxServlet usually called by the designated DeferredServletContext which is explicitly created by some code.
      The calling DeferredServletContext is responsible for registering this servlet (in the outer servlet context).
      Parameters:
      servletName - The name of this demultiplexing servlet for logging purpose.
      dsc - The DeferredServletContext to be used with this servlet.
  • Method Details

    • init

      public void init(jakarta.servlet.ServletConfig initConfig) throws jakarta.servlet.ServletException
      Sets the designated config. If this servlet has been created by the servlet container (via web.xml), the DeferredServletContext will be created here. Subclasses should usually call this method first!
      Specified by:
      init in interface jakarta.servlet.Servlet
      Overrides:
      init in class jakarta.servlet.http.HttpServlet
      Throws:
      jakarta.servlet.ServletException
    • getServletConfig

      public jakarta.servlet.ServletConfig getServletConfig()
      Specified by:
      getServletConfig in interface jakarta.servlet.Servlet
      Overrides:
      getServletConfig in class jakarta.servlet.GenericServlet
    • service

      public void service(jakarta.servlet.ServletRequest req, jakarta.servlet.ServletResponse res) throws jakarta.servlet.ServletException, IOException
      Determines the target servlet for the designated request, wraps the request (to adapt the context and servlet paths appropriately, i. e. hide this servlet) and forward/demultiplex the request to the corresponding sub servlet.

      If the target servlet is this, the complete request will be forwarded to HttpServlet.service(ServletRequest, ServletResponse) thus using the normal HTTP request handling.

      Specified by:
      service in interface jakarta.servlet.Servlet
      Overrides:
      service in class jakarta.servlet.http.HttpServlet
      Throws:
      jakarta.servlet.ServletException
      IOException
    • getServletInfo

      public String getServletInfo()
      Specified by:
      getServletInfo in interface jakarta.servlet.Servlet
      Overrides:
      getServletInfo in class jakarta.servlet.GenericServlet
    • destroy

      public void destroy()
      Removes the mapping for and calls destroy() on all known sub servlets.
      Specified by:
      destroy in interface jakarta.servlet.Servlet
      Overrides:
      destroy in class jakarta.servlet.GenericServlet
    • getPaths

      protected Collection<String> getPaths(String name)
      Gets the paths for the servlet with the designated name or null if no corresponding paths are known.
      Parameters:
      name - The name of the servlet for which to get the paths.
      Returns:
      The (unmodifiable) paths for the servlet with the designated name or an empty collection if no corresponding paths are known.
    • getServletForTarget

      protected Pair<DynamicServlet,String> getServletForTarget(String target)
      Gets the servlet for the designated (request) target. This tries to match the path mappings with the designated target. If the target is relative (does not start with /), the target will be interpreted as servlet name.
      Parameters:
      target - The path within the context of this servlet or the servlet name.
      Returns:
      A pair with the servlet and its hierarchical context or the 404 servlet for the designated target if no other servlet can be found.
    • addServletWithMapping

      protected Collection<String> addServletWithMapping(DynamicServlet servlet, Collection<String> pathSpec)
      Adds the designated servlet with the designated path specifications. The paths will be checked so that already existing paths will not be used for different servlets. If such paths exist, they will be removed. So check the returned paths for the actually used path specifications. If the designated servlet (name) has already been added with paths, the corresponding paths will be removed before adding the current ones.
      It there is already a servlet of the same name and this has been initialised, an IllegalStateException will be thrown. You cannot change the paths after a servlet has been initialised.
      Parameters:
      servlet - The servlet (for) which to add (the designated paths).
      pathSpec - The paths which to add for the designated servlet.
      Returns:
      The (unmodifiable) paths created for the designated servlet and the designated paths. If there are already different servlets registered for some of the designated paths, these paths will be removed and will therefore not be in the returned paths.
      Throws:
      IllegalStateException - If a servlet with the name of the designated servlet already exists and has already been initialised, an IllegalStateException will be thrown.
    • removeServletWithMapping

      protected void removeServletWithMapping(DynamicServlet servlet)
      Remove all previously added URL mappings for the designated servlet.
      Parameters:
      servlet - The servlet which to remove including all its mappings.
    • subServletDeployed

      protected void subServletDeployed(DynamicServlet servlet, String servletContext)
      Signals that the designated sub servlet has been deployed now. This adds the servlet to the internal servlet map.
      Parameters:
      servlet - The servlet which to add to the internal servlet map.
      servletContext - The hierarchical servlet context, i. e. more or less the main URL mapping of the servlet.
    • getDefaultDemuxServletName

      public static String getDefaultDemuxServletName()
      Gets a default name for this demultiplexing servlet. This is the GlobalMessagesLoader.GLOBAL_COMPANY_NAME followed by DemuxServlet.
      Returns:
      A default name for this demultiplexing servlet.
    • servletDeployed

      public void servletDeployed(jakarta.servlet.ServletContext context, Collection<String> urlPatterns)
      Description copied from interface: DynamicServlet
      Notifies the servlet that it has been deployed with the designated context and the designated patterns. Note that the servlet usually will not have been initialised yet.
      Specified by:
      servletDeployed in interface DynamicServlet
      Parameters:
      context - The servlet context of this servlet.
      urlPatterns - The URL patterns (mapping) this servlet has been deployed with.
    • servletUndeployed

      public final void servletUndeployed(jakarta.servlet.ServletContext context)
      Description copied from interface: DynamicServlet
      Notifies the servlet that it has been undeployed.
      Specified by:
      servletUndeployed in interface DynamicServlet
      Parameters:
      context - The servlet context of this servlet.