How Tomcat Works

Application 2

There is a serious problem in the first application. In the ServletProcessor1 class's process method, you upcast the instance of ex02.pyrmont.Request to javax.servlet.ServletRequest and pass it as the first argument to the servlet's service method. You also upcast the instance of ex02.pyrmont.Response to javax.servlet.ServletResponse and pass it as the second argument to the servlet's service method.

try {
    servlet = (Servlet) myClass.newInstance();
    servlet.service((ServletRequest) request,
    (ServletResponse) response);
    }

 This compromises security. Servlet programmers who know the internal workings of this servlet container can downcast the ServletRequest and ServletResponse instances back to ex02.pyrmont.Request and ex02.pyrmont.Response respectively and call their public methods. Having a Request instance, they can call its parse method. Having a Response instance, they can call its sendStaticResource method.

You cannot make the parse and sendStaticResource methods private because they will be called from other classes. However, these two methods are not supposed to be available from inside a servlet. One solution is to make both Request and Response classes have default access modifier, so that they cannot be used from outside the ex02.pyrmont package. However, there is a more elegant solution: by using facade classes. See the UML diagram in Figure 2.2.

Figure 2.2: Façade classes

In this second application, we add two façade classes: RequestFacade and ResponseFacade.RequestFacade implements the ServletRequest interface and is instantiated by passing a Request instance that it assigns to a ServletRequest object reference in its constructor. Implementation of each method in the ServletRequest interface invokes the corresponding method of the Request object. However, the ServletRequest object itself is private and cannot be accessed from outside the class. Instead of upcasting the Request object to ServletRequest and passing it to the service method, we construct a RequestFacade object and pass it to the service method. Servlet programmers can still downcast the ServletRequest instance back to RequestFacade, however they can only access the methods available in the ServletRequest interface. Now, the parseUri method is safe.

Listing 2.7 shows an incomplete RequestFacade class.

Listing 2.7: The RequestFacade class

package ex02.pyrmont;

public class RequestFacade implements ServletRequest {
    private ServleLRequest request = null;
    public RequestFacade(Request request) {
        this.request = request;
    }
    /* implementation of the ServletRequest*/
    public Object getAttribute(String attribute) {
        return request.getAttribute(attribute);
    }
    public Enumeration getAttributeNames() {
        return request.getAttributeNames();
    }
    ...
}

Notice the constructor of RequestFacade. It accepts a Request object but immediately assigns it to the private servletRequest object reference. Notice also each method in the RequestFacade class invokes the corresponding method in the ServletRequest object.

The same applies to the ResponseFacade class.

Here are the classes used in Application 2:

  • HttpServer2
  • Request
  • Response
  • StaticResourceProcessor
  • ServletProcessor2
  • Constants

The HttpServer2 class is similar to HttpServer1, except that it uses ServletProcessor2 in its await method, instead of ServletProcessor1:

if (request.getUri().startWith("/servlet/")) {
    servletProcessor2 processor = new ServletProcessor2();
    processor.process(request, response);
    } else {
    ...
}

The ServletProcessor2 class is similar to ServletProcessor1, except in the following part of its process method:

Servlet servlet = null;
RequestFacade requestFacade = new RequestFacade(request);
ResponseFacade responseFacade = new ResponseFacade(response);
try {
    servlet = (Servlet) myClass.newInstance();
    servlet.service((ServletRequest) requestFacade, (ServletResponse) responseFacade);
    }

To run the application on Windows, type this from the working directory:

java -classpath ./lib/servlet.jar;./ ex02.pyrmont.HttpServer2

In Linux, you use a colon to separate two libraries.

java -classpath ./lib/servlet.jar:./ ex02.pyrmont.HttpServer2

You can use the same URLs as in Application1 and you will get the same result.