Showing posts with label validate. Show all posts
Showing posts with label validate. Show all posts

Friday, December 25, 2009

Validating empty text field using JSF

JSF has a pretty comprehensive support for validations, but it is lack of a validation for an empty field. The built-in “required” property of JSF is not so usable, since it validates empty fields only. If a field has a space in it, JSF will accept it. In most scenarios, when inputting text in a form, a space (or several spaces) is considered to be an empty field. Since JSF doesn’t support “out of the box” validation for empty field, we will write our own Validator that will do the job.

Writing a JSF Validator mainly involves 3 things:

  1. Writing the Validator code by implementing a JSF Validator interface.
  2. Registering Validator in JSF faces-config.xml.
  3. Using the Validator in a JSF page.

In order to write the Validator we have to implement “validate” method of Validator interface. This method will be called automatically by JSF, when we use the Validator in some of our input fields. Our Validator class simply checks that the field value is not empty. If the field is empty a ValidationException is thrown from the Validator. JSF mechanism knows to treat this exception as a validation error, when it checks the form inputs for validation errors. Let’s have a look at the Validator code:

package com.bashan.blog.jsf.validator;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;
/**
 * @author Bashan
 */
public class RequiredValidator implements Validator {
  public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
    if (value == null || "".equals(value.toString().trim())) {
      FacesMessage message = new FacesMessage();
      String messageStr = (String)component.getAttributes().get("message");
      if (messageStr == null) {
        messageStr = "Please enter data";
      }
      message.setDetail(messageStr);
      message.setSummary(messageStr);
      message.setSeverity(FacesMessage.SEVERITY_ERROR);
      throw new ValidatorException(message);
    }
  }
}

Note, that the Validator tries to get an attribute named “message” from the component for which it is attached. The “message” attribute should contain a custom error message to show to the user. If “message” attribute is not used, a default error message: “Please enter data” is shown to the user.

Now, let’s register the Validator in JSF faces-config.xml file. This file should be located under the “WEB-INF” directory by default:

<?xml version="1.0" encoding="windows-1255"?>
<!DOCTYPE faces-config PUBLIC
  "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.1//EN"
  "http://java.sun.com/dtd/web-facesconfig_1_1.dtd">
<faces-config> 
  <validator>
    <validator-id>RequiredValidator</validator-id>
    <validator-class>com.bashan.blog.jsf.validator.RequiredValidator</validator-class>
  </validator>
</faces-config>

You can see in this “faces-config.xml” file the validator id, which is used to call the validator from a JSF page, and the JSF class corresponds to this validator id.

Finally, let’s have a look how this validator is used in a JSF page:

<h:inputTextarea id="someText" value="#{support.message}" styleClass="textarea1" required="true" requiredMessage="Please write something">
  <f:attribute name="message" value="Please write something" />
  <f:validator validatorId="RequiredValidator" />             
</h:inputTextarea>
<div>
  <h:message for="someText" styleClass="error"/>
</div>

This is only a fragment of a JSF page, showing a text area control and a message under it. Note, that the control can be any JSF input like <h:inputText />. Also note for the <f:attribue /> control used for sending a custom message to the Validator. Another important thing worth mentioning, it that the “required” attribute of the <h:inputTextArea /> control is also used with the same error message (using the “requiredMessage” property). One can say, using 2 validations is redundant, and that only the “RequiredValidator” could have been used. This was true, unless JSF mechanism had a problematic issue with empty fields: When field is empty (has no value and no spaces) validators and converters are not invoked. For this reason, both “required” and “RequiredValidtor” are needed to be used.

Saturday, October 31, 2009

Date validation with Java

Even though there are many fancy calendar inputs on the internet, sometimes, the easiest way to let simple users to input date in web application is by using 3 drop downs: day, month and year. On the server side, we combine these 3 values to create a proper date instance. But, before converting these 3 values to date we need to make sure, the values create a valid date. There are few cases in which an invalid date can be inputted. For example, when a month with 30 days is selected along with day: 31.

Validating that the 3 values: day, month, year really constructs a proper date is an easy task in Java. But, the idea behind it, is not as trivial as it looks. The calendar class can create date instance from day, month and year, but it doesn’t make sure the values are in the range. For example, day with values 33 can be accepted without an exception being raised.

In order to make sure a date is valid we will do a small trick:

  • Construct a string date representation for the inputted values: day, month, year (we can choose any format).
  • Convert the string date to a java date instance by using a date formatter.
  • Convert the date back to a string again.
  • Check the original string we built against the converted date.

If both strings are equal, that means date is valid.

Here is the Java code that does the task:

package com.bashan.blog.date;
import org.apache.commons.lang.StringUtils;
import java.util.Date;
import java.text.SimpleDateFormat;
import java.text.Format;
import java.text.ParseException;
public class DateUtil {
  public static boolean isDateValid(int day, int month, int year)
  {
    try
    {
      String date = StringUtils.leftPad(day + "", 2, "0") + "/" + StringUtils.leftPad(month + "", 2, "0") + "/" + year;
      String dateFormat = "dd/MM/yyyy";
      Date dateSimple = new SimpleDateFormat(dateFormat).parse(date);
      Format formatter = new SimpleDateFormat(dateFormat);
      return date.equals(formatter.format(dateSimple));
    }
    catch (ParseException e)
    {
      return false;
    }
  }
}

Note that this code uses StringUtils.leftPad method, which is part of Apache Commons Lang project.

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!