# Catalina Functional Specifications

## Invoker 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_HOME/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:

> > 1. Calculate the `{ServletPath}` for this request, either from request attribute `javax.servlet.include.servlet_path` or by calling `request.getServletPath()`.
> > 2. 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).
> > 3. Parse the calculated `{PathInfo}` value as follows:
> >    1. Ignore the leading slash character.
> >    2. Accumulate characters up to the next '/' (if any) as the `{ServletSelector}`.
> >    3. 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.
> > 4. Determine whether `{ServletSelector}` is the name of an existing servlet definition, and process it as follows:
> >    1. Ask our associated `Context` to find and return a child `Wrapper` named `{ServletSelector}`.
> >    2. If there is no such child, skip to the next major step.
> >    3. Register a new servlet mapping for this `Wrapper`, using a URL pattern calculated as follows: `{ServletPath}` + "/" + `{ServletSelector}` + "/*"
> >    4. Create a request dispatcher using a path calculated as follows: `{ServletPath}` + "/" + `{ServletSelector}` + `{PathRemainder}`
> >    5. Forward this request to the created request dispatcher, and exit from this request.
> > 5. Assume that `{ServletSelector}` is the fully qualified name of a Java class that implements `javax.servlet.Servlet` and process it as follows:
> >    1. Synthesize a new `{ServletName}` for the servlet definition that will be created.
> >    2. 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.
> >    3. 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).
> >    4. Instantiate an instance of this class. If an error occurs, return HTTP status 404 (not found).
> >    5. If this class does not implement the `javax.servlet.Servlet` interface, return HTTP status 404 (not found).
> >    6. Create and register a new `Wrapper` child with our `Context`, under name `{ServletName}`.
> >    7. Register a new servlet mapping for this `Wrapper`, using a URL pattern calculated as follows: `{ServletPath}` + "/" + `{ServletSelector}` + "/*"
> >    8. Create a request dispatcher using a path calculated as follows: `{ServletPath}` + "/" + `{ServletSelector}` + `{PathRemainder}`
> >    9. Forward this request to the created request dispatcher, and exit from this request.

> Finalization Functionality

> > No specific processing is required when the `destroy()` method is called:

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.

Copyright © 1999-2002, Apache Software Foundation