Links Administrative Apps Internal Servlets Realm Implementations  | Catalina Functional SpecificationsInvoker Servlet| Overview |  
  | Introduction |  
    The purpose of the Invoker Servlet is to allow a
    web application to dynamically register new servlet definitions
    that correspond with a <servlet> element in the
    /WEB-INF/web.xml deployment descriptor, and execute
    requests utilizing the new servlet definitions.  From the perspective
    of the newly registered servlets, all servlet lifecycle requirements
    of the Servlet Specification (such as calling init() and
    destroy() at the correct times) will be respected. 
    |   
  | External Specifications |  
    I do not know of any formal specification of the behavior of an
    invoker servlet that is publicly available.  Anyone know of one? 
    |   
  | Implementation Requirements |  
    The implementation of this functionality shall conform to the
    following requirements: 
    
    - Implemented as a servlet.
 
    - Exist in the 
org.apache.catalina.servlets package
        so that it can be loaded by the Catalina class loader. 
    - Implement the 
org.apache.catalina.ContainerServlet
        interface, so that it gains knowledge of the Wrapper
        that is responsible for itself and, therefore, access to other
        internal Catalina components. 
    - Support a configurable debugging detail level.
 
    - Log debugging and operational messages (suitably internationalized)
        via the 
getServletContext().log() method. 
     
    |   
  |  
 | Dependencies |  
  | Environmental Dependencies |  
    The following environmental dependencies must be met in order for
    the Invoker servlet to operate correctly: 
    
    - The invoker servlet must be registered in the application deployment
        descriptor (or the default deployment descriptor in file
        
$CATALINA_BASE/conf/web.xml) using a "path mapped"
        servlet mapping.  The historical default mapping is to URL pattern
        "/servlet/*", although the invoker servlet must operate
        correctly with an arbitrary mapping. 
     
    |   
  | Container Dependencies |  
    Correct operation of the invoker servlet depends on the following
    specific features of the surrounding container: 
    
    - Correct support for the 
ContainerServlet interface,
        including calling setWrapper() before
        the init() method of the invoker servlet is called. 
    - The web application class loader must be stored as the context
        class loader of the request processing thread.
 
     
    |   
  |  
 | Functionality |  
  | Initialization Functionality |  
    The following processing must be performed when the init()
    method of the invoker servlet is called: 
    
    - Ensure that the container has called 
setWrapper().  If
        not, throw a permanent UnavailableException. 
    - Look up and cache the 
Context that corresponds to our
        Wrapper.  This is the component with which new servlet
        definitions and mappings will be registered. 
     
    |   
  | Per-Request Functionality |  
    On each request, the following processing shall be performed: 
    
    - Calculate the 
{ServletPath} for this request, either from
        request attribute javax.servlet.include.servlet_path or
        by calling request.getServletPath(). 
    - Calculate the 
{PathInfo} for this request, either from
        request attribute javax.servlet.include.path_info or
        by calling request.getPathInfo().  If the calculated
        {PathInfo} is null, return HTTP status 400
        (bad request). 
    - Parse the calculated 
{PathInfo} value as follows:
        
        - Ignore the leading slash character.
 
        - Accumulate characters up to the next '/' (if any) as the
            
{ServletSelector}. 
        - If a '/' was encountered, accumulate all characters from that
            slash (inclusive) to the end of the string as
            
{PathRemainder}.  If no slash was encountered,
            set {PathRemainder} to a zero-length string. 
          
    - Determine whether 
{ServletSelector} is the name of an
        existing servlet definition, and process it as follows:
        
        - Ask our associated 
Context to find and return a
            child Wrapper named {ServletSelector}.
             
        - If there is no such child, skip to the next major step.
 
        - Register a new servlet mapping for this 
Wrapper,
            using a URL pattern calculated as follows:
            {ServletPath} + "/" + {ServletSelector}
            + "/*" 
        - Create a request dispatcher using a path calculated as follows:
            
{ServletPath} + "/" + {ServletSelector}
            + {PathRemainder} 
        - Forward this request to the created request dispatcher, and
            exit from this request.
 
          
    - Assume that 
{ServletSelector} is the fully qualified
        name of a Java class that implements javax.servlet.Servlet
        and process it as follows:
        
        - Synthesize a new 
{ServletName} for the servlet
            definition that will be created. 
        - If there is already a child 
Wrapper associated with
            this name, return HTTP status 500 (internal server error), because
            a mapping should have already been created for this servlet. 
        - Attempt to load a class named 
{ServletSelector} from
            the web application class loader (i.e. the context class loader
            for our current thread).  If this fails, return HTTP status 404
            (not found). 
        - Instantiate an instance of this class.  If an error occurs,
            return HTTP status 404 (not found).
 
        - If this class does not implement the
            
javax.servlet.Servlet interface, return HTTP status
            404 (not found). 
        - Create and register a new 
Wrapper child with our
            Context, under name {ServletName}. 
        - Register a new servlet mapping for this 
Wrapper,
            using a URL pattern calculated as follows:
            {ServletPath} + "/" + {ServletSelector}
            + "/*" 
        - Create a request dispatcher using a path calculated as follows:
            
{ServletPath} + "/" + {ServletSelector}
            + {PathRemainder} 
        - Forward this request to the created request dispatcher, and
            exit from this request.
 
          
     
    |   
  
  |  
 | Testable Assertions |  
  In addition the the assertions implied by the functionality requirements
  listed above, the following additional assertions shall be tested to
  validate the behavior of the invoker servlet: 
  
  - It is possible to access an existing servlet definition by name
      through the invoker.  The existing servlet definition can include
      either a 
<servlet-class> or
      <jsp-file> subelement. 
  - When an existing servlet definition is accessed by name, the request
      will be ultimately processed by the same servlet instance that would
      have processed it had a mapping to that servlet definition been used
      on the request directly.
 
  - It is possible to access an anonymous servlet by class name
      through the invoker.
 
  - When an anonymous servlet is accessed, the servlet instance is processed
      according to the lifecycle requirements of the Servlet Specification.
      
 
  - When an anonymous servlet is accessed, the servlet instance receives
      a 
ServletConfig instance with no servlet initialization
      parameters. 
  - It is possible to utilize the invoker servlet via a direct request.
 
  - It is possible to utilize the invoker servlet via a call to
      
RequestDispatcher.forward(), or the corresponding
      <jsp:forward> tag in a JSP page. 
  - It is possible to utilize the invoker servlet via a call to
      
RequestDispatcher.include(), or the corresponding
      <jsp:include> tag in a JSP page. 
  - It is possible to use any HTTP method (including GET and POST) that
      is supported by the Servlet class that is ultimately executed.
 
  - The invoker servlet should never be asked to process a second or
      subsequent request for the same 
{ServletSelector} (because
      it will have registered an appropriate servlet mapping. 
   
  |  
  |