How Servlet Containers Work
Pages: 1, 2, 3, 4
The HttpServer1 Class
The HttpServer1 class in this application is similar to the
HttpServer class in the simple web server application in the
previous article. However, in this application, the HttpServer1
can serve both static resources and servlets. To request a static resource, use
a URL in the following format:
http://machineName:port/staticResource
This is exactly how you requested a static resource in the web server application in the previous article. To request a servlet, you use the following URL:
http://machineName:port/servlet/servletClass
Therefore, if you are using a browser locally to request a servlet called
PrimitiveServlet, enter the following URL in the browser's address or URL
box:
http://localhost:8080/servlet/PrimitiveServlet
The class' await method, given in Listing 2.2, waits for HTTP
requests until a shutdown command is issued. It is similar to the
await method discussed in the previous article.
Listing 2.2. The HttpServer1 class'
await method
public void await() {
ServerSocket serverSocket = null;
int port = 8080;
try {
serverSocket = new ServerSocket(port, 1,
InetAddress.getByName("127.0.0.1"));
}
catch (IOException e) {
e.printStackTrace();
System.exit(1);
}
// Loop waiting for a request
while (!shutdown) {
Socket socket = null;
InputStream input = null;
OutputStream output = null;
try {
socket = serverSocket.accept();
input = socket.getInputStream();
output = socket.getOutputStream();
// create Request object and parse
Request request = new Request(input);
request.parse();
// create Response object
Response response = new Response(output);
response.setRequest(request);
// check if this is a request for a servlet or a static resource
// a request for a servlet begins with "/servlet/"
if (request.getUri().startsWith("/servlet/")) {
ServletProcessor1 processor = new ServletProcessor1();
processor.process(request, response);
}
else {
StaticResourceProcessor processor =
new StaticResourceProcessor();
processor.process(request, response);
}
// Close the socket
socket.close();
//check if the previous URI is a shutdown command
shutdown = request.getUri().equals(SHUTDOWN_COMMAND);
}
catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
}
The difference between the await method in Listing 2.2 and the
one in the previous article is that in Listing 2.2, the request can be
dispatched to either a StaticResourceProcessor or a
ServletProcessor. The request is forwarded to the latter if the
URI contains the string "/servlet/." Otherwise, the request is
passed to the StaticResourceProcessor instance.
The Request Class
A servlet's service method accepts a
javax.servlet.ServletRequest instance and a
javax.servlet.ServletResponse instance from the servlet container.
The container therefore must construct a ServletRequest object and
a ServletResponse object to pass to the service
method of the servlet being served.
The ex02.pyrmont.Request class represents a request object to
pass to the service method. As such, it must implement the
javax.servlet.ServletRequest interface. This class has to provide
implementations for all methods in the interface. However, we'd like to make it
very simple and implement only a few of the methods. To compile the
Request class, you'll need to provide blank implementations for
those methods. If you look at the Request class, you can see that
all methods whose signatures return an object instance return a
null, such as the following:
...
public Object getAttribute(String attribute) {
return null;
}
public Enumeration getAttributeNames() {
return null;
}
public String getRealPath(String path) {
return null;
}
...
In addition, the Request class still has the parse
and the getUri methods, which were discussed in the previous
article.
The Response Class
The Response class implements
javax.servlet.ServletResponse. As such, the class must provide
implementations for all of the methods in the interface. Similar to the
Request class, I leave the implementations of all methods "blank,"
except the getWriter method.
public PrintWriter getWriter() {
// autoflush is true, println() will flush,
// but print() will not.
writer = new PrintWriter(output, true);
return writer;
}
The second argument to the PrintWriter class' constructor is a
Boolean indicating whether or not autoflush is enabled. Passing true as the
second argument will make any call to a println method flush the
output. However, a print call does not flush the output.
Therefore, if a call to a print method happens to be the last line
in a servlet's service method, the output is not sent to the
browser. This imperfection will be fixed in the later applications.
The Response class still has the
sendStaticResource method discussed in the previous article.
The StaticResourceProcessor Class
The StaticResourceProcessor class is used to serve requests for
static resources. Its only method is process, as shown in Listing
2.3.
Listing 2.3. The StaticResourceProcessor class'
process method
public void process(Request request, Response response) {
try {
response.sendStaticResource();
}
catch (IOException e) {
e.printStackTrace();
}
}
The process method receives two arguments: a
Request instance and a Response instance. It simply
calls the sendStaticResource method of the Response
class.