Go4Expert

Go4Expert (http://www.go4expert.com/)
-   Java (http://www.go4expert.com/articles/java-tutorials/)
-   -   Sessions In Servlets (Part-2) (http://www.go4expert.com/articles/sessions-servlets-part-2-t21701/)

techgeek.in 8Apr2010 10:27

Sessions In Servlets (Part-2)
 

Introduction



In the last article on servlet, we noted that HTTP is the protocol most-commonly used to communicate with web applications. Unfortunately, HTTP offers no mechanism for data to be retained between requests; in other words it can't track the activities of a user across requests.
Associating requests with a particular user in this way is often known as maintaining a session, and many web applications make use of sessions.
There are various mechanisms that have been devised to enable us to do so. These include:
  • Rewriting URLs
  • Creating cookies
  • Using hidden form fields

Let's begin by discussing the URL rewriting approach to session tracking.

Session Tracking Using URL Rewriting



URL rewriting is based on the idea of embedding a unique ID (generated by the server) in each URL of the response from the server. That is, while generating the response to the first request, the server embeds this ID in each URL. When the client submits a request to one such URL, the browser sends this ID back to the server. The server can therefore identify the ID with all requests. Let's examine this approach with the aid of an example. This servlet does the following:
  • Checks to see if the client sent any token with its request
  • If no token was sent, a new one is created
  • Provides two links back to the servlet - one including the token, and one not.

Here's the source code for the TokenServlet:

Code:

    package sessions;
    import java.io.*;
    import java.util.Random;
    import javax.servlet.http.*;
    import javax.servlet.ServletException;
    public class TokenServlet extends HttpServlet
                {
          protected void doGet(HttpServletRequest request, HttpServletResponse response)
          throws ServletException, IOException
                    {
                      //First we get the token from the request:

                      String tokenID = request.getParameter("tokenID");
                      //Then we prepare the response:

                      response.setContentType("text/html");
                      PrintWriter writer = response.getWriter();
                      writer.println("<html><head><title>Tokens</title></head><body ");
                      writer.println("style=\"font-family:verdana;font-size:10pt\">");
                      //If the client did not send any token we create a new one:

                      if(tokenID == null)
                            {
                              Random rand = new Random();
                              tokenID = Long.toString(rand.nextLong());
                              writer.println("<p>Welcome. A new token " +  tokenID + " is now  established</p>");
                            }
                        else
                            {
                        //If the client sent a token then we acknowledge the client:

                            writer.println("<p>Welcome back. Your token is " + tokenID + ".</p>");
                            }
                      //Then we prepare the links for sending requests back:

                      String requestURLSame = request.getRequestURL().toString() +
                              "?token=" + tokenID;
                      String requestURLNew = request.getRequestURL().toString();
                      //Finally, we write the response and close the connection:


                      writer.println("<p>Click <a href=" + requestURLSame + ">here</a> again to continue browsing with the " +  "same identity.</p>");
                      writer.println("<p>Otherwise, click <a href=" + requestURLNew +
                      ">here</a> again to start browsing with a new identity.</p>");
                      writer.close();
                  }
              }

Create a web application called token, compile the source code above, and add the class to the WEB-INF/class/sessions directory. Then create the following simple deployment descriptor for the web application:

Code:

<?xml version="1.0"?>

    <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
                            "http://java.sun.com/dtd/web-app_2_3.dtd">

    <web-app>
      <servlet>
        <servlet-name>track</servlet-name>
        <servlet-class>sessions.TokenServlet</servlet-class>
      </servlet>
      <servlet-mapping>
        <servlet-name>track</servlet-name>
        <url-pattern>/track/*</url-pattern>
      </servlet-mapping>
    </web-app>

Deploy the web application, restart Tomcat, and navigate to http://localhost:8080/token/track. You should see something like:

http://www.go4expert.com/images/arti...ets/image1.jpg

The initial request http://localhost:8080/token/track does not include the query parameter tokenID. The servlet creates a new token, and generates two links. The first link includes a query string while the second link doesn't. If you click on the first link, you will see the following page:

http://www.go4expert.com/images/arti...ets/image2.jpg

Since there is a query parameter in the request, the servlet recognizes the user from this parameter, and displays the Welcome back message. If you click instead on the second link, the browser displays a page with a different token:

http://www.go4expert.com/images/arti...ets/image3.jpg

Although this technique can solve the problem of session tracking, it has two important limitations:
  • Since the token is visible in the URL during a session, these sessions will not be very secure.
  • Since links in static pages are hard-wired, they can't be dynamically changed for every user, so we can only use this system with servlets or other dynamic pages.

An alternative is to use cookies. As you will see in the following section, cookies eliminate the above limitations.

Session Tracking Using Cookies



Cookies provide a better alternative to explicit URL rewriting, because cookies are not sent as query strings but are exchanged within the bodies of HTTP requests and responses. Since there is no need to rewrite URLs, session handling via cookies does not depend on whether the content is static or dynamic.
All modern browsers can recognize and receive cookies from web servers, and then send them back along with requests. However, there is a limitation with cookies. All browsers allow users to disable this functionality, which leads to browsers not recognizing cookies. This is because cookies have a bad press - they have sometimes been used to gather information about consumers without their knowledge. A cookie is a string sent via the HTTP request and HTTP response headers. It has the following parameters:

Parameter---> Description
1) Name ----> Name of cookie.
2) Value ---> A value of the cookie.
3) Comment -> A comment explaining the purpose of the cookie.
4) Max-Age -> Maximum age of the cookie (a time in seconds after which the client should not send the cookie back to the server).
5) Domain --> Domain to which the cookie should be sent.
6) Path ----> The path to which the cookie should be sent.
7) Secure --> Specifies if the cookie should be sent securely via HTTPS.
8) Version -> Version of the cookie protocol. Version 0 is meant for the original Netscape version of cookies. Version 1 is meant for cookies standardized via RFC 2109.

In order to send a cookie to a client, a server creates a cookie header and attaches it to the HTTP response. The client receives the request and extracts the cookie response header. This cookie data is usually stored in a file on the client's system.When the client makes another request, to help the client decide whether to send the cookie back to the server or not, depending on two parameters: Domain and Path. The path is given relative to the domain. For instance, in the URL http://www.myserver.com/shop/top100, myserver.com is the domain, and /shop/top100 is the path. If the Path parameter is not specified, the cookie applies to any path under the specified domain. Whenever the client makes a request to any URL matching the specified path within this domain, the client sends the cookie along with the request as a header. Let's say the response from the server contains links to http://www.myserver.com, http://sales.myserver.com and http://support.myserver.com and the Path parameter has not been set. When the user clicks of any of these links, the browser sends the cookie back, since all these links are under the same myserver.com domain, and any path in this domain is appropriate.

Working With Cookies in Servlets

The Java Servlet API includes a class javax.servlet.http.Cookie that abstracts the notion of a cookie. The javax.servlet.http.HttpServletRequest and javax.servlet.http.HttpServletResponse interfaces provide methods to add cookies to HTTP responses and to retrieve cookies from HTTP requests.
The Cookie class abstracts a cookie. A Cookie instance has the following constructor, which instantiates a cookie instance with the given name and value:

public Cookie(String name, String value)

This class has many methods that make working with cookies easier. It has getter and setter methods for all of the cookie parameters, for example:

public String getName()
public void setName(String name)


You can use these methods to access or change the name of a cookie. There are similar methods to access or change other parameters (such as path, header, and so on) of a cookie.

In order to set cookies, the javax.servlet.http.HttpServletResponse interface has the following method:

public void addCookie(Cookie cookie)

We can call this method as many times as we wish in order to set multiple cookies. To extract all cookies contained in the HTTP request, the javax.servlet.HttpServletRequest interface has this method:

public Cookie[] getCookies()

We write an example CookieServlet to track the user using cookies .
In this case, the servlet performs the following actions:
  • Checks if there is a cookie contained in the incoming request
  • If there is none, it creates a cookie, and sends it along with the response
  • If there is a cookie, it just displays the value of the cookie

Code:

package sessions;

    import ava.io.*;
    import java.util.Random;
    import javax.servlet.http.*;
    import javax.servlet.http.*;
    import javax.servlet.ServletException;

    public class CookieServlet extends HttpServlet {

      protected void doGet(HttpServletRequest request, HttpServletResponse response)
                                              throws ServletException, IOException {
        Cookie[] cookies = request.getCookies();
        Cookie token = null;

/*The servlet first retrieves all of the cookies contained in the request object. Provided there are cookies present, the servlet then checks each cookie to see if the name of the cookie is "token":*/

        if(cookies != null) {
          for(int i = 0; i < cookies.length; i++) {
            if(cookies[i].getName().equals("token")) {
              token = cookies[i];
              break;
            }
          }
        }

        response.setContentType("text/html");
        PrintWriter writer = response.getWriter();
        writer.println("<html><head><title>Tokens</title></head><body ");
        writer.println("style=\"font-family:verdana;font-size:10pt\">");
        String reset = request.getParameter("reset");

/*If a cookie with name "token" is not found, the servlet creates a cookie called "token" and adds it to the response. The servlet creates a random number. The servlet then created a cookie with the following parameters:

Name: "token"
Value: A random number (converted into a string)
Comment: "Token to identify user"
Max-Age: -1, indicating that the cookie should be discarded when the browser exits
Path: "/cookie/track", so that the browser sends the cookie to only requests under http://localhost:8080/cookie/track.*/


        if(token == null || (reset != null && reset.equals("yes"))) {
          Random rand = new Random();
          long id = rand.nextLong();

          writer.println("<p>Welcome. A new token " +
                        id + " is now established</p>");

          token = new Cookie("token", Long.toString(id));
          token.setComment("Token to identify user");
          token.setMaxAge(-1);
          token.setPath("/cookie/track");
The servlet then adds the cookie to the Response object:

          response.addCookie(token);
        else {

/*In order to facilitate recreating the identity, the servlet also expects a request parameter "reset". If this parameter is sent with a value of "yes", the servlet recreates the cookie as above, so that the client gets a new token. Otherwise, the servlet does not set the cookie, and just prints a message as shown below:*/

          writer.println("Welcome back. Your token is " + token.getValue() + ".</p>");
        }

        String requestURLSame = request.getRequestURL().toString();
        String requestURLNew = request.getRequestURL() + "?reset=yes";

        writer.println("<p>Click <a href=" + requestURLSame +
                      ">here</a> again to continue browsing with the " +
                      "same identity.</p>");
        writer.println("<p>Otherwise, click <a href=" + requestURLNew +
                      ">here</a> again to start browsing with a new identity.</p>");
        writer.println("</body></html>");
        writer.close();
      }
    }

Now create a new web application as you did for the URL rewriting example, and call it cookie. Compile the class above and place the class in the cookie/WEB-INF/classes/sessions/ directory.

Code:

<?xml version="1.0"?>

    <!DOCTYPE web-app
        PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
        "http://java.sun.com/dtd/web-app_2_3.dtd">

    <web-app>
      <servlet>
        <servlet-name>track</servlet-name>
        <servlet-class>CookieServlet</servlet-class>
      </servlet>

      <servlet-mapping>
        <servlet-name>track</servlet-name>
        <url-pattern>/track/*</url-pattern>
      </servlet-mapping>
    </web-app>

Deploy the web application, restart Tomcat, and navigate to http://localhost:8080/cookies/track.

http://www.go4expert.com/images/arti...image1_001.jpg

Click on the first link to get the following page:

http://www.go4expert.com/images/arti...image2_001.jpg

The token number is the same. The browser sent the cookie back to the server along with the request, and the server recognized it. Notice that the first link (in the second line) is the same as the one you entered in the address bar in the browser.
From the client perspective, there are two differences here from URL rewriting:
The token was not included in the query string
While displaying the page, the browser received a cookie from the server
If you instead click on the link on the third line, a fresh token will be created, and a new cookie will be set. In order for the server to recreate the token, you should note that there is an additional query parameter passed called "reset", with value "yes".

Session Tracking Using Hidden Form Fields



The third alternative to session handling is via hidden form fields. HTML forms allow fields to be hidden, which means that such fields are not displayed when the form is rendered on the browser. While preparing a page with a form, the server can add one or more hidden fields within the form. When the client submits the form, the browser transfers the values in the hidden fields along with the other visible fields (if any) to the server. We can use this mechanism to track a user. The following HiddenFieldServlet illustrates this point:

Code:

package sessions;

    import java.io.*;
    import java.util.Random;
    import javax.servlet.http.*;
    import javax.servlet.ServletException;

    public class HiddenFieldServlet extends HttpServlet {

      protected void doGet(HttpServletRequest request, HttpServletResponse response)
                                              throws ServletException, IOException {
//First we get the token from the request:

        String token = request.getParameter("token");

//Then we prepare the response:

        response.setContentType("text/html");
        PrintWriter writer = response.getWriter();
        writer.println("<html><head><title>Tokens</title></head><body ");
        writer.println("style=\"font-family:verdana;font-size:10pt\">");
//If the client did not sent any token we create a new one:

        if(token == null) {
          Random rand = new Random();
          token = Long.toString(rand.nextLong());
          writer.println("<p>Welcome. A new token " +
                        token + " is now established</p>");
        } else {
//If the client sent a token we acknowledge the client:

          writer.println("<p>Welcome back. Your token is " + token + ".</p>");
        }
//Then we prepare a URL for the client to send requests back:

        String requestURL = request.getRequestURL().toString();
//We finish by writing two forms. First we write a form with the token as a hidden field:

        writer.println("<p>");
        writer.println("<form method='GET' action='" + requestURL + "'>");
        writer.println("<input type='hidden' name='token' value='" + token + "'/>");
        writer.println("<input type='submit' value='Click Here'/>");
        writer.println("</form>");
        writer.println(" to continue browsing with the same identity.</p>");

//Then we write another form without the hidden field:

        writer.println("<form method='GET' action='" + requestURL + "'>");
        writer.println("<input type='submit' value='Click Here'/>");
        writer.println("</form>");
        writer.println(" to start browsing with a new identity.</p>");
        writer.close();
      }
    }

In this servlet, instead of using the usual <href> tags, we used buttons (within forms) for the user to respond to. In the first form, the only parameter is a hidden field, while the second form has no parameters at all.
Compile the above class and place the class file in the hidden/WEB-INF/classes/sessions/ directory.
Then create the following simple deployment descriptor for the web application:
Code:

<?xml version="1.0"?>

    <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
                            "http://java.sun.com/dtd/web-app_2_3.dtd">

    <web-app>
      <servlet>
        <servlet-name>track</servlet-name>
        <servlet-class>sessions.HiddenFieldServlet</servlet-class>
      </servlet>

      <servlet-mapping>
        <servlet-name>track</servlet-name>
        <url-pattern>/track/*</url-pattern>
      </servlet-mapping>
    </web-app>

Deploy the web application, restart Tomcat, and go to http://localhost:8080/hidden/track. You should see the following:

http://www.go4expert.com/images/arti...image3_001.jpg

Instead of hyperlinks, the response contains two buttons. This is because the forms we created above do not have any visible fields.

Click on the first button to see a page similar to the following:

http://www.go4expert.com/images/arti...ets/image4.jpg

If you now click on the second button, a new token is allocated.

A significant disadvantage to this form of maintaining session is obviously that we need to create forms, which is not particularly convenient when your content has hyper links and not forms.

shabbir 3May2010 13:16

Re: Sessions In Servlets (Part-2)
 
Nominate this article for Article of the month - Apr 2010


All times are GMT +5.5. The time now is 05:51.