You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by ma...@apache.org on 2009/12/03 08:23:51 UTC

svn commit: r886688 - /myfaces/trinidad/branches/trinidad-2.0.x/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXEditableValueTemplate.java

Author: matzew
Date: Thu Dec  3 07:23:44 2009
New Revision: 886688

URL: http://svn.apache.org/viewvc?rev=886688&view=rev
Log:
TRINIDAD-1650 - add support for "empty field validation" and BeanValidation API

Modified:
    myfaces/trinidad/branches/trinidad-2.0.x/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXEditableValueTemplate.java

Modified: myfaces/trinidad/branches/trinidad-2.0.x/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXEditableValueTemplate.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/trinidad-2.0.x/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXEditableValueTemplate.java?rev=886688&r1=886687&r2=886688&view=diff
==============================================================================
--- myfaces/trinidad/branches/trinidad-2.0.x/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXEditableValueTemplate.java (original)
+++ myfaces/trinidad/branches/trinidad-2.0.x/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXEditableValueTemplate.java Thu Dec  3 07:23:44 2009
@@ -22,10 +22,13 @@
 
 import javax.el.ValueExpression;
 
+import javax.faces.FacesException;
 import javax.faces.application.Application;
 import javax.faces.application.FacesMessage;
 import javax.faces.component.EditableValueHolder;
 import javax.faces.component.UIComponent;
+import javax.faces.component.UIInput;
+import javax.faces.context.ExternalContext;
 import javax.faces.context.FacesContext;
 import javax.faces.convert.Converter;
 import javax.faces.convert.ConverterException;
@@ -39,10 +42,13 @@
 import javax.faces.render.Renderer;
 import javax.faces.validator.Validator;
 import javax.faces.validator.ValidatorException;
+import javax.validation.Validation;
+import javax.validation.ValidationException;
 
 import org.apache.myfaces.trinidad.logging.TrinidadLogger;
 import org.apache.myfaces.trinidad.bean.FacesBean;
 import org.apache.myfaces.trinidad.bean.PropertyKey;
+import org.apache.myfaces.trinidad.util.ClassLoaderUtils;
 import org.apache.myfaces.trinidad.util.MessageFactory;
 import org.apache.myfaces.trinidad.util.LabeledFacesMessage;
 
@@ -65,8 +71,10 @@
     "org.apache.myfaces.trinidad.UIXEditableValue.REQUIRED";
   static public final String CONVERSION_MESSAGE_ID =
     "org.apache.myfaces.trinidad.UIXEditableValue.CONVERSION";
-
-
+  static public final String TRINIDAD_BEAN_VALIDATION_AVAILABLE =
+    "org.apache.myfaces.trinidad.UIXEditableValue.BEAN_VALIDATION_AVAILABLE";
+  static public final String VALIDATE_EMPTY_FIELDS_PARAM_NAME =
+    "org.apache.myfaces.trinidad.UIXEditableValue.VALIDATE_EMPTY_FIELDS";
 
   /**
    * Convenience method to reset this component's value to an
@@ -287,18 +295,17 @@
     if (!isValid())
       return;
 
-    // If our value is empty, only check the required property
-    if (isEmpty(newValue))
+    // If our value is empty, check the required property
+    boolean isEmpty = isEmpty(newValue); 
+    if (isEmpty && isRequired())
     {
-      if (isRequired())
-      {
-        FacesMessage message = _getRequiredFacesMessage(context);
-        context.addMessage(getClientId(context), message);
-        setValid(false);
-      }
+      FacesMessage message = _getRequiredFacesMessage(context);
+      context.addMessage(getClientId(context), message);
+      setValid(false);
     }
-    // If our value is not empty, call all validators
-    else
+    
+    // If our value is not empty, OR we should do empty field validation, call all validators
+    if (!isEmpty || _shouldValidateEmptyFields(context)) 
     {
       Iterator<Validator> validators = (Iterator<Validator>)getFacesBean().entries(VALIDATORS_KEY);
       while (validators.hasNext())
@@ -456,6 +463,102 @@
             (((String) value).trim().length() == 0));
   }
 
+  /**
+   * Checks if the <code>validateValue()</code> should handle
+   * empty field validation (part of BeanValidation and JSF 2.0).
+   * 
+   * @return a (cached) boolean to identify empty field validation
+   */
+  private boolean _shouldValidateEmptyFields(FacesContext context)
+  {
+    ExternalContext ec = context.getExternalContext();
+    Boolean shouldValidateEmptyFields = (Boolean)ec.getApplicationMap().get(VALIDATE_EMPTY_FIELDS_PARAM_NAME);
+
+    if (shouldValidateEmptyFields == null)
+    {
+      // From the JSF 2.0 specification:
+      // The implementation must obtain the init parameter Map  from the ExternalContext and inspect the value
+      // for the key given by the value of the symbolic constant VALIDATE_EMPTY_FIELDS_PARAM_NAME.
+      String param = ec.getInitParameter(UIInput.VALIDATE_EMPTY_FIELDS_PARAM_NAME);
+
+      // If there is no value under that key, use the same key and look in the
+      // application map from the ExternalContext. 
+      if (param == null)
+      {
+        param = (String) ec.getApplicationMap().get(UIInput.VALIDATE_EMPTY_FIELDS_PARAM_NAME);
+      }
+
+      // null means the same as auto (see SPEC on page 11-5)
+      if (param == null)
+      {
+        param = "auto";
+      }
+      else
+      {
+        // The environment variables are case insensitive...
+        param = param.toLowerCase();
+      }
+
+      if (param.equals("auto") && _isBeanValidationAvailable(context))
+      {
+        shouldValidateEmptyFields = Boolean.TRUE;
+      }
+      else
+      {  
+        shouldValidateEmptyFields = Boolean.valueOf(param);
+      }
+
+      ec.getApplicationMap().put(VALIDATE_EMPTY_FIELDS_PARAM_NAME, shouldValidateEmptyFields);
+    }
+
+    return shouldValidateEmptyFields;
+  }
+  
+  /**
+   * This boolean indicates if Bean Validation is present.
+   *
+   * @return a (cached) boolean to identify if bean validation is present
+   */
+  private boolean _isBeanValidationAvailable(FacesContext context)
+  {
+    ExternalContext ec = context.getExternalContext();
+    Boolean couldLoadBeanValidationAPI = (Boolean) ec.getApplicationMap().get(TRINIDAD_BEAN_VALIDATION_AVAILABLE);
+
+    if (couldLoadBeanValidationAPI == null)
+    {
+      try
+      {
+        couldLoadBeanValidationAPI = Boolean.valueOf(ClassLoaderUtils.loadClass("javax.validation.Validation") != null);
+
+        if (couldLoadBeanValidationAPI)
+        {
+          try
+          {
+            // Trial-error approach to check for Bean Validation impl existence.
+            Validation.buildDefaultValidatorFactory().getValidator();
+          }
+          catch (ValidationException ve)
+          {
+            // SPEC section 3.5.6.2:
+            // TODO do a i18n version of the error msg
+            throw new FacesException("A ValidatorFactory can not be retrieved", ve);
+          }
+        }
+      }
+      catch (ClassNotFoundException cnfe)
+      {
+        // SPEC section 3.5.6.2:
+        // if a Bean Validation provider is not present, bean validation is disabled
+        // TODO need a better warning here, which has more information
+        _LOG.warning(cnfe);
+        couldLoadBeanValidationAPI = Boolean.FALSE;
+      }
+
+      ec.getApplicationMap().put(TRINIDAD_BEAN_VALIDATION_AVAILABLE, couldLoadBeanValidationAPI);
+    }
+
+    return couldLoadBeanValidationAPI;
+  }
 
   /**
    * Executes validation logic.