CHAPTER 1

image

Introduction to Servlets

Java servlets were the first technology for producing dynamic Java web applications. Sun Microsystems released the first Java Servlet specification in 1997. Since then it has undergone tremendous change, making it more powerful and easing development more with each release. The 3.0 version was released as part of Java EE 6 in December 2009. Servlets are at the base of all Java EE applications. Although many developers use servlet frameworks such as Java Server Pages (JSP) and Java Server Faces (JSF), both of those technologies compile pages into Java servlets behind the scenes via the servlet container. That said, a fundamental knowledge of Java servlet technology could be very useful for any Java web developer.

Servlets are Java classes that conform to the Java Servlet API, which allows a Java class to respond to requests. Although servlets can respond to any type of request, they are most commonly written to respond to web-based requests. A servlet must be deployed to a Java servlet container in order to become usable. The Servlet API provides a number of objects that are used to enable the functionality of a servlet within a web container. Such objects include the request and response objects, pageContext, and a great deal of others, and when these objects are used properly, they enable a Java servlet to perform just about any task a web-based application needs to do.

As mentioned, servlets can produce not only static content but also dynamic content. Since a servlet is written in Java, any valid Java code can be used within the body of the servlet class. This empowers Java servlets and allows them to interact with other Java classes, the web container, the underlying file server, and much more.

This chapter will get you started developing and deploying servlets. You will learn how to install Oracle’s GlassFish application server, a robust servlet container, which will enable you to deploy sophisticated Java enterprise applications. You will be taught the basics of developing servlets, how to use them with client web sessions, and how to link a servlet to another application. All the while, you will learn to use standards from the latest release of the Java Servlet API, which modernizes servlet development and makes it much easier and more productive than in years past.

image Note   You can run the examples within this chapter by deploying the JavaEERecipes.war file (contained in the sources) to a local Java EE application server container such as GlassFish v4. You can also set up the NetBeans project entitled JavaEERecipes that is contained in the sources, build it, and deploy to GlassFish v4. Otherwise, you can run the examples in Chapter 1 stand-alone using the instructions provided in Recipe 1-3. If you deploy the JavaEERecipes.war file to a Java EE application server container, you can visit the following URL to load the examples for this chapter: http://localhost:8080/JavaEERecipes/faces/chapter01/index.xhtml.

1-1. Setting Up a Java Enterprise Environment

Problem

You want to set up an environment that you can use to deploy and run Java servlets and other Java enterprise technologies.

Solution

Download and install Oracle’s GlassFish application server from the GlassFish web site. The version used for this book is the open source edition, release 4.0, and it can be downloaded from http://glassfish.java.net/ in the “Download” section.  Select the .zip or .tar.gz download format, and decompress the downloaded files within a directory on your workstation. I will refer to that directory as /JAVA_DEV/Glassfish. The GlassFish distribution comes prepackaged with a domain so that developers can get up and running quickly. Once the .zip file has been unpacked, you can start the domain by opening a command prompt or terminal and starting GlassFish using the following statement:

/PATH_TO_GLASSFISH/Glassfish/bin/asadmin start-domain domain1

The domain will start, and it will be ready for use. You will see output from the server that looks similar to the following:

Waiting for domain1 to start ............
Successfully started the domain : domain1
domain  Location: /PATH_TO_GLASSFISH/glassfish/domains/domain1
Log File: /PATH_TO_GLASSFISH/glassfish/domains/domain1/logs/server.log
Admin Port: 4848
Command start-domain executed successfully.

How It Works

The development of Java EE applications begins with a Java EE–compliant application server. A Java EE–compliant server contains all the essential components to provide a robust environment for deploying and hosting enterprise Java applications. The GlassFish application server is the industry standard for Java EE 7, and there are two versions of the server: open source, and licensed by Oracle. For the purposes of this book, the open source edition will be used. However, in a production environment, you may want to consider using the Oracle-licensed version so that technical support will be available if needed.

Installing GlassFish is easy. It consists of downloading an archive and uncompressing it on your development machine. Once you’ve completed this, the application server will make use of your locally installed Java development kit (JDK) when it is started. Once the server starts, you can open a browser and go to http://localhost:4848 to gain access to the GlassFish administrative console. Most Java EE developers who deploy on GlassFish use the administrative console often. The administrative console provides developers with the tools needed to deploy web applications, register databases with Java Naming and Directory Interface (JNDI), set up security realms for a domain, and do much more. To access the GlassFish administrative console for the first time, use the user name of admin and the password of adminadmin. You should take some time to become familiar with the administrative console because the more you know about it, the easier it will be to maintain your Java EE environment.

Installing the GlassFish application server is the first step toward developing Java applications for the enterprise. While other applications servers such as JBoss, Apache TomEE, and WebLogic are very well adopted, GlassFish offers developers a solid environment that is suitable for production use and easy to learn. It also has the bonus of being an open source application server and the reference implementation for Java EE 7.

1-2. Developing a Servlet

Problem

You want to develop a web page that enables you to include dynamic content.

Solution

Develop a Java servlet class, and compile it to run within a Java servlet container. In this example, a simple servlet is created that will display some dynamic content to the web page. The following is the servlet code that contains the functionality for the servlet:

package org.javaeerecipes.chapter01.recipe01_02;

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Recipe 1-2: Developing a Servlet
 * @author juneau
 */
public class SimpleServlet extends HttpServlet {

    /**
     * Processes requests for both HTTP
     * <code>GET</code> and
     * <code>POST</code> methods.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        try {
           // Place page output here
            out.println("<html>");
            out.println("<head>");
            out.println("<title>Servlet SimpleServlet</title>");
            out.println("</head>");
            out.println("<body>");
            out.println("<h2>Servlet SimpleServlet at " + request.getContextPath() + "</h2>");
            out.println("<br/>Welcome to Java EE Recipes!");
            out.println("</body>");
            out.println("</html>");
        } finally {
            out.close();
        }
    }

   /**
     * Handles the HTTP GET
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /**
     * Handles the HTTP POST
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /**
     * Returns a short description of the servlet for documentation purposes.
     *
     * @return a String containing servlet description
     */
    @Override
    public String getServletInfo() {
        return "Short description";
    }// </editor-fold>
}

The following code is the web deployment descriptor. This file is required for application deployment to a servlet container. It contains the servlet configuration and mapping that maps the servlet to a URL. In Recipe 1-4 you will learn how to omit the servlet configuration and mapping from the web.xml file to make servlet development, deployment, and maintenance easier.

<?xml version="1.0"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
        http://xmlns.jcp.org/xml/ns/javaee/web-app_3_0.xsd"
    version="3.0">

    <servlet>
        <servlet-name>SimpleServlet</servlet-name>
        <servlet-class>org.javaeerecipes.chapter1.recipe01_02.SimpleServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>SimpleServlet</servlet-name>
        <url-pattern>/SimpleServlet</url-pattern>
    </servlet-mapping>
               <welcome-file-list>
        <welcome-file> /SimpleServlet </welcome-file>
    </welcome-file-list>
</web-app>

image Note   Many web applications use a page named index.html or index.xhtml as their welcome file. There is nothing wrong with doing that, and as a matter of fact, it is the correct thing to do. The use of /SimpleServlet as the welcome file in this example is to make it easier to follow for demonstration purposes.

To compile the Java servlet, use the javac command-line utility. The following line was excerpted from the command line, and it compiles the SimpleServlet.java file into a class file. First, traverse into the directory containing the SimpleServlet.java file; then, execute the following:

javac -cp /JAVA_DEV/Glassfish/glassfish/modules/javax.servlet-api.jar SimpleServlet.java

Once the servlet code has been compiled into a Java class file, it is ready to package for deployment.

image Note   You may want to consider installing a Java integrated development environment (IDE) to increase your development productivity. There are several very good IDEs available to developers, so be sure to choose one that contains the features you find most important and useful for development. As the author of this book on Java EE 7, I recommend installing NetBeans 7.3 or newer for development. NetBeans is an open source IDE that is maintained by Oracle, and it includes support for all the cutting-edge features that the Java industry has to offer, including EJB development with Java EE 7, JavaFX 2.0 support, and more. To learn more about working with NetBeans and Java EE 7, please see the appendix of this book.

How It Works

Java servlets provide developers with the flexibility to design applications using a request-response programming model. Servlets play a key role in the development of service-oriented and web application development on the Java platform. Different types of servlets can be created, and each of them is geared toward providing different functionality. The first type is the GenericServlet, which provides services and functionality. The second type, HttpServlet, is a subclass of GenericServlet, and servlets of this type provide functionality and a response that uses HTTP. The solution to this recipe demonstrates the latter type of servlet because it displays a result for the user to see within a web browser.

Servlets conform to a life cycle for processing requests and posting results. First, the Java servlet container calls the servlet’s constructor. The constructor of every servlet must take no arguments. Next, the container calls the servlet init method, which is responsible for initializing the servlet. Once the servlet has been initialized, it is ready for use. At that point, the servlet can begin processing. Each servlet contains a service method, which handles the requests being made and dispatches them to the appropriate methods for request handling. Implementing the service method is optional. Finally, the container calls the servlet’s destroy method, which takes care of finalizing the servlet and taking it out of service.

Every servlet class must implement the javax.servlet.Servlet interface or extend another class that does. In the solution to this recipe, the servlet named SimpleServlet extends the HttpServlet class, which provides methods for handling HTTP processes. In this scenario, a browser client request is sent from the container to the servlet; then the servlet service method dispatches the HttpServletRequest object to the appropriate method provided by HttpServlet. Namely, the HttpServlet class provides the doGet, doPut, doPost, and doDelete methods for working with an HTTP request. The HttpServlet class is abstract, so it must be subclassed, and then an implementation can be provided for its methods. In the solution to this recipe, the doGet method is implemented, and the responsibility of processing is passed to the processRequest method, which writes a response to the browser using the PrintWriter. Table 1-1 describes each of the methods available to an HttpServlet.

Table 1-1. HttpServlet Methods

Method Name Description
doGet Used to process HTTP GET requests. Input sent to the servlet must be included in the URL address. For example: ?myName=Josh&myBook=JavaEERecipes.
doPost Used to process HTTP POST requests. Input can be sent to the servlet within HTML form fields. See Recipe 1-7 for an example.
doPut Used to process HTTP PUT requests.
doDelete Used to process HTTP DELETE requests.
doHead Used to process HTTP HEAD requests.
doOptions Called by the container to allow OPTIONS request handling.
doTrace Called by the container to handle TRACE requests.
getLastModified Returns the time that the HttpServletRequest object was last modified.
init Initializes the servlet.
destroy Finalizes the servlet.
getServletInfo Provides information regarding the servlet.

A servlet generally performs some processing within the implementation of its methods and then returns a response to the client. The HttpServletRequest object can be used to process arguments that are sent via the request. For instance, if an HTML form contains some input fields that are sent to the server, those fields would be contained within the HttpServletRequest object. The HttpServletResponse object is used to send responses to the client browser. Both the doGet and doPost methods within a servlet accept the same arguments, namely, the HttpServletRequest and HttpServletResponse objects.

image Note   The doGet method is used to intercept HTTP GET requests, and doPost is used to intercept HTTP POST requests. Generally, the doGet method is used to prepare a request before displaying for a client, and the doPost method is used to process a request and gather information from an HTML form.

In the solution to this recipe, both the doGet and doPost methods pass the HttpServletRequest and HttpServletResponse objects to the processRequest method for further processing. The HttpServletResponse object is used to set the content type of the response and to obtain a handle on the PrintWriter object in the processRequest method. The following lines of code show how this is done, assuming that the identifier referencing the HttpServletResponse object is response:

response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();

A GenericServlet can be used for providing services to web applications. This type of servlet is oftentimes used for logging events because it implements the log method. A GenericServlet implements both the Servlet and ServletConfig interfaces, and to write a generic servlet, only the service method must be overridden.

1-3. Packaging, Compiling, and Deploying a Servlet

Problem

You have written a Java servlet and now want to package it and deploy it for use.

Solution

Compile the sources, set up a deployable application, and copy the contents into the GlassFish deployment directory. From the command line, use the javac command to compile the sources.

javac -cp /PATH_TO_GLASSFISH/Glassfish/glassfish/modules/javax.servlet-api.jar SimpleServlet.java

After the class has been compiled, deploy it along with the web.xml deployment descriptor, conforming to the appropriate directory structure.

QUICK START

To quickly get started with packaging, compiling, and deploying the example application for the servlet recipes in this chapter on GlassFish or other servlet containers such as Apache Tomcat, follow these steps:

  1. Create a single application named SimpleServlet by making a directory named SimpleServlet.
  2. Create the WEB-INF, WEB-INF/classes, and WEB-INF/lib directories inside SimpleServlet.
  3. Drag the Chapter 1 sources (beginning with the org directory) in the WEB-INF/classes directory you created, as well as the contents of the web folder, into the root of your SimpleServlet directory.
  4. Copy the web.xml file that is in the source’s recipe01_02 directory into the WEB-INF directory you created.
  5. Download the JavaMail API code from Oracle, and copy the mail.jar file from the download into the WEB-INF/lib directory you created. This API will be used to send mail in future recipes.
  6. Set your CLASSPATH to include the mail.jar file you downloaded in step 5.
  7. At the command prompt, change directories so that you are in the classes directory you created in step 2. Compile each recipe with the command javac orgjavaeerecipeschapter01 ecipe1_x*.java, where x is equal to the recipe number.
  8. Copy your SimpleServlet application directory to the /JAVA_DEV/Glassfish/glassfish/domains/domain1/autodeploy directory for GlassFish or the /Tomcat/webapps directory for Tomcat.

Test the application by launching a browser and going to http://localhost:8080/SimpleServlet/servlet_name, where servlet_name corresponds to the servlet name in each recipe. If using Tomcat, you may need to restart the server in order for the application to deploy.

How It Works

To compile the sources, you can use your favorite Java IDE such as NetBeans or Eclipse, or you can use the command line. For the purposes of this recipe, I will do just that. If you’re using the command line, you must ensure you are using the javac command that is associated with the same Java release that you will be using to run your servlet container. In this example, we will say that the location of the Java SE 7 installation is at the following path:

/Library/Java/JavaVirtualMachines/1.7.0.jdk/Contents/Home

This path may differ in your environment if you are using a different operating system and/or installation location. To ensure you are using the Java runtime that is located at this path, set the JAVA_HOME environment variable equal to this path. On OS X and *nix operating systems, you can set the environment variable by opening the terminal and typing the following:

export JAVA_HOME=/Library/Java/JavaVirtualMachines/1.7.0.jdk/Contents/Home

If you are using Windows, use the SET command within the command line to set up the JAVA_HOME environment variable.

set JAVA_HOME=C:your-java-se-path

Next, compile your Java servlet sources, and be sure to include the javax.servlet-api.jar file that is packaged with your servlet container (use servlet-api.jar for Tomcat) in your CLASSPATH. You can set the CLASSPATH by using the –cp flag of the javac command. The following command should be executed at the command line from within the same directory that contains the sources. In this case, the source file is named SimpleServlet.java.

javac -cp /path_to_jar/javax.servlet-api.jar SimpleServlet.java

Next, package your application by creating a directory and naming it after your application. In this case, create a directory and name it SimpleServlet. Within that directory, create another directory named WEB-INF. Traverse into the WEB-INF directory, and create another directory named classes. Lastly, create directories within the classes directory in order to replicate your Java servlet package structure. For this recipe, the SimpleServlet.java class resides within the Java package org.javaeerecipes.chapter01.recipe01_02, so create a directory for each of those packages within the classes directory. Create another directory within WEB-INF and name it lib; any JAR files containing external libraries should be placed within the lib directory. In the end, your directory structure should resemble the following:

SimpleServlet
|_WEB-INF
        |_classes
              |_org
                    |_javaeerecipes
                                 |_chapter01
                                          |_recipe01_02
        |_lib

Place your web.xml deployment descriptor within the WEB-INF directory, and place the compiled SimpleServlet.class file within the recipe01_02 directory. The entire contents of the SimpleServlet directory can now be copied within the deployment directory for your application server container to deploy the application. Restart the application server if using Tomcat, and visit the URL http://localhost:8080/SimpleServlet/SimpleServlet to see the servlet in action.

1-4. Registering Servlets Without WEB-XML

Problem

Registering servlets in the web.xml file is cumbersome, and you want to deploy servlets without modifying web.xml at all.

Solution

Use the @WebServlet annotation to register the servlet, and omit the web.xml registration. This will alleviate the need to modify the web.xml file each time a servlet is added to your application. The following adaptation of the SimpleServlet class that was used in Recipe 1-2 includes the @WebServlet annotation and demonstrates its use:

package org.javaeerecipes.chapter01.recipe01_04;

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Recipe 1-4 - Registering Servlets without WEB-XML
 * @author juneau
 */
@WebServlet(name = "SimpleServletNoDescriptor", urlPatterns = {"/SimpleServletNoDescriptor"})
public class SimpleServletNoDescriptor extends HttpServlet {

    /**
     * Processes requests for both HTTP
     * <code>GET</code> and
     * <code>POST</code> methods.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        try {
            /*
             * TODO output your page here. You may use following sample code.
             */
            out.println("<html>");
            out.println("<head>");
            out.println("<title>Servlet SimpleServlet</title>");
            out.println("</head>");
            out.println("<body>");
            out.println("<h2>Servlet SimpleServlet at " + request.getContextPath() + "</h2>");
            out.println("<br/>Look ma, no WEB-XML!");
            out.println("</body>");
            out.println("</html>");
        } finally {
            out.close();
        }
    }

    /**
     * Handles the HTTP <code>GET</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /**
     * Handles the HTTP <code>POST</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

}

In the end, the servlet will be accessible via a URL in the same way that it would if the servlet were registered within web.xml.

image Note   Remove the existing servlet mapping within the web.xml file in order to make use of the @WebServlet annotation.

How It Works

There are a couple of ways to register servlets with a web container. The first way is to register them using the web.xml deployment descriptor, as demonstrated in Recipe 1-2. The second way to register them is to use the @WebServlet annotation. The Servlet 3.0 API introduced the @WebServlet annotation, which provides an easier technique to use for mapping a servlet to a URL. The @WebServlet annotation is placed before the declaration of a class, and it accepts the elements listed in Table 1-2.

Table 1-2. @WebServlet Annotation Elements

Element Description
description Description of the servlet
displayName The display name of the servlet
initParams Accepts list of @WebInitParam annotations
largeIcon The large icon of the servlet
loadOnStartup Load on start-up order of the servlet
name Servlet name
smallIcon The small icon of the servlet
urlPatterns URL patterns that invoke the servlet

In the solution to this recipe, the @WebServlet annotation maps the servlet class named SimpleServletNoDescriptor to the URL pattern of /SimpleServletNoDescriptor, and it also names the servlet SimpleServletNoDescriptor.

@WebServlet(name="SimpleServletNoDescriptor", urlPatterns={"/SimpleServletNoDescriptor"})

The new @WebServlet can be used rather than altering the web.xml file to register each servlet in an application. This provides ease of development and manageability. However, in some cases, it may make sense to continue using the deployment descriptor for servlet registration, such as if you do not want to recompile sources when a URL pattern changes. If you look at the web.xml listing in Recipe 1-2, you can see the following lines of XML, which map the servlet to a given URL and provide a name for the servlet. These lines of XML perform essentially the same function as the @WebServlet annotation in this recipe.

<servlet>
    <servlet-name>SimpleServletNoDescriptor</servlet-name>
    <servlet-class>org.javaeerecipes.chapter01.recipe01_04.SimpleServletNoDescriptor</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>SimpleServletNoDescriptor</servlet-name>
    <url-pattern>/SimpleServletNoDescriptor</url-pattern>
</servlet-mapping>

1-5. Displaying Dynamic Content with a Servlet

Problem

You want to display some content to a web page that may change depending upon server-side activity or user input.

Solution

Define a field within your servlet to contain the dynamic content that is to be displayed. Post the dynamic content on the page by appending the field containing it using the PrintWriter println method. The following example servlet declares a Date field and updates it with the current Date each time the page is loaded:

package org.javaeerecipes.chapter01.recipe01_05;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Recipe 1-5: Displaying Dynamic Content with a Servlet
 *
 * @author juneau
 */
@WebServlet(name = "CurrentDateAndTime", urlPatterns = {"/CurrentDateAndTime"})
public class CurrentDateAndTime extends HttpServlet {
    
    Date currDateAndTime;

    /**
     * Processes requests for both HTTP
     * <code>GET</code> and
     * <code>POST</code> methods.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        try {
            out.println("<html>");
            out.println("<head>");
            out.println("<title>Servlet CurrentDateAndTime</title>");
            out.println("</head>");
            out.println("<body>");
            out.println("<h1>Servlet CurrentDateAndTime at " + request.getContextPath() + "</h1>");
            out.println("<br/>");
            synchronized(currDateAndTime){
              currDateAndTime = new Date();
              out.println("The current date and time is: " + currDateAndTime);
            }
            out.println("</body>");
            out.println("</html>");
        } finally {
            out.close();
        }
    }

/**
     * Handles the HTTP
     * <code>GET</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /**
     * Handles the HTTP
     * <code>POST</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }
}

image Note   Servlets are mutithreaded, and many client requests may be using a servlet concurrently. When a field is declared as a Servlet class member (not within a method) as you have done with currDateAndTime, you have to assure that only one client request can manipulate the field at any instance. You do this by synchronizing around the use of the field, as shown in the processRequest() method. You synchronize around the smallest block of code you can manage in order to minimize latency.

synchronized( currDateAndTime ) {
    currDateAndTime = new Date();
    out.println("The current date and time is: " + currDateAndTime);
}

The resulting output from this servlet will be the current date and time.

How It Works

One of the reasons why Java servlets are so useful is because they allow dynamic content to be displayed on a web page. The content can be taken from the server itself, a database, another web site, or many other web-accessible resources. Servlets are not static web pages; they are dynamic, and that is arguably their biggest strength.

In the solution to this recipe, a servlet is used to display the current time and date on the server. When the servlet is processed, the doGet method is called, which subsequently makes a call to the processRequest method, passing the request and response objects. Therefore, the processRequest method is where the bulk of the work occurs. The processRequest method creates a PrintWriter by calling the response.getWriter method, and the PrintWriter is used to display content on the resulting web page. Next, the current date and time are obtained from the server by creating a new Date and assigning it to the currDateAndTime field. Lastly, the processRequest method sends the web content through the out.println method, and the contents of the currDateAndTime field are concatenated to a String and sent to out.println as well. Each time the servlet is processed, it will display the current date and time at the time in which the servlet is invoked because a new Date is created with each request.

This example just scratches the surface of what is possible with a Java servlet. Although displaying the current date and time is trivial, you could alter that logic to display the contents of any field contained within the servlet. Whether it be an int field that displays a calculation that was performed by the servlet container or a String field containing some information, the possibilities are endless.

1-6. Handling Requests and Responses

Problem

You want to create a web form that accepts user input and supply a response based upon the input that has been received.

Solution

Create a standard HTML-based web form, and when the submit button is clicked, invoke a servlet to process the end-user input and post a response. To examine this technique, you will see two different pieces of code. The following code is HTML that is used to generate the input form. This code exists within the file recipe01_06.html. Please browse to /SimpleServlet/recipe01_06.html to execute the example. Pay particular attention to the <form> and <input> tags. You will see that the form’s action parameter lists a servlet name, MathServlet.

<html>
    <head>
    <title>Simple Math Servlet</title>
    </head>
    <body>
        <h1>This is a simple Math Servlet</h1>
        <form method="POST" action="MathServlet">
            <label for="numa">Enter Number A: </label>
            <input type="text" id="numa" name="numa"/><br><br>
            <label for="numb">Enter Number B: </label>
            <input type="text" id="numb" name="numb"/><br/><br/>
            <input type="submit" value="Submit Form"/>
            <input type="reset" value="Reset Form"/>
        </form>
    </body>
</html>

Next, take a look at the following code for a servlet named MathServlet. This is the Java code that receives the input from the HTML code listed earlier, processes it accordingly, and posts a response.

package org.javaeerecipes.chapter01.recipe01_06;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;

import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;

/**
 * Recipe 1-6: Handling Requests and Responses
 */
// Uncomment the following line to run example stand-alone
//@WebServlet(name="SessionServlet", urlPatterns={"/MathServlet"})

// The following will allow the example to run within the context of the JavaEERecipes example
// enterprise application (JavaEERecipes.war distro or Netbeans Project
@WebServlet(name = "MathServlet", urlPatterns = {"/chapter01/MathServlet"})public class MathServlet extends HttpServlet {

    public void doPost(HttpServletRequest req, HttpServletResponse res)
            throws IOException, ServletException {

        res.setContentType("text/html");

        // Store the input parameter values into Strings
        String numA = req.getParameter("numa");
        String numB = req.getParameter("numb");

        PrintWriter out = res.getWriter();
        out.println("<html><head>");
        out.println("<title>Test Math Servlet</title>");
        out.println(" <style>body { font-family: 'Lucida Grande', "
                + "'Lucida Sans Unicode';font-size: 13px; }</style>");
        out.println("</head>");
        out.println("<body>");

        try {
            int solution = Integer.valueOf(numA) + Integer.valueOf(numB);

            /*
             * Display some response to the user
             */
            out.println("<p>Solution: "
                    + numA + " + " + numB + " = " + solution + "</p>");

        } catch (java.lang.NumberFormatException ex) {
            // Display error if an exception is raised
            out.println("<p>Please use numbers only. . .try again.</p>");
        }
        out.println("<br/><br/>");
        out.println("<a href='recipe1_6.html'>Add Two More Numbers</a>");
        out.println("</body></html>");

        out.close();
    }
}

image Note   To run the example, copy the previous HTML code into an HTML file within the web root of your JavaEERecipes application named recipe1_6.html, and then enter the following address into your browser: http://localhost:8080/JavaEERecipes/recipe1_6.html. This assumes you are using default port numbers for your application server installation.  If using the NetBeans project that was packaged with the sources, you do not need to worry about copying the code as everything is pre-configured.

How It Works

Servlets make it easy to create web applications that adhere to a request and response life cycle. They have the ability to provide HTTP responses and also process business logic within the same body of code. The ability to process business logic makes servlets much more powerful than standard HTML code. The solution to this recipe demonstrates a standard servlet structure for processing requests and sending responses. An HTML web form contains parameters that are sent to a servlet. The servlet then processes those parameters in some fashion and publishes a response that can be seen by the client. In the case of an HttpServlet object, the client is a web browser, and the response is a web page.

Values can be obtained from an HTML form by using HTML <input> tags embedded within an HTML <form>. In the solution to this recipe, two values are accepted as input, and they are referenced by their id attributes as numa and numb. There are two more <input> tags within the form; one of them is used to submit the values to the form action, and the other is used to reset the form fields to blank. The form action is the name of the servlet that the form values will be passed to as parameters. In this case, the action is set to MathServlet. The <form> tag also accepts a form-processing method, either GET or POST. In the example, the POST method is used because form data is being sent to the action; in this case, data is being sent to MathServlet. You could, of course, create an HTML form as detailed as you would like and then have that data sent to any servlet in the same manner. This example is relatively basic; it serves to give you an understanding of how the processing is performed.

The <form> action attribute states that the MathServlet should be used to process the values that are contained within the form. The MathServlet name is mapped back to the MathServlet class via the web.xml deployment descriptor or the @WebServlet annotation. Looking at the MathServlet code, you can see that a doPost method is implemented to handle the processing of the POST form values. The doPost method accepts HttpServletRequest and HttpServletResponse objects as arguments. The values contained with the HTML form are embodied within the HttpServletRequest object. To obtain those values, call the request object’s getParameter method, passing the id of the input parameter you want to obtain. In the solution to this recipe, those values are obtained and stored within local String fields.

String numA = req.getParameter("numa");
String numB = req.getParameter("numb");

Once the values are obtained, they can be processed as needed. In this case, those String values are converted into int values, and then they are added together to generate a sum and stored into an int field. That field is then presented as a response on a resulting web page.

int solution = Integer.valueOf(numA) + Integer.valueOf(numB);

As mentioned, the HTML form could be much more complex, containing any number of <input> fields. Likewise, the servlet could perform more complex processing of those field values. This example is merely the tip of the iceberg, and the possibilities are without bounds. Servlet-based web frameworks such as Java Server Pages and Java Server Faces hide many of the complexities of passing form values to a servlet and processing a response. However, the same basic framework is used behind the scenes.

1-7. Listening for Servlet Container Events

Problem

You want to have the ability to listen for application start-up and shutdown events.

Solution

Create a servlet context event listener to alert when the application has started up or when it has been shut down. The following solution demonstrates the code for a context listener, which will log application start-up and shutdown events and send e-mail alerting of such events:

package org.javaeerecipes.chapter01.recipe01_07;

import java.util.Properties;
import javax.mail.Message;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletContextEvent;
import javax.servlet.annotation.WebListener;

@WebListener
public class StartupShutdownListener implements ServletContextListener {

    public void contextInitialized(ServletContextEvent event) {
        System.out.println("Servlet startup. . .");
        System.out.println(event.getServletContext().getServerInfo());
        System.out.println(System.currentTimeMillis());
        sendEmail("Servlet context has initialized");
    }

    public void contextDestroyed(ServletContextEvent event) {
        System.out.println("Servlet shutdown. . .");
        System.out.println(event.getServletContext().getServerInfo());
        System.out.println(System.currentTimeMillis());
        // See error in server.log file if mail is unsuccessful
        sendEmail("Servlet context has been destroyed. . .");
    }

    /**
     * This implementation uses the GMail smtp server
     * @param message
     * @return
     */
    private boolean sendEmail(String message) {
       boolean result = false;
       String smtpHost = "smtp.gmail.com";
       String smtpUsername = "username";
       String smtpPassword = "password";
       String from = "fromaddress";
       String to = "toaddress";
       int smtpPort = 587;
       System.out.println("sending email. . .");
        try {
            // Send email here
            
            //Set the host smtp address
            Properties props = new Properties();
            props.put("mail.smtp.host", smtpHost);
            props.put("mail.smtp.auth", "true");
            props.put("mail.smtp.starttls.enable", "true");

            // create some properties and get the default Session
            Session session = Session.getInstance(props);

            // create a message
            Message msg = new MimeMessage(session);

            // set the from and to address
            InternetAddress addressFrom = new InternetAddress(from);
            msg.setFrom(addressFrom);
            InternetAddress[] address = new InternetAddress[1];
            address[0] = new InternetAddress(to);
            msg.setRecipients(Message.RecipientType.TO, address);
            msg.setSubject("Servlet container shutting down");
            // Append Footer
            msg.setContent(message, "text/plain");
            Transport transport = session.getTransport("smtp");
            transport.connect(smtpHost, smtpPort, smtpUsername, smtpPassword);
            
            Transport.send(msg);

            result = true;
        } catch (javax.mail.MessagingException ex) {
            ex.printStackTrace();
            result = false;
        }
        return result;
    }
}

image Note   To run this example, you may need additional external JARs in your CLASSPATH. Specifically, make sure you have mail.jar and javaee.jar.

How It Works

Sometimes it is useful to know when certain events occur within the application server container. This concept can be useful under many different circumstances, but most often it would likely be used for initializing an application upon start-up or cleaning up after an application upon shutdown. A servlet listener can be registered with an application to indicate when it has been started up or shut down. Therefore, by listening for such events, the servlet has the opportunity to perform some actions when they occur.

To create a listener that performs actions based upon a container event, you must develop a class that implements the ServletContextListener interface. The methods that need to be implemented are contextInitialized and contextDestroyed. Both of the methods accept a ServletContextEvent as an argument, and they are automatically called each time the servlet container is initialized or shut down, respectively. To register the listener with the container, you can use one of the following techniques:

  • Utilize the @WebListener annotation, as demonstrated by the solution to this recipe.
  • Register the listener within the web.xml application deployment descriptor.
  • Use the addListener methods defined on ServletContext.

For example, to register this listener within web.xml, you would need to add the following lines of XML:

<listener>
    <listener-class> org.javaeerecipes.chapter01.recipe01_07.StartupShutdownListener</listener-class>
</listener>

Neither way is better than the other. The only time that listener registration within the application deployment descriptor (web.xml) would be more helpful is if you had the need to disable the listener in some cases. On the other hand, to disable a listener when it is registered using @WebListener, you must remove the annotation and recompile the code. Altering the web deployment descriptor does not require any code to be recompiled.

There are many different listener types, and the interface that the class implements is what determines the listener type. For instance, in the solution to this recipe, the class implements the ServletContextListener interface. Doing so creates a listener for servlet context events. If, however, the class implements HttpSessionListener, it would be a listener for HTTP session events. The following is a complete listing of listener interfaces:

javax.servlet.ServletRequestListener
javax.servlet.ServletRequestAttrbiteListener
javax.servlet.ServletContextListener
javax.servlet.ServletContextAttributeListener
javax.servlet.HttpSessionListener
javax.servlet.HttpSessionAttributeListener

It is also possible to create a listener that implements multiple listener interfaces. To learn more about listening for different situations such as attribute changes, please see Recipe 1-10.

1-8. Setting Initialization Parameters

Problem

A servlet you are writing requires the ability to accept one or more parameters to be set upon initialization.

Solution #1

Set the servlet initialization parameters using the @WebInitParam annotation. The following code sets an initialization parameter that is equal to a String value:

package org.javaeerecipes.chapter01.recipe01_08;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.*;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;

@WebServlet(name="SimpleServletCtx1", urlPatterns={"/SimpleServletCtx1"},
initParams={ @WebInitParam(name="name", value="Duke") })
public class SimpleServletCtx1 extends HttpServlet {
  
    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse res)
        throws IOException, ServletException {

        res.setContentType("text/html");

        PrintWriter out = res.getWriter();

        /* Display some response to the user */

        out.println("<html><head>");
        out.println("<title>Simple Servlet Context Example</title>");
        out.println(" <style>body { font-family: 'Lucida Grande', " +
            "'Lucida Sans Unicode';font-size: 13px; }</style>");
        out.println("</head>");
        out.println("<body>");
        
        out.println("<p>This is a simple servlet to demonstrate context!  Hello "
                                 + getServletConfig().getInitParameter("name") + "</p>");

        out.println("</body></html>");
        out.close();
    }
}

To execute the example using the sources for this book, load the following URL into your web browser: http://localhost:8080/JavaEERecipes/SimpleServletCtx1. The resulting web page will display the following text:

This is a simple servlet to demonstrate context! Hello Duke

Solution #2

Place the init parameters inside the web.xml deployment descriptor file. The following lines are excerpted from the web.xml deployment descriptor for the SimpleServlet application. They include the initialization parameter names and values.

<web-app>
    <servlet>
        <servlet-name>SimpleServletCtx1</servlet-name>
        <servlet-class> org.javaeerecipes.chapter01.recipe01_08.SimpleServletCtx1</servlet-class>

        <init-param>
            <param-name>name</param-name>
            <param-value>Duke</param-value>
        </init-param>
    . . .
    </servlet>
    . . .
</web-app>

How It Works

Oftentimes there is a requirement to set initialization parameters for a servlet in order to initialize certain values. Servlets can accept any number of initialization parameters, and there are a couple of ways in which they can be set. The first solution is to annotate the servlet class with the @WebInitParam annotation, as demonstrated in Solution #1, and the second way to set an initialization parameter is to declare the parameter within the web.xml deployment descriptor, as demonstrated in Solution #2. Either way will work; however, the solution using @WebInitParam is based upon the newer Java Servlet 3.0 API. Therefore, Solution #1 is the more contemporary approach, but Solution #2 remains valid for following an older model or using an older Java servlet release.

To use the @WebInitParam annotation, it must be embedded within the @WebServlet annotation. Therefore, the servlet must be registered with the web application via the @WebServlet annotation rather than within the web.xml file. For more information on registering a servlet via the @WebServlet annotation, see Recipe 1-4.

The @WebInitParam annotation accepts a name-value pair as an initialization parameter. In the solution to this recipe, the parameter name is name, and the value is Duke.

@WebInitParam(name="name", value="Duke")

Once set, the parameter can be used within code by calling getServletConfig().getInitializationParameter() and passing the name of the parameter, as shown in the following line of code:

out.println("<p>This is a simple servlet to demonstrate context!  Hello "
                                 + getServletConfig().getInitParameter("name") + "</p>");

The annotations have the benefit of providing ease of development, and they also make it easier to maintain servlets as a single package rather than jumping back and forth between the servlet and the deployment descriptor. However, those benefits come at the cost of compilation because in order to change the value of an initialization parameter using the @WebInitParam annotation, you must recompile the code. Such is not the case when using the web.xml deployment descriptor. It is best to evaluate your application circumstances before committing to a standard for naming initialization parameters.

1-9. Filtering Web Requests

Problem

You want to invoke certain processing if a specified URL is used to access your application. For instance, if a specific URL were used to access your application, you would want to log the user’s IP address.

Solution

Create a servlet filter that will be processed when the specified URL format is used to access the application. In this example, the filter will be executed when a URL conforming to the format of /* is used. This format pertains to any URL in the application. Therefore, any page will cause the servlet to be invoked.

package org.javaeerecipes.chapter01.recipe01_09;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.*;

/**
 * Recipe 1-9 This filter obtains the IP address of the remote host and logs
 * it.
 *
* @author juneau
 */
@WebFilter("/*")
public class LoggingFilter implements Filter {

    private FilterConfig filterConf = null;

    public void init(FilterConfig filterConf) {
        this.filterConf = filterConf;
    }

    public void doFilter(ServletRequest request,
            ServletResponse response,
            FilterChain chain)
            throws IOException, ServletException {
        String userAddy = request.getRemoteHost();
        filterConf.getServletContext().log("Vistor User IP: " + userAddy);
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {
        throw new UnsupportedOperationException("Not supported yet.");
    }
}

The filter could contain any processing; the important thing to note is that this servlet is processed when a specified URL is used to access the application.

image Note   To invoke the filter, load a URL for the application with which the filter is associated. For the purposes of this example, load the following URL (for the previous recipe) to see the filter add text to the server log: http://localhost:8080/JavaEERecipes/SimpleServletCtx1.

How It Works

Web filters are useful for preprocessing requests and invoking certain functionality when a given URL is visited. Rather than invoking a servlet that exists at a given URL directly, any filter that contains the same URL pattern will be invoked prior to the servlet. This can be helpful in many situations, perhaps the most useful for performing logging, authentication, or other services that occur in the background without user interaction.

Filters must implement the javax.servlet.Filter interface. Methods contained within this interface include init, destroy, and doFilter. The init and destroy methods are invoked by the container. The doFilter method is used to implement tasks for the filter class. As you can see from the solution to this recipe, the filter class has access to the ServletRequest and ServletResponse objects. This means the request can be captured, and information can be obtained from it. This also means the request can be modified if need be. For example, including the user name in the request after an authentication filter has been used.

If you want to chain filters or if more than one filter exists for a given URL pattern, they will be invoked in the order in which they are configured in the web.xml deployment descriptor. It is best to manually configure the filters if you are using more than one per URL pattern rather than using the @WebFilter annotation. To manually configure the web.xml file to include a filter, use the <filter> and <filter-mapping> XML elements along with their associated child element tags. The following excerpt from a web.xml configuration file shows how the filter that has been created for this recipe may be manually configured within the web.xml file:

<filter>
    <filter-name>LoggingFilter</filter-name>
    <filter-class>LoggingFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>LogingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Of course, the @WebFilter annotation takes care of the configuration for you, so in this case the manual configuration is not required.

image Note   As of Servlet 3.1 API, if a filter invokes the next entity in the chain, each of the filter service methods must run in the same thread as all filters that apply to the servlet.

1-10. Listening for Attribute Changes

Problem

You want to have the ability to do something within a servlet when a servlet attribute is added, removed, or updated.

Solution

Generate an attribute listener servlet to listen for such events as attributes being added, removed, or modified. The following class demonstrates this technique by implementing HttpSessionAttributeListener and listening for attributes that are added, removed, or replaced within the HTTP session:

package org.javaeerecipes.chapter01.recipe01_10;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;

/**
 * Recipe 1-10:  Attribute Listener
 */
@WebListener
public final class AttributeListener implements ServletContextListener,
        HttpSessionAttributeListener {

    private ServletContext context = null;

    public void attributeAdded(HttpSessionBindingEvent se) {
        HttpSession session = se.getSession();
        String id = session.getId();
        String name = se.getName();
        String value = (String) se.getValue();
        String message = new StringBuffer("New attribute has been added to session: ").append("Attribute Name: ").append(name).append(" ").append("Attribute Value:").append(value).toString();
        log(message);
    }

    public void attributeRemoved(HttpSessionBindingEvent se) {
        HttpSession session = se.getSession();
        String id = session.getId();
        String name = se.getName();
        if (name == null) {
            name = "Unknown";
        }
        String value = (String) se.getValue();
        String message = new StringBuffer("Attribute has been removed: ")
        .append("Attribute Name: ").append(name).append(" ").append("Attribute Value:")
        .append(value).toString();
        log(message);
    }

    public void attributeReplaced(HttpSessionBindingEvent se) {
        String name = se.getName();
        if (name == null) {
            name = "Unknown";
        }
        String value = (String) se.getValue();
        String message = new StringBuffer("Attribute has been replaced: ").append(name).toString();
        log(message);
    }

    private void log(String message) {
        if (context != null) {
            context.log("SessionListener: " + message);
        } else {
            System.out.println("SessionListener: " + message);
        }
    }

    @Override
    public void contextInitialized(ServletContextEvent event) {
        this.context = event.getServletContext();
        log("contextInitialized()");
    }

    @Override
    public void contextDestroyed(ServletContextEvent event) {
// Do something
    }
}

Messages will be displayed within the server log file indicating when attributes have been added, removed, or replaced.

How It Works

In some situations, it can be useful to know when an attribute has been set or what an attribute value has been set to. The solution to this recipe demonstrates how to create an attribute listener in order to determine this information. To create a servlet listener, you must implement one or more of the servlet listener interfaces. To listen for HTTP session attribute changes, implement HttpSessionAttributeListener. In doing so, the listener will implement the attributeAdded, attributeRemoved, and attributeReplaced methods. Each of these methods accepts HttpSessionBindingEvent as an argument, and their implementation defines what will occur when an HTTP session attribute is added, removed, or changed, respectively.

In the solution to this recipe, you can see that each of the three methods listed in the previous paragraph contains a similar implementation. Within each method, the HttpSessionBindingEvent is interrogated and broken down into String values, which represent the ID, name, and value of the attribute that caused the listener to react. For instance, in the attributeAdded method, the session is obtained from HttpSessionBindingEvent, and then the session ID is retrieved from that via the use of getSession. The attribute information can be obtained directly from the HttpSessionBindingEvent using the getId and getName methods, as shown in the following lines of code:

HttpSession session = se.getSession();
String id = session.getId();
String name = se.getName();
String value = (String) se.getValue();

After these values are obtained, the application can do whatever it needs to do with them. In this recipe, the attribute ID, name, and session ID are simply logged and printed.

String message = new StringBuffer("New attribute has been added to session: 
")
.append("Attribute Name: ").append(name).append(" ")
.append("Attribute Value:").append(value).toString();
log(message);

The body of the attributeReplaced and attributeRemoved methods contain similar functionality. In the end, the same routine is used within each to obtain the attribute name and value, and then something is done with those values.

A few different options can be used to register the listener with the container. The @WebListener annotation is the easiest way to do so, and the only downfall to using it is that you will need to recompile code in order to remove the listener annotation if you ever need to do so. The listener can be registered within the web deployment descriptor, or it can be registered using one of the addListener methods contained in ServletContext.

Although the example in the recipe does not perform any life-changing events, it does demonstrate how to create and use an attribute listener. In the real world, such a listener could become handy if an application needed to capture the user name of everyone who logs in or needed to send an e-mail whenever a specified attribute is set.

1-11. Applying a Listener to a Session

Problem

You want to listen for sessions to be created and destroyed so that you can count how many active sessions your application currently contains as well as perform some initialization for each session.

Solution

Create a session listener, and implement the sessionCreated and sessionDestroyed methods accordingly. In the following example, a servlet is used to keep track of active sessions. Each time someone works with the application, a counter has one added to it. Likewise, each time a person leaves the application, then the counter goes down by one.

package org.javaeerecipes.chapter01.recipe01_11;

import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

/**
 * Recipe 1-11: Applying a Session Listener
 *
 * @author juneau
 */
@WebListener
public class SessionListener implements HttpSessionListener {

    private int numberOfSessions;

    public SessionListener() {
        numberOfSessions = 0;
    }

    public int getNumberOfSessions() {
        return numberOfSessions;
    }

    @Override
    public void sessionCreated(HttpSessionEvent arg) {
        HttpSession session = arg.getSession();
        session.setMaxInactiveInterval(60);
        session.setAttribute("testAttr", "testVal");
        synchronized (this) {
            numberOfSessions++;
        }
        System.out.println("Session created, current count: " + numberOfSessions);
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent arg) {
        HttpSession session = arg.getSession();
        synchronized (this) {
            numberOfSessions--;
        }
        System.out.println("Session destroyed, current count: " + numberOfSessions);
        System.out.println("The attribute value: " + session.getAttribute(("testAttr")));
    }
}

Each time a new visitor visits the application, a new session is started, and testAttr is set. When the session times out, then it will be destroyed, and any attributes that have been set for the session will be removed.

How It Works

A meaningful way to track web application users is to place values in their HttpSession object. Using a Java servlet, session attributes can be set, which will exist for the life of the HttpSession. Once the session is invalidated, the attributes will be removed. To set up a session listener, create a Java servlet, annotate it with the @WebListener annotation, and implement javax.servlet.http.HttpSessionListener. Doing so will force the implementation of both the sessionCreated and sessionDestroyed methods, which is where the session magic occurs.

In the example to this recipe, the sessionCreated method first obtains a handle on the current HttpSession object by calling the HttpSessionEvent object’s getSession method. The handle is assigned to an HttpSession variable named session. Now that you have that variable initialized with the session object, it can be used to set the time of life and place attributes that will live and die with the session’s life. The first session configuration performed in the example is to set the maximum inactive life to 60 (seconds), after which time the servlet container will invalidate the session. Next an attribute named testAttr is set in the session and given a value of testVal.

HttpSession session = arg.getSession();
session.setMaxInactiveInterval(60);
session.setAttribute("testAttr", "testVal");

A field within the servlet named numberOfSessions is declared, and it is incremented each time a new session is started. Following the session.setAttribute() call, the counter is incremented within a synchronized statement. Finally, a message is printed to the server log indicating that a new session was created and providing the total active session count.

image Note   Placing the increment within the synchronized statement helps avoid concurrency issues with the field. For more information on Java synchronization and concurrency, please see the online documentation at http://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html.

The sessionDestroyed method is called on a session once the maximum number of inactive seconds has passed. In this example, the method will be called after 60 seconds of inactivity. Within the sessionDestroyed method, another synchronization statement decrements the numberOfSessions field value by one, and then a couple of lines are printed to the server log indicating that a session has been destroyed and providing the new total number of active sessions.

Session listeners can be used to set cookies and perform other useful tactics to help manage a user’s experience. They are easy to use and very powerful.

1-12. Managing Session Attributes

Problem

You want to maintain some information regarding an individual session on a per-session basis when a user visits your site.

Solution

Make use of session attributes to retain session-based information. To do so, use the HttpServletRequest object to obtain access to the session, and then use the getAttribute() and setAttribute() methods accordingly. In the following scenario, an HTML page is used to capture a user’s e-mail address, and then the e-mail address is placed into a session attribute. The attribute is then used by Java servlets across different pages of the application in order to maintain state.

The following code demonstrates what the HTML form (recipe01_12.html) may look like in this scenario:

<html>
    <head>
        <title></title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    </head>
    <body>
        <h1>Provide an email address to use with this transaction</h1>
        <br/>
        <form method="POST" action="SessionServlet">
            <input type="text" id="email" name="email"/>
            <br/>
            <input type="submit" value="Submit"/>
        </form>
    </body>
</html>

Next, the Java servlet named SessionServlet using a URL pattern of /SessionServlet is initiated when the form is submitted. Any form input values are passed to SessionServlet and processed accordingly.

package org.javaeerecipes.chapter01.recipe01_12;

import java.io.*;
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;

// Uncomment the following line to run example stand-alone
//@WebServlet(name="SessionServlet", urlPatterns={"/SessionServlet"})

// The following will allow the example to run within the context of the JavaEERecipes example
// enterprise application (JavaEERecipes.war distro or Netbeans Project
@WebServlet(name="SessionServlet", urlPatterns={"/chapter01/SessionServlet"}) public class SessionServlet extends HttpServlet {
  public void doPost (HttpServletRequest req, HttpServletResponse res)
       throws ServletException, IOException {
  
   // Obtain he Session object
      
      HttpSession session = req.getSession(true);
  
   // Set up a session attribute

      String email = (String)
      session.getAttribute ("session.email");
      if (email == null) {
          email = req.getParameter("email");
          session.setAttribute ("session.email", email);
      }
      String sessionId = session.getId();

      res.setContentType("text/html");
      PrintWriter out = res.getWriter();
      out.println("<html>");
      out.println("<head><title>Working with sessions</title></head>");
      out.println("<body>");
      out.println("<h1>Session Test</h1>");
      out.println ("Your email address is: " + email + "<br/><br/>");
      out.println ("Your session id: " + sessionId);
      out.println("</body></html>");
   }
}

In the end, the e-mail address that was entered within the original HTML form was captured and used throughout the different pages in the application.

How It Works

Since the beginning of web development, session attributes have been used to retain important information regarding a user’s session. This concept holds true when developing using Java servlets as well, and servlets make it easy to set and get the attribute values. All HttpServlet classes must implement doGet or doPost methods in order to process web application events. In doing so, these methods have access to the HttpServletRequest object as it is passed to them as an argument. An HttpSession object can be gleaned from the HttpServletRequest, and therefore, it can be used to retrieve and set attributes as needed.

In the solution to this recipe, an HTTP session attribute is used to store an e-mail address. That address is then used throughout the application within different servlet classes by obtaining the session object and then retrieving the attribute value.

// Obtain the Session object
   HttpSession session = req.getSession(true);
// Set up a session attribute
   String email = (String)
   session.getAttribute ("session.email");
   if (email == null) {
       email = req.getParameter("email");
       session.setAttribute ("session.email", email);
   }

Any attributes will remain in the HttpSession object as long as the session remains valid. The session ID will remain consistent when traversing between pages. You can see that the solution to this recipe obtains and prints the current session ID for reference. Using attributes in the HttpSession is a good way to pass data around to maintain a session’s state.

1-13. Downloading a File

Problem

You want to enable your servlet application to have the ability to download a given file.

Solution

Write a servlet that will accept the name and path of a chosen file and then read the file and stream it to the file requestor. The following web page can be used to select a file for the servlet to download. Although the following HTML (recipe 01_13.html) contains a statically typed file name, it could very well contain a dynamic list of files from a database or other source:

<!DOCTYPE html>
<html>
    <head>
        <title></title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    </head>
    <body>
        <h1>Click on the link below to download the file.</h1>
        <br/>
        <a href="DownloadServlet?filename=downloadTest.txt">Download test file</a>
        <br/>
        
    </body>
</html>

image Note   For the example in this recipe, you can create and edit a file in your root directory and name the file downloadTest.txt to see the servlet transfer the data to your browser client.

When a user clicks the link presented on the web page from the previous HTML, the following servlet will be used to download the given file by passing the HttpServletRequest and HttpServletResponse objects to it along with the file that should be downloaded:

package org.javaeerecipes.chapter01.recipe01_13;

import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Recipe 1-13
 *
 * @author juneau
 */
// Uncomment the following line to run example stand-alone
//@WebServlet(name = "DownloadServlet", urlPatterns = {"/DownloadServlet"})

// The following will allow the example to run within the context of the JavaEERecipes example
// enterprise application (JavaEERecipes.war distro or Netbeans Project
@WebServlet(name = "DownloadServlet", urlPatterns = {"/chapter01/DownloadServlet"})public class DownloadServlet extends HttpServlet {

    /**
     * Handles the HTTP
     * <code>GET</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // Read parameter from form that contains the filename to download
        String fileToDownload = request.getParameter("filename");
        // Call the download method with the given file
        System.err.println("Downloading file now. . .");
        doDownload(request, response, fileToDownload);
    }

    
    /**
     *  Sends a file to the output stream.
     *
     *  @param req The request
     *  @param resp The response
     *  @param original_filename The name the browser should receive.
     */
    private void doDownload( HttpServletRequest request, HttpServletResponse response,
                             String originalFile) throws IOException {
        final int BYTES = 1024;
        int                 length   = 0;
        ServletOutputStream outStream = response.getOutputStream();
        ServletContext      context  = getServletConfig().getServletContext();

 
        response.setContentType( (context.getMimeType( originalFile ) != null) ?
                context.getMimeType( originalFile ) : "text/plain" );
        response.setHeader( "Content-Disposition", "attachment; filename="" + originalFile + """ );

        InputStream in = context.getResourceAsStream("/" + originalFile);
        byte[] bbuf = new byte[BYTES];
        
        while ((in != null) && ((length = in.read(bbuf)) != -1))
        {
            outStream.write(bbuf,0,length);
        }

        outStream.flush();
        outStream.close();
    }

    /**
     * Returns a short description of the servlet.
     *
     * @return a String containing servlet description
     */
    @Override
    public String getServletInfo() {
        return "Short description";
    }
}

The servlet will not produce a response; it will simply download the given file to the end user when the user clicks the link to download the file.

How It Works

Downloading files is an essential task for almost any web application. Performing the steps that are provided by this recipe will make it easy to achieve this task. The example in this recipe demonstrates an easy case in which users can visit a web page, click a file to download, and have the file retrieved from the server and copied to their machine. The HTML is very simplistic in this example, and it lists a URL link that invokes the servlet and passes the name of the file that is to be downloaded. When the user clicks the link, the name of the file is passed to /DownloadServlet as a parameter with the name filename. When the link is clicked, the servlet doGet method is invoked. The first task that is performed in the doGet method is to read the filename parameter from the invoking web page. That information is then passed to the doDownload method along with the HttpServletRequest and HttpServletResponse objects.

In the doDownload method, the ServletOutputStream is obtained from the HttpServletResponse object, and the ServletContext is obtained for later use. To download a file, the servlet must provide a response of the same type that matches that of the file to be downloaded. It must also indicate in the response header that an attachment is to be included. Therefore, the first tasks to be performed by the doDownload method involve setting up the HttpServletResponse appropriately.

response.setContentType( (context.getMimeType( originalFile ) != null) ?
                context.getMimeType( originalFile ) : "text/plain" );
response.setHeader( "Content-Disposition", "attachment; filename="" + originalFile + """ );

The file name, in this case originalFile, is used to obtain the MIME type of the file. If the MIME type of the file is null, then text/plain will be returned. The attachment is set up in the response header as well, by appending the file name as an attachment to the Content-Disposition. Next, the doDownload method obtains a reference to the file that is to be downloaded by calling the ServletContext getResourceAsStream method and passing the name of the file. This will return an InputStream object that can be used to read the contents of the indicated file. A byte buffer is then created, which will be used to obtain chunks of data from the file when it is being read. The final real task is to read the file contents and copy them to the output stream. This is done using a while loop, which will continue to read from the InputStream until everything has been processed. Chunks of data are read in and written to the output stream using the loop.

while ((in != null) && ((length = in.read(bbuf)) != -1))
{
    outStream.write(bbuf,0,length);
}

Lastly, the ServletOutputStream object’s flush method is called to clear the contents, and it is then closed to release resources. The magic of downloading files using a Java servlet may be a bit obfuscated by this example, however, because a static file is being used as the download source in this example. In real life, the HTML page would probably contain a list of files that are contained within a database, and then when the user selects a file to download, the servlet will process that file accordingly, even extracting the file from the database if necessary.

1-14. Dispatching Requests

Problem

You want to write a servlet that hands off requests to other servlets based upon the task that needs to be accomplished. Furthermore, you want the requests to be handed off without redirecting the client to another site, and therefore, the URL in the browser should not change.

Solution

Create a request dispatcher servlet, which will decide which task needs to be completed and then send the request to an appropriate servlet to achieve that task. The following example demonstrates this concept via an HTML form that accepts two numbers from the user and allows the user to decide what type of mathematical evaluation should be performed by the server. The servlet processes the request by first determining which type of mathematical evaluation should be performed and then dispatching the request to the appropriate servlet to perform the task.

The following HTML form accepts two numbers from the user and allows them to choose which type of math to perform against the numbers:

<html>
    <head>
        <title></title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    </head>
    <body>
        <h1>Request Dispatch Example</h1>
        <p>Perform a mathematical evaluation.  Insert two numbers to be evaluated and then
            choose the type of evaluation to perform.</p>
        <form method="POST" action="MathDispatcher">
            <label for="numa">Enter Number A: </label>
            <input type="text" id="numa" name="numa"/><br><br>
            <label for="numb">Enter Number B: </label>
            <input type="text" id="numb" name="numb"/><br/><br/>
            <select id="matheval" name="matheval">
                <option value="add">Add the numbers</option>
                <option value="subtract">Subtract the numbers</option>
                <option value="multiply">Multiply the numbers</option>
                <option value="divide">Divide the numbers</option>
            </select>
            <input type="submit" value="Submit Form"/>
            <input type="reset" value="Reset Form"/>
        </form>
    </body>
</html>

The next piece of code is the servlet that will dispatch requests accordingly depending upon the value of the matheval field:

package org.javaeerecipes.chapter01.recipe01_14;

import java.io.IOException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 *
 * @author juneau
 */
// Uncomment the following line to run example stand-alone
//@WebServlet(name = "MathDispatcher", urlPatterns = {"/MathDispatcher"})

// The following will allow the example to run within the context of the JavaEERecipes example
// enterprise application (JavaEERecipes.war distro or Netbeans Project
@WebServlet(name = "MathDispatcher", urlPatterns = {"/chapter01/MathDispatcher"})
public class MathDispatcher extends HttpServlet {

    /**
     * Handles the HTTP
     * <code>POST</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
         System.out.println("In the servlet. . .");
        // Store the input parameter values into Strings
                String eval = request.getParameter("matheval");
                ServletContext sc = getServletConfig().getServletContext();
                RequestDispatcher rd = null;
                int evaluate = 0;
                int add = 0;
                int subtract = 1;
                int multiply = 2;
                int divide = 3;
                if(eval.equals("add"))
                    evaluate = add;
                if (eval.equals("subtract"))
                    evaluate = subtract;
                if (eval.equals("multiply"))
                    evaluate = multiply;
                if(eval.equals("divide")){
                    evaluate = divide;
                }
                switch(evaluate){
                    case(0): rd =  sc.getRequestDispatcher("/AddServlet");
                                 rd.forward(request, response);
                                 break;
                    case(1): rd =  sc.getRequestDispatcher("/SubtractServlet");
                                      rd.forward(request, response);
                                      break;
                    case(2): rd =  sc.getRequestDispatcher("/MultiplyServlet");
                                      rd.forward(request, response);
                                      break;
                    case(3): rd =  sc.getRequestDispatcher("/DivideServlet");
                                    rd.forward(request, response);
                                    break;
                }
                        
    }

 
    /**
     * Returns a short description of the servlet.
     *
     * @return a String containing servlet description
     */
    @Override
    public String getServletInfo() {
        return "Short description";
    }
}

Next is an example of one of the servlets that the request will be dispatched to. The following is the code for the AddServlet, which will add the two numbers and return the sum to the user:

package org.javaeerecipes.chapter01.recipe01_14;

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 *
 * @author juneau
 */
// Uncomment the following line to run example stand-alone
//@WebServlet(name = "AddServlet", urlPatterns = {"/AddServlet"})

// The following will allow the example to run within the context of the JavaEERecipes example
// enterprise application (JavaEERecipes.war distro or Netbeans Project
@WebServlet(name = "AddServlet", urlPatterns = {"/chapter01/AddServlet"})
public class AddServlet extends HttpServlet {

    /**
     * Processes requests for both HTTP
     * <code>GET</code> and
     * <code>POST</code> methods.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        // Store the input parameter values into Strings
                String numA = request.getParameter("numa");
                String numB = request.getParameter("numb");
                int sum = Integer.valueOf(numA) + Integer.valueOf(numB);
        try {
            out.println("<html>");
            out.println("<head>");
            out.println("<title>The Sum of the Numbers</title>");
            out.println("</head>");
            out.println("<body>");
            out.println("<h1>Sum: " + sum + "</h1>");
            out.println("<br/>");
            out.println("<a href=recipe01_14.html>Try Again</a>");
            out.println("</body>");
            out.println("</html>");
        } finally {
            out.close();
        }
    }

    /**
     * Handles the HTTP
     * <code>GET</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /**
     * Handles the HTTP
     * <code>POST</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /**
     * Returns a short description of the servlet.
     *
     * @return a String containing servlet description
     */
    @Override
    public String getServletInfo() {
        return "Short description";
    }
}

Each of the other servlets is very similar to AddServlet, except the mathematical evaluation is different. To see a full listing of the code, please take a look at the sources for this book.

How It Works

Sometimes it is a good idea to hide the forwarding of requests from the end user. Other times it just makes sense to hand off a request from one servlet to another so that another type of processing can take place. These are just two examples of when it is handy to perform a request dispatch within a servlet. Forwarding a request versus dispatching a request is different because a forwarded request hands off the request on the client side, whereas a dispatched request hands off the request on the server side. The difference can be quite large since the end user has no idea of server-side dispatches, whereas the browser is redirected to a different URL when the request is forwarded on the client side.

Dispatching requests is an easy task. The facilities for doing so are built right into the ServletContext, so once you obtain a reference to ServletContext, then you simply call the getRequestDispatcher method to obtain a RequestDispatcher object that can be used to dispatch the request. When calling the getRequestDispatcher method, pass a String containing the name of the servlet that you want to hand off the request to. You can actually obtain a RequestDisptacher object for any valid HTTP resource within the application by passing the appropriate URL for the resource in String format to the getRequestDispatcher method. Therefore, if you’d rather dispatch to a JSP or HTML page, you can do that as well. After a RequestDispatcher object has been obtained, invoke its forward method by passing the HttpServletRequest and HttpServletResponse objects to it. The forward method performs the task of handing off the request.

rd = sc.getRequestDispatcher("/AddServlet");
rd.forward(request, response);

In the case of the example in this recipe, you can dispatch requests to different servlets in order to perform a specific task. Once handed off, the servlet that has obtained the request is responsible for providing the response to the client. In this case, the servlet returns the result of the specified mathematical evaluation.

1-15. Redirecting to a Different Site

Problem

You need to redirect the browser to another URL when a specific URL within your application is visited.

Solution

Use the HttpServletResponse object’s sendRedirect() method to redirect from the servlet to another URL. In the following example, when a URL that matches the /redirect pattern is used, then the servlet will redirect the browser to another site:

import java.io.IOException;
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;

@WebServlet(name="RedirectServlet", urlPatterns={"/redirect"})
public class RedirectServlet extends HttpServlet {
  
        @Override
    public void doGet(HttpServletRequest req, HttpServletResponse res)
        throws IOException, ServletException {
                String site = "http://www.apress.com";
                
        res.sendRedirect(site);
    }
}

In this example, the servlet will redirect to the www.apress.com web site.

How It Works

There are some cases in which a web application needs to redirect traffic to another site or URL within the same or another application. For such cases, the HttpServletResponse sendRedirect method can be of use. The sendRedirect method accepts a URL in String format and then redirects the web browser to the given URL. Given that sendRedirect accepts a String-based URL makes it easy to build dynamic URLs as well. For instance, some applications may redirect to a different URL based upon certain parameters that are passed from a user. Dynamic generation of a URL in such cases may look something like the following:

String redirectUrl = null;
If(parameter.equals("SOME STRING")
    redirectUrl = "/" + urlPathA;
else
    redirectUrl = "/" + urlPathB;
res.sendRedirect(redirectUrl);

The sendRedirect() method can also come in handy for creating the control for web menus and other page items that can send web traffic to different locations.

image Note   This simple redirect, as opposed to servlet chaining, does not pass the HttpRequest object along to the target address.

1-16. Securely Maintaining State Within the Browser

Problem

You have the requirement to save a user’s state within the browser for your application.

Solution

Use “HTTP only” browser cookies to save the state. In the following example, one servlet is used to place some session information into a cookie in the browser. Another servlet is then called, which reads the cookie information and displays it to the user. The following servlet demonstrates how to store a cookie in the browser using a Java servlet:

package org.javaeerecipes.chapter01.recipe01_16;

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Recipe 1-16: Securing State within the Browser
 * @author juneau
 */
@WebServlet(name = "SetCookieServlet", urlPatterns = {"/SetCookieServlet"})
public class SetCookieServlet extends HttpServlet {

 
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        Cookie cookie = new Cookie("sessionId","12345");
        cookie.setHttpOnly(true);
        cookie.setMaxAge(-30);
        response.addCookie(cookie);
        try {
            out.println("<html>");
            out.println("<head>");
            out.println("<title>SetCookieServlet</title>");
            out.println("</head>");
            out.println("<body>");
            out.println("<h1>Servlet SetCookieServlet is setting a cookie into the browser</h1>");
            out.println("<br/><br/>");
            out.println("<a href='DisplayCookieServlet'>Display the cookie contents.</a>");
            out.println("</body>");
            out.println("</html>");
        } finally {
            out.close();
        }
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

 
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

}

The next code listing demonstrates a servlet that reads the cookies in the browser and prints out the contents:

package org.javaeerecipes.chapter01.recipe01_16;

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Recipe 1-16: Securely Maintaining State within the Browser
 * @author juneau
 */
@WebServlet(name = "DisplayCookieServlet", urlPatterns = {"/DisplayCookieServlet"})
public class DisplayCookieServlet extends HttpServlet {

    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        Cookie[] cookies = request.getCookies();
        
        try {
            out.println("<html>");
            out.println("<head>");
            out.println("<title>Display Cookies</title>");
            out.println("</head>");
            out.println("<body>");
            for(Cookie cookie:cookies){
                out.println("<p>");
                out.println("Cookie Name: " + cookie.getName());
                out.println("<br/>");
                out.println("Value: " + cookie.getValue());
                out.println("</p>");
            }
            out.println("</body>");
            out.println("</html>");
        } finally {
            out.close();
        }
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

}

How It Works

Using cookies to store data within the browser is a technique that has been in practice for years. Since Servlet 3.0 API, the ability to mark a cookie as HTTP only has become available. This allows the cookie to be safeguarded against client-side scripting attacks, making the cookie more secure. Any standard servlet can create a cookie and place it into the current session. Similarly, any servlet that is contained within the same session can read or update a session’s cookies values. In the example for this recipe, two servlets are used to demonstrate how cookies work. The first servlet that is listed is responsible for creating a new cookie and setting it into the browser session. The second servlet is responsible for displaying the contents of the cookie to the user.

To create a cookie, simply instantiate a new javax.servlet.http.Cookie object and assign a name and value to it. Passing both the name and value into the Cookie constructor at the time of instantiation can assign a name and value, or it can be done by passing values to the cookie’s setName and setValue methods. Once the cookie has been instantiated, properties can be set that will help to configure the cookie. In the example to this recipe, the cookie’s setMaxAge and setHttpOnly methods are called, setting the time of life for the cookie and ensuring that it will be guarded against client-side scripting. For a complete listing of cookie properties, please refer to Table 1-3. Finally, the cookie is placed into the response by passing it to the response object’s addCookie method.

Cookie cookie = new Cookie("sessionId","12345");
cookie.setHttpOnly(true);
cookie.setMaxAge(-30);
response.addCookie(cookie);

Table 1-3. Cookie Property Methods

Property Description
setComment Sets a comment to describe the cookie.
setDomain Specifies the domain in which the cookie belongs.
setHttpOnly Marks the cookie as HTTP only.
setMaxAge Sets the maximum lifetime of the cookie. A negative value indicates that the cookie will expire when the session ends.
setPath Specifies a path for the cookie to which the client should return it.
setSecure Indicates that the cookie should be sent only using a secure protocol.
setValue Assigns a value to the cookie.
setVersion Specifies the version of the cookie protocol that the cookie will comply with.

The second servlet, DisplayCookieServlet, in the example is responsible for reading and displaying the session’s cookies values. When DisplayCookieServlet is invoked, its processRequest method is called, which obtains the cookies within the response object by calling response.getCookies() and setting the result to an array of Cookie objects.

Cookie[] cookies = request.getCookies();

The cookie object array can now be iterated over in order to obtain each cookie and print out its contents. The servlet does so by using a for loop and printing out each cookie’s name and value.

for(Cookie cookie:cookies){
        out.println("<p>");
        out.println("Cookie Name: " + cookie.getName());
        out.println("<br/>");
        out.println("Value: " + cookie.getValue());
        out.println("</p>");
}

1-17. Finalizing Servlet Tasks

Problem

There are some resources you want to have your servlet clean up once the servlet is no longer in use.

Solution

The solution to the problem is twofold. First, provide code for performing any cleanup within the servlet destroy method. Second, in the case that there are potentially long-running methods, code them so that you will become aware of a shutdown and, if necessary, halt and return so that the servlet can shut down cleanly. The following code excerpt is a small example of a destroy method. In this code, it is being used to initialize local variables and is setting the beingDestroyed boolean value to indicate that the servlet is shutting down.

. . .
/**
     * Used to finalize the servlet
     */
    public void destroy() {
        // Tell the servlet it is shutting down
        setBeingDestroyed(true);
        // Perform any cleanup
        thisString = null;

    }
. . .

The code within the destroy method may successfully achieve a full cleanup of the servlet, but in the case where there may be a long-running task, then it must be notified of a shutdown. The following excerpt is a block of code that signifies a long-running task. The task should stop processing once the shutdown is indicated by the beingDestroyed value becoming true.

for (int x = 0; (x <= 100000 && !isBeingDestroyed()); x++) {
    doSomething();
}

How It Works

The finalization of a servlet can be very important, especially if the servlet is using some resources that may lead to a memory leak, making use of a reusable resource such as a database connection or in order to persist some values for another session. In such cases, it is a good idea to perform cleanup within the servlet destroy method. Every servlet contains a destroy method (which may be implemented to overload default behavior) that is initiated once the servlet container determines that a servlet should be taken out of service.

The destroy method is called once all of a servlet’s service methods have stopped running. However, if there is a long-running service method, then a server grace period can be set that would cause any running service to be shut down when the grace period is reached. As mentioned earlier, the destroy method is the perfect place to clean up resources. However, the destroy method is also a good place to help clean up after long-running services. Cleanup can be done by setting a servlet-specific local variable to indicate that the servlet is being destroyed and by having the long-running service check the state of that variable periodically. If the variable indicates that the destroy method has been called, then it should stop executing.

1-18. Reading and Writing with Nonblocking I/O

Problem

You want to read and write I/O in an asynchronous, nonblocking manner.

Solution

Use the Non-Blocking I/O API that is part of the Servlet 3.1 release. To use the new technology, implement the new ReadListener interface when performing nonblocking reads, and implement the WriteListener interface for performing nonblocking writes. The implementation class can then be registered to a ServletInputStream or ServletOutputStream so that reads or writes can be performed when the listener finds that servlet content can be read or written without blocking.

The following sources are those of a ReadListener implementation that reside in the source file org.javaeerecipes.chapter01.recipe01_18.AcmeReadListenerImpl.java, and they demonstrate how to implement the ReadListener:

package org.javaeerecipes.chapter01.recipe01_18;

import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.AsyncContext;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;

public class AcmeReadListenerImpl implements ReadListener {

    private ServletInputStream is = null;
    private AsyncContext async = null;

    public AcmeReadListenerImpl(ServletInputStream in, AsyncContext ac) {
        this.is = in;
        this.async = ac;
        System.out.println("read listener initialized");
    }

    @Override
    public void onDataAvailable() {
        System.out.println("onDataAvailable");
        try {
            StringBuilder sb = new StringBuilder();
            int len = -1;
            byte b[] = new byte[1024];
            while (is.isReady()
                    && (len = is.read(b)) != -1) {
                String data = new String(b, 0, len);
                System.out.println(data);
            }
        } catch (IOException ex) {
            Logger.getLogger(AcmeReadListenerImpl.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

 

    @Override
        public void onAllDataRead() {
        System.out.println("onAllDataRead");
        async.complete();
        
    }

    @Override
        public void onError(Throwable thrwbl) {
        System.out.println("Error: " + thrwbl);
        async.complete();
    }
    
}

Next, use the listener by registering it to a ServletInputStream (in the case of the ReadListener) or a ServletOutputStream (in the case of a WriteListener). For this example, I’ll show a servlet that utilizes the AcmeReadListenerImpl class. The sources for the following class reside within the file org.javaeerecipes.chapter01.recipe01_18.AcmeReaderExample.java:

package org.javaeerecipes.chapter01.recipe01_18;

import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.concurrent.CountDownLatch;
import javax.servlet.AsyncContext;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(urlPatterns = {"/AcmeReaderServlet"}, asyncSupported=true)
public class AcmeReaderServlet extends HttpServlet {

 
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        try (PrintWriter output = response.getWriter()) {
            String filename = "test.txt";
            ServletContext context = getServletContext();

            InputStream in = context.getResourceAsStream(filename);
            output.println("<html>");
            output.println("<head>");
            output.println("<title>Acme Reader</title>");
            output.println("</head>");
            output.println("<body>");
            output.println("<h1>Welcome to the Acme Reader Servlet</h1>");
            output.println("<br/><br/>");
            output.println("<p>Look at the server log to see data that was read asynchronously from a file<p>");
            AsyncContext asyncCtx = request.startAsync();
            ServletInputStream input = request.getInputStream();
            input.setReadListener(new AcmeReadListenerImpl(input, asyncCtx));

            output.println("</body>");
            output.println("</html>");
        } catch (Exception ex){
            System.out.println("Exception Occurred: " + ex);
        }
    }

 
  // Http Servlet Methods . . .
. . .
}

The last piece of code that we need is the servlet that invokes the AcmeReaderServlet, passing the message that needs to be processed. In this example, a file from the server is passed to the AcmeReaderServlet as input, which then is asynchronously processed via the AcmeReadListenerImpl class.  The following code is taken from org.javaeerecipes.chapter01.recipe01_18.ReaderExample.java.

package org.javaeerecipes.chapter01.recipe01_18;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(name = "ReaderExample", urlPatterns = {"/ReaderExample"})
public class ReaderExample extends HttpServlet {

    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        String filename = "/WEB-INF/test.txt";
        ServletContext context = getServletContext();

        InputStream in = context.getResourceAsStream(filename);
        try (PrintWriter out = response.getWriter()) {
            String path = "http://"
                    + request.getServerName()
                    + ":"
                    + request.getServerPort()
                    + request.getContextPath()
                    + "/AcmeReaderServlet";
            out.println("<html>");
            out.println("<head>");
            out.println("<title>Intro to Java EE 7 - Servlet Reader Example</title>");
            out.println("</head>");
            out.println("<body>");
            out.println("<h1>Servlet ReaderExample at " + request.getContextPath() + "</h1>");
            out.println("Invoking the endpoint: " + path + "<br>");
            out.flush();
            URL url = new URL(path);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setChunkedStreamingMode(2);
            conn.setDoOutput(true);
            conn.connect();
            if (in != null) {
                InputStreamReader inreader = new InputStreamReader(in);
                BufferedReader reader = new BufferedReader(inreader);
                String text = "";
                out.println("Beginning Read");
                try (BufferedWriter output = new BufferedWriter(new OutputStreamWriter(conn.getOutputStream()))) {
                    out.println("got the output. . .beginning loop");
                    while ((text = reader.readLine()) != null) {
                        out.println("reading text: " + text);
                        out.flush();
                        output.write(text);
  
                        Thread.sleep(1000);
                        output.write("Ending example now..");
                        out.flush();
                    }
                    output.flush();
                    output.close();
                }
            }
            out.println("Review the GlassFish server log for messages. . .");
            out.println("</body>");
            out.println("</html>");
        } catch (InterruptedException | IOException ex) {
            Logger.getLogger(ReaderExample.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    @Override
    public String getServletInfo() {
        return "Short description";
    }
}

When the servlet is visited, the asynchronous, nonblocking read of the test.txt file will occur, and its text will be displayed in the server log.

How It Works

Servlet technology has allowed only traditional (blocking) input/output during request processing since its inception. In the Servlet 3.1 release, the new Non-Blocking I/O API makes it possible for servlets to read or write without any blocking. This means other tasks can be performed at the same time that a read or write is occurring, without any wait. Such a solution opens up a new realm of possibilities for servlets, making them much more flexible for use along with modern technologies such as the WebSockets protocol.

To implement a nonblocking I/O solution, new programming interfaces have been added to ServletInputStream and ServletOutputStream, as well as two event listeners: ReadListener and WriteListener. ReadListener and WriteListener interfaces make the servlet I/O processing occur in a nonblocking manner via callback methods that are invoked when servlet content can be read or written without blocking. Use the ServletInputStream.setReadListener(ServletInputStream, AsyncContext) method to register a ReadListener with a ServletInputStream, and use the I/O read ServletInputStream.setWriteListener(ServletOutputStream,AsyncContext) method for registering a WriteListener. The following lines of code demonstrate how to register a ReadListener implementation with a ServletInputStream:

AsyncContext context = request.startAsync();
ServletInputStream input = request.getInputStream();
input.setReadListener(new ReadListenerImpl(input, context));

image Note   In Servlet 3.0, AsyncContext was introduced to represent an execution context for an asynchronous operation that is initiated on a servlet request. To use the asynchronous context, a servlet should be annotated as a @WebServlet, and the asyncSupported attribute of the annotation must be set to true. The @WebFilter annotation also contains the asyncSupported attribute.

After a listener has been registered with a ServletInputStream, the status on a nonblocking read can be checked by calling the methods ServletInputStream.isReady and ServletInputStream.isFinished. For instance, a read can begin once the ServletInputStream.isReady method returns a true, as shown here:

while (is.isReady() && (b = input.read()) != -1)) {
len = is.read(b);
String data = new String(b, 0, len);
}

To create a ReadListener or WriteListener, three methods must be overridden: onDataAvailable, onAllDataRead, and onError. The onDataAvailable method is invoked when data is available to be read or written, onAllDataRead is invoked once all the data has been read or written, and onError is invoked if an error is encountered. The code for AcmeReadListenerImpl in the solution to this recipe demonstrates how to override these methods.

The AsyncContext.complete() method is called in the onAllDataRead method to indicate that the read has been completed and to commit the response. This method is also called in the onError implementation so that the read will complete, so it is important to perform any cleanup within the body of the onError method to ensure that no resources are leaked, and so on.

To implement a WriteListener, make use of the new ServletOutputStream.canWrite() method, which determines whether data can be written in a nonblocking fashion. A WriteListener implementation class must override a couple of methods: onWritePossible and onError. The onWritePossible method is invoked when a nonblocking write can occur. The write implementation should take place within the body of this method. The onError method is much the same as its ReadListener implementation counterpart, because it is invoked when an error occurs.

The following lines of code demonstrate how to register a WriteListener with a ServletOutputStream:

AsyncContext context = request.startAsync();
ServletOutputStream os = response.getOutputStream();
os.setWriteListener(new WriteListenerImpl(os, context));

The WriteListener implementation class must include overriding methods for onWritePossible and onError. The following is an example for a WriteListener implementation class:

import javax.servlet.AsyncContext;
import javax.servlet.ServletOutputStream;
import javax.servlet.WriteListener;

public class WriteListenerImpl implements WriteListener {

    ServletOutputStream os;
    AsyncContext context;
    
    public WriteListenerImpl(ServletOutputStream out, AsyncContext ctx){
        this.os = out;
        this.context = ctx;
        System.out.println("Write Listener Initialized");
    }

    @Override
    public void onWritePossible() {
        System.out.println("Now possible to write. . .");
        // Write implementation goes here. . .
    }

    @Override
    public void onError(Throwable thrwbl) {
        System.out.println("Error occurred");
        context.complete();
    }
    
}

image Note   In most cases, the ReadListener and WriteListener implementation classes can be embedded within the calling servlet. They have been broken out into separate classes for the examples in this book for demonstration purposes.

The new Non-Blocking I/O API helps bring the Servlet API into compliance with new web standards. The new API makes it possible to create web-based applications that perform well in an asynchronous fashion.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.107.100