ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

How Servlet Containers Work
Pages: 1, 2, 3, 4

Application 2

There is a serious problem in the first application. In the ServletProcessor1 class' process method, we upcast the instance of ex02.pyrmont.Request to javax.servlet.ServletRequest, passing it as the first argument to the servlet's service method. We 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 our servlet container can downcast the ServletRequest and ServletResponse instances back to Request and Response 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 in the ex02.pyrmont package. However, these two methods are not supposed to be available from inside of a servlet. One solution is to give both Request and Response classes a default access modifier, so that they cannot be used from outside the ex02.pyrmont package. However, there is a more elegant solution: using facade classes.

In this second application, we add two facade classes:RequestFacade and ResponseFacade. The RequestFacade class implements the ServletRequest interface and is instantiated by passing a Request instance, which it assigns to a ServletRequest object reference in its constructor. The implementation of each method in the ServletRequest interface invokes the corresponding method of the Request object, but 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. The servlet programmer can still downcast the ServletRequest instance back to the RequestFacade; however, he can only access the methods available in the ServletRequest interface. Now, the parseUri method is safe.

Listing 2.5 shows the incomplete RequestFacade class.

Listing 2.5. The RequestFacade class

package ex02.pyrmont;

public class RequestFacade implements ServletRequest {
    private ServletRequest 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 that 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().startsWith("/servlet/")) {
   ServletProcessor2 processor = new ServletProcessor2();
   processor.process(request, response);
}
else {
    ...
}

The ServletProcessor2 class is similar to ServletProcessor1, except in the following part of the 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);
}

Compiling and Running the Application

To compile the application, type the following from the working directory.

javac -d . -classpath ./lib/servlet.jar src/ex02/pyrmont/*.java

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

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

In Linux, use a semicolon to separate between libraries.

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

You can use the same URLs as Application1 to receive the same result.

Summary

This article discussed a simple servlet container that can be used to serve static resources, as well as to process servlets as simple as PrimitiveServlet. It also provided background information on the javax.servlet.Servlet interface.

Budi Kurniawan is a senior J2EE architect and author.


Return to ONJava.com.