HTTP and Servlets

Practice for Week 2

This laboratory exercise involves developing a Hello World servlet, step by step. It gets easier once you've worked out the process - your first servlet will be your hardest!

In theory, creating a Servlet is a complex process:

  1. Write the code
  2. Compile
  3. Lay out class files and other resources in a special directory structure
  4. Compress the directory structure using jar (this uses the zip file format), and rename the file to a ".war" extension.
  5. Deploy the ".war" file to the web application server (e.g., copy to a special folder).

However, NetBeans will do steps 2-5 for you, at the "click of a button".

Create a Servlet

  1. Create a new Project
    1. In the category "Java Web", select the "Web Application" project type
    2. Choose a name: Week2
    3. Ensure the Server is "GlassFish Server 4.1.1" and the Java EE Version is "Java EE 7 Web" (the context path is the address on the web-server that your application will be deployed to)
    4. Don't add any frameworks
  2. Create a new File
    1. Choose File... New File...
    2. In the "Web" category, select the "Servlet" file type
    3. Enter the class name "HelloWorld" and the package name "au.edu.uts.aip.week2
    4. Leave the URL Pattern as-is (i.e., "/HelloWorld")

The generated Servlet is quite complex, let's replace it with something simple. Delete the code and copy-and-paste this code in its place:

package au.edu.uts.aip.week2;

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

@WebServlet("/HelloWorld")
public class HelloWorld extends HttpServlet {

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

        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        out.println("<html>");
        out.println("<head><title>First Servlet</title>");
        out.println("<body><p>Hello, World!</p></body>");
        out.println("</html>");

    }

}

Run the Servlet

Now, run the project (click the green play button). Your application will be compiled, GlassFish Server 4.1.1 and Java DB Database will be automatically started (this could take a while), your application will be deployed to the GlassFish server and a web browser will open.

Now, modify the address on your browser to the following address:

http://localhost:8080/Week2/HelloWorld

  • http is the protocol
  • localhost is the name of the server
  • 8080 is the port the server is running on (normally web servers run on port 80 but development systems often run on port 8080)
  • /Week2 is the context path from when we created the project
  • /HelloWorld is the url pattern of the Servlet (i.e., the pattern inside the @WebServlet("/HelloWorld"))

The message, "Hello, World!" should appear!

See if you can edit the Java code to display some other message. Note that when you save the file, NetBeans will automatically compile and deploy your application -- you do not need to click the run button again.

Reflection

Can you explain each line of code in this Servlet?

The goal of this exercise is to create a Servlet that maintains a counter of the number of times it has been invoked since it was last reloaded by the web server. It will use a class variable (i.e. static) to keep count of the number of invocations. Each time the Servlet is invoked, it will print out the value of the counter.

You can do this exercise in the same project, Week2.

Create a new Servlet named Counter.java:

  • Inside the "Week2" project, look in "Source Packages" and right click on the au.uts.edu.aip.week2 package
  • Select New... Other...
  • In the "Web" category choose the "Servlet" file type
  • Name the class "Counter" (without the quotes), the package should already be au.uts.edu.aip.week2
  • Leave the Servlet Name and URL Pattern as-is

Create the Servlet

Your objective is to create a Servlet that will generate a response such as:

<html>
<head><title>Counter</title>
<body><p>Number of requests since reload: 1</p></body>
</html>

The number 1 should increase each time the page is requested.

Hints

To declare a variable to hold the value of your counter:

private int counter = 0;

To increase the counter, you can use a method:

private synchronized int increaseCounter() {
  counter = counter + 1;
  return counter;
}

A different way to increase the counter is with a synchronized block:

int currentCount;
synchronized (this) {
  counter = counter + 1;
  currentCount = counter;
}

In Java, you can turn an integer (int) into a String using the concatenation operator (+):

String result = "Number of requests since reload: " + currentCount;
out.println(result);

Reflect

Why does the counter go back to 1 every time you save a change to your Java code?

What does synchronized mean? Why is it necessary?

Why does increaseCounter() return a value or, equivalently, why was the variable currentCount used in the synchronized block?

The goal of this exercise is to create a Servlet that can print out the value of a counter but can also be set to a custom value.

You can continue this exercise in the same project: Week2.

Create a Form

Begin by creating a HTML form that you will use to view and set the value of the counter.

  • In your NetBeans project, right click on the "Web Pages" (or "web") folder.
  • Click "New..." and then "Other...".
  • Then, in the "HTML5" category, select the "HTML File" file type.

On the next screen, give the file a simple name such as "set-counter" (without the quotes).

Create a form such as the following:

<!DOCTYPE html>
<html>
    <head>
        <title>Settable Counter</title>
    </head>
    <body>
        <form action="SettableCounter" method="GET">
            <p>Set counter to: <input type="text" name="newValue"></p>
            <p><input type="submit" value="Set Counter"></p>
        </form>
    </body>
</html>

If your application server is running, you should be able to see the page by visiting:

http://localhost:8080/Week2/set-counter.html

Create the SettableCounter Servlet

Notice the action attribute of the form element of our HTML page: action="SettableCounter".

We must now create a Servlet that will respond to requests on this path.

We can do this by creating a Servlet (i.e., a Java class that extends HttpServlet like we have done previously) and ensuring that the class is annotated with @WebServlet("/SettableCounter").

Now notice the method attribute of the form element of our HTML page: method="GET". This means that we will need to implement the doGet method of our Servlet.

Your objective is to create a Servlet that will:

Hints

You can read a form parameter using the following code:

String newValueString = request.getParameter("newValue");

If there is no form value, then the result is null. You can test for this with an if-statement:

if (null == newValueString) {
  // show counter
} else {
  // set counter
}

In Java, you can convert a String containing a number into an integer with the following code:

int newValue = Integer.parseInt(newValueString);

Remember: To see the counter increase, you will need to access the Servlet directly without any parameters:

http://localhost:8080/Week2/SettableCounter

(NOT: http://localhost:8080/Week2/SettableCounter?newValue=50)

Reflection / Challenge

How can you change this Servlet to handle post requests (i.e., modify the original HTML code so that the so that the form has method="POST" and then change the Servlet accordingly)?

What happens if you enter something that isn't a number (e.g., "abcd")? How can you fix this?

The goal of this exercise is to create a Servlet that will print out two different counter values:

  • The total number times the Servlet has been requested, since it was reloaded
  • The total number of times the current user has requested the Servlet

This requires the use of sessions and session variables in your servlet.

Sessions

Java servlets have built-in support for session management. This simplifies the task of creating a web application that keeps track of interactions with a user.

The abstraction used in Java is the notion of session attributes that can be stored in a session object. The session object acts like a container. You can store attributes (name/value pairs) into the session object, and you can retrieve attributes out of the session object. Attributes that are stored in the session object will still keep their value in between successive HTTP requests. Each "attribute value" is, of course, a Java object.

Each attribute stored in the session has a name, and a value. The name is just a String. The value is a Java object. The HttpSession class uses the methods setAttribute() and getAttribute for storing and retrieving attributes in sessions respectively.

Where do you get the session object from in the first place? From the request object. You get the session from the request. If there was already a session established, then you will have access to all the variables stored in the session. However if there was not already a session established, one will be created automatically (by default), and you will then have access to a blank session object in which you can store variables.

Create a Servlet

Create a new Servlet (call it SessionCounter) that will generate HTML similar to the following:

<!DOCTYPE html>
<html>
    <head>
        <title>Counter</title>
    </head>
    <body>
        <p>Number of requests since reload: 10</p>
        <p>Number of requests in this session: 5</p>
        <p><a href="SessionCounter">Reload this page</a></p>
    </body>
</html>

Note a browser will share session information among its tabs and windows. To test your code properly, you will need to either use two separate browsers, two separate computers, use an "Incognito"-mode browser window or wipe your browser's cookies.

Hints

This code will access the session object and store a value in it:

HttpSession session = request.getSession();
session.setAttribute("sessionCounter", userCounter);

This code will retrieve the session object and then get a value from that object:

HttpSession session = request.getSession();
Integer sessionCounter = (Integer)session.getAttribute("sessionCounter");
if (session.isNew() || null == sessionCounter) {
  // no session counter saved yet
} else {
  int userCount = sessionCounter;
  // handle the user's count
}

To use quotes (") inside a Java string, you need to escape it with a backslash (\").

e.g., out.println("<p><a href=\"SessionCounter\">Reload this page</a></p>");

Reflect

What happens if the Servlet is reloaded (e.g., you make a change to the source code and save the file so it gets compiled and deployed)? Does the servlet counter get reset? Does the session counter get reset? Why?

What happens if cookies are disabled in the browser? Why?

GlassFish will user Cookies where possible. If Cookies are unavailable it can use URL rewriting to keep track of users by the URLs of their requests. To make this work, you need to ensure that every URL is encoded by web server. Instead of using this code:

out.println("<p><a href=\"SessionCounter\">Reload this page</a></p>");

You should encode your URLs like this:

String url = response.encodeURL("SessionCounter");
out.println("<p><a href=\"" + url + "\">Reload this page</a></p>");

Now, change your code and see how your application works if Cookies are disabled in the browser.

What happens to the URL when you click on "Reload this page"?

Before Leaving

Don't forget to re-enable cookies in your browser!