You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shale.apache.org by cr...@apache.org on 2006/11/27 22:08:28 UTC

svn commit: r479765 - in /shale/framework/trunk/shale-validator: ./ src/main/java/org/apache/shale/validator/ src/main/java/org/apache/shale/validator/faces/ src/main/java/org/apache/shale/validator/tag/ src/main/java/org/apache/shale/validator/util/ s...

Author: craigmcc
Date: Mon Nov 27 13:08:26 2006
New Revision: 479765

URL: http://svn.apache.org/viewvc?view=rev&rev=479765
Log:
Progress checkin to make it possible for others to provide feedback on the
remodelling I'm doing on the Shale - Commons Validator integration.  Key
pieces so far:

* Use a ServletContextListener to precalculate and cache a bunch
  of stuff at application startup (no, I didn't measure it, but
  doing string tokenizing on every call to every validator on every
  request cannot be a good thing :-).  As an added bonus, configuration
  errors that will cause later runtime problems are detected
  and complained about.

* New AbstractValidator base class that makes it trivially simple
  to implement a JSF validator class on top of Commons Validator --
  just set up your vars array, select the Commons Validator you want
  to use, and call a convenience method on the base class.

* New IntegerValidator that combines the functionality of "integer"
  and "intRange" into its own Validator class (the choice is made
  depending on whether the user specifies the min and max or not).

I haven't fleshed out a tag class for IntegerValidator yet (I'm toying
with changing the default tag library prefix so you can just say
"<validate:integer/>" for this :-), or finished up the client side
JavaScript generation yet, so there might still be some changes needed
due to that.

A bunch of stuff still remains to do, but feedback early on would be
appreciated.

SHALE-340

Added:
    shale/framework/trunk/shale-validator/src/main/java/org/apache/shale/validator/tag/
    shale/framework/trunk/shale-validator/src/main/java/org/apache/shale/validator/util/
    shale/framework/trunk/shale-validator/src/main/java/org/apache/shale/validator/util/ShaleValidatorAction.java   (with props)
    shale/framework/trunk/shale-validator/src/main/java/org/apache/shale/validator/validator/
    shale/framework/trunk/shale-validator/src/main/java/org/apache/shale/validator/validator/AbstractValidator.java   (with props)
    shale/framework/trunk/shale-validator/src/main/java/org/apache/shale/validator/validator/IntegerValidator.java   (with props)
    shale/framework/trunk/shale-validator/src/main/java/org/apache/shale/validator/validator/package.html   (with props)
    shale/framework/trunk/shale-validator/src/test/java/org/apache/shale/validator/faces/
    shale/framework/trunk/shale-validator/src/test/java/org/apache/shale/validator/faces/ValidatorLifecycleListenerTestCase.java   (with props)
    shale/framework/trunk/shale-validator/src/test/java/org/apache/shale/validator/util/
    shale/framework/trunk/shale-validator/src/test/java/org/apache/shale/validator/validator/
    shale/framework/trunk/shale-validator/src/test/java/org/apache/shale/validator/validator/AbstractValidatorTestCase.java   (with props)
    shale/framework/trunk/shale-validator/src/test/java/org/apache/shale/validator/validator/ConcreteValidator.java   (with props)
    shale/framework/trunk/shale-validator/src/test/java/org/apache/shale/validator/validator/IntegerValidatorTestCase.java   (with props)
    shale/framework/trunk/shale-validator/src/test/resources/org/apache/shale/validator/TestBundle.properties   (with props)
Modified:
    shale/framework/trunk/shale-validator/   (props changed)
    shale/framework/trunk/shale-validator/src/main/java/org/apache/shale/validator/Globals.java
    shale/framework/trunk/shale-validator/src/main/java/org/apache/shale/validator/faces/ValidatorLifecycleListener.java

Propchange: shale/framework/trunk/shale-validator/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Mon Nov 27 13:08:26 2006
@@ -0,0 +1 @@
+target

Modified: shale/framework/trunk/shale-validator/src/main/java/org/apache/shale/validator/Globals.java
URL: http://svn.apache.org/viewvc/shale/framework/trunk/shale-validator/src/main/java/org/apache/shale/validator/Globals.java?view=diff&rev=479765&r1=479764&r2=479765
==============================================================================
--- shale/framework/trunk/shale-validator/src/main/java/org/apache/shale/validator/Globals.java (original)
+++ shale/framework/trunk/shale-validator/src/main/java/org/apache/shale/validator/Globals.java Mon Nov 27 13:08:26 2006
@@ -36,6 +36,15 @@
 
 
     /**
+     * <p>Application scope attribute under which we store a <code>Map</code>
+     * of arrays of <code>ShaleValidatorAction</code> instances, keyed by the
+     * logical name of the Commons Validator action to be executed.</p>
+     */
+    public static final String VALIDATOR_ACTIONS =
+      "org.apache.shale.validator.ACTIONS";
+
+
+    /**
      * <p>Application scope attribute under which we store the Commons
      * Validator resources that have been configured.</p>
      */

Modified: shale/framework/trunk/shale-validator/src/main/java/org/apache/shale/validator/faces/ValidatorLifecycleListener.java
URL: http://svn.apache.org/viewvc/shale/framework/trunk/shale-validator/src/main/java/org/apache/shale/validator/faces/ValidatorLifecycleListener.java?view=diff&rev=479765&r1=479764&r2=479765
==============================================================================
--- shale/framework/trunk/shale-validator/src/main/java/org/apache/shale/validator/faces/ValidatorLifecycleListener.java (original)
+++ shale/framework/trunk/shale-validator/src/main/java/org/apache/shale/validator/faces/ValidatorLifecycleListener.java Mon Nov 27 13:08:26 2006
@@ -21,7 +21,10 @@
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 import javax.faces.FacesException;
 import javax.servlet.ServletContext;
 import javax.servlet.ServletContextEvent;
@@ -29,8 +32,10 @@
 import org.apache.commons.beanutils.PropertyUtils;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.apache.commons.validator.ValidatorAction;
 import org.apache.commons.validator.ValidatorResources;
 import org.apache.shale.validator.Globals;
+import org.apache.shale.validator.util.ShaleValidatorAction;
 import org.xml.sax.SAXException;
 
 /**
@@ -67,7 +72,8 @@
             log.info("Finalizing Validator Integration");
         }
 
-        // Clean up our cache of dialog configuration information
+        // Clean up our cached configuration information
+        event.getServletContext().removeAttribute(Globals.VALIDATOR_ACTIONS);
         event.getServletContext().removeAttribute(Globals.VALIDATOR_RESOURCES);
 
         // Clean up dependency libraries we have used
@@ -103,30 +109,93 @@
         }
         context.setAttribute(Globals.VALIDATOR_RESOURCES, resources);
 
+        // Configure and cache precalculated arrays of validator actions
+        // to be performed at runtime
+        Map actions = validatorActions(resources);
+        context.setAttribute(Globals.VALIDATOR_ACTIONS, actions);
+
     }
 
 
     // --------------------------------------------------------- Private Methods
 
 
-   /**
-    * <p>Configure the validator resources to be used by this application,
-    * by reading the list of resources configured on the context init
-    * parameter named by <code>Globals.VALIDATOR_RULES</code> (if any),
-    * followed by reading the default resource named by
-    * <code>Globals.DEFAULT_VALIDATOR_RULES</code> (if it has not already
-    * been processed).</p>
-    *
-    * @param context <code>ServletContext</code> for this application
-    *
-    * @exception IllegalArgumentException if a specified resource cannot
-    *  be located, or if a malformed URL is constructed from the
-    *  specified resource name
-    * @exception IOException if an input/output error occurs while
-    *  processing the specified configuration resources
-    * @exception SAXException if an XML parsing error occurs while
-    *  processing the specified configuration resources
-    */
+    /**
+     * <p>Configure precalcualted lists of validator actions that will be
+     * used to perform server side validation processing at runtime.</p>
+     *
+     * @param resources <code>ValidatorResources</code> for this application
+     *
+     * @exception IllegalArgumentException if the configuration resources
+     *  specify invalid validator types, or classes or methods that
+     *  cannot be loaded
+     */
+    private Map validatorActions(ValidatorResources resources) {
+
+        // Use the validator resources to precalculate a map of
+        // ShaleValidatorAction wrappers for the Commons Validator
+        // ValidatorAction configuration information
+        Map map = new HashMap();
+        Iterator entries = resources.getValidatorActions().entrySet().iterator();
+        while (entries.hasNext()) {
+            Map.Entry entry = (Map.Entry) entries.next();
+            if ("includeJavaScriptUtilities".equals(entry.getKey())) {
+                continue;
+            }
+            map.put((String) entry.getKey(),
+                    new ShaleValidatorAction(resources,
+                                             (ValidatorAction) entry.getValue()));
+        }
+
+        // Next, create arrays of the ShaleValidatorAction instances to be
+        // processed for each validator type, taking into account the
+        // configured dependencies that must also be tested
+        ShaleValidatorAction[] result = null;
+        Map results = new HashMap();
+        List list = null;
+        Iterator actions = map.entrySet().iterator();
+        while (actions.hasNext()) {
+            Map.Entry action = (Map.Entry) actions.next();
+            list =
+              ((ShaleValidatorAction) action.getValue()).getAction().getDependencyList();
+            if (list == null) {
+                list = new ArrayList(0);
+            }
+            result = new ShaleValidatorAction[list.size() + 1];
+            for (int i = 0; i < list.size(); i++) {
+                result[i] = (ShaleValidatorAction) map.get((String) list.get(i));
+                if (result[i] == null) {
+                    throw new IllegalArgumentException((String) action.getKey());
+                }
+            }
+            result[result.length - 1] = (ShaleValidatorAction) action.getValue();
+            results.put((String) action.getKey(), result);
+        }
+
+        // Return the map of created arrays
+        return results;
+
+    }
+
+
+    /**
+     * <p>Configure the validator resources to be used by this application,
+     * by reading the list of resources configured on the context init
+     * parameter named by <code>Globals.VALIDATOR_RULES</code> (if any),
+     * followed by reading the default resource named by
+     * <code>Globals.DEFAULT_VALIDATOR_RULES</code> (if it has not already
+     * been processed).</p>
+     *
+     * @param context <code>ServletContext</code> for this application
+     *
+     * @exception IllegalArgumentException if a specified resource cannot
+     *  be located, or if a malformed URL is constructed from the
+     *  specified resource name
+     * @exception IOException if an input/output error occurs while
+     *  processing the specified configuration resources
+     * @exception SAXException if an XML parsing error occurs while
+     *  processing the specified configuration resources
+     */
     private ValidatorResources validatorResources(ServletContext context)
       throws IOException, SAXException {
 

Added: shale/framework/trunk/shale-validator/src/main/java/org/apache/shale/validator/util/ShaleValidatorAction.java
URL: http://svn.apache.org/viewvc/shale/framework/trunk/shale-validator/src/main/java/org/apache/shale/validator/util/ShaleValidatorAction.java?view=auto&rev=479765
==============================================================================
--- shale/framework/trunk/shale-validator/src/main/java/org/apache/shale/validator/util/ShaleValidatorAction.java (added)
+++ shale/framework/trunk/shale-validator/src/main/java/org/apache/shale/validator/util/ShaleValidatorAction.java Mon Nov 27 13:08:26 2006
@@ -0,0 +1,348 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shale.validator.util;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import org.apache.commons.validator.Arg;
+import org.apache.commons.validator.Field;
+import org.apache.commons.validator.Form;
+import org.apache.commons.validator.ValidatorAction;
+import org.apache.commons.validator.ValidatorResources;
+
+/**
+ * <p>Custom wrapper around a Commons Validator <code>ValidatorAction</code>
+ * that precalculates as many of the introspective lookup operations as
+ * possible.  This ensures that runtime operation of the validator checks
+ * can proceed as quickly as possible.</p>
+ */
+public final class ShaleValidatorAction {
+    
+
+    // ------------------------------------------------------------ Constructors
+
+
+    /**
+     * <p>Create a new instance of ShaleValidatorAction that wraps the
+     * specified <code>ValidatorAction</code>.</p>
+     *
+     * @param resources <code>ValidatorResources</code> for this application
+     * @param action The <code>ValidatorAction</code> to be wrapped
+     *
+     * @exception IllegalArgumentException if configuration data is missing
+     *  or incorrect
+     */
+    public ShaleValidatorAction(ValidatorResources resources,
+                                ValidatorAction action) {
+
+        this.resources = resources;
+        this.action = action;
+        precalculate();
+
+    }
+    
+
+    // -------------------------------------------------------- Static Variables
+
+
+    /**
+     * <p>The prefix for form names that correspond to validator types.</p>
+     */
+    private static final String FORM_NAME_PREFIX = "org.apache.shale.validator.";
+
+
+    /**
+     * <p>Map of the classes for primitive Java types, keyed by the Java
+     * keywords for the corresponding primitive.</p>
+     */
+    private static final Map PRIMITIVE_TYPES = new HashMap();
+    static {
+        PRIMITIVE_TYPES.put("boolean", boolean.class);
+        PRIMITIVE_TYPES.put("byte", byte.class);
+        PRIMITIVE_TYPES.put("char", char.class);
+        PRIMITIVE_TYPES.put("double", double.class);
+        PRIMITIVE_TYPES.put("float", float.class);
+        PRIMITIVE_TYPES.put("int", int.class);
+        PRIMITIVE_TYPES.put("long", long.class);
+        PRIMITIVE_TYPES.put("short", short.class);
+    }
+
+
+    // ------------------------------------------------------ Instance Variables
+
+
+    /**
+     * <p>The <code>ValidatorAction</code> that we are wrapping.</p>
+     */
+    private ValidatorAction action = null;
+
+
+    /**
+     * <p>The class containing the validation method to be called for this action.</p>
+     */
+    private Class clazz = null;
+
+
+    /**
+     * <p>The field definition containing the mappings for parameter and
+     * message subtitution for this validator type.</p>
+     */
+    private Field field = null;
+
+
+    /**
+     * <p>The form definition corresponding to this validator type that is used
+     * for mapping parameter and message arguments.</p>
+     */
+    private Form form = null;
+
+
+    /**
+     * <p>Return an instance of the specified validation class, if the requested
+     * validation method is not static.</p>
+     */
+    private Object instance = null;
+
+
+    /**
+     * <p>Array of message arguments defining replacement parameters for error
+     * messages related to this validator.</p>
+     */
+    private Arg[] messageArgs = null;
+
+
+    /**
+     * <p>The validation <code>Method</code> to be called for this action.</p>
+     */
+    private Method method = null;
+
+
+    /**
+     * <p>Array of parameter arguments defining values to be sent in to
+     * the validator method for this validator.</p>
+     */
+    private Arg[] parameterArgs = null;
+
+
+    /**
+     * <p>The <code>ValidatorResources</code> for this application.</p>
+     */
+    private ValidatorResources resources = null;
+
+
+    /**
+     * <p>The parameter signature for the validation method to be called
+     * for this action.</p>
+     */
+    private Class[] signature = null;
+
+
+    // -------------------------------------------------------------- Properties
+
+
+    /**
+     * <p>Return the <code>ValidatorAction</code> instance we are wrapping.</p>
+     */
+    public ValidatorAction getAction() {
+        return this.action;
+    }
+
+
+    /**
+     * <p>Return an instance of the requested validator class, if the requested
+     * validation method is not static.  If the method is static, return
+     * <code>null</code> instead.</p>
+     */
+    public Object getInstance() {
+        return this.instance;
+    }
+
+
+    /**
+     * <p>Return an array of argument metadata describing subtitution values
+     * for error messages emitted by this validator type.</p>
+     */
+    public Arg[] getMessageArgs() {
+        return this.messageArgs;
+    }
+
+
+    /**
+     * <p>Return the lookup key for the error message template to be used
+     * if this validation fails.</p>
+     */
+    public String getMessageKey() {
+        return this.action.getMsg();
+    }
+
+
+    /**
+     * <p>Return the validation <code>Method</code> to be called for this
+     * action.</p>
+     */
+    public Method getMethod() {
+        return this.method;
+    }
+
+
+    /**
+     * <p>Return an array of argument metadata describing the parameter values
+     * to be sent to the validation method for this validator type.</p>
+     */
+    public Arg[] getParameterArgs() {
+        return this.parameterArgs;
+    }
+
+
+    /**
+     * <p>Return the parameter signature for the validation method to be called
+     * for this action.</p>
+     */
+    public Class[] getSignature() {
+        return this.signature;
+    }
+
+
+    // --------------------------------------------------------- Private Methods
+
+
+    /**
+     * <p>Precalculate the values to be returned by our public properties.</p>
+     *
+     * @exception IllegalArgumentException if configuration data is missing
+     *  or incorrect
+     */
+    private void precalculate() {
+
+        List list = null;
+        String value = null;
+        String values = null;
+
+        // Acquire a reference to the class loader we will use
+        ClassLoader loader = Thread.currentThread().getContextClassLoader();
+        if (loader == null) {
+            loader = this.getClass().getClassLoader();
+        }
+
+        // Look up the class that contains the validation method
+        // we will be calling
+        try {
+            this.clazz = loader.loadClass(action.getClassname());
+        } catch (ClassNotFoundException e) {
+            throw new IllegalArgumentException(action.getClassname(), e);
+        }
+
+        // Calculate the method parameter signature of the validation
+        // method we will be calling
+        list = new ArrayList();
+        values = action.getMethodParams().trim();
+        while (values.length() > 0) {
+            // Identify the class name of the next class to be loaded
+            int comma = values.indexOf(',');
+            if (comma >= 0) {
+                value = values.substring(0, comma).trim();
+                values = values.substring(comma + 1);
+            } else {
+                value = values.trim();
+                values = "";
+            }
+            if (value.length() == 0) {
+                break;
+            }
+            // Add the corresponding class instance to our list
+            Class clazz = (Class) PRIMITIVE_TYPES.get(value);
+            if (clazz == null) {
+                try {
+                    clazz = loader.loadClass(value);
+                } catch (ClassNotFoundException e) {
+                    throw new IllegalArgumentException(value, e);
+                }
+            }
+            list.add(clazz);
+        }
+        this.signature = (Class[]) list.toArray(new Class[list.size()]);
+
+        // Look up the validation method we will be calling
+        try {
+            this.method = this.clazz.getMethod(action.getMethod(), this.signature);
+        } catch (NoSuchMethodException e) {
+            throw new IllegalArgumentException(action.getName(), e);
+        }
+
+        // Create an instance of the validator class if we need one
+        // (which is true only if the validation method is not static
+        if (!Modifier.isStatic(this.method.getModifiers())) {
+            try {
+                this.instance = clazz.newInstance();
+            } catch (IllegalAccessException e) {
+                throw new IllegalArgumentException(action.getName(), e);
+            } catch (InstantiationException e) {
+                throw new IllegalArgumentException(action.getName(), e);
+            }
+        }
+
+        // Cache the form definition associated with this validator action type
+        this.form = resources.getForm(Locale.getDefault(),
+                                      FORM_NAME_PREFIX + action.getName());
+        if (this.form == null) {
+            throw new IllegalArgumentException(FORM_NAME_PREFIX + action.getName());
+        }
+
+        // Look up the predefined "fields" from our form definition
+        // and cache interesting information
+        this.field = this.form.getField(action.getName());
+        if (this.field == null) {
+            throw new IllegalArgumentException("Field " + action.getName());
+        }
+        this.messageArgs = field.getArgs("message");
+        if (this.messageArgs == null) {
+            this.messageArgs = new Arg[0];
+        }
+        this.parameterArgs = field.getArgs("parameter");
+        if (this.parameterArgs == null) {
+            this.parameterArgs = new Arg[0];
+        }
+
+        // FIXME - For some reason, Commons Validator is returning a trailing
+        // null Arg in the parameterArgs array sometimes, so strip it off
+        // if present
+        if ((this.parameterArgs.length > 0)
+         && (this.parameterArgs[this.parameterArgs.length - 1] == null)) {
+            Arg[] results = new Arg[this.parameterArgs.length - 1];
+            System.arraycopy(this.parameterArgs, 0, results, 0, results.length);
+            this.parameterArgs = results;
+        }
+
+        // For robustness, validate the length of the parameter arguments
+        // and parameter signature arrays, which should be identical
+        if (this.parameterArgs.length != this.signature.length) {
+            throw new IllegalArgumentException(this.action.getName()
+              + ": signature defines " + this.signature.length
+              + " elements but " + this.parameterArgs.length
+              + " parameter arguments are specified");
+        }
+
+    }
+
+
+}

Propchange: shale/framework/trunk/shale-validator/src/main/java/org/apache/shale/validator/util/ShaleValidatorAction.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: shale/framework/trunk/shale-validator/src/main/java/org/apache/shale/validator/util/ShaleValidatorAction.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: shale/framework/trunk/shale-validator/src/main/java/org/apache/shale/validator/validator/AbstractValidator.java
URL: http://svn.apache.org/viewvc/shale/framework/trunk/shale-validator/src/main/java/org/apache/shale/validator/validator/AbstractValidator.java?view=auto&rev=479765
==============================================================================
--- shale/framework/trunk/shale-validator/src/main/java/org/apache/shale/validator/validator/AbstractValidator.java (added)
+++ shale/framework/trunk/shale-validator/src/main/java/org/apache/shale/validator/validator/AbstractValidator.java Mon Nov 27 13:08:26 2006
@@ -0,0 +1,405 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shale.validator.validator;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.text.MessageFormat;
+import java.util.Locale;
+import java.util.Map;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+import javax.faces.application.FacesMessage;
+import javax.faces.component.StateHolder;
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+import javax.faces.validator.Validator;
+import javax.faces.validator.ValidatorException;
+import org.apache.commons.validator.Arg;
+import org.apache.commons.validator.ValidatorResources;
+import org.apache.shale.util.ConverterHelper;
+import org.apache.shale.validator.Globals;
+import org.apache.shale.validator.util.ShaleValidatorAction;
+
+/**
+ * <p>Abstract base class for validators that use Apache Commons Validator
+ * as their foundation.</p>
+ */
+public abstract class AbstractValidator implements Validator, StateHolder {
+    
+
+    // ------------------------------------------------------------ Constructors
+
+
+    // ------------------------------------------------------ Manifest Constants
+
+
+    /**
+     * <p>Variable name in a <code>vars</code> map representing the argument
+     * that was being evaluated, and should be included in any error message.
+     * Typically, this will be either the value itself or a user-friendly
+     * (localized) field label.</p>
+     */
+    protected static final String ARG_VALUE =
+            "arg";
+
+
+    /**
+     * <p>Name of the resource bundle containing default message templates.</p>
+     */
+    static final String DEFAULT_RESOURCE_BUNDLE =
+            "org.apache.shale.validator.messages";
+
+
+    /**
+     * <p>Variable name in a <code>vars</code> map representing the maximum
+     * value that should be accepted by this <code>Validator</code>.</p>
+     */
+    protected static final String MAXIMUM_VALUE =
+            "max";
+
+
+    /**
+     * <p>Variable name in a <code>vars</code> map representing the minimum
+     * value that should be accepted by this <code>Validator</code>.</p>
+     */
+    protected static final String MINIMUM_VALUE =
+            "min";
+
+
+    /**
+     * <p>Variable name in a <code>vars</code> map representing the submitted
+     * value that should be validated by this <code>Validator</code>.</p>
+     */
+    protected static final String SUBMITTED_VALUE =
+            "submittedValue";
+
+
+    // -------------------------------------------------------- Static Variables
+
+
+    /**
+     * <p>Converter helper instance we can use in the <code>convert()</code>
+     * method implementation.</p>
+     */
+    protected static final ConverterHelper helper = new ConverterHelper();
+
+
+
+    // -------------------------------------------------------------- Properties
+
+
+    private boolean client = true;
+
+
+    /**
+     * <p>Return a flag describing whether this validator should be enforced
+     * on the client side or not.  Default is <code>true</code>.</p>
+     */
+    public boolean isClient() {
+        return this.client;
+    }
+
+
+    /**
+     * <p>Set a flag describing whether this validator should be enforced
+     * on the client side or not.</p>
+     *
+     * @param client The new client enforcement flag
+     */
+    public void setClient(boolean client) {
+        this.client = client;
+    }
+
+
+    private String message = null;
+
+
+    /**
+     * <p>Return the custom error message template for this validator, if any.
+     * If not defined, a standard error message template (based on which
+     * validator type is selected) will be used instead.</p>
+     */
+    public String getMessage() {
+        return this.message;
+    }
+
+
+    /**
+     * <p>Set the custom error message template for this validator.</p>
+     *
+     * @param message The new custom error message template, or <code>null</code>
+     *  to select the standard template
+     */
+    public void setMessage(String message) {
+        this.message = message;
+    }
+
+
+    // ------------------------------------------------------- Validator Methods
+
+
+    /**
+     * <p>Perform the correctness checks implemented by this
+     * {@link Validator} against the specified {@link UIComponent}.
+     * If any violations are found, a {@link ValidatorException}
+     * will be thrown containing the {@link javax.faces.application.FacesMessage}
+     * describing the failure.</p>
+     *
+     * <p><strong>IMPLEMENTATION NOTE</strong>:  Unlike earlier implementations
+     * of Shale Validator integration, validators that subclass this class do
+     * not support the option to skip server side validation.</p>
+     *
+     * @param context <code>FacesContext</code> for the current request
+     * @param component <code>UIComponent</code> we are checking for correctness
+     * @param value The value to validate
+     *
+     * @throws ValidatorException if validation fails
+     * @throws NullPointerException if <code>context</code>
+     *  or <code>component</code> is <code>null</code>
+     */
+    public abstract void validate(FacesContext context,
+                                  UIComponent  component,
+                                  Object       value) throws ValidatorException;
+
+
+    // ----------------------------------------------------- StateHolder Methods
+
+
+    /** {@inheritDoc} */
+    public void restoreState(FacesContext context, Object state) {
+        Object[] values = (Object[]) state;
+        this.client = Boolean.TRUE.equals((Boolean) values[0]);
+        this.message = (String) values[1];
+    }
+
+
+    /** {@inheritDoc} */
+    public Object saveState(FacesContext context) {
+        Object[] values = new Object[2];
+        values[0] = this.client ? Boolean.TRUE : Boolean.FALSE;
+        values[1] = this.message;
+        return values;
+    }
+
+
+    private boolean transientValue = false;
+
+
+    /** {@inheritDoc} */
+    public boolean isTransient() {
+        return this.transientValue;
+    }
+
+
+    /** {@inheritDoc} */
+    public void setTransient(boolean transientValue) {
+        this.transientValue = transientValue;
+    }
+
+
+    // ---------------------------------------------------------- Object Methods
+
+
+    // ------------------------------------------------------- Protected Methods
+
+
+    /**
+     * <p>Return an array of <code>ShaleValidatorAction</code>s to execute
+     * for a given validation, starting with the configured dependent
+     * actions, and ending with the action corresponding to the specified
+     * action type.  If there is no defined action with the specified
+     * type, return <code>null</code>.</p>
+     *
+     * @param context <code>FacesContext</code> for the current request
+     * @param type Type of the validator action for which to return actions
+     */
+    protected ShaleValidatorAction[] actions(FacesContext context, String type) {
+
+        Map actions = (Map) context.getExternalContext().
+          getApplicationMap().get(Globals.VALIDATOR_ACTIONS);
+        return (ShaleValidatorAction[]) actions.get(type);
+
+    }
+
+
+    /**
+     * <p>Use the registered converters to convert the specified value
+     * to the specified type.</p>
+     *
+     * @param context <code>FacesContext</code> for the current request
+     * @param value Value to be converted
+     * @param type Type to which the value should be converted
+     */
+    protected Object convert(FacesContext context, Object value, Class type) {
+
+        // Is the specified value null?  If so, return it unchanged
+        if (value == null) {
+            return null;
+        }
+
+        // Is the specified value of the correct type already?
+        // If so, return it unchanged
+        if (type.isInstance(value)) {
+            return value;
+        }
+
+        // Is the target type String?  If so, use the asString() conversion
+        if (type == String.class) {
+            if (value instanceof String) {
+                return value;
+            } else {
+                return helper.asString(context, value.getClass(), value);
+            }
+        }
+
+        // Is the source type String?  If so, use the asObject() conversion
+        if (value instanceof String) {
+            return helper.asObject(context, type, (String) value);
+        }
+
+        // Fall back to converting to String, then to the requested type
+        String string = helper.asString(context, value.getClass(), value);
+        return helper.asObject(context, type, string);
+
+    }
+
+
+    /**
+     * <p>Return the locale-sensitive error message template for this
+     * validator.  The application specified resource bundle (if any)
+     * is searched first, followed by the default resource bundle.</p>
+     *
+     * @param context <code>FaceContext</code> for the current request
+     * @param key Message key for the requested template
+     */
+    protected String message(FacesContext context, String key) {
+
+        // Set up variables we will need
+        ResourceBundle bundle = null;
+        Locale locale = context.getViewRoot().getLocale();
+        ClassLoader loader = Thread.currentThread().getContextClassLoader();
+        if (loader == null) {
+            loader = this.getClass().getClassLoader();
+        }
+        String message = null;
+
+        // Search for a match in the application resource bundle (if any)
+        String name = context.getApplication().getMessageBundle();
+        if (name != null) {
+            bundle = ResourceBundle.getBundle(name, locale, loader);
+            if (bundle != null) {
+                try {
+                    message = bundle.getString(key);
+                } catch (MissingResourceException e) {
+                    message = null;
+                }
+                if (message != null) {
+                    return message;
+                }
+            }
+        }
+
+        // Otherwise, search the default resource bundle
+        bundle = ResourceBundle.getBundle(DEFAULT_RESOURCE_BUNDLE, locale, loader);
+        try {
+            return bundle.getString(key);
+        } catch (MissingResourceException e) {
+            return "???" + key + "???";
+        }
+
+    }
+
+
+    /**
+     * <p>Return the <code>ValidatorResources</code> that describe the
+     * validation rules to be enforced by this application.</p>
+     *
+     * @param context <code>FacesContext</code> for the current request
+     */
+    protected ValidatorResources resources(FacesContext context) {
+
+        return (ValidatorResources) context.getExternalContext().
+          getApplicationMap().get(Globals.VALIDATOR_RESOURCES);
+
+    }
+
+
+    /**
+     * <p>Perform a validation using the specified Commons Validator type.</p>
+     *
+     * @param context <code>FacesContext</code> for the current request
+     * @param component <code>UIComponent</code> whose value is being validated
+     * @param value The value being validated
+     * @param type Type of validation to be performed
+     * @param vars Mutable map of values to be passed in to the validation
+     *
+     * @exception ValidatorException if a validation error occurs
+     */
+    protected void validate(FacesContext context, UIComponent component,
+                            Object value, String type, Map vars)
+      throws ValidatorException {
+
+        // Look up the actions we must perform
+        ShaleValidatorAction[] actions = actions(context, type);
+        if (actions == null) {
+            throw new IllegalArgumentException("No validator for type '"
+                                               + type + "' has been configured");
+        }
+
+        // Perform the actions in order, throwing a ValidatorException
+        // on the first one that fails (per the standard Validator contract)
+        for (int i = 0; i < actions.length; i++) {
+            Object instance = actions[i].getInstance();
+            Method method = actions[i].getMethod();
+            Class[] signature = actions[i].getSignature();
+            Arg[] args = actions[i].getParameterArgs();
+            Object[] parameters = new Object[signature.length];
+            for (int j = 0; j < parameters.length; j++) {
+                parameters[j] = convert(context, vars.get(args[j].getKey()), signature[j]);
+            }
+            Boolean result = null;
+            try {
+                result = (Boolean) method.invoke(instance, parameters);
+            } catch (IllegalAccessException e) {
+                ;
+            } catch (InvocationTargetException e) {
+                ;
+            }
+            if (!result.booleanValue()) {
+                String error = getMessage();
+                if (error == null) {
+                    error = message(context, actions[i].getMessageKey());
+                }
+                args = actions[i].getMessageArgs();
+                parameters = new Object[args.length];
+                for (int j = 0; j < parameters.length; j++) {
+                    parameters[j] = vars.get(args[j].getKey());
+                }
+                Locale locale = context.getViewRoot().getLocale();
+                String formatted = new MessageFormat(error, locale).format(parameters);
+                FacesMessage message =
+                  new FacesMessage(FacesMessage.SEVERITY_ERROR, formatted, null);
+                throw new ValidatorException(message);
+            }
+        }
+
+    }
+    
+
+}

Propchange: shale/framework/trunk/shale-validator/src/main/java/org/apache/shale/validator/validator/AbstractValidator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: shale/framework/trunk/shale-validator/src/main/java/org/apache/shale/validator/validator/AbstractValidator.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: shale/framework/trunk/shale-validator/src/main/java/org/apache/shale/validator/validator/IntegerValidator.java
URL: http://svn.apache.org/viewvc/shale/framework/trunk/shale-validator/src/main/java/org/apache/shale/validator/validator/IntegerValidator.java?view=auto&rev=479765
==============================================================================
--- shale/framework/trunk/shale-validator/src/main/java/org/apache/shale/validator/validator/IntegerValidator.java (added)
+++ shale/framework/trunk/shale-validator/src/main/java/org/apache/shale/validator/validator/IntegerValidator.java Mon Nov 27 13:08:26 2006
@@ -0,0 +1,151 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shale.validator.validator;
+
+import java.util.HashMap;
+import java.util.Map;
+import javax.faces.component.EditableValueHolder;
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+import javax.faces.validator.ValidatorException;
+
+/**
+ * <p><code>Validator</code> implementation that will perform both format
+ * and (optional) range checks on an integer value.</p>
+ */
+public final class IntegerValidator extends AbstractValidator {
+
+
+    // -------------------------------------------------------------- Properties
+
+
+    private int maximum = Integer.MAX_VALUE;
+    private boolean maximumSet = false;
+
+
+    /**
+     * <p>Return the configured maximum value for this validator.</p>
+     */
+    public int getMaximum() {
+        return this.maximum;
+    }
+    
+
+    /**
+     * <p>Set the configured maximum value for this validator.</p>
+     *
+     * @param maximum The new maximum value
+     */
+    public void setMaximum(int maximum) {
+        this.maximum = maximum;
+        this.maximumSet = true;
+    }
+
+
+    private int minimum = Integer.MIN_VALUE;
+    private boolean minimumSet = false;
+
+
+    /**
+     * <p>Return the configured minimum value for this validator.</p>
+     */
+    public int getMinimum() {
+        return this.minimum;
+    }
+    
+
+    /**
+     * <p>Set the configured minimum value for this validator.</p>
+     *
+     * @param minimum The new minimum value
+     */
+    public void setMinimum(int minimum) {
+        this.minimum = minimum;
+        this.minimumSet = true;
+    }
+
+
+    // ------------------------------------------------------- Validator Methods
+
+
+    /** {@inheritDoc} */
+    public void validate(FacesContext context,
+                         UIComponent  component,
+                         Object       value) throws ValidatorException {
+
+        // Build a map of variables passed in to Commons Validator
+        Map vars = new HashMap();
+        vars.put(ARG_VALUE, // FIXME - consider using component.getLabel() in JSF 1.2
+                 ((EditableValueHolder) component).getSubmittedValue());
+        if (maximumSet) {
+            vars.put(MAXIMUM_VALUE, new Integer(maximum));
+        } else {
+            vars.put(MAXIMUM_VALUE, new Integer(Integer.MAX_VALUE));
+        }
+        if (minimumSet) {
+            vars.put(MINIMUM_VALUE, new Integer(minimum));
+        } else {
+            vars.put(MINIMUM_VALUE, new Integer(Integer.MIN_VALUE));
+        }
+        vars.put(SUBMITTED_VALUE,
+                 ((EditableValueHolder) component).getSubmittedValue());
+
+        // Invoke the appropriate Commons Validator type
+        if (maximumSet || minimumSet) {
+            super.validate(context, component, value, "intRange", vars);
+        } else {
+            super.validate(context, component, value, "integer", vars);
+        }
+
+    }
+
+
+    // ----------------------------------------------------- StateHolder Methods
+
+
+    /** {@inheritDoc} */
+    public void restoreState(FacesContext context, Object state) {
+
+        Object[] values = (Object[]) state;
+        super.restoreState(context, values[0]);
+        maximum = ((Integer) values[1]).intValue();
+        maximumSet = ((Boolean) values[2]).booleanValue();
+        minimum = ((Integer) values[3]).intValue();
+        minimumSet = ((Boolean) values[4]).booleanValue();
+
+    }
+
+
+    /** {@inheritDoc} */
+    public Object saveState(FacesContext context) {
+
+        Object[] values = new Object[5];
+        values[0] = super.saveState(context);
+        values[1] = new Integer(maximum);
+        values[2] = this.maximumSet ? Boolean.TRUE : Boolean.FALSE;
+        values[3] = new Integer(minimum);
+        values[4] = this.minimumSet ? Boolean.TRUE : Boolean.FALSE;
+        return values;
+
+    }
+
+
+    // ---------------------------------------------------------- Object Methods
+
+
+}

Propchange: shale/framework/trunk/shale-validator/src/main/java/org/apache/shale/validator/validator/IntegerValidator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: shale/framework/trunk/shale-validator/src/main/java/org/apache/shale/validator/validator/IntegerValidator.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: shale/framework/trunk/shale-validator/src/main/java/org/apache/shale/validator/validator/package.html
URL: http://svn.apache.org/viewvc/shale/framework/trunk/shale-validator/src/main/java/org/apache/shale/validator/validator/package.html?view=auto&rev=479765
==============================================================================
--- shale/framework/trunk/shale-validator/src/main/java/org/apache/shale/validator/validator/package.html (added)
+++ shale/framework/trunk/shale-validator/src/main/java/org/apache/shale/validator/validator/package.html Mon Nov 27 13:08:26 2006
@@ -0,0 +1,26 @@
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+
+<!-- $Id$ -->
+
+<body>
+
+<p>This package contains a set of JSF validators that use
+the Apache Commons Validator API to perform both
+client- and server-side validation.</p>
+
+</body>

Propchange: shale/framework/trunk/shale-validator/src/main/java/org/apache/shale/validator/validator/package.html
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: shale/framework/trunk/shale-validator/src/main/java/org/apache/shale/validator/validator/package.html
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: shale/framework/trunk/shale-validator/src/test/java/org/apache/shale/validator/faces/ValidatorLifecycleListenerTestCase.java
URL: http://svn.apache.org/viewvc/shale/framework/trunk/shale-validator/src/test/java/org/apache/shale/validator/faces/ValidatorLifecycleListenerTestCase.java?view=auto&rev=479765
==============================================================================
--- shale/framework/trunk/shale-validator/src/test/java/org/apache/shale/validator/faces/ValidatorLifecycleListenerTestCase.java (added)
+++ shale/framework/trunk/shale-validator/src/test/java/org/apache/shale/validator/faces/ValidatorLifecycleListenerTestCase.java Mon Nov 27 13:08:26 2006
@@ -0,0 +1,185 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shale.validator.faces;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import javax.servlet.ServletContextEvent;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+import org.apache.commons.validator.ValidatorAction;
+import org.apache.commons.validator.ValidatorResources;
+import org.apache.shale.test.base.AbstractJsfTestCase;
+import org.apache.shale.validator.Globals;
+import org.apache.shale.validator.util.ShaleValidatorAction;
+
+/**
+ * <p>Test case for the initializations performed by
+ * <code>ValidatorLifecycleListener</code> at application startup.</p>
+ */
+public class ValidatorLifecycleListenerTestCase extends AbstractJsfTestCase {
+    
+
+    // ------------------------------------------------------------ Constructors
+
+
+    // Construct a new instance of this test case.
+    public ValidatorLifecycleListenerTestCase(String name) {
+        super(name);
+    }
+
+
+    // ---------------------------------------------------- Overall Test Methods
+
+
+    // Set up instance variables required by this test case.
+    protected void setUp() throws Exception {
+
+        super.setUp();
+
+        listener = new ValidatorLifecycleListener();
+        listener.contextInitialized(new ServletContextEvent(servletContext));
+
+    }
+
+
+    // Return the tests included in this test case.
+    public static Test suite() {
+
+        return (new TestSuite(ValidatorLifecycleListenerTestCase.class));
+
+    }
+
+
+    // Tear down instance variables required by this test case.
+    protected void tearDown() throws Exception {
+
+        listener.contextDestroyed(new ServletContextEvent(servletContext));
+        listener = null;
+
+        super.tearDown();
+
+    }
+
+
+    // -------------------------------------------------------- Static Variables
+
+
+    /**
+     * <p>The number of ShaleVariableAction entries that should be present
+     * for each logical type, keyed by the type name.</p>
+     *
+     * <p><strong>IMPLEMENTATION NOTE</strong> - The contents of this map
+     * will need to be adjusted whenever changes are made to the preregistered
+     * validators in <code>validator-rules.xml</code>.</p>
+     */
+    private static final Map ACTION_COUNTS = new HashMap();
+    static {
+        ACTION_COUNTS.put("byte", new Integer(1));
+        ACTION_COUNTS.put("creditCard", new Integer(1));
+        ACTION_COUNTS.put("date", new Integer(1));
+        ACTION_COUNTS.put("double", new Integer(1));
+        ACTION_COUNTS.put("doubleRange", new Integer(2));
+        ACTION_COUNTS.put("email", new Integer(1));
+        ACTION_COUNTS.put("float", new Integer(1));
+        ACTION_COUNTS.put("floatRange", new Integer(2));
+        ACTION_COUNTS.put("integer", new Integer(1));
+        ACTION_COUNTS.put("intRange", new Integer(2));
+        ACTION_COUNTS.put("long", new Integer(1));
+        ACTION_COUNTS.put("mask", new Integer(1));
+        ACTION_COUNTS.put("maxlength", new Integer(1));
+        ACTION_COUNTS.put("minlength", new Integer(1));
+        ACTION_COUNTS.put("required", new Integer(1));
+        ACTION_COUNTS.put("short", new Integer(1));
+        ACTION_COUNTS.put("url", new Integer(1));
+    }
+
+
+    // ------------------------------------------------------ Instance Variables
+
+
+    /**
+     * <p>ValidatorLifecycleListener used to load configuration resources</p>
+     */
+    ValidatorLifecycleListener listener = null;
+
+
+    // ------------------------------------------------- Individual Test Methods
+
+
+    // Test whether the precalculated validator actions includes the data
+    // that it should
+    public void testActions() {
+
+        // Acquire the configuration data we will need
+        ValidatorResources resources = (ValidatorResources)
+          servletContext.getAttribute(Globals.VALIDATOR_RESOURCES);
+        Map vamap = resources.getValidatorActions();
+        Map actions = (Map)
+          servletContext.getAttribute(Globals.VALIDATOR_ACTIONS);
+
+        // The precalculated map will not include an entry for
+        // "includeJavaScriptUtilities" because it is not a real validation type
+        assertEquals(vamap.size() - 1, actions.size());
+
+        // Verify the number of actions for each precalculated validator
+        // This also indirectly checks that all entries that should be
+        // precalculated are actually present
+        Iterator entries = ACTION_COUNTS.entrySet().iterator();
+        while (entries.hasNext()) {
+            Map.Entry entry = (Map.Entry) entries.next();
+            String key = (String) entry.getKey();
+            Integer value = (Integer) entry.getValue();
+            ValidatorAction va = resources.getValidatorAction(key);
+            assertTrue("ValidatorAction " + key + " is present", va != null);
+            ShaleValidatorAction[] action = (ShaleValidatorAction[])
+              actions.get(key);
+            assertTrue("ShaleValidatorAction[] " + key + " is present", action != null);
+            assertEquals("ShaleValidatorAction[] " + key + " has correct size",
+                         value.intValue(), action.length);
+            if (action.length > 1) {
+                assertTrue("First two actions for " + key + " are not identical",
+                           action[0] != action[1]);
+            }
+        }
+
+    }
+
+
+    // Test a pristine instance of the listener
+    public void testPristine() {
+
+        assertNotNull(listener);
+
+        ValidatorResources resources = (ValidatorResources)
+          servletContext.getAttribute(Globals.VALIDATOR_RESOURCES);
+        assertNotNull(resources);
+        Map vamap = resources.getValidatorActions();
+
+        Map actions = (Map)
+          servletContext.getAttribute(Globals.VALIDATOR_ACTIONS);
+        assertNotNull(actions);
+
+    }
+
+
+    // --------------------------------------------------------- Private Methods
+
+
+}

Propchange: shale/framework/trunk/shale-validator/src/test/java/org/apache/shale/validator/faces/ValidatorLifecycleListenerTestCase.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: shale/framework/trunk/shale-validator/src/test/java/org/apache/shale/validator/faces/ValidatorLifecycleListenerTestCase.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: shale/framework/trunk/shale-validator/src/test/java/org/apache/shale/validator/validator/AbstractValidatorTestCase.java
URL: http://svn.apache.org/viewvc/shale/framework/trunk/shale-validator/src/test/java/org/apache/shale/validator/validator/AbstractValidatorTestCase.java?view=auto&rev=479765
==============================================================================
--- shale/framework/trunk/shale-validator/src/test/java/org/apache/shale/validator/validator/AbstractValidatorTestCase.java (added)
+++ shale/framework/trunk/shale-validator/src/test/java/org/apache/shale/validator/validator/AbstractValidatorTestCase.java Mon Nov 27 13:08:26 2006
@@ -0,0 +1,192 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shale.validator.validator;
+
+import java.util.Locale;
+import java.util.ResourceBundle;
+import javax.faces.validator.Validator;
+import javax.servlet.ServletContextEvent;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+import org.apache.commons.validator.ValidatorAction;
+import org.apache.commons.validator.ValidatorResources;
+import org.apache.shale.test.base.AbstractJsfTestCase;
+import org.apache.shale.validator.faces.ValidatorLifecycleListener;
+import org.apache.shale.validator.util.ShaleValidatorAction;
+
+/**
+ * <p>Test case for the utility methods provided by
+ * <code>AbstractValidator</code>.  The protected <code>validate()</code>
+ * method is not tested here, as it is presumed that this will be exercised
+ * repeatedly by the test cases for the various concrete validators.</p>
+ */
+public class AbstractValidatorTestCase extends AbstractJsfTestCase {
+
+
+    // ------------------------------------------------------------ Constructors
+
+
+    // Construct a new instance of this test case.
+    public AbstractValidatorTestCase(String name) {
+        super(name);
+    }
+
+
+    // ---------------------------------------------------- Overall Test Methods
+
+
+    // Set up instance variables required by this test case.
+    protected void setUp() throws Exception {
+
+        super.setUp();
+        application.setMessageBundle("org.apache.shale.validator.TestBundle");
+        facesContext.getViewRoot().setLocale(Locale.US);
+
+        listener = new ValidatorLifecycleListener();
+        listener.contextInitialized(new ServletContextEvent(servletContext));
+
+        validator = new ConcreteValidator();
+
+    }
+
+
+    // Return the tests included in this test case.
+    public static Test suite() {
+
+        return (new TestSuite(AbstractValidatorTestCase.class));
+
+    }
+
+
+    // Tear down instance variables required by this test case.
+    protected void tearDown() throws Exception {
+
+        validator = null;
+
+        listener.contextDestroyed(new ServletContextEvent(servletContext));
+        listener = null;
+
+        super.tearDown();
+
+    }
+
+
+    // -------------------------------------------------------- Static Variables
+
+
+    /**
+     * <p>Default resource bundle for error message lookup
+     */
+    protected static final ResourceBundle defaultBundle =
+      ResourceBundle.getBundle(AbstractValidator.DEFAULT_RESOURCE_BUNDLE, Locale.US);
+
+
+    // ------------------------------------------------------ Instance Variables
+
+
+    /**
+     * <p>ValidatorLifecycleListener used to load configuration resources</p>
+     */
+    protected ValidatorLifecycleListener listener = null;
+
+
+    /**
+     * <p>Validator instance under test.</p>
+     */
+    protected ConcreteValidator validator = null;
+
+
+    // ------------------------------------------------- Individual Test Methods
+
+
+    // Test retrieving actions arrays
+    public void testActions() {
+
+        ShaleValidatorAction actions[] = null;
+
+        actions = validator.actions(facesContext, "double");
+        assertNotNull(actions);
+        assertEquals(1, actions.length);
+
+        actions = validator.actions(facesContext, "doubleRange");
+        assertNotNull(actions);
+        assertEquals(2, actions.length);
+
+        actions = validator.actions(facesContext, "intRange");
+        assertNotNull(actions);
+        assertEquals(2, actions.length);
+        assertEquals("integer", actions[0].getAction().getName());
+        assertEquals("intRange", actions[1].getAction().getName());
+
+        actions = validator.actions(facesContext, "???undefined???");
+        assertNull(actions);
+
+    }
+
+
+    // Test type conversions via registered converters
+    public void testConvert() {
+
+        ; // FIXME - add some tests for conversions
+
+    }
+
+
+    // Test retrieving messages
+    public void testMessage() {
+
+        String message = null;
+
+        // Check a message that should be overridden by the application
+        message = validator.message(facesContext, "errors.long");
+        assertNotNull(message);
+        assertEquals("Custom Long Error Message", message);
+
+        // Check a message that should be grabbed from the default resources
+        message = validator.message(facesContext, "errors.integer");
+        assertNotNull(message);
+        assertEquals(defaultBundle.getString("errors.integer"), message);
+
+        // Check a message that should be undefined
+        message = validator.message(facesContext, "???undefined???");
+        assertNull(message);
+
+    }
+
+
+    // Test retrieving resources
+    public void testResources() {
+
+        ValidatorAction action = null;
+
+        ValidatorResources resources = validator.resources(facesContext);
+        assertNotNull(resources);
+
+        action = resources.getValidatorAction("integer");
+        assertNotNull(action);
+
+        action = resources.getValidatorAction("intRange");
+        assertNotNull(action);
+
+        action = resources.getValidatorAction("???undefined");
+        assertNull(action);
+
+    }
+
+
+}

Propchange: shale/framework/trunk/shale-validator/src/test/java/org/apache/shale/validator/validator/AbstractValidatorTestCase.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: shale/framework/trunk/shale-validator/src/test/java/org/apache/shale/validator/validator/AbstractValidatorTestCase.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: shale/framework/trunk/shale-validator/src/test/java/org/apache/shale/validator/validator/ConcreteValidator.java
URL: http://svn.apache.org/viewvc/shale/framework/trunk/shale-validator/src/test/java/org/apache/shale/validator/validator/ConcreteValidator.java?view=auto&rev=479765
==============================================================================
--- shale/framework/trunk/shale-validator/src/test/java/org/apache/shale/validator/validator/ConcreteValidator.java (added)
+++ shale/framework/trunk/shale-validator/src/test/java/org/apache/shale/validator/validator/ConcreteValidator.java Mon Nov 27 13:08:26 2006
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shale.validator.validator;
+
+import java.util.Map;
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+import javax.faces.validator.ValidatorException;
+import org.apache.commons.validator.ValidatorResources;
+import org.apache.shale.validator.util.ShaleValidatorAction;
+
+/**
+ * <p>Simple concrete implementation of <code>AbstractValidator</code>.</p>
+ */
+public class ConcreteValidator extends AbstractValidator {
+
+
+    public void validate(FacesContext context, UIComponent component, Object value)
+      throws ValidatorException {
+
+        ; // Do nothing
+
+    }
+    
+
+    // Expose the following protected methods publicly for testing purposes
+
+
+    public ShaleValidatorAction[] actions(FacesContext context, String type) {
+        return super.actions(context, type);
+    }
+
+
+
+    public Object convert(FacesContext context, Object value, Class type) {
+        return super.convert(context, value, type);
+    }
+
+
+    public String message(FacesContext context, String key) {
+        return super.message(context, key);
+    }
+
+
+
+    public ValidatorResources resources(FacesContext context) {
+        return super.resources(context);
+    }
+
+
+
+    public void validate(FacesContext context, UIComponent component,
+                         Object value, String type, Map vars)
+      throws ValidatorException {
+        super.validate(context, component, value, type, vars);
+    }
+
+
+}

Propchange: shale/framework/trunk/shale-validator/src/test/java/org/apache/shale/validator/validator/ConcreteValidator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: shale/framework/trunk/shale-validator/src/test/java/org/apache/shale/validator/validator/ConcreteValidator.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: shale/framework/trunk/shale-validator/src/test/java/org/apache/shale/validator/validator/IntegerValidatorTestCase.java
URL: http://svn.apache.org/viewvc/shale/framework/trunk/shale-validator/src/test/java/org/apache/shale/validator/validator/IntegerValidatorTestCase.java?view=auto&rev=479765
==============================================================================
--- shale/framework/trunk/shale-validator/src/test/java/org/apache/shale/validator/validator/IntegerValidatorTestCase.java (added)
+++ shale/framework/trunk/shale-validator/src/test/java/org/apache/shale/validator/validator/IntegerValidatorTestCase.java Mon Nov 27 13:08:26 2006
@@ -0,0 +1,387 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shale.validator.validator;
+
+import java.util.Locale;
+import java.util.ResourceBundle;
+import javax.faces.component.UIForm;
+import javax.faces.component.UIInput;
+import javax.faces.validator.Validator;
+import javax.faces.validator.ValidatorException;
+import javax.servlet.ServletContextEvent;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+import org.apache.commons.validator.ValidatorAction;
+import org.apache.commons.validator.ValidatorResources;
+import org.apache.shale.test.base.AbstractJsfTestCase;
+import org.apache.shale.validator.faces.ValidatorLifecycleListener;
+import org.apache.shale.validator.util.ShaleValidatorAction;
+
+/**
+ * <p>Test case for <code>IntegerValidator</code>.</p>
+ */
+public class IntegerValidatorTestCase extends AbstractJsfTestCase {
+
+
+    // ------------------------------------------------------------ Constructors
+
+
+    // Construct a new instance of this test case.
+    public IntegerValidatorTestCase(String name) {
+        super(name);
+    }
+
+
+    // ---------------------------------------------------- Overall Test Methods
+
+
+    // Set up instance variables required by this test case.
+    protected void setUp() throws Exception {
+
+        super.setUp();
+        facesContext.getViewRoot().setLocale(Locale.US);
+
+        listener = new ValidatorLifecycleListener();
+        listener.contextInitialized(new ServletContextEvent(servletContext));
+
+        form = new UIForm();
+        form.setId("form");
+        facesContext.getViewRoot().getChildren().add(form);
+
+        input = new UIInput();
+        input.setId("input");
+        form.getChildren().add(input);
+
+        validator = new IntegerValidator();
+        input.addValidator(validator);
+
+    }
+
+
+    // Return the tests included in this test case.
+    public static Test suite() {
+
+        return (new TestSuite(IntegerValidatorTestCase.class));
+
+    }
+
+
+    // Tear down instance variables required by this test case.
+    protected void tearDown() throws Exception {
+
+        validator = null;
+        input = null;
+        form = null;
+
+        listener.contextDestroyed(new ServletContextEvent(servletContext));
+        listener = null;
+
+        super.tearDown();
+
+    }
+
+
+    // -------------------------------------------------------- Static Variables
+
+
+    // ------------------------------------------------------ Instance Variables
+
+
+    /**
+     * <p>The form component for our input form.</p>
+     */
+    private UIForm form = null;
+
+
+    /**
+     * <p>The text field component for our input form.</p>
+     */
+    private UIInput input = null;
+
+
+    /**
+     * <p>ValidatorLifecycleListener used to load configuration resources</p>
+     */
+    private ValidatorLifecycleListener listener = null;
+
+
+    /**
+     * <p>Validator instance under test.</p>
+     */
+    private IntegerValidator validator = null;
+
+
+    // ------------------------------------------------- Individual Test Methods
+
+
+    /**
+     * <p>Tests for invalid input with no range limits.</p>
+     */
+    public void testInvalidInput() {
+
+        // NOTE - null and zero-length string are irrelevant inputs, because
+        // JSF will not call validators in that scenario
+
+        input.setSubmittedValue("a");
+        try {
+            validator.validate(facesContext, input, null);
+            fail("Should have thrown ValidatorException");
+        } catch (ValidatorException e) {
+            ; // Expected result
+//            System.err.println("a: " + e.getFacesMessage().getSummary());
+        }
+
+        input.setSubmittedValue("b123");
+        try {
+            validator.validate(facesContext, input, null);
+            fail("Should have thrown ValidatorException");
+        } catch (ValidatorException e) {
+            ; // Expected result
+//            System.err.println("b123: " + e.getFacesMessage().getSummary());
+        }
+
+        input.setSubmittedValue("456c");
+        try {
+            validator.validate(facesContext, input, null);
+            fail("Should have thrown ValidatorException");
+        } catch (ValidatorException e) {
+            ; // Expected result
+//            System.err.println("456c: " + e.getFacesMessage().getSummary());
+        }
+
+        input.setSubmittedValue(" 789 ");
+        try {
+            validator.validate(facesContext, input, null);
+            fail("Should have thrown ValidatorException");
+        } catch (ValidatorException e) {
+            ; // Expected result
+//            System.err.println(" 789 : " + e.getFacesMessage().getSummary());
+        }
+
+    }
+
+
+    /**
+     * <p>Test cases where a maximum range value has been specified
+     * with an invalid value.</p>
+     */
+    public void testInvalidMaximum() {
+
+        input.setSubmittedValue("234");
+        validator.setMaximum(123);
+        try {
+            validator.validate(facesContext, input, null);
+            fail("Should have thrown ValidatorException");
+        } catch (ValidatorException e) {
+            ; // Expected result
+//            System.err.print("234: " + e.getFacesMessage().getSummary());
+        }
+
+    }
+
+
+    /**
+     * <p>Test cases where a minimum range value has been specified
+     * with an invalid value.</p>
+     */
+    public void testInvalidMinimum() {
+
+        input.setSubmittedValue("123");
+        validator.setMinimum(234);
+        try {
+            validator.validate(facesContext, input, null);
+            fail("Should have thrown ValidatorException");
+        } catch (ValidatorException e) {
+            ; // Expected result
+//            System.err.print("123: " + e.getFacesMessage().getSummary());
+        }
+
+    }
+
+
+    /**
+     * <p>Test cases where a minimum and minimum range value has been specified
+     * with an invalid value.</p>
+     */
+    public void testInvalidRange() {
+
+        input.setSubmittedValue("a");
+        validator.setMinimum(0);
+        validator.setMaximum(234);
+        try {
+            validator.validate(facesContext, input, null);
+            fail("Should have thrown ValidatorException");
+        } catch (ValidatorException e) {
+            ; // Expected result
+//            System.err.println("a: " + e.getFacesMessage().getSummary());
+        }
+
+        input.setSubmittedValue("-1");
+        validator.setMinimum(0);
+        validator.setMaximum(234);
+        try {
+            validator.validate(facesContext, input, null);
+            fail("Should have thrown ValidatorException");
+        } catch (ValidatorException e) {
+            ; // Expected result
+//            System.err.println("-1: " + e.getFacesMessage().getSummary());
+        }
+
+        input.setSubmittedValue("235");
+        validator.setMinimum(0);
+        validator.setMaximum(234);
+        try {
+            validator.validate(facesContext, input, null);
+            fail("Should have thrown ValidatorException");
+        } catch (ValidatorException e) {
+            ; // Expected result
+//            System.err.println("-1: " + e.getFacesMessage().getSummary());
+        }
+
+    }
+
+
+    /**
+     * <p>Tests for valid input with no range limits.</p>
+     */
+    public void testValidInput() {
+
+        // NOTE - null and zero-length string are irrelevant inputs, because
+        // JSF will not call validators in that scenario
+
+        input.setSubmittedValue("0");
+        try {
+            validator.validate(facesContext, input, null);
+        } catch (ValidatorException e) {
+            fail("Should not have thrown ValidatorException: " +
+                    e.getFacesMessage().getSummary());
+        }
+
+        input.setSubmittedValue("123");
+        try {
+            validator.validate(facesContext, input, null);
+        } catch (ValidatorException e) {
+            fail("Should not have thrown ValidatorException: " +
+                    e.getFacesMessage().getSummary());
+        }
+
+        input.setSubmittedValue("-456");
+        try {
+            validator.validate(facesContext, input, null);
+        } catch (ValidatorException e) {
+            fail("Should not have thrown ValidatorException: " +
+                    e.getFacesMessage().getSummary());
+        }
+
+    }
+
+
+    /**
+     * <p>Test cases where a maximum range value has been specified
+     * with a valid value.</p>
+     */
+    public void testValidMaximum() {
+
+        input.setSubmittedValue("123");
+        validator.setMaximum(234);
+        try {
+            validator.validate(facesContext, input, null);
+        } catch (ValidatorException e) {
+            fail("Should not have thrown ValidatorException: " +
+                    e.getFacesMessage().getSummary());
+        }
+
+        input.setSubmittedValue("234");
+        validator.setMaximum(234);
+        try {
+            validator.validate(facesContext, input, null);
+        } catch (ValidatorException e) {
+            fail("Should not have thrown ValidatorException: " +
+                    e.getFacesMessage().getSummary());
+        }
+
+    }
+
+
+    /**
+     * <p>Test cases where a minimum range value has been specified
+     * with a valid value.</p>
+     */
+    public void testValidMinimum() {
+
+        input.setSubmittedValue("0");
+        validator.setMinimum(0);
+        try {
+            validator.validate(facesContext, input, null);
+        } catch (ValidatorException e) {
+            fail("Should not have thrown ValidatorException: " +
+                    e.getFacesMessage().getSummary());
+        }
+
+        input.setSubmittedValue("123");
+        validator.setMinimum(0);
+        try {
+            validator.validate(facesContext, input, null);
+        } catch (ValidatorException e) {
+            fail("Should not have thrown ValidatorException: " +
+                    e.getFacesMessage().getSummary());
+        }
+
+    }
+
+
+    /**
+     * <p>Test cases where a minimum and minimum range value has been specified
+     * with a valid value.</p>
+     */
+    public void testValidRange() {
+
+        input.setSubmittedValue("0");
+        validator.setMinimum(0);
+        validator.setMaximum(234);
+        try {
+            validator.validate(facesContext, input, null);
+        } catch (ValidatorException e) {
+            fail("Should not have thrown ValidatorException: " +
+                    e.getFacesMessage().getSummary());
+        }
+
+        input.setSubmittedValue("123");
+        validator.setMinimum(0);
+        validator.setMaximum(234);
+        try {
+            validator.validate(facesContext, input, null);
+        } catch (ValidatorException e) {
+            fail("Should not have thrown ValidatorException: " +
+                    e.getFacesMessage().getSummary());
+        }
+
+        input.setSubmittedValue("234");
+        validator.setMinimum(0);
+        validator.setMaximum(234);
+        try {
+            validator.validate(facesContext, input, null);
+        } catch (ValidatorException e) {
+            fail("Should not have thrown ValidatorException: " +
+                    e.getFacesMessage().getSummary());
+        }
+
+    }
+
+
+}

Propchange: shale/framework/trunk/shale-validator/src/test/java/org/apache/shale/validator/validator/IntegerValidatorTestCase.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: shale/framework/trunk/shale-validator/src/test/java/org/apache/shale/validator/validator/IntegerValidatorTestCase.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: shale/framework/trunk/shale-validator/src/test/resources/org/apache/shale/validator/TestBundle.properties
URL: http://svn.apache.org/viewvc/shale/framework/trunk/shale-validator/src/test/resources/org/apache/shale/validator/TestBundle.properties?view=auto&rev=479765
==============================================================================
--- shale/framework/trunk/shale-validator/src/test/resources/org/apache/shale/validator/TestBundle.properties (added)
+++ shale/framework/trunk/shale-validator/src/test/resources/org/apache/shale/validator/TestBundle.properties Mon Nov 27 13:08:26 2006
@@ -0,0 +1,20 @@
+# Test Application Resource Bundle
+# -----------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to you under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# -----------------------------------------------------------------------------
+
+errors.Long=Custom Long Error Message
+

Propchange: shale/framework/trunk/shale-validator/src/test/resources/org/apache/shale/validator/TestBundle.properties
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: shale/framework/trunk/shale-validator/src/test/resources/org/apache/shale/validator/TestBundle.properties
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL