Chapter 10. External Services

Implementing Custom Converters and Validators

The custom converters and validators that you saw in Chapter 6 have a shortcoming: They do not allow parameters. For example, we may want to specify a separator character for the credit card converter so that the page designer can choose whether to use dashes or spaces to separate the digit groups. In other words, custom converters should have the same capabilities as the standard f:convertNumber and f:convertDateTime tags. Specifically, we would like page designers to use tags, such as the following:

  <h:outputText value="#{payment.card}">      <corejsf:convertCreditcard separator="-"/>   </h:outputText>

To achieve this, we need to implement a custom converter tag. As with custom component tags, custom converter tags require a significant amount of programming, but the payback is a reusable tag that is convenient for page authors.

Custom Converter Tags

As with custom component tags, you need to put descriptions of custom converter tags into a TLD file. Place that file into the WEB-INF directory. Listing 9-23 shows the TLD file that describes a convertCreditcard custom tag.

Listing 9-23. custom-converter/web/WEB-INF/converter.tld

  1. <?xml version="1.0" encoding="UTF-8"?>   2. <taglib xmlns="http://java.sun.com/xml/ns/javaee"   3.    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   4.    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee   5.       http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"   6.    version="2.1">   7.    <tlib-version>1.1</tlib-version>   8.    <tlib-version>1.1</tlib-version>   9.    <short-name>converter</short-name>  10.    <uri>http://corejsf.com/converter</uri>  11.  12.    <tag>  13.       <name>convertCreditcard</name>  14.       <tag-class>com.corejsf.CreditCardConverterTag</tag-class>  15.       <body-content>empty</body-content>  16.       <attribute>  17.          <name>separator</name>  18.          <deferred-value>  19.             <type>java.lang.String</type>  20.          </deferred-value>  21.       </attribute>  22.    </tag>  23. </taglib>     

The entries in this file should be mostly self-explanatory. The purpose of the file is to specify the class name for the tag handler (com.corejsf.CreditCardConverterTag) and the permitted attributes of the tag (in our case, separator). Note the uri tag that identifies the tag library.

The deferred-value child element inside the definition of the separator attribute indicates that the attribute is defined by a value expression that should yield a string. The attribute value can be a constant string or a string that contains #{...} expressions.

You reference the TLD identifier in a taglib directive of the JSF page, such as

  <%@ taglib uri="http://corejsf.com/converter" prefix="corejsf" %>

You need to implement a tag handler class that fulfills three purposes:

  1. To specify the converter class

  2. To gather the tag attributes

  3. To configure a converter object, using the gathered attributes

For a converter, the tag handler class should be a subclass of ConverterELTag. As you will see later, the handlers for custom validators need to subclass ValidatorELTag.

Note

Before JSF 1.2, you needed to subclass ConverterTag or ValidatorTag. These classes are now deprecated.


Your tag handler class must specify a setter method for each tag attribute. For example,

  public class ConvertCreditCardTag extends ConverterELTag {      private ValueExpression separator;      public void setSeparator(ValueExpression newValue) { separator = newValue; }      ...   }     

To configure a converter instance with the tag attributes, override the create-Converter method. Construct a converter object and set its properties from the tag attributes. For example,

  public Converter createConverter() throws JspException {      CreditCardConverter converter = new CreditCardConverter();      ELContext elContext = FacesContext.getCurrentInstance().getELContext();      converter.setSeparator((String) separator.getValue(elContext));      return converter;   }     

This method sets the separator property of the CreditCardConverter.

Finally, you need to define a release method for each tag handler class that resets all instance fields to their defaults:

  public void release() {      separator = null;   }

Listing 9-24 shows the complete tag class.

Listing 9-24. custom-converter/src/java/com/corejsf/CreditCardConverterTag.java

  1. package com.corejsf;   2.   3. import javax.el.ELContext;   4. import javax.el.ValueExpression;   5. import javax.faces.context.FacesContext;   6. import javax.faces.convert.Converter;   7. import javax.faces.webapp.ConverterELTag;   8. import javax.servlet.jsp.JspException;   9.  10. public class CreditCardConverterTag extends ConverterELTag {  11.    private ValueExpression separator;  12.  13.    public void setSeparator(ValueExpression newValue) {  14.       separator = newValue;  15.    }  16.  17.    public Converter createConverter() throws JspException {  18.       CreditCardConverter converter = new CreditCardConverter();  19.       ELContext elContext = FacesContext.getCurrentInstance().getELContext();  20.       converter.setSeparator((String) separator.getValue(elContext));  21.       return converter;  22.    }  23.  24.    public void release() {  25.       separator = null;  26.    }  27. }     

javax.faces.webapp.ConverterELTag JSF 1.2

  • protected void createConverter()

    Override this method to create the converter and customize it by setting the properties specified by the tag attributes.

  • void release()

    Clears the state of this tag so that it can be reused.


javax.el.ValueExpression JSF 1.2

  • Object getValue(ELContext context)

    Gets the current value of this value expression.


javax.faces.context.FacesContext JSF 1.0

  • ELContext getELContext() JSF 1.2

    Gets the context for evaluating expressions in the expression language.


Saving and Restoring State

When implementing converters or validators, you have two choices for state saving. The easy choice is to make your converter or validator class serializable. Implement the Serializable interface and follow the usual rules for Java serialization.

In the case of the credit card converter, we have a single instance field of type String, which is a serializable type. Therefore, we only need to implement the Serializable interface:

  public class CreditCardConverter implements Converter, Serializable { ... }     

The second choice is to supply a default constructor and implement the State-Holder interface. This is more work for the programmer, but it can yield a slightly more efficient encoding of the object state. Frankly, for small objects such as the credit card converter, this second choice is not worth the extra trouble.

In the interest of completeness, we describe the technique, using the standard DateTimeConverter as an example.

In the saveState method of the StateHolder interface, construct a serializable object that describes the instance fields. The obvious choice is an array of objects that holds the instance fields. In the restoreState method, restore the instance fields from that object.

  public class DateTimeConverter implements Converter, StateHolder {      public Object saveState(FacesContext context) {        Object[] values = new Object[6];        values[0] = dateStyle;        values[1] = locale;        values[2] = pattern;        values[3] = timeStyle;        values[4] = timeZone;        values[5] = type;        return values;     }     public void restoreState(FacesContext context, Object state) {        Object[] values = (Object[]) state;        dateStyle = (String) values[0];        locale = (Locale) values[1];        pattern = (String) values[2];        timeStyle = (String) values[3];        timeZone = (TimeZone) values[4];        type = (String) values[5];    }    ...  }     

Moreover, the StateHolder interface also requires you to add a transient property. If the property is set, this particular object will not be saved. The property is the analog of the transient keyword used in Java serialization.

  public class DateTimeConverter implements Converter, StateHolder {      private boolean transientFlag; // "transient" is a reserved word      public boolean isTransient() { return transientFlag; }      public void setTransient(boolean newValue) { transientFlag = newValue; }      ...   }     

Caution

Converters, validators, and event listeners that implement neither the Serializable nor the StateHolder interface are skipped when the view is saved.


Note

Here is an easy experiment to verify that converters must save their state. Configure the custom-converter application to save state on the client by adding this parameter to web.xml:

<context-param>    <param-name>javax.faces.STATE_SAVING_METHOD</param-name>    <param-value>client</param-value> </context-param>

Comment out the Serializable interface of the CreditCardConverter class. To the result.jsp page, add the button

<h:commandButton value="Test State Saving"/>

Enter a credit card number in index.jsp, click the "Process" button, and see the number formatted with dashes: 4111-1111-1111-1111. Click the "Test State Saving" button and see the dashes disappear.


The Sample Custom Converter Application

This completes the discussion of the custom converter example. Figure 9-12 shows the directory structure. Most files are unchanged from the preceding example. However, result.jsp calls the custom converter (see Listing 9-25).

Figure 9-12. Directory structure of the custom converter program


The tag handler is in Listing 9-25. The modified converter and configuration file are in Listings 9-26 and 9-27.

Listing 9-25. custom-converter/web/result.jsp

  1. <html>   2.    <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>   3.    <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>   4.    <%@ taglib uri="http://corejsf.com/converter" prefix="corejsf" %>   5.    <f:view>   6.       <head>   7.          <link href="styles.css" rel="stylesheet" type="text/css"/>   8.          <title><h:outputText value="#{msgs.title}"/></title>   9.       </head>  10.       <body>  11.          <h:form>  12.             <h1><h:outputText value="#{msgs.paymentInformation}"/></h1>  13.             <h:panelGrid columns="2">  14.                <h:outputText value="#{msgs.amount}"/>  15.                <h:outputText value="#{payment.amount}">  16.                   <f:convertNumber type="currency"/>  17.                </h:outputText>  18.  19.                <h:outputText value="#{msgs.creditCard}"/>  20.                <h:outputText value="#{payment.card}">  21.                   <corejsf:convertCreditcard separator="-"/>  22.                </h:outputText>  23.  24.                <h:outputText value="#{msgs.expirationDate}"/>  25.                <h:outputText value="#{payment.date}">  26.                   <f:convertDateTime pattern="MM/yyyy"/>  27.                </h:outputText>  28.             </h:panelGrid>  29.             <h:commandButton value="#{msgs.back}" action="back"/>  30.          </h:form>  31.       </body>  32.    </f:view>  33. </html>     

Listing 9-26. custom-converter/src/java/com/corejsf/CreditCardConverter.java

  1. package com.corejsf;   2.   3. import java.io.Serializable;   4.   5. import javax.faces.component.UIComponent;   6. import javax.faces.context.FacesContext;   7. import javax.faces.convert.Converter;   8. import javax.faces.convert.ConverterException;   9.  10. public class CreditCardConverter implements Converter, Serializable {  11.    private String separator;  12.  13.    // PROPERTY: separator  14.    public void setSeparator(String newValue) { separator = newValue; }  15.  16.    public Object getAsObject(  17.       FacesContext context,  18.       UIComponent component,  19.       String newValue)  20.       throws ConverterException {  21.       StringBuilder builder = new StringBuilder(newValue);  22.       int i = 0;  23.       while (i < builder.length()) {  24.          if (Character.isDigit(builder.charAt(i)))  25.             i++;  26.          else  27.             builder.deleteCharAt(i);  28.       }  29.       return new CreditCard(builder.toString());  30.    }  31.  32.    public String getAsString(  33.       FacesContext context,  34.       UIComponent component,  35.       Object value)  36.       throws ConverterException {  37.       // length 13: xxxx xxx xxx xxx  38.       // length 14: xxxxx xxxx xxxxx  39.       // length 15: xxxx xxxxxx xxxxx  40.       // length 16: xxxx xxxx xxxx xxxx  41.       // length 22: xxxxxx xxxxxxxx xxxxxxxx  42.       if (!(value instanceof CreditCard))  43.          throw new ConverterException();  44.       String v = ((CreditCard) value).toString();  45.       String sep = separator;  46.       if (sep == null) sep = " ";  47.       int[] boundaries = null;  48.       int length = v.length();  49.       if (length == 13)  50.          boundaries = new int[] { 4, 7, 10 };  51.       else if (length == 14)  52.          boundaries = new int[] { 5, 9 };  53.       else if (length == 15)  54.          boundaries = new int[] { 4, 10 };  55.       else if (length == 16)  56.          boundaries = new int[] { 4, 8, 12 };  57.       else if (length == 22)  58.          boundaries = new int[] { 6, 14 };  59.       else  60.          return v;  61.       StringBuilder result = new StringBuilder();  62.       int start = 0;  63.       for (int i = 0; i < boundaries.length; i++) {  64.          int end = boundaries[i];  65.          result.append(v.substring(start, end));  66.          result.append(sep);  67.          start = end;  68.       }  69.       result.append(v.substring(start));  70.       return result.toString();  71.    }  72. }     

Listing 9-27. custom-converter/web/WEB-INF/faces-config.xml

  1. <?xml version="1.0"?>   2. <faces-config xmlns="http://java.sun.com/xml/ns/javaee"   3.    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   4.    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee   5.         http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd"   6.    version="1.2">   7.    <navigation-rule>   8.       <from-view-id>/index.jsp</from-view-id>   9.       <navigation-case>  10.          <from-outcome>process</from-outcome>  11.          <to-view-id>/result.jsp</to-view-id>  12.       </navigation-case>  13.    </navigation-rule>  14.  15.    <navigation-rule>  16.       <from-view-id>/result.jsp</from-view-id>  17.       <navigation-case>  18.          <from-outcome>back</from-outcome>  19.          <to-view-id>/index.jsp</to-view-id>  20.       </navigation-case>  21.    </navigation-rule>  22.  23.    <converter>  24.       <converter-id>com.corejsf.CreditCard</converter-id>  25.       <converter-class>com.corejsf.CreditCardConverter</converter-class>  26.    </converter>  27.  28.    <converter>  29.       <converter-for-class>com.corejsf.CreditCard</converter-for-class>  30.       <converter-class>com.corejsf.CreditCardConverter</converter-class>  31.    </converter>  32.  33.    <managed-bean>  34.       <managed-bean-name>payment</managed-bean-name>  35.       <managed-bean-class>com.corejsf.PaymentBean</managed-bean-class>  36.       <managed-bean-scope>session</managed-bean-scope>  37.    </managed-bean>  38.  39.    <application>  40.       <resource-bundle>  41.          <base-name>com.corejsf.messages</base-name>  42.          <var>msgs</var>  43.       </resource-bundle>  44.    </application>  45. </faces-config>     

Custom Validator Tags

In the preceding sections, you saw how to implement a custom converter that offers page authors the same convenience as the standard JSF tags. In this section, you will see how to provide a custom validator.

The steps for providing a custom validator are almost the same as those for a custom converter:

1.

Produce a TLD file and reference it in your JSF pages.

2.

Implement a tag handler class that extends the ValidatorELTag class, gathers the attributes that the TLD file advertises, and passes them to a validator object.

3.

Implement a validator class that implements the Validator interface. Supply the validate method in the usual way, by throwing a ValidatorException if an error is detected. Implement the Serializable or StateHolder interface to save and restore the state of validator objects.

As an example, let us do a thorough job validating credit card numbers (see Listing 9-27). We want to carry out three checks:

1.

The user has supplied a value.

2.

The number conforms to the Luhn formula.

3.

The number starts with a valid prefix.

Figure 9-13. Thoroughly validating a credit card number


A credit card's prefix indicates card type for example, a prefix between 51 and 55 is reserved for MasterCard, and a prefix of 4 indicates Visa. We could write custom code for this purpose, but instead we chose to implement a more general (and more useful) validator that validates arbitrary regular expressions.

We use that validator in the following way:

  <corejsf:validateRegex expression="[3-6].*"      errorDetail="#{msgs.unknownType}"/>

The regular expression [3-6].* denotes any string that starts with the digits 3 through 6. Of course, we could easily design a more elaborate regular expression that does a more careful check.

You will find the validator code in Listing 9-28. When reading through the code, keep in mind that the moral of the story here has nothing to do with regular expressions per se. Instead, the story is about what validators do when their component's data is invalid: They generate a faces message, wrap it inside a validator exception, and throw it.

By default, the validator displays an error message that complains about failing to match a regular expression. If your application's audience includes users who are unfamiliar with regular expressions, you will want to change the message. We give you attributes errorSummmary and errorDetail for this purpose.

We use a custom tag so that we can supply parameters to the validator. Implementing a custom tag for a validator is similar to creating a custom converter tag, which we described earlier in this chapter. However, the custom validator tag must extend the ValidatorTag class.

You can find the implementation of the RegexValidatorTag class in Listing 9-29.

Figure 9-14 shows the application's directory structure. Listing 9-32 shows the JSF page with the triple validation of the credit card field.

Figure 9-14. Directory structure of the thoroughly validating application


Listing 9-30 shows faces-config.xml. Note the mapping of the validator ID to the validator class. The validator tag class is defined in the TLD file (Listing 9-31).

You have now seen how to implement custom tags for components, converters, and validators. We covered all essential issues that you will encounter as you develop custom tags. The code in this chapter should make a good starting point for your own implementations.

javax.faces.webapp.ValidatorTag

  • void setValidatorId(String id)

    Sets the ID of this validator. The ID is used to look up the validator class.

  • protected void createValidator()

    Override this method to customize the validator by setting the properties specified by the tag attributes.


Listing 9-28. custom-validator/src/java/com/corejsf/RegexValidator.java

  1. package com.corejsf;   2.   3. import java.io.Serializable;   4. import java.text.MessageFormat;   5. import java.util.Locale;   6. import java.util.regex.Pattern;   7. import javax.faces.application.FacesMessage;   8. import javax.faces.component.UIComponent;   9. import javax.faces.context.FacesContext;  10. import javax.faces.validator.Validator;  11. import javax.faces.validator.ValidatorException;  12.  13. public class RegexValidator implements Validator, Serializable {  14.    private String expression;  15.    private Pattern pattern;  16.    private String errorSummary;  17.    private String errorDetail;  18.  19.    public void validate(FacesContext context, UIComponent component,  20.          Object value) {  21.       if (value == null) return;  22.       if (pattern == null) return;  23.       if(!pattern.matcher(value.toString()).matches()) {  24.          Object[] params = new Object[] { expression, value };  25.          Locale locale = context.getViewRoot().getLocale();  26.          FacesMessage message = com.corejsf.util.Messages.getMessage(  27.                "com.corejsf.messages", "badRegex", params);  28.          if (errorSummary != null)  29.             message.setSummary(  30.                   new MessageFormat(errorSummary, locale).format(params));  31.          if (errorDetail != null)  32.             message.setDetail(  33.                   new MessageFormat(errorDetail, locale).format(params));  34.          throw new ValidatorException(message);  35.       }  36.    }  37.  38.    // PROPERTY: expression  39.    public void setExpression(String newValue) {  40.       expression = newValue;  41.       pattern = Pattern.compile(expression);  42.    }  43.  44.    // PROPERTY: errorSummary  45.    public void setErrorSummary(String newValue) {  46.       errorSummary = newValue;  47.    }  48.  49.    // PROPERTY: errorDetail  50.    public void setErrorDetail(String newValue) {  51.       errorDetail = newValue;  52.    }  53. }     

Listing 9-29. custom-validator/src/java/com/corejsf/RegexValidatorTag.java

  1. package com.corejsf;   2.   3. import javax.el.ELContext;   4. import javax.el.ValueExpression;   5. import javax.faces.context.FacesContext;   6. import javax.faces.validator.Validator;   7. import javax.faces.webapp.ValidatorELTag;   8. import javax.servlet.jsp.JspException;   9.  10. public class RegexValidatorTag extends ValidatorELTag {  11.    private ValueExpression expression;  12.    private ValueExpression errorSummary;  13.    private ValueExpression errorDetail;  14.  15.    public void setExpression(ValueExpression newValue) {  16.       expression = newValue;  17.    }  18.  19.    public void setErrorSummary(ValueExpression newValue) {  20.       errorSummary = newValue;  21.    }  22.  23.    public void setErrorDetail(ValueExpression newValue) {  24.       errorDetail = newValue;  25.    }  26.  27.    public Validator createValidator() throws JspException {  28.       RegexValidator validator = new RegexValidator();  29.       ELContext elContext = FacesContext.getCurrentInstance().getELContext();  30.  31.       validator.setExpression((String) expression.getValue(elContext));  32.       if (errorSummary != null)  33.          validator.setErrorSummary((String) errorSummary.getValue(elContext));  34.       if (errorDetail != null)  35.          validator.setErrorDetail((String) errorDetail.getValue(elContext));  36.  37.       return validator;  38.    }  39.  40.    public void release() {  41.       expression = null;  42.       errorSummary = null;  43.       errorDetail = null;  44.    }  45. }     

Listing 9-30. custom-validator/web/WEB-INF/faces-config.xml

  1. <?xml version="1.0"?>   2.   3. <faces-config xmlns="http://java.sun.com/xml/ns/javaee"   4.    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   5.    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee   6.    http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd"   7.    version="1.2">   8.    <navigation-rule>   9.       <from-view-id>/index.jsp</from-view-id>  10.       <navigation-case>  11.          <from-outcome>process</from-outcome>  12.          <to-view-id>/result.jsp</to-view-id>  13.       </navigation-case>  14.    </navigation-rule>  15.  16.    <navigation-rule>  17.       <from-view-id>/result.jsp</from-view-id>  18.       <navigation-case>  19.          <from-outcome>back</from-outcome>  20.          <to-view-id>/index.jsp</to-view-id>  21.       </navigation-case>  22.    </navigation-rule>  23.  24.    <converter>  25.       <converter-id>com.corejsf.CreditCard</converter-id>  26.       <converter-class>com.corejsf.CreditCardConverter</converter-class>  27.    </converter>  28.  29.    <converter>  30.       <converter-for-class>com.corejsf.CreditCard</converter-for-class>  31.       <converter-class>com.corejsf.CreditCardConverter</converter-class>  32.    </converter>  33.  34.    <validator>  35.       <validator-id>com.corejsf.CreditCard</validator-id>  36.       <validator-class>com.corejsf.CreditCardValidator</validator-class>  37.    </validator>  38.  39.    <validator>  40.       <validator-id>com.corejsf.Regex</validator-id>  41.       <validator-class>com.corejsf.RegexValidator</validator-class>  42.    </validator>  43.  44.    <managed-bean>  45.       <managed-bean-name>payment</managed-bean-name>  46.       <managed-bean-class>com.corejsf.PaymentBean</managed-bean-class>  47.       <managed-bean-scope>session</managed-bean-scope>  48.    </managed-bean>  49.  50.    <application>  51.       <resource-bundle>  52.          <base-name>com.corejsf.messages</base-name>  53.          <var>msgs</var>  54.       </resource-bundle>  55.    </application>  56. </faces-config>     

Listing 9-31. custom-validator/web/WEB-INF/validator.tld

  1. <?xml version="1.0" encoding="UTF-8"?>   2. <taglib xmlns="http://java.sun.com/xml/ns/javaee"   3.    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   4.    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee   5.       http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"   6.    version="2.1">   7.    <tlib-version>1.1</tlib-version>   8.    <short-name>validator</short-name>   9.    <uri>http://corejsf.com/validator</uri>  10.    <tag>  11.       <name>validateRegex</name>  12.       <tag-class>com.corejsf.RegexValidatorTag</tag-class>  13.       <body-content>empty</body-content>  14.       <attribute>  15.          <name>expression</name>  16.          <deferred-value>  17.             <type>java.lang.String</type>  18.          </deferred-value>  19.       </attribute>  20.       <attribute>  21.          <name>errorSummary</name>  22.          <deferred-value>  23.             <type>java.lang.String</type>  24.          </deferred-value>  25.       </attribute>  26.       <attribute>  27.          <name>errorDetail</name>  28.          <deferred-value>  29.             <type>java.lang.String</type>  30.          </deferred-value>  31.       </attribute>  32.    </tag>  33. </taglib>     

Listing 9-32. custom-validator/web/index.jsp

  1. <html>   2.    <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>   3.    <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>   4.    <%@ taglib uri="http://corejsf.com/validator" prefix="corejsf" %>   5.    <f:view>   6.       <head>   7.          <link href="styles.css" rel="stylesheet" type="text/css"/>   8.          <title><h:outputText value="#{msgs.title}"/></title>   9.       </head>  10.       <body>  11.          <h:form>  12.             <h1><h:outputText value="#{msgs.enterPayment}"/></h1>  13.          <h:panelGrid columns="2">  14.             <h:outputText value="#{msgs.amount}"/>  15.             <h:inputText  value="#{payment.amount}">  16.                <f:convertNumber minFractionDigits="2"/>  17.             </h:inputText>  18.  19.             <h:outputText value="#{msgs.creditCard}"/>  20.             <h:inputText  value="#{payment.card}" required="true">  21.                <f:validator validator/>  22.                <corejsf:validateRegex expression="[3-6].*"  23.                   errorDetail="#{msgs.unknownType}"/>  24.             </h:inputText>  25.  26.             <h:outputText value="#{msgs.expirationDate}"/>  27.             <h:inputText  value="#{payment.date}">  28.                <f:convertDateTime pattern="MM/yyyy"/>  29.             </h:inputText>  30.          </h:panelGrid>  31.          <h:messages style  32.             showSummary="false" showDetail="true"/>  33.          <br/>  34.          <h:commandButton value="Process" action="process"/>  35.        </h:form>  36.     </body>  37.  </f:view>  38. </html>     



Core JavaServerT Faces
Core JavaServer(TM) Faces (2nd Edition)
ISBN: 0131738860
EAN: 2147483647
Year: 2004
Pages: 84

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net