Tomcat(8-2) The Wrapper Application

The wrapper application demonstrates how to write a minimal container module.

The-Wrapper-Application

The wrapper wraps the ModernServlet that you have used in the previous chapters. This application proves that you can have a servlet container consisting only of one wrapper. All classes are not fully developed, implementing only methods that must be present in the class. Let's look at the classes in detail.

SimpleWrapper

This class implements the org.apache.catalina.Wrapper interface and provides implementations of allocate and load methods. Among others, this class declares the following variables:

private Loader loader;
protected Container parent;

The loader variable is a Loader that is used to load the servlet class. The parent variable represents a parent container. This means that this wrapper can be a child container of another container, such as a context.

Pay special attention to its getLoader method, which is given in the following.

public Loader getLoader() {
    if (loader != null) return (loader);
    if (parent != null) return (parent.getLoader());
    return (null);
}

The getLoader returns and Loader instance that is used to loader the servlet class. if this wrapper is associated with a loader, this loader will be returned. if not, it will return the Loader of the parent container. if no parent is available, this method returns null; This class has a Pipeline and sets a basic valve for this Pipeline. You do this in the SimpleWrapper class's constructor.

Here, Pipeline is an instance of SimplePipeline as declared in the class:

private SimplePipeline pipeline = new SimplePipeline(this);

Implemented method of the SimpleWrapper class

// Implemented method of the SimpleWrapper class
public class SimpleWrapper implements Wrapper, Pipeline {
    // the servlet instance
    private Servlet instance = null;
    private String servletClass;
    private Loader loader;
    private String name;
    private SimplePipeline pipeline = new SimplePipeline(this);
    protected Container parent = null;
    public SimpleWrapper() {
        pipeline.setBasic(new SimpleWrapperValve());
    }
    public synchronized void addValve(Valve valve) {
        pipeline.addValve(valve);
    }
    public Servlet allocate() throws ServletException {
        // Load and initialize our instance if necessary
        if (instance == null) {
            try {
                instance = loadServlet();
            } catch (ServletException e) {
                throw e;
            } catch (Throwable e) {
                throw new ServletException("Cannot allocate a servlet instance", e);
            }
        }
        return instance;
    }
    private Servlet loadServlet() throws ServletException {
        if (instance != null)
            return instance;
        Servlet servlet = null;
        String actualClass = servletClass;
        if (actualClass == null) {
            throw new ServletException("servlet class has not been specified");
        }
        Loader loader = getLoader();
        // Acquire an instance of the class loader to be used
        if (loader == null) {
            throw new ServletException("No loader.");
        }
        ClassLoader classLoader = loader.getClassLoader();
        // Load the specified servlet class from the appropriate class loader
        Class classClass = null;
        try {
            if (classLoader != null) {
                classClass = classLoader.loadClass(actualClass);
            }
        } catch (ClassNotFoundException e) {
            throw new ServletException("Servlet class not found");
        }
        // Instantiate and initialize an instance of the servlet class itself
        try {
            servlet = (Servlet) classClass.newInstance();
        } catch (Throwable e) {
            throw new ServletException("Failed to instantiate servlet");
        }
        // Call the initialization method of this servlet
        try {
            servlet.init(null);
        } catch (Throwable f) {
            throw new ServletException("Failed initialize servlet.");
        }
        return servlet;
    }
    public Loader getLoader() {
        if (loader != null)
            return (loader);
        if (parent != null)
            return (parent.getLoader());
        return (null);
    }

 

SimpleWrapperValve

The SimpleWrapperValve class is the basic valve that is declared to processing the request for SimpleWrapper class. It implements the Valve interface and Contained interface. The most important method is invoke method described as the follows:

public void invoke(Request request, Response response, ValveContext valveContext) throws IOException, ServletException {
    SimpleWrapper wrapper = (SimpleWrapper) getContainer();
    ServletRequest sreq = request.getRequest();
    ServletResponse sres = response.getResponse();
    Servlet servlet = null;
    HttpServletRequest hreq = null;
    if (sreq instanceof HttpServletRequest)
        hreq = (HttpServletRequest) sreq;
    HttpServletResponse hres = null;
    if (sres instanceof HttpServletResponse)
        hres = (HttpServletResponse) sres;
    // Allocate a servlet instance to process this request
    try {
        servlet = wrapper.allocate();
        if (hres != null && hreq != null) {
            servlet.service(hreq, hres);
        } else {
            servlet.service(sreq, sres);
        }
    } catch (ServletException e) {
    }
}

Because SimpleWrapperValve is used as the basic valve, its invoke method does not need to call the invokeNext method of the ValveContext passed to it. The invoke method call the allocate method of SimpleWrapper class to obtain a servlet instance the wrapper represents. It then calls the servlet’s service method. Notice that the basic valve of the wrapper’s pipeline invokes the servlet’s service method, not the wrapper itself.

The ClientIPLoggerValve class

This class is a Valve that prints the client’s IP address to console. This class’s invoke method is given in listing:

public class ClientIPLoggerValve implements Valve, Contained {
    protected Container container;
    public void invoke(Request request, Response response,ValveContext valveContext) throws IOException, ServletException {
    // Pass this request on to the next valve in our pipeline
        valveContext.invokeNext(request, response);
        System.out.println("Client IP Logger Valve");
        ServletRequest sreq = request.getRequest();
        System.out.println(sreq.getRemoteAddr());
        System.out.println("------------------------------------");
    }

Pay attention to the invoke method. The first thing this method does is call the invokeNext method of valve context to invoke the next valve in the pipeline, if any. It then prints a few line of string that includes the output of the getRemoteAddr method of the request object.

BootStrap1

This class is used to start the application:

import ex05.pyrmont.core.SimpleLoader;
import ex05.pyrmont.core.SimpleWrapper;
import ex05.pyrmont.valves.ClientIPLoggerValve;
import ex05.pyrmont.valves.HeaderLoggerValve;
import org.apache.catalina.Loader;
import org.apache.catalina.Pipeline;
import org.apache.catalina.Valve;
import org.apache.catalina.Wrapper;
import org.apache.catalina.connector.http.HttpConnector;
public final class Bootstrap1 {
    public static void main(String[] args) {
        HttpConnector connector = new HttpConnector();
        Wrapper wrapper = new SimpleWrapper();
        wrapper.setServletClass("ModernServlet");
        Loader loader = new SimpleLoader();
        Valve valve1 = new HeaderLoggerValve();
        Valve valve2 = new ClientIPLoggerValve();
        wrapper.setLoader(loader);
        ((Pipeline) wrapper).addValve(valve1);
        ((Pipeline) wrapper).addValve(valve2);
        connector.setContainer(wrapper);
        try {
            connector.initialize();
            connector.start();
            // make the application wait until we press a key.
            System.in.read();
        }catch (Exception e) {
            e.printStackTrace();
        }
    }
}

After creating an instance of HttpConnector and SimpleWrapper. The main method assigns the ModermServlet to setServletClass method of SimpleWrapper. Telling the Wrapper the name of the class to be load.

wrapper.setServletClass("ModernServlet");

It ten creates a loader and two Valves and sets the loader to wrapper. The two valves are then added to the wrapper’s pipeline. Finally, the wrapper is set as the container of the connector and the connector is initialized and started.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章