servlet
The Servlet Technology
• The Benefits of Servlets
• Servlet Application Architecture
• How a Servlet Works
• The Tomcat Servlet Container
• Six Steps to Running Your First Servlet
• Summary
The servlet technology is the foundation of web application development using the Java programming language. It is one of the most important Java technologies, and it is the underlying technology for another popular Java technology for web application development: JavaServer Pages (JSP). Therefore, understanding the servlet technology and its architecture is important if you want to be a servlet developer. Even if you plan to develop your Java web application using JSP pages alone, understanding the servlet technology helps you build a more efficient and effective JSP application.
The aim of this chapter is to introduce the servlet technology and make you comfortable with it by presenting step-by-step instructions that enable you to build and run a servlet application.
In particular, this chapter discusses the following topics:
• The benefits of servlets
• Servlet application architecture
• How a servlet works
• How to write and run your first servlet application
Throughout this book, Tomcat 4.0 is used as both the servlet container and JSP container. In this chapter, you learn how to configure Tomcat quickly so that you can run your first servlet application.
Chapter 1. The Servlet Technology
• The Benefits of Servlets
• Servlet Application Architecture
• How a Servlet Works
• The Tomcat Servlet Container
• Six Steps to Running Your First Servlet
• Summary
The servlet technology is the foundation of web application development using the Java programming language. It is one of the most important Java technologies, and it is the underlying technology for another popular Java technology for web application development: JavaServer Pages (JSP). Therefore, understanding the servlet technology and its architecture is important if you want to be a servlet developer. Even if you plan to develop your Java web application using JSP pages alone, understanding the servlet technology helps you build a more efficient and effective JSP application.
The aim of this chapter is to introduce the servlet technology and make you comfortable with it by presenting step-by-step instructions that enable you to build and run a servlet application.
In particular, this chapter discusses the following topics:
• The benefits of servlets
• Servlet application architecture
• How a servlet works
• How to write and run your first servlet application
Throughout this book, Tomcat 4.0 is used as both the servlet container and JSP container. In this chapter, you learn how to configure Tomcat quickly so that you can run your first servlet application.
The Benefits of Servlets
When it first emerged, this great thing we call the Internet consisted of only static contents written using Hypertext Markup Language (HTML). At that time, anyone who could author HTML pages was considered an Internet expert.
This did not last long, however.
Soon dynamic web contents were made possible through the Common Gateway Interface (CGI) technology. CGI enables the web server to call an external program and pass HTTP request information to that external program to process the request. The response from the external program is then passed back to the web server, which forwards it to the client browser. CGI programs can be written in any language that can be called by the web server. Over the course of time, Perl became the most popular language to write CGI programs.
As the Internet became more and more popular, however, the number of users visiting a popular web site increased exponentially, and it became apparent that CGI had failed to deliver scalable Internet applications. The flaw in CGI is that each client request makes the web server spawn a new process of the requested CGI program. As we all know, process creation is an expensive operation that consumes a lot of CPU cycles and computer memory.
Gradually, new and better technologies will replace CGI as the main technology for web application development. The world has witnessed the following technologies trying to dominate web development:
• ColdFusion. Allaire's ColdFusion provides HTML-like custom tags that can be used to perform a number of operations, especially querying a database. This technology had its glamorous time in the history of the World Wide Web as the main technology for web application programming. Its glorious time has since gone with the invention of other technologies.
• Server-side JavaScript (SSJS). SSJS is an extension of the JavaScript language, the scripting language that still rules client-side web programming. SSJS can access Java classes deployed at the server side using the LiveWire technology from Netscape.
• PHP. PHP is an exciting open-source technology that has matured in recent years. The technology provides easy web application development with its session management and includes some built-in functionality, such as file upload. The number of programmers embracing PHP as their technology of choice has risen sharply in recent years.
• Servlet. The servlet technology was introduced by Sun Microsystems in 1996. This technology is the main focus of this book and will be explained in more detail in this and coming chapters.
• JavaServer Pages (JSP). JSP is an extension of the servlet technology. This, too, is the center of attention in this book.
• Active Server Pages (ASP). Microsoft's ASP employs scripting technologies that work in Windows platforms, even though there have been efforts to port this technology to other operating systems. Windows ASP works with the Internet Information Server web server. This technology will soon be replaced by Active Server Pages.NET.
• Active Server Pages.NET (ASP.NET). This technology is part of Microsoft's .NET initiative. Interestingly, the .NET Framework employs a runtime called the Common Language Runtime that is very similar to Java Virtual Machine and provides a vast class library available to all .NET languages and from ASP.NET pages. ASP.NET is an exciting technology. It introduced several new technologies including state management that does not depend on cookies or URL rewriting.
In the past, ASP and servlet/JSP have been the main technologies used in web application development. With the release of ASP.NET, it is not hard to predict that this technology will become the servlet/JSP's main competitor. ASP (and ASP.NET) and servlet/JSP each have their own fans, and it is not easy to predict which one will come out the winner. The most likely outcome is that neither will be an absolute winner that corners the market; instead the technologies will probably run head-to-head in the coming years.
Servlet (and JSP) offers the following benefits that are not necessarily available in other technologies:
• Performance. The performance of servlets is superior to CGI because there is no process creation for each client request. Instead, each request is handled by the servlet container process. After a servlet is finished processing a request, it stays resident in memory, waiting for another request.
• Portability. Similar to other Java technologies, servlet applications are portable. You can move them to other operating systems without serious hassles.
• Rapid development cycle. As a Java technology, servlets have access to the rich Java library, which helps speed up the development process.
• Robustness. Servlets are managed by the Java Virtual Machine. As such, you don't need to worry about memory leak or garbage collection, which helps you write robust applications.
• Widespread acceptance. Java is a widely accepted technology. This means that numerous vendors work on Java-based technologies. One of the advantages of this widespread acceptance is that you can easily find and purchase components that suit your needs, which saves precious development time.
Servlet Application Architecture
A servlet is a Java class that can be loaded dynamically into and run by a special web server. This servlet-aware web server is called a servlet container, which also was called a servlet engine in the early days of the servlet technology.
Servlets interact with clients via a request-response model based on HTTP. Because servlet technology works on top of HTTP, a servlet container must support HTTP as the protocol for client requests and server responses. However, a servlet container also can support similar protocols, such as HTTPS (HTTP over SSL) for secure transactions.
In a JSP application, the servlet container is replaced by a JSP container. Both the servlet container and the JSP container often are referred to as the web container or servlet/JSP container, especially if a web application consists of both servlets and JSP pages.
Note
a servlet application also can include static content, such as HTML pages and image files. Allowing the servlet container to serve static content is not preferable because the content is faster if served by a more robust HTTP server, such as the Apache web server or Microsoft Internet Information Server. As such, it is common practice to put a web server at the front to handle all client requests..
A Java web application architecture employing a J2EE server is different from the diagrams in Figures 1.1 and 1.2.
How a Servlet Works
A servlet is loaded by the servlet container the first time the servlet is requested. The servlet then is forwarded the user request, processes it, and returns the response to the servlet container, which in turn sends the response back to the user. After that, the servlet stays in memory waiting for other requests—it will not be unloaded from the memory unless the servlet container sees a shortage of memory. Each time the servlet is requested, however, the servlet container compares the timestamp of the loaded servlet with the servlet class file. If the class file timestamp is more recent, the servlet is reloaded into memory. This way, you don't need to restart the servlet container every time you update your servlet.
The Tomcat Servlet Container
A number of servlet containers are available today. The most popular one—and the one recognized as the official servlet/JSP container—is Tomcat. Originally designed by Sun Microsystems, Tomcat source code was handed over to the Apache Software Foundation in October 1999. In this new home, Tomcat was included as part of the Jakarta Project, one of the projects of the Apache Software Foundation. Working through the Apache process, Apache, Sun, and other companies—with the help of volunteer programmers worldwide—turned Tomcat into a world-class servlet reference implementation. Two months after the handover, Tomcat version 3.0 was released. Tomcat went through several 3.x releases until version 3.3 was introduced.
The successor of version 3.3 is the current version, version 4.0. The 4.0 servlet container (Catalina) is based on a completely new architecture and has been developed from the ground up for flexibility and performance. Version 4.0 implements the Servlet 2.3 and JSP 1.2 specifications, and it is this version you will be using in this book.
Another popular servlet container is JRun from Allaire Corporation. JRun is available in three editions: Developer, Professional, and Enterprise. The Developer edition is free but not licensed for deployment. The Professional and Enterprise editions grant you the license for deployment with a fee. You can download JRun from http://commerce.allaire.com/download.
Tomcat by itself is a web server. This means that you can use Tomcat to service HTTP requests for servlets, as well as static files (HTML, image files, and so on). In practice, however, since it is faster for non-servlet, non-JSP requests, Tomcat normally is used as a module with another more robust web server, such as Apache web server or Microsoft Internet Information Server. Only requests for servlets or JSP pages are passed to Tomcat.
To write a servlet, you need at least version 1.2 of the Java Development Kit. If you have not already downloaded one, you can download JDK 1.2 from http://java.sun.com/j2se. The reference implementation for both servlets and JSP are not included in J2SE, but they are included in Tomcat. Tomcat is written purely in Java.
Six Steps to Running Your First Servlet
After you have installed and configured Tomcat, you can put it into service. Basically, you need to follow six steps to go from writing your servlet to running it. These steps are summarized as follows:
1. Create a directory structure under Tomcat for your application.
2. Write the servlet source code. You need to import the javax.servlet package and the javax.servlet.http package in your source file.
3. Compile your source code.
4. Create a deployment descriptor.
5. Run Tomcat.
6. Call your servlet from a web browser.
The sections that follow walk you through each of these steps.
Step 1: Create a Directory Structure Under Tomcat
Note
The directory where Tomcat is installed is often referred to as %CATALINA_HOME%. In previous versions of Tomcat, this directory was called %TOMCAT_HOME%.
When you install Tomcat, several subdirectories are automatically created under the Tomcat home directory (%CATALINA_HOME%). One of the subdirectories is webapps. The webapps directory is where you store your web applications. A web application is a collection of servlets and other content installed under a specific subset of the server's URL namespace. A separate directory is dedicated for each servlet application. Therefore, the first thing to do when you build a servlet application is create an application directory. To create a directory structure for an application called myApp, follow these steps:
1. Create a directory called myApp under the webapps directory. The directory name is important because this also appears in the URL to your servlet.
2. Create the and WEB-INF directories under myApp, and create a directory named classes under WEB-INF. The directory classes under WEB-INF is for your Java classes. If you have HTML files, put them directly under the myApp directory. You may also want to create a directory called images under myApp for all your image files.
Note that the examples, manager, ROOT, tomcat-doc, and webdav directories are for applications that are created automatically when you install Tomcat.
Step 2: Write the Servlet Source Code
In this step, you prepare your source code. You can write the source code yourself using your favorite text editor or copy it from the accompanying CD.
Tip
The source code for all examples in this book are also available on the book's web site. Check out www.newriders.com to download the files you need.
The code in Listing 1.1 shows a simple servlet called TestingServlet. The file is named TestingServlet.java. The servlet sends a few HTML tags and some text to the browser. For now, don't worry if you haven't got a clue about how it works.
Listing 1.1 TestingServlet.java
Now, save your TestingServlet.java file to the WEB-INF/classes directory under myApp. Placing your source code here will make it inaccessible from a web browser. Static files, such as HTML files and image files, should be placed directly under the myApp directory or a directory under it.
Warning
Placing your source code files outside the WEB-INF directory will make them viewable from a browser.
Step 3: Compile Your Source Code
For your servlet source code to compile, you need to include the path to the servlet.jar file in your CLASSPATH environment variable. The servlet.jar is located in the common\lib\ subdirectory under %CATALINA_HOME%.
For example, if you installed Tomcat under the C:\drive on Windows and you named the install directory tomcat, type the following command from the directory where TestingServlet.java resides.
javac classpath C:\tomcat\common\lib\servlet.jar TestingServlet.java
Alternatively, to save you typing the class path every time you compile your source code, you can add the complete path to the servlet.jar file to your CLASSPATH environment variable. Again, if you have installed Tomcat under C:\and named the install directory tomcat, you must add C:\tomcat\ common\lib\servlet.jar to the CLASSPATH environment variable. Afterward, you can compile your source by simply typing the following.
javac TestingServlet.java
Note
If you are using Windows, remember that the new environment variable takes effect only for new console windows. In other words, after changing a new environment variable, open a new console window for typing in your command lines.
Step 4: Create the Deployment Descriptor
A deployment descriptor is an optional component in a servlet application. The descriptor takes the form of an XML document called web.xml and must be located in the WEB-INF directory of the servlet application. When present, the deployment descriptor contains configuration settings specific to that application.
To create the deployment descriptor, you now need to create a web.xml file and place it under the WEB-INF directory under myApp.
The web.xml for this example application must have the following content.
The web.xml file has one element—web-app. You should write all your servlets under . For each servlet, you have a element and you need the and elements. The is the name for your servlet, by which it is known Tomcat. The is the compiled file of your servlet without the .class extension.
Having more than one servlet in an application is very common. For every servlet, you need a element in the web.xml file. For example, the following shows you how web.xml looks if you add another servlet called Login:
Step 5: Run Tomcat
If Tomcat is not already running, you need to start it.
Step 6: Call Your Servlet from a Web Browser
Now, you can call your servlet from a web browser. By default, Tomcat runs on port 8080 in the myApp virtual directory under the servlet subdirectory. The servlet that you wrote in the preceding steps is named Testing. The URL for that servlet has the following format:
http://domain-name/virtual-directory/servlet/servlet-name
Any static file can be accessed using the following URL:
http://domain-name/virtual-directory/staticFile.html
For example, a Logo.gif file under the myApp/images/ directory can be accessed using the following URL.
http://domain-name/virtual-directory/images/Logo.gif
If you run the web browser from the same computer as Tomcat, you can replace the domain-name part with "localhost". In that case, the URL for your servlet is
http://localhost:8080/myApp/servlet/Testing
In the deployment descriptor you wrote in Step 4, you actually mapped the servlet class file called TestingServlet with the name "Testing," so that your servlet can be called by specifying its class file (TestingServlet) or its name (Testing). Without a deployment descriptor, you must call the servlet by specifying its class name; that is, TestingServlet. This means that if you did not write a deployment descriptor in Step 4, you need to use the following URL to call your servlet:
http://localhost:8080/myApp/servlet/TestingServlet
Typing the URL in the Address or Location box of your web browser will give you the string "Welcome to the Servlet Testing Center,".
Congratulations. You have just written your first servlet.
If you don't want to type the port number each time, you can change the default port of Tomcat so that it runs on port 80, the default port for a web server. However, the rest of the book will use Tomcat's default port 8080.
Note
You will find code for various servlets in this chapter and the next. To run each individual servlet, you need to repeat these six steps. To avoid repetition, I do not mention these steps for every servlet presented in this book. You don't need to worry about these steps if you are using a Java development tool, such as Borland's JBuilder or IBM's VisualAge, because those steps are taken care of by the RAD program.
Summary
This chapter has given you the big picture of how to build a servlet application. Specifically, you learned about the benefits of servlets, explored servlet application architecture, and discovered how a servlet works inside the servlet container. You also have been shown how to configure Tomcat and followed the six steps you need to build your own servlets. The next chapter digs deeper into the servlet technology by presenting the Java Servlet specification Application Programming Interface (API) version 2.3
CONTENTS
Inside Servlets
• The javax.servlet Package
• A Servlet's Life Cycle
• Obtaining Configuration Information
• Preserving the ServletConfig
• The Servlet Context
• Sharing Information Among Servlets
• Requests and Responses
• The GenericServlet Wrapper Class
• Creating Thread-Safe Servlets
• Summary
Watching your servlet in action, as you did in Chapter 1, "The Servlet Technology," should bring you confidence. And, as some people say, having confidence is half the battle in learning anything. To be an expert, however, you need to understand the nuts and bolts of the Java Servlet specification Application Programming Interface (API). This book has been written using the latest release of the servlet specification API—version 2.3. Two packages are available for servlet programmers: javax.servlet and javax.servlet.http. The first one contains basic classes and interfaces that you can use to write servlets from the scratch. The second package, javax.servlet.http, offers more advanced classes and interfaces that extend classes and interfaces from the first package. It is much more convenient to program using the second package.
When you learn something, it is best to start with the basics and build a strong foundation. For example, understanding the javax.servlet.Servlet interface is very important because it encapsulates the life cycle methods of a servlet and it is the interface that all servlets must implement. You also need to know the servlet's context, which represents a servlet's environment, and the servlet's configuration. Because of the importance of these items, this chapter introduces you to members of the javax.servlet package. In this chapter, you also will see that oftentimes several ways exist to do the same thing.
After a few examples, I will introduce you to the GenericServlet class, a member of the javax.servlet package that acts as a wrapper for the javax.servlet.Servlet interface. Extending this class makes your code simpler because you need to provide implementations only for methods that you need to use.
To run each example in this chapter, you need to compile the source code and copy the resulting class file into the classes directory under the WEB-INF directory of your application. Refer to Chapter 1 if you have forgotten the six steps you need to run your servlet.
The rest of this chapter explains and uses the interfaces and classes of the javax.servlet package. The chapters that follow focus more on the second package.
The javax.servlet Package
The javax.servlet package contains seven interfaces, three classes, and two exceptions. Instead of using the conventional approach by explaining each interface and class in alphabetical order—thus making the book feel like a dictionary—I present the discussions based on functions and offer examples that demonstrate each function.
Nevertheless, mastering all the members of this package is important. To help you, a complete reference is given in Appendix B, "The javax.servlet Package Reference."
The seven interfaces are as follows:
• RequestDispatcher
• Servlet
• ServletConfig
• ServletContext
• ServletRequest
• ServletResponse
• SingleThreadModel
The three classes are as follows:
• GenericServlet
• ServletInputStream
• ServletOutputStream
And, finally, the exception classes are these:
• ServletException
• UnavailableException
A Servlet's Life Cycle
Let there be servlet. This interface in the javax.servlet package is the source of all activities in servlet programming. Servlet is the central abstraction of the Java servlet technology. Every servlet you write must implement this javax.servlet.Servlet interface, either directly or indirectly. The life cycle of a servlet is determined by three of its methods: init, service, and destroy.
The init( ) Method
The init method is called by the servlet container after the servlet class has been instantiated. The servlet container calls this method exactly once to indicate to the servlet that the servlet is being placed into service. The init method must complete successfully before the servlet can receive any requests.
You can override this method to write initialization code that needs to run only once, such as loading a database driver, initializing values, and so on. In other cases, you normally leave this method blank.
The signature of this method is as follows:
public void init(ServletConfig config) throws ServletException
The init method is important also because the servlet container passes a ServletConfig object, which contains the configuration values stated in the web.xml file for this application. More on ServletConfig can be found later in this chapter, in the section,
This method also can throw a ServletException. The servlet container cannot place the servlet into service if the init method throws a ServletException or the method does not return within a time period defined by the web server.
Note
ServletException is the most important exception in servlet programming. In fact, a lot of methods in the javax.servlet and javax.servlet.http packages can throw this exception when a problem exists in a servlet.
The service( ) Method
The service method is called by the servlet container after the servlet's init method to allow the servlet to respond to a request.
Servlets typically run inside multithreaded servlet containers that can handle multiple requests concurrently. Therefore, you must be aware to synchronize access to any shared resources, such as files, network connections, and the servlet's class and instance variables. For example, if you open a file and write to that file from a servlet, you need to remember that a different thread of the same servlet also can open the same file. See the section, "Creating Thread-Safe Servlets," for more on the topic of multithreading and synchronization.
This method has the following signature:
public void service(ServletRequest request, ServletResponse response)
throws ServletException, java.io.IOException
The servlet container passes a ServletRequest object and the ServletResponse object. The ServletRequest object contains the client's request and the ServletResponse contains the servlet's response. These two objects are important because they enable you to write custom code that determines how the servlet services the client request.
The service method throws a ServletException if an exception occurs that interferes with the servlet's normal operation. The service method also can throw a java.io.IOException if an input or output exception occurs during the execution of this method.
As the name implies, the service method exists so that you can write code that makes the servlet function the way it is supposed to.
The destroy( ) Method
The servlet container calls the destroy method before removing a servlet instance from service. This normally happens when the servlet container is shut down or the servlet container needs some free memory.
This method is called only after all threads within the servlet's service method have exited or after a timeout period has passed. After the servlet container calls this method, it will not call the service method again on this servlet.
The destroy method gives the servlet an opportunity to clean up any resources that are being held (for example, memory, file handles, and threads) and make sure that any persistent state is synchronized with the servlet's current state in memory.
The signature of this method is as follows:
public void destroy()
Demonstrating the Life Cycle of a Servlet
Listing 2.1 contains the code for a servlet named PrimitiveServlet, a very simple servlet that exists to demonstrate the life cycle of a servlet. The PrimitiveServlet class implements javax.servlet.Servlet (as all servlets must) and provides implementations for all the five methods of servlet. What it does is very simple. Each time any of the init, service, or destroy methods is called, the servlet writes the method's name to the console.
Listing 2.1 PrimitiveServlet.java
After you compile the source code into the myApp\WEB-INF\classes directory, add the servlet to the web.xml under the name Primitive, as shown in Listing 2.2.
Listing 2.2 The web.xml File for PrimitiveServlet
You should then be able to call this servlet from your browser by typing the following URL:
http://localhost:8080/myApp/servlet/Primitive
The first time the servlet is called, the console displays these two lines:
init
service
This tells you that the init method is called, followed by the service method. However, on subsequent requests, only the service method is called. The servlet adds the following line to the console:
service
This proves that the init method is called only once.
What are the getServletInfo and getServletConfig doing in Listing 2.1 ? Nothing. They can be useful, but in the PrimitiveServlet class, they are just there to meet the specification that a class must provide implementations for all methods in the interface it implements.
You can return any string in the getServletInfo method, such as your company name or the author name or other information deemed necessary. Other people might extend your servlet class and might want to know what useful information the designer of the servlet has provided.
The getServletConfig is more important. We will see how it can be of use next.
Obtaining Configuration Information
The servlet specification allows you to configure your application. You'll find more information on this topic in the discussion of the deployment descriptor in
"Application Deployment." In this chapter, I present an example that demonstrates how you can retrieve configuration information from the application web.xml file.
For each servlet registered in the web.xml file, you have the option of specifying a set of initial parameter name/value pairs that you can retrieve from inside the servlet. The following web.xml file contains a servlet called ConfigDemo whose class is named ConfigDemoServlet.class. The servlet has two initial parameter name/value pairs. The first parameter is named adminEmail and its value is admin@brainysoftware.com. The second parameter is named adminContactNumber and the value for this parameter is 04298371237.
Why would you want to use an initial parameter? For practicality. Hardcoding information in the servlet code means that you have to recompile the servlet if the information changes. A web.xml file is plain text. You can edit its content easily using a text editor.
The code that retrieves the initial parameter name and values is given in Listing 2.3.
To retrieve initial parameters, you need the ServletConfig object passed by the servlet container to the servlet. After you get the ServletConfig object, you then can use its getInitParameterNames and getInitParameter methods. The getInitParameterNames does not take an argument and returns an Enumeration containing all the parameter names in the ServletConfig object. The getInitParameter takes a String containing the parameter name and returns a String containing the value of the parameter.
Because the servlet container passes a ServletConfig object to the init method, it is easiest to write the code in the init method. The code in Listing 2.3 loops through the Enumeration object called parameters that is returned from the getInitParameterNames method. For each parameter, it outputs the parameter name and value. The parameter value is retrieved using the getInitParameter method.
Listing 2.3 Retrieving Initial Parameters
The output of the code in the console is as follows:
Parameter name : adminContactNumber
Parameter value : 04298371237
Parameter name : adminEmail
Parameter value : admin@brainysoftware.com
Preserving the ServletConfig
The code in Listing 2.3 shows how you can use the ServletConfig object in the init method. Sometimes, however, you may want more flexibility. For example, you may want to have access to the ServletConfig object from the service method, when you are servicing the user. In this case, you need to preserve the ServletConfig object to a class level variable. This task is not difficult. You need to create a ServletConfig object variable and set it to the ServletConfig object returned by the servlet container in the init method.
Listing 2.4 gives the code that preserves the ServletConfig object for later use. First, you need a variable for the ServletConfig object.
ServletConfig servletConfig;
Then, in the init method, you write the following code:
servletConfig = config;
Now the servletConfig variable references the ServletConfig object returned by the servlet container. The getServletConfig method is provided to do just that: return the ServletConfig object.
public ServletConfig getServletConfig() {
return servletConfig;
}
If you extend the ReserveConfigServlet class, you can still retrieve the ServlerConfig object by calling the getServletConfig method.
Listing 2.4 Preserving the ServletConfig Object
The Servlet Context
In servlet programming, the servlet context is the environment where the servlet runs. The servlet container creates a ServletContext object that you can use to access information about the servlet's environment.
A servlet also can bind an object attribute into the context by name. Any object bound into a context is available to any other servlet that is part of the same web application.
How do you obtain the ServletContext object? Indirectly, from the ServletConfig object passed by the servlet container to the servlet's init method. The ServletConfig interface has a method called getServletContext that returns the ServletContext object. You then can use the ServletContext interface's various methods to get the information you need. These methods include the following:
• getMajorVersion. This method returns an integer representing the major version for the servlet API that the servlet container supports. If the servlet container supports the servlet API version 2.3, this method will return 2.
• getMinorVersion. This method returns an integer representing the minor version of the servlet API that the servlet container supports. For the servlet API version 2.3, this method will return 3.
• getAttributeNames. This method returns an enumeration of strings representing the names of the attributes currently stored in the ServletContext.
• getAttribute. This method accepts a String containing the attribute name and returns the object bound to that name.
• setAttribute. This method stores an object in the ServletContext and binds the object to the given name. If the name already exists in the ServletContext, the old bound object will be replaced by the object passed to this method.
• removeAttribute. This method removes from the ServletContext the object bound to a name. The removeAttribute method accepts one argument: the name of the attribute to be removed.
The code in Listing 2.5 shows a servlet named ContextDemoServlet that retrieves some of the servlet context information, including attribute names and values, minor and major versions of the servlet container, and the server info.
Listing 2.5 Retrieving Servlet Context Information
The output of the code is as follows. This output may be different on your computer, depending on the version of Tomcat you are using, the operating system, and so on.
Attribute name : javax.servlet.context.tempdirAttribute value :
..\work\localhost\myApp
Attribute name : org.apache.catalina.resources
Attribute value : org.apache.naming.resources.ProxyDirContext@24e2e3
Attribute name : org.apache.catalina.WELCOME_FILES
Attribute value : [Ljava.lang.String;@2bb7e0
Attribute name : org.apache.catalina.jsp_classpath
Attribute value : C:\tomcat4\webapps\myApp\WEB-INF\classes;
.
.
. Major version : 2Minor version : 3
Server info : Apache Tomcat/4.0-b5
Sharing Information Among Servlets
For some applications, you want to make certain types of information available to all the servlets. You can share this information—such as a database connection string or a page count—among the servlets by using attributes in the ServletContext object.
The following example uses two servlets: AttributeSetterServlet and DisplayAttributesServlet. The AttributeSetterServlet servlet, shown in Listing 2.6, binds the name password to a String object containing the word "ding-dong". The servlet does this by first obtaining the ServletContext object from the ServletConfig object passed by the servlet container to the init method. Then the servlet uses the setAttribute method to bind "password" with "ding-dong".
Listing 2.6 The AttributeSetterServlet
The code in Listing 2.7 is the servlet that retrieves all attribute name/value pairs in the ServletContext object. The init method of this servlet preserves the ServletConfig object into servletConfig. The service method then uses the ServletConfig interface's getServletContext method to obtain the ServletContext object. After you get the ServletContext object, you can then use its getAttributeNames method to get an Enumeration of all attribute names and loop through it to obtain each attribute's value, which it outputs to the console along with the attribute name.
Listing 2.7 DisplayAttributesServlet
To see the servlets work, first you need to call the AttributeSetterServlet servlet to set the attribute "password". You then call the DisplayAttributesServlet to get an Enumeration of the names of all attributes and display the values.
The output is given here:
Attribute name : javax.servlet.context.tempdir
Attribute value : C:\123data\JavaProjects\JavaWebBook\work\localhost_8080
Attribute name : password
Attribute value : dingdong
Attribute name : sun.servlet.workdir
Attribute value : C:\123data\JavaProjects\JavaWebBook\work\localhost_8080
Requests and Responses
Requests and responses are what a web application is all about. In a servlet application, a user using a web browser sends a request to the servlet container, and the servlet container passes the request to the servlet.
In a servlet paradigm, the user request is represented by the ServletRequest object passed by the servlet container as the first argument to the service method. The service method's second argument is a ServletResponse object, which represents the response to the user.
The ServletRequest Interface
The ServletRequest interface defines an object used to encapsulate information about the user's request, including parameter name/value pairs, attributes, and an input stream.
The ServletRequest interface provides important methods that enable you to access information about the user. For example, the getParameterNames method returns an Enumeration containing the parameter names for the current request. To get the value of each parameter, the ServletRequest interface provides the getParameter method.
The getRemoteAddress and getRemoteHost methods are two methods that you can use to retrieve the user's computer identity. The first returns a string representing the IP address of the computer the client is using, and the second method returns a string representing the qualified host name of the computer.
The following example, shown in Listings 2.8 and 2.9, shows a ServletRequest object in action. The example consists of an HTML form in a file named index.html that you need to put in the application directory—that is, under myApp—and a servlet called RequestDemoServlet.
Listing 2.8 index.html
Listing 2.9 RequestDemoServlet
To run the example, first request the index.html file by using the following URL:
http://localhost:8080/myApp/index.html
Figure 2.2 shows the index.html file in which "haywood" has been typed in as the value for author.
Figure 2.2. The index.html file.
When you submit the form, you should see the list of attribute names and values in your console.
The ServletResponse Interface
The ServletResponse interface represents the response to the user. The most important method of this interface is getWriter, from which you can obtain a java.io.PrintWriter object that you can use to write HTML tags and other text to the user.
The code in Listings 2.10 and 2.11 offer an HTML file named index2.html and a servlet whose service method is overridden with code that outputs some HTML tags to the user. This servlet modifies the example in Listings 2.8 and 2.9 that retrieves various information about the user. Instead of sending the information to the console, the service method sends it back to the user.
Note that the code in Listing 2.10 is similar to the code in Listing 2.8, except that in Listing 2.10 the value for the form's ACTION attribute is servlet/ResponseDemoServlet.
Listing 2.10 index2.html
Listing 2.11 The ResponseDemoServlet
To run the example, first request the index2.html file by using the following URL:
http://localhost:8080/myApp/index2.html
Figure 2.3 shows the index2.html file in which "haywood" has been typed in as the value for author.
Figure 2.3. The index2.html file.
When you submit the form, the ResponseDemoServlet is invoked and your browser should display an image similar to Figure 2.4.
Figure 2.4. Utilizing the ServletResponse object.
The GenericServlet Wrapper Class
Throughout this chapter, you have been creating servlet classes that implement the javax.servlet.Servlet interface. Everything works fine, but there are two annoying things that you've probably noticed:
1. You have to provide implementations for all five methods of the Servlet interface, even though most of the time you only need one. This makes your code look unnecessarily complicated.
2. The ServletConfig object is passed to the init method. You need to preserve this object to use it from other methods. This is not difficult, but it means extra work.
The javax.servlet package provides a wrapper class called GenericServlet that implements two important interfaces from the javax.servlet package: Servlet and ServletConfig, as well as the java.io.Serializable interface. The GenericServlet class provides implementations for all methods, most of which are blank. You can extend GenericServlet and override only methods that you need to use. Clearly, this looks like a better solution.
The code in Listing 2.12 is a servlet called SimpleServlet that extends GenericServlet. The code provides the implementation of the service method that sends some output to the browser. Because the service method is the only method you need, only this method needs to appear in the class. Compared to all servlet classes that implement the javax.servlet.Servlet interface directly, SimpleServlet looks much cleaner and clearer.
Listing 2.12 Extending GenericServlet
The output from the SimpleServlet servlet is shown in Figure 2.5.
Figure 2.5. Extending GenericServlet.
Creating Thread-Safe Servlets
A servlet container allows multiple requests for the same servlet by creating a different thread to service each request. In many cases, each thread deals with its own ServletRequest and ServletResponse objects that are isolated from other threads. Problems start to arise, however, when your servlet needs to access an external resource. To understand the problem introduced by multithreaded servlets, consider the following "playing dog" illustration.
Imagine a servlet accessing an external resource as a dog who enjoys moving tennis balls from one box to another. Each box can hold ten balls, no matter how the balls are arranged. The boxes and the balls are an external resource to the dog. To play, the dog needs two boxes and ten balls. Initially, those ten balls are placed in the first box. The dog moves all balls from the first box to the second, one ball at a time. The dog is smart enough to count to ten. Therefore, it knows when it's finished.
Now imagine a second thread of the same servlet as a second dog that plays the same game. Because there are only two boxes and ten balls for both dogs, the two dogs share the same "external resource." The game goes like this:
1. The first dog starts first (the servlet receives a call from a user).
2. After the first dog moves three balls, the second dog starts to play (the servlet is invoked by the second user). What will happen?
The two dogs sharing the same balls are illustrated in Figure 2.6.
Figure 2.6. Understanding multi-threaded code.
The first dog and the second dog will not find enough balls to finish the game, and both will be confused.
If somehow the second dog can be queued to wait to start until the first dog finishes, however, the two dogs are happy.
That's what happens when two threads of the same servlet need to access an external resource, such as opening a file and writing to it. Consider the following example, which reflects a real-world situation.
The code in Listing 2.13 presents a page counter servlet. What it does is simple. The servlet overrides the service method to do the following:
1. Open the counter.txt file using a BufferedReader, read the number into a counter, and close the file.
2. Increment the counter.
3. Write the counter back to the counter.txt file.
4. Display the counter in the web browser.
Imagine what happens if there are two users, Boni and Bulbul, who request the servlet. First Boni requests it, and then a couple of nanoseconds after Boni, Bulbul requests the same servlet. The scenario probably looks like this:
1. The service method executes Steps 1 and 2, and then gets distracted by the other request.
2. The method then does Step 1 from Bulbul before continuing to do Step 3 and 4 for Boni.
What happens next? Boni and Bulbul get the same number, which is not how it is supposed to be. The servlet has produced an incorrect result. As you can see in Listing 2.13, the servlet is an unsafe multithreaded servlet.
Listing 2.13 Unsafe Multi-Threaded Servlet
To solve the problem, remember the solution to the "playing dog" illustration: When the second dog waited until the first dog finished playing, both dogs could complete the game successfully.
This is exactly how you solve the problem in a servlet needing to service two users at the same time: by making the second user wait until the first servlet finishes serving the first user. This solution makes the servlet single-threaded.
This solution is very easy to do because of the marker SingleThreadedServlet interface. You don't need to change your code; you need only to implement the interface.
The code in Listing 2.14 is the modification of the code in Listing 2.13. Nothing changes, except that the SingleThreadedServlet class now implements SingleThreadModel, making it thread safe.
Listing 2.14 Safe Multi-Threaded Servlet
Now, if a user requests the service of the servlet while the servlet is servicing another user, the user who comes later will have to wait.
If you want to experience erroneous multi-threading yourself, the code in Listing 2.15 provides the SingleThreadedServlet with a delay of 6 seconds. Open two browsers and request the same servlet quickly. Notice that you get the same number for both browsers.
Listing 2.15 Demonstrating an Unsafe Multi-Threaded Servlet
What the code does is simple: It opens the counter.txt file, reads the value, increments the value, and writes the incremented value back to the file.
However, between the line of code that increments the value and the line of code that writes the incremented value back to the user, we inserted the following code:
Now you have time to request the same servlet from the second browser. The value shown in both browsers will be the same if the second request comes before the first thread of the servlet has the time to update the value in the counter.txt file.
An inexperienced programmer would wonder whether a good solution might be to make every servlet implement the SingleThreadModel interface. The answer is no. If a servlet never accesses an external resource, queuing the second request will create unnecessary delay to the subsequent user after the first. Also, if the external resource is accessed but there is no need to update its value, you don't need to implement the SingleThreadModel interface. For example, if the service method of a servlet needs only to read a static value from a file, you can let multiple threads of the servlet open and read the file at the same time.
Summary
This chapter introduced you to most of the interfaces and classes of the javax.servlet package, one of the two packages provided for servlet programming. This package contains basic classes and interfaces that are extended by members of the second package: javax.servlet.http. Understanding the basic classes and interfaces in javax.servlet is important, even though you use them less often than the javax.servlet.http package members in real-world applications. This chapter also showed you how to implement the SingleThreadModel interface to solve the problem multi-threaded servlets can have when accessing the same external resource.
The next chapter shows you how to write servlets that use the members of the second Servlet API package, javax.servlet.http.
CONTENTS