Oracle ADF Faces - Client-side Converters and Validators
Introduction

One of the benefits of ADF Faces is that it supports client-side versions of converters and validators. This means that errors can be caught on the client and a round trip avoided. This chapter will explain how a developer can write their own converters and validators in such a way to take advantage of this feature. This chapter assumes knowledge of JSF converters and validators, so please make sure you understand how they work before continuing.

The basic idea of ADF Faces client conversion and validation is that it works on the client in a very similar way to how it works on the server, except the language on the client is javascript instead of java. There are javascript Converter objects that support the methods getAsString() and getAsObject(). A Converter can throw a ConverterException. There are javascript Validator objects that support the validate() method. A Validator can throw a ValidatorException.

Note: this chapter describes a preliminary implementation which may change in future releases of ADF Faces.

Client-side Converters

Let's say you've written a javax.faces.convert.Converter implementation and now you want to add client-side conversion. The first thing to do is write a version of the converter in javascript. Here is the javascript code for the converter "interface".

/**
 * Converter "interface" similar to javax.faces.convert.Converter,
 * except that all relevant information must be passed to the constructor
 * as the context and component are not passed to the getAsString or getAsObject method 
 *
 */
function Converter()
{
}

/**
 * Convert the specified model object value, into a String for display
 *
 * @param value Model object value to be converted 
 */
Converter.prototype.getAsString = function(value){}

/**
 * Convert the specified string value into a model data object 
 * which can be passed to validators
 *
 * @param value String value to be converted 
 */
Converter.prototype.getAsObject = function(value){}
Converters can throw a ConverterException, here is the signature:
  • ConverterException(detail)
    • detail - Localized detail message text

Let's say we have implemented a social security number converter which converts a String to/from an Integer. To get a version of this working on the client we would need two things, a javascript implementation of the converter and a javascript constructor for each instance of the converter on the page.

Let's take a look at an example of a javascript converter implementation for our social security number converter:

      function ssnGetAsString(value)
      {
        return value.substring(0,3) + '-' + 
               value.substring(3,5) + '-' + 
               value.substring(5);
      }
      
      function ssnGetAsObject(value)
      {
        if (!value)
          return (void 0);
          
        var len=value.length;
        var messageKey = SSNConverter.NOT;
        if (len < 9 )
          messageKey = SSNConverter.SHORT;
        else if (len > 11)
          messageKey = SSNConverter.LONG;
        else if (len == 9)
        { 
          if (!isNaN(value))
            return value;
        }
        else if (len == 11 && value.charAt(3) == '-' && value.charAt(6) == '-')
        {
          var result = value.substring(0,3) + 
                       value.substring(4,6) + 
                       value.substring(7);
          
          if (!isNaN(result))
            return result;
        }
        
        if (messageKey!=void(0) && this._messages!=void(0))
          return new ConverterException(this._messages[messageKey]);
          
        return (void 0);
      }
      
      function SSNConverter(messages)
      {
        this._messages = messages;
      }
      
      SSNConverter.prototype = new Converter();
      SSNConverter.prototype.getAsString = ssnGetAsString;
      SSNConverter.prototype.getAsObject = ssnGetAsObject;
      
      SSNConverter.SHORT = 'S';
      SSNConverter.LONG  = 'L';
      SSNConverter.NOT   = 'N';
      

And here's an example of a javascript constructor to get an instance of the javascript converter defined above:

      new SSNConverter({S:\'Value "{0}" in "{1}" is too short.\',
                        L:\'Value "{0}" in "{1}" is too long.\',
                        N:\'Value "{0}" in "{1}" is not a social security number.\'})
      

In the current implementation if there is a ConverterException ADF Faces gets the detail string out of the exception and displays it replacing '{0}' with the value entered by the user and '{1}' with the label of the field.

At this point we have the javascript to use on the client, but we need a way to provide it from our Java Converter object. This is achieved by implementing the interface oracle.adf.view.faces.converter.ClientConverter , which has two methods. The first method is getClientScript() , which is expected to return an implementation of the javascript Converter object. The second method is getClientConversion() , which is expected to return a javascript constructor which will be used to instant iate an instance of the converter.

Continuing with our social security number converter example, here's our social security number converter Java class (the details of the Java code has been removed from the getAsObject() and getAsString() methods) which implements ClientConverter:

    package oracle.adfdemo.view.faces.convertValidate;
    
    
    import javax.faces.application.FacesMessage;
    import javax.faces.component.UIComponent;
    import javax.faces.context.FacesContext;
    import javax.faces.convert.Converter;
    import javax.faces.convert.ConverterException;
    
    import oracle.adf.view.faces.converter.ClientConverter;
    
    
    /**
     * <p>Social Security number converter.</p>
     * 
     */
    public class SSNConverter implements Converter, ClientConverter
    {
        public static final String CONVERTER_ID = "oracle.adfdemo.SSN";
    
        public Object getAsObject(
          FacesContext context, 
          UIComponent component, 
          String value)
        {
          // some Java code ...
        }    
        
        public String getAsString(
          FacesContext context, 
          UIComponent component, 
          Object value)
        {
          // some Java code ...
        }
     
    
      public String getClientConversion(
        FacesContext context,
       UIComponent component)
      {    
        // in a real app the messages would be translated
        return "new SSNConverter({" + 
                   "S:'Value \"{0}\" in \"{1}\" is too short.'," + 
                   "L:'Value \"{0}\" in \"{1}\" is too long.'," + 
                   "N:'Value \"{0}\" in \"{1}\" " + 
                               "is not a social security number.'})";
      }
    
      
      public String getClientScript(
       FacesContext context,
       UIComponent component)
      {      
        // check if the script has already been returned this request
        Object scriptReturned = 
                    context.getExternalContext().getRequestMap().get(CONVERTER_ID);
                    
        // if scriptReturned is null the script hasn't been returned yet  
        if ( scriptReturned == null)
        {
          context.getExternalContext().getRequestMap().put(CONVERTER_ID, 
                                                           Boolean.TRUE);  
          return  _sSSNjs;
        }
        // if scriptReturned is not null, then script has already been returned,
        // so don't return it again.
        else
          return null;
    
       }
      private static final String _sSSNjs =
        "function ssnGetAsString(value)"+
        "{return value.substring(0,3) + '-' " + 
              "+ value.substring(3,5) + '-' + value.substring(5);}" +
        "function ssnGetAsObject(value)" +
          "{if (!value)return (void 0);" + 
          "var len=value.length;"+
          "var messageKey = SSNConverter.NOT;" +
          "if (len < 9 )"+
            "messageKey = SSNConverter.SHORT;" +
          "else if (len > 11)"+
            "messageKey = SSNConverter.LONG;" +
          "else if (len == 9)" +
          "{ if (!isNaN(value))" +
              "return value;" +
          "}" +        
          "else if (len == 11 && value.charAt(3) == '-' && " +
                    "value.charAt(6) == '-')" +
          "{" +
            "var result = value.substring(0,3) + value.substring(4,6) + " + 
                        "value.substring(7);"+
            "if (!isNaN(result))"+
              "return result;" +
          "}" +
         "if (messageKey!=void(0) && this._messages!=void(0))" +
           "return new ConverterException(this._messages[messageKey]);" +
         "return void(0);}" +
        "function SSNConverter(messages)" +
          "{this._messages = messages;}" +
        "SSNConverter.prototype = new Converter();" +
        "SSNConverter.prototype.getAsString = ssnGetAsString;" +
        "SSNConverter.prototype.getAsObject = ssnGetAsObject;" +
        "SSNConverter.SHORT = 'S';" +
        "SSNConverter.LONG  = 'L';" +
        "SSNConverter.NOT   = 'N';";
          
    }

      

Now assuming we've created a tag for this converter named convertSSN, we'd get client conversion just by attaching the converter in the normal way, for example:


<af:inputText value="#{data.ssn}" 
            label="ssn converter">
  <afdemo:convertSSN/>              
</af:inputText>              
      

Client-side Validators

The general idea of writing client validators is almost exactly the same as writing client converters. Let's say you've written a javax.faces.validator.Validator implementation and now you want to add client-side validation. The first thing to do is write a version of the validator in javascript. Here is the javascript code for the Validator "interface".

/**
 * Validator "interface" similar to javax.faces.validator.Validator,
 * except that all relevant information must be passed to the constructor
 * as the context and component are not passed to the validate method 
 *
 */
function Validator()
{
}

/**
 * Perform the correctness checks implemented by this Validator. 
 * If any violations are found, a ValidatorException will be thrown 
 */
Validator.prototype.validate = function(value){}
      
The validator can throw javascript ValidatorException objects:
  • ValidatorException(detail)
    • detail - Localized detail message text

Once you have a javascript implementation of the validator and constructor, they are plugged in to the Java code using oracle.adf.view.faces.validator.ClientValidator , which has similar methods to ClientConverter, and functions in exactly the same wa y. Please see the client-side converters section of this document for more information. An example will be provided in a future version of this document.

Copyright © 2003-2006, Oracle Corporation. All Rights Reserved.

E-mail this page
Printer View Printer View
Oracle Is The Information Company About Oracle | Oracle RSS Feeds | Careers | Contact Us | Site Maps | Legal Notices | Terms of Use | Privacy