Tomcat Servlet Container

Today I pored into Tomcat’s Servlet Container mechanism.

What is a Servlet,

Servlet is an interface defined in javax.servlet package. It declars some essential methods for the life cycle of a servlet and they are implemented by every servlet and are invoked via a HTTP Request by the server. The following is Servlet’s essential methods,

public void init(ServletConfig config) throws ServletException
public void service(ServletRequest request, ServletResponse response)
throws ServletException, java.io.IOException
public void destroy()

1. The init() method is invoked during initialization stage of the servlet life cycle. It is passed an object implementing the javax.servlet.ServletConfig interface, which allows the servlet to access initialization parameters from the web application.

2. The service() method is invoked upon each request after its initialization. Each request is serviced in its own separate thread. The web container calls the service() method of the servlet for every request. The service() method determines the kind of request being made and dispatches it to an appropriate method to handle the request.

3. The destroy() method is invoked when the servlet object should be destroyed. It releases the resources being held.

Servlet container is designed for handling Servlet resources. Tomcat Servlet container is an implementation of org.apache.catalina.Container.

Basically a Tomcat Servlet container should do,

1. it should implement invoke() method specified by interface org.apache.catalina.Container. In this way, Tomcat’s default connector will invoke this method.

2.invoke() should create a ClassLoader and load the requested Servlet class.

    /**
     * Process the specified Request, and generate the corresponding Response,
     * according to the design of this particular Container.
     *
     * @param request Request to be processed
     * @param response Response to be produced
     *
     * @exception IOException if an input/output error occurred while
     *  processing
     * @exception ServletException if a ServletException was thrown
     *  while processing this request
     */
    public void invoke(Request request, Response response)
        throws IOException, ServletException;

Let’s how Craig R. McClanahan implements his Catalina Servlet Container. Catalina defines its interfaces in org.apache.catalina

The following is the Class Diagram I generated from Tomcat 6.x source code for org.apache.catalina

Container

1. It has a root container interface: org.apache.catalina.container. In Tomcat, it has four categories containers: Engine, Host, Context, and Wrapper.

Tomcat Architecture, http://tomcat.apache.org/tomcat-5.5-doc/architecture/overview.html

Engine

An Engine represents request processing pipeline for a specific Service. As a Service may have multiple Connectors, the Engine received and processes all requests from these connectors, handing the response back to the appropriate connector for transmission to the client. The Engine interface may be implemented to supply custom Engines, though this is uncommon.

Note that the Engine may be used for Tomcat server clustering via the jvmRoute parameter. Read the Clustering documentation for more information.

Host

Host is an association of a network name, e.g. http://www.yourcompany.com, to the Tomcat server. An Engine may contain multiple hosts, and the Host element also supports network aliases such as yourcompany.com and abc.yourcompany.com. Users rarely create custom Hosts because the StandardHost implementation provides significant additional functionality.

Context

Context represents a web application. A Host may contain multiple contexts, each with a unique path. The Context interface may be implemented to create custom Contexts, but this is rarely the case because theStandardContext provides significant additional functionality.

Besides that, it also has a wrapper interface.

Wrapper

A Wrapper represents an independent Servlet.

All of the Engine, Host, Context and Wrapper extend from root interface Container and add additional dedicated methods. Take Engine interface as example,

Method Summary
 java.lang.String getDefaultHost()
Return the default hostname for this Engine.
 java.lang.String getJvmRoute()
Retrieve the JvmRouteId for this engine.
 Service getService()
Return the Service with which we are associated (if any).
 void setDefaultHost(java.lang.String defaultHost)
Set the default hostname for this Engine.
 void setJvmRoute(java.lang.String jvmRouteId)
Set the JvmRouteId for this engine.
 void setService(Service service)
Set the Service with which we are associated (if any).

Their implemenations are StandardEngine, StandHost, StandardContext, and StandardWrapper repectively.

Princpiles in Container:

1. Every container can have more than one sub containers. Basically, one Context container will have more than one Wrapper instances; one Host container can have more than one Context instances. As one wrapper means one Servlet instance, hence a wrapper container could not have its child container.

    /**
     * Add a new child Container to those associated with this Container,
     * if supported.  Prior to adding this Container to the set of children,
     * the child's <code>setParent()</code> method must be called, with this
     * Container as an argument.  This method may thrown an
     * <code>IllegalArgumentException</code> if this Container chooses not
     * to be attached to the specified Container, in which case it is not added
     *
     * @param child New child Container to be added
     *
     * @exception IllegalArgumentException if this exception is thrown by
     *  the <code>setParent()</code> method of the child Container
     * @exception IllegalArgumentException if the new child does not have
     *  a name unique from that of existing children of this Container
     * @exception IllegalStateException if this Container does not support
     *  child Containers
     */
    public void addChild(Container child);
    /**
     * Return the child Container, associated with this Container, with
     * the specified name (if any); otherwise, return <code>null</code>
     *
     * @param name Name of the child Container to be retrieved
     */
    public Container findChild(String name);

    /**
     * Return the set of children Containers associated with this Container.
     * If this Container has no children, a zero-length array is returned.
     */
    public Container[] findChildren();
    /**
     * Remove an existing child Container from association with this parent
     * Container.
     *
     * @param child Existing child Container to be removed
     */
    public void removeChild(Container child);

So for any new containers, ASA they implements org.apache.catalina.Container interface, Catalina Servlet Engine can easily incorporate them by using above methods.

For other utility components, like Loader, Logger, Manager, Resources, etc. Catalina also provides getter/setter methods to help plugin them.


    /**
     * Return the Loader with which this Container is associated.  If there is
     * no associated Loader, return the Loader associated with our parent
     * Container (if any); otherwise, return <code>null</code>.
     */
    public Loader getLoader();

    /**
     * Set the Loader with which this Container is associated.
     *
     * @param loader The newly associated loader
     */
    public void setLoader(Loader loader);

    /**
     * Return the Logger with which this Container is associated.  If there is
     * no associated Logger, return the Logger associated with our parent
     * Container (if any); otherwise return <code>null</code>.
     */
    public Log getLogger();

    /**
     * Return the Manager with which this Container is associated.  If there is
     * no associated Manager, return the Manager associated with our parent
     * Container (if any); otherwise return <code>null</code>.
     */
    public Manager getManager();

    /**
     * Set the Manager with which this Container is associated.
     *
     * @param manager The newly associated Manager
     */
    public void setManager(Manager manager);

The design philosophy from Catalina is superb and elegant. We can learn how to design our plugin-supported system by following its design.
😉