Saturday, August 29, 2009

Tracking User Sessions in a web application using Java

Sometimes we would like to keep track after users in our web application. We would like to see how many active sessions we have and even which of the users are guests and which are logged. Java supplied an Interfaces called HttpSessionListener that can help us achieving this goal. This interface supplies 2 methods:

  • sessionCreated – Activated when a new session is created.
  • sessionDestroyed – Activated when session expires and being deleted from server.

Using this 2 methods we can implement our own Session Tracker. We will store all the currently active sessions in a Set.

This is our SessionTracker class implementing HttpSessionListener. The code is pretty straight forward and easy to understand:

package com.bashan.blog.session;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import java.util.*;
public class SessionTracker implements HttpSessionListener {
  private static Set<HttpSession> sessions = new HashSet<HttpSession>();
  public void sessionCreated(HttpSessionEvent httpSessionEvent) {
    sessions.add(httpSessionEvent.getSession());
  }
  public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
    sessions.remove(httpSessionEvent.getSession());
  }
  public static List<HttpSession> getSessions() {
    List<HttpSession> sessionsList = new ArrayList<HttpSession>(sessions);
    Collections.sort(sessionsList, new SessionComparator());
    return Collections.unmodifiableList(sessionsList);
  }
  public static class SessionComparator implements Comparator<HttpSession> {
    public int compare(HttpSession session1, HttpSession session2) {
      return (int) (session1.getLastAccessedTime() - session2.getLastAccessedTime());
    }
  }
}

Note that we return the currently active sessions as a list sorted according to the last access time. Of course, you can choose another way of sorting the sessions. In addition, note that we are using a static Set member in order to store all the active sessions. You might want to consider synchronization when adding or removing objects to/from the set. I believe that the chances of a synchronization issues in this case are pretty low, but sometimes it is better not taking any chances… ;-)

Our next step is to register our SessionTracker, so the Web Server will be able to use it. This is done in the web.xml file of our Web Server. considering our web server web.xml was empty, after registering the SessionTracker it should look like:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         version="2.5">
  <listener>
    <listener-class>
      com.bashan.blog.session.SessionTracker
    </listener-class>
  </listener>
</web-app>

Now, suppose we would like to see all the active sessions in our web application. We can write a small JSP page that will show a table of all active sessions:

<%@ page import="com.bashan.blog.session.SessionTracker" %>
<%@ page import="java.util.List" %>
<%@ page import="java.util.Date" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>Active Sessions</title>
    <style type="text/css">
      .bold
      {
          font-weight:bold;
      }
      .tableBorder
        {
          BORDER-RIGHT: #000000 1px solid;
          BORDER-TOP: 0px;
          BORDER-LEFT: 0px;
          BORDER-BOTTOM: #000000 1px solid
        }
      .tdBorder
        {
          BORDER-RIGHT: 0px;
          BORDER-TOP: #000000 1px solid;
          BORDER-LEFT: #000000 1px solid;
          BORDER-BOTTOM: 0px
        }
    </style>
  </head>
  <body>
  <table class="tableBorder" cellpadding="4" cellspacing="0">
    <tr>
      <td class="tdBorder bold">
        Last Activity
      </td>
      <td class="tdBorder bold">
        Created
      </td>
      <td class="tdBorder bold">
        Session ID
      </td>
    </tr>
    <%
      List<HttpSession> sessions = SessionTracker.getSessions();
      for (HttpSession currentSession : sessions)
      {
    %>
    <tr>
      <td class="tdBorder">
        <%= new Date(currentSession.getLastAccessedTime()) %>
      </td>
      <td class="tdBorder">
        <%= new Date(currentSession.getCreationTime()) %>
      </td>
      <td class="tdBorder">
        <%= currentSession.getId() %>
      </td>
    </tr>
    <%
      }
    %>
  </table>
  </body>
</html>
Assuming your web application allow users to login to the system, you probably store logged user information in the Session. It will be nice adding a column showing logged user details like user name, email or any other important information.

Tuesday, August 18, 2009

Sending HTML Email with embedded Images using Apache Commons EMail

Sometimes we would like to send emails that have better looking and are more rich in their content. Today’s most email clients know to show HTML email content. That means that the body of the email is actually HTML rather than plain text. Sending HTML emails is quite simple and can be done using Apache Commons Email. Here is an example class built on Apache Commons Email that sends HTML email:

package com.bashan.blog.mail;
import org.apache.commons.mail.EmailException;
import org.apache.commons.mail.HtmlEmail;
public class Mailer {
  protected String host;
  protected String username = null;
  protected String password = null;
  protected boolean isTLS = false;
  public Mailer(String host, String username, String password, boolean isTLS) {
    this.host = host;
    this.username = username;
    this.password = password;
    this.isTLS = isTLS;
  }
  public Mailer(String host, String username, String password) {
    this(host, username, password, false);
  }
  public Mailer(String host) {
    this(host, null, null, false);
  }
  public void sendHTMLMail(String fromEmail,
                           String fromName,
                           String[] toEmail,
                           String[] toName,
                           String subject,
                           String html,
                           String alternateText) throws EmailException {
    HtmlEmail email = new HtmlEmail();
    email.setHostName(host);
    email.setFrom(fromEmail, fromName);
    for (int i = 0; i < toEmail.length; i++) {
      email.addTo(toEmail[i], toName[i]);
    }
    if (username != null) {
      email.setAuthentication(username, password);
    }
    email.setTLS(isTLS);
    email.setSubject(subject);
    email.setHtmlMsg(html);
    email.setTextMsg(alternateText);
    email.send();
  }
}

In order to use this code, make sure to put “commons-email.jar” as well as “mail.jar” (Java mail) in your class path. The latest version of “mail.jar” can be easily found by searching “java mail” in Google and downloading from Sun web site.

Note that the method “sendHTMLMail” contains property named: “alternateText”. This property is used for mail clients that does not support receiving HTML mails.

Suppose we would like to make our HTML email look better and add some image to it. We don’t want the image to be sent as a regular attachment. We would like the image to be embedded in our HTML mail message by using the image tag (img).

Luckily, Apache Commons Email supplies a simple way of doing it by using the “embed” method. For example, in order to embed an image that is placed in some URL we can do:

String id = email.embed(new URL("http://server.com/someimage.png"), "Example");

Note that “embed” method takes 2 arguments. First is the URL pointing to the image location and second is the image name. Note also that the “embed” method returns a String id. This id is used as a reference to the image embedded in the mail message. For example, our HTML mail message can look like:

email.setHtmlMsg("<html><body><image src='cid:" + id + "'></body></html>");

Note that the embedded image is referenced by using the prefix: “cid:” in the image “src” property.

As you can see, the embed method returns an id that is being later used in the construction of the HTML. this makes it a bit harder embedding images in HTML mail messages, since we don’t know the id of the embedded image when passing the HTML code as an argument. We can easily solve this problem by defining our own convention of referencing the embedded images that will later will be replaced with the proper id. Our convention will be: Each embed resource which we would like to embed in our HTML code will be named:

${resource number}

For example, suppose we would like to embed a single image. our HTML code will look like:

<html><body><img src='${0}' /></body></html>

Where the: ${0} means, we would like to put our first image in the “src” property.

Support we have 2 images that we want to use 4 times in our HTML. For example:

<html>
  <body>
    <img src='${0}' />
    <img src='${1}' />
    <img src='${0}' />
    <img src='${1}' />
  </body>
</html>

In this example we want to embed in our HTML 2 images and show them one after another twice. Of course that in the code, we will make sure to replace all the occurrences with: ${resource number} with the proper id of the embedded image.

Since an embedded resource is actually defined by 2 parameters: URL and name, we will define an inner static class that will represent a resource. This class is named: Resource. The class is pretty straight forward and need no explanations. An array of this class will be used for passing our method as many resources as we would like to embed in our HTML mail message. Of course that the “resource number” signifies the position of the resource we would like to embed in our Resources array. For example: “${3}” means we would like to embed the 4th resource from our resources array.

We can now have a look at our complete “sendHTMLMail” method that also knows to send multiple embedded resources along with the HTML mail message. Note that the old method for sending HTML mails without resources is still supported:

package com.bashan.blog.mail;
import org.apache.commons.mail.EmailException;
import org.apache.commons.mail.HtmlEmail;
import java.net.MalformedURLException;
import java.net.URL;
public class Mailer {
  protected String host;
  protected String username = null;
  protected String password = null;
  protected boolean isTLS = false;
  public Mailer(String host, String username, String password, boolean isTLS) {
    this.host = host;
    this.username = username;
    this.password = password;
    this.isTLS = isTLS;
  }
  public Mailer(String host, String username, String password) {
    this(host, username, password, false);
  }
  public Mailer(String host) {
    this(host, null, null, false);
  }
  public void sendHTMLMail(String fromEmail,
                           String fromName,
                           String[] toEmail,
                           String[] toName,
                           String subject,
                           String html,
                           String alternateText,
                           Resource[] resources) throws EmailException {
    HtmlEmail email = new HtmlEmail();
    email.setHostName(host);
    email.setFrom(fromEmail, fromName);
    for (int i = 0; i < toEmail.length; i++) {
      email.addTo(toEmail[i], toName[i]);
    }
    if (username != null) {
      email.setAuthentication(username, password);
    }
    if (resources != null) {
      int i = 0;
      for (Resource resource : resources) {
        String id = email.embed(resource.getUrl(), resource.getName());
        html = html.replaceAll("\\$\\{" + i++ + "\\}", "cid:" + id);
      }
    }
    email.setTLS(isTLS);
    email.setSubject(subject);
    email.setHtmlMsg(html);
    email.setTextMsg(alternateText);
    email.send();
  }
  public void sendHTMLMail(String fromEmail,
                           String fromName,
                           String[] toEmail,
                           String[] toName,
                           String subject,
                           String html,
                           String alternateText) throws EmailException {
    sendHTMLMail(fromEmail, fromName, toEmail, toName, subject, html, alternateText, null);
  }
  public static class Resource {
    private URL url;
    private String name;
    public Resource(URL url, String name) {
      this.url = url;
      this.name = name;
    }
    public Resource(String url, String name) throws MalformedURLException {
      this(new URL(url), name);
    }
    public URL getUrl() {
      return url;
    }
    public void setUrl(URL url) {
      this.url = url;
    }
    public String getName() {
      return name;
    }
    public void setName(String name) {
      this.name = name;
    }
  }
  public static void main(String[] args) throws Exception {
    new Mailer("smtp.gmail.com", "youruser@gmail.com", "yourpassword", true).sendHTMLMail(
        "admin@test.com", "Tester", new String[]{"guy.bashan@gmail.com"}, new String[]{"Guy Bashan"}, "Testing HTML Email",
        "<html><body><table><tr><td>Image 1</td><td>Image 2</td></tr><tr><td>" +
            "<img src='${0}'/></td><td><img src='${1}'/></td></tr></table></body></html>", "alternate HTML",
        new Resource[]{new Resource("http://www.google.com/intl/en_ALL/images/logo.gif", "Google Logo 1"),
            new Resource("http://www.google.com/intl/en_ALL/images/logo.gif", "Google Logo 2")});
  }
}

In the bottom of the Mailer class you can find a small test program that sends HTML mail message with 2 embed images of Google logo.

Saturday, August 15, 2009

Handling JSF ViewExpiredException with Ajax server polling

One of the problem with JSF and other web technologies that are base on ViewState, is that when session expires, also view expires. In this case, when you are on a page, session expires and you do some action (like navigating between table pages or submitting a form) you get ViewExpiredException with a message telling: “No saved view state could be found for the view identifier: /some_page.jsp”. One way of solving this issue is by using a Filter or JSF PhaseListener that will catch the exception and redirect the user to the login screen or will automatically login the user again and direct him to some page (if user login information is stored on a cookie on the local machine). This is a nice solution, but it still doesn’t cover this scenario:

  • User leave computer on login screen.
  • Session expires.
  • User come back to the computer, enter login details and press the “login” button.
  • JSF throws ViewExpiredException that is being cached by Filter/PhaseListener and user is being redirected to the login screen and login details are being cleared.
  • User doesn’t understand what happened, tries to login again. This time ViewState already exists in session and login takes place successfully.

This case probably can be solved by all sort of solutions. One of them will be to simply write the login page without JSF. I heard that .NET technology allows a page to disable ViewState simply by setting a property: EnableViewState=”false”. I looked for a way of doing it in JSF and had no luck.

Anyway, there is a neat way of elegantly working around this problem by simply polling the server every fixed interval of time (for example 5 minutes), causing the server to never loose session as long as browser is open with our web application. If session never expires, ViewExpiredException will never be thrown.

Polling there server can be done in all sort of ways. I have chosen what I think is the simplest way requiring the least technologies in order to accomplish this task: Generating a request to an image using a small JavaScript code. The image can be anything, but of course, putting a small pixel as an image is preferred, since it will consume less resources.

Generating a request to an image, can be done very easily in JavaScript by creating a new Image class:

var image = new Image();
image.src = "pixel.gif";

Since browsers tend to cache resources, we may want to make sure our request is not being cached. This can easily be done be calling the image with a dummy parameter that contains random data. This will trick the browser to think we are making a request to a new resource, although we are actually calling same resource every time:

var image = new Image();
image.src = "pixel.gif?ind=" + Math.random();

Now, all is left to do, is make sure this request is being called every fixed amount of time. For example 5 minutes. This can be done by using JavaScript method called: window.setInterval which calls a function every given amount of millisecond. Here is how the complete code looks:

<script type="text/javascript">
  function dummyRequest()
  {
    var image = new Image();
    image.src = "pixel.gif?ind=" + Math.random();
  }
  window.setInterval("dummyRequest();", 5 * 1000 * 60);
</script>

Of course that it will be best to place this code on your web application header file (or template file, depending on the technology you are using), in order to apply the server polling functionally on all the web application pages automatically.

In addition, a good idea is to place this code on an external JavaScript file, since the browser will cache it and download it only once.

Saturday, August 8, 2009

Validate IPv4 in Java using Regular Expressions

Validating an IP is a very easy task in Java. IPv4 structure is combined from 4 parts, each part moves from 0 to 255. So in order to validate an IP, we need to split it to 4 parts (according the the “.” character) and check that each part (octet) is a numeric value that lies in the range of 0 to 255. Here is an example implementing IP validation:

package com.bashan.blog.ip;
import org.apache.commons.lang.StringUtils;
public class IpValidate {
  public static boolean isValidIp2(String ip) {
    String[] octets = ip.split("\\.");
    if (ip.endsWith(".") || octets.length != 4) {
      return false;
    }
    for (String octet : octets) {
      if (StringUtils.isNumeric(octet)) {
        int num = Integer.parseInt(octet);
        if (num < 0 || num > 255) {
          return false;
        }
      } else {
        return false;
      }
    }
    return true;
  }
}

Note that this code uses StringUtils.isNumeric function taken from Apache Commons Lang. It is possible to skip this function by simply putting the Integer.parseInt function in a “try” and “catch” expression and catching the exception: NumberFormatException.

When dealing with text validations, usually the first thing coming in mind is taking advantage of Regular Expressions. But, is it a good solution for validating IP? Well, the answer is a bit more complex than it looks. Regular expressions is a great tool for validating and extracting data from text. But when it comes to numerical ranges, it doesn’t give a good solution. checking only if a text value is in the range of 0 to 255 yields the following regular expression:

(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)

This expression is quite straight forward: We are checking if a given text:

  • Starting with 25 and then any number from 0 to 5.
  • OR text is starting with 2 and then any number from 0 to 4 and then any number from 0 to 9.
  • OR text is starting with 01 and then a number from 0 to 9 or text is starting with number from 0 to 9 and then another number from 0 to 9.

This whole expression is for checking if a single number is between 0 to 255 only!

So, does it really worth bothering constructing such a complex expression for simply validating an IP?

We will consider 2 main things in order to answer that question:

  • Does the code of of validating an IP using regular expression is really simpler?
  • Does it perform better?

To answer the first question we will simply look at the complete function for validating an IP using regular expressions:

package com.bashan.blog.ip;
import java.util.regex.Pattern;
public class IpValidate {
  public static final String _255 = "(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)";
  public static final Pattern pattern = Pattern.compile("^(?:" + _255 + "\\.){3}" + _255 + "$");
  public static boolean isValidIp(String ip) {
    return pattern.matcher(ip).matches();
  }
}

As you can see, the function itself is much simpler and shorter. The only thing that is quite complex is the regular expression. But it can also be simplified by reusing the expression for finding a digit between 0 to 255.

And what about performance? for this case we will build a small test program. The program will contain 2 methods:

  • isValidIp1 – Validate IP using regular expression.
  • isValidIp2 – Validate IP by splitting a string and checking its parts.

Each method will be called 10 million times with different random IPs. Approximately half of the IPs will be valid and the rest will be invalid. The time for each series of calls will be measured for comparison.

This is our test program:

package com.bashan.blog.ip;
import org.apache.commons.lang.StringUtils;
import java.util.Date;
import java.util.Random;
import java.util.regex.Pattern;
public class IpValidate {
  public static final String _255 = "(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)";
  public static final Pattern pattern = Pattern.compile("^(?:" + _255 + "\\.){3}" + _255 + "$");
  private final static int NUM_TESTS = 10000000;
  private static final Random random = new Random();
  public static boolean isValidIp1(String ip) {
    return pattern.matcher(ip).matches();
  }
  public static boolean isValidIp2(String ip) {
    String[] octets = ip.split("\\.");
    if (ip.endsWith(".") || octets.length != 4) {
      return false;
    }
    for (String octet : octets) {
      if (StringUtils.isNumeric(octet)) {
        int num = Integer.parseInt(octet);
        if (num < 0 || num > 255) {
          return false;
        }
      } else {
        return false;
      }
    }
    return true;
  }
  private static String getRandomIp() {
    return random.nextInt(306) + "." + random.nextInt(306) + "." +
        random.nextInt(306) + "." + random.nextInt(306);
  }
  public static void main(String[] args) {
    int countValid = 0;
    Date date = new Date();
    for (int i = 0; i < NUM_TESTS; i++) {
      if (isValidIp1(getRandomIp())) {
        countValid++;
      }
    }
    System.out.println("\"Regular Expression\" Test:");
    System.out.println("Time in ms: " + (new Date().getTime() - date.getTime()));
    System.out.println("Valid ips: " + countValid + "/" + NUM_TESTS);
    countValid = 0;
    date = new Date();
    for (int i = 0; i < NUM_TESTS; i++) {
      if (isValidIp2(getRandomIp())) {
        countValid++;
      }
    }
    System.out.println();
    System.out.println("\"Split and check range\" Validation Test: ");
    System.out.println("Time in ms: " + (new Date().getTime() - date.getTime()));
    System.out.println("Valid ips: " + countValid + "/" + NUM_TESTS);
  }
}

And this is a sample output:

"Regular Expression" Test:
Time in ms: 12353
Valid ips: 4898508/10000000
"Split and check range" Validation Test:
Time in ms: 18963
Valid ips: 4899584/10000000

We can easily notice that the regular expression IP validation, despite its complex expression, is significantly more efficient with more than 50% better performance!