Re: Proposed changes to DefaultFormMap & FormType

Shawn Wilson <[email protected]>
Newsgroups gmane.comp.java.enhydra.barracuda.general
Message-ID <[email protected]>
Oops I realized I had a bug in the FormType.java I attached to my last 
email. Please use the version attached to this email instead.

-shawn

Shawn Wilson wrote:
> One behavior of DefaultFormMap doesn't quite ring right to me. As it
> currently is, when DefaultFormMap.map(ServletRequest) is called and any
> element is unparsable then that ParseException is associated to the
> element and mapping continues, like I think it should.
> 
> However, the issue is that when you get to
> DefaultFormMap.validateElements() any element that holds a
> ParseException does not get considered invalid and so validation may
> return successful even though there were problems during parsing.
> Clearly the form is not valid if some of the elements are not parsable.
> 
> I have attached a patched DefaultFormMap.java and FormType.java that I
> believe solve this issue. Do a search for saw_040203.1 to see what I
> changed.
> 
> In order for this behavior to work correctly I had to make a change that
> might impact the way others use DefaultFormMap. Let's say we have a form
> element of type FormType.INTEGER. What currently happens is if the user
> did not enter a value the element attempts to parse the empty string
> into an Integer and so a ParseException occurs. I don't believe this
> should happen since empty strings coming from the ServletRequest should
> really be considered null values. If I want an optional numeric field on
> my web form I should either get back an Integer object or the value
> null, both of which are considered valid. If I don't want null as an
> allowed value then I should of course use the NotNullValidator.
> 
> One other change I made in FormType is I added a message string to each
> of the ParseExceptions that are thrown. This way if you use a generic
> error model like we do you can use ParseException.getMessage() as a
> message to display on the page.
> 
> Does all this make sense? Will these propose changes negatively impact
> the way anyone is currently using DefaultFormMap? Any feedback is welcome.
> 
> Jake/Christian: If this looks good to you guys and no-one else complains
> can you commit these changes to CVS?
> 
> Thanks,
> -shawn
> 
> 
> ------------------------------------------------------------------------
> 
> /*
>  * Enhydra Java Application Server Project
>  *
>  * The contents of this file are subject to the Enhydra Public License
>  * Version 1.1 (the "License"); you may not use this file except in
>  * compliance with the License. You may obtain a copy of the License on
>  * the Enhydra web site (http://www.enhydra.org/).
>  *
>  * Software distributed under the License is distributed on an "AS IS"
>  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
>  * the License for the specific terms governing rights and limitations
>  * under the License.
>  *
>  * The Initial Developer of the Enhydra Application Server is Lutris
>  * Technologies, Inc. The Enhydra Application Server and portions created
>  * by Lutris Technologies, Inc. are Copyright Lutris Technologies, Inc.
>  * All Rights Reserved.
>  *
>  * Contributor(s): Chris Webb, Diez Roggisch, Iman L. Crawford, Christian Cryder, Jacob Kjome
>  *
>  * $Id: FormType.java,v 1.25 2003/04/02 15:57:30 christianc Exp $
>  */
> package org.enhydra.barracuda.core.forms;
> 
> import java.math.BigDecimal;
> import java.text.*;
> import java.util.*;
> 
> import org.enhydra.barracuda.plankton.*;
> 
> /**
>  * This class defines all valid FormTypes. Currently we support:
>  *
>  * <ul>
>  *        <li>String</li>
>  *        <li>Boolean</li>
>  *        <li>Integer</li>
>  *        <li>Long</li>
>  *        <li>Short</li>
>  *        <li>Double</li>
>  *        <li>Float</li>
>  *        <li>BigDecimal</li>
>  *        <li>Date</li>
>  * </ul>
>  * @author  Chris Webb <[email protected]>
>  * @author  Diez Roggisch <[email protected]>
>  * @author  Iman L. Crawford <[email protected]>
>  * @author  Christian Cryder <[email protected]>
>  * @author  Jacob Kjome <[email protected]>
>  * @version %I%, %G%
>  * @since   1.0
>  */
> public abstract class FormType {
> 
>     // String type definition.
>     public static FormType STRING = new FormType() {
>             public Class getFormClass() {
>                 return String.class;
>             }
> 
>             public Object parse(String origVal, Locale locale) throws ParseException {
>                 return origVal;
>             }
> 
>             public Object [] getTypeArray(int size) {
>                 return new String [size];
>             }
> 
>         };
> 
>     // Boolean type definition.
>     public static FormType BOOLEAN = new FormType() {
>             public Class getFormClass() {
>                 return Boolean.class;
>             }
> 
>             public Object parse(String origVal, Locale locale) throws ParseException {
>                 // Eliminate the obvious.
>                 if (origVal==null)
>                     return null;
> 
>                 String tval = origVal.trim().toLowerCase();
>                 //csc_061902.1            if (tval.equals("on") || tval.equals("yes") || tval.equals("true")) {
>                 if (tval.equals("on") || tval.equals("yes") || tval.equals("true") || tval.equals("y")) {   //csc_061902.1
>                     origVal = "true";
>                     //csc_061902.1            } else if (tval.equals("off") || tval.equals("no") || tval.equals("false")) {
>                 } else if (tval.equals("off") || tval.equals("no") || tval.equals("false") || tval.equals("n")) {   //csc_061902.1
>                     origVal = "false";
>                 } else {
>                     //saw_040203.1 - initialize the exception with a message
>                     //throw new ParseException(e);
>                     throw new ParseException(e, "Value must be a boolean");
>                 }
>                 return new Boolean(origVal);
>             }
> 
>             public Object [] getTypeArray(int size) {
>                 return new Boolean [size];
>             }
> 
>         };
> 
>     // Integer type definition.
>     public static FormType INTEGER = new FormType() {
>             public Class getFormClass() {
>                 return Integer.class;
>             }
> 
>             public Object parse(String origVal, Locale locale) throws ParseException {
>                 // Eliminate the obvious.
>                 if (origVal==null)
>                     return null;
> 
>                 try {
>                     return new Integer(origVal);
>                 } catch (NumberFormatException e) {
>                     try {
>                         //this basically handles the case where the user
>                         //typed in an integer value like 123.00...we convert
>                         //that value to a double, then to an int, and then form
>                         //a new double from that. If the values are equal, we
>                         //know no roundoff occurred, meaning the decimal places
>                         //were all zeros, and we're in business. Otherwise, throw
>                         //the exception
>                         Double d1 = new Double(origVal);
>                         int d1val = d1.intValue();
>                         Double d2 = new Double(d1val);
>                         if (d1.equals(d2)) {
>                             return new Integer(d1val);
>                         } else {
>                             throw e;
>                         }
>                     } catch (NumberFormatException e2) {
>                         //saw_040203.1 - initialize the exception with a message
>                         //throw new ParseException(e2);
>                         throw new ParseException(e2, "Value must be a number");
>                     }
>                 }
>             }
>             public Object [] getTypeArray(int size) {
>                 return new Integer [size];
>             }
> 
> 
>         };
> 
>     // Long type definition.
>     public static FormType LONG = new FormType() {
>             public Class getFormClass() {
>                 return Long.class;
>             }
> 
>             public Object parse(String origVal, Locale locale) throws ParseException {
>                 // Eliminate the obvious.
>                 if (origVal==null)
>                     return null;
> 
>                 // ilc_022702.1_start
>                 // check for 0's after decimal place.
>                 // val = new Long(origVal);
>                 try {
>                     return new Long(origVal);
>                 } catch (NumberFormatException e) {
>                     try {
>                         //this basically handles the case where the user
>                         //typed in an integer value like 123.00...we convert
>                         //that value to a double, then to an int, and then form
>                         //a new double from that. If the values are equal, we
>                         //know no roundoff occurred, meaning the decimal places
>                         //were all zeros, and we're in business. Otherwise, throw
>                         //the exception
>                         Double d1 = new Double(origVal);
>                         long d1val = d1.longValue();
>                         Double d2 = new Double(d1val);
>                         if (d1.equals(d2)) {
>                             return new Long(d1val);
>                         } else {
>                             throw e;
>                         }
>                     } catch (NumberFormatException e2) {
>                         //saw_040203.1 - initialize the exception with a message
>                         //throw new ParseException(e2);
>                         throw new ParseException(e2, "Value must be an integer");
>                     }
>                 }
>                 // ilc_022702.1_end
>             }
> 
>             public Object [] getTypeArray(int size) {
>                 return new Long [size];
>             }
> 
>         };
> 
>     // Short type definition.
>     public static FormType SHORT = new FormType() {
>             public Class getFormClass() {
>                 return Short.class;
>             }
> 
>             public Object parse(String origVal, Locale locale) throws ParseException {
>                 // Eliminate the obvious.
>                 if (origVal==null)
>                     return null;
> 
>                 // ilc_022702.2_start
>                 // check for 0's after decimal place.
>                 // val = new Short(origVal);
>                 try {
>                     return new Short(origVal);
>                 } catch (NumberFormatException e) {
>                     try {
>                         //this basically handles the case where the user
>                         //typed in an integer value like 123.00...we convert
>                         //that value to a double, then to an int, and then form
>                         //a new double from that. If the values are equal, we
>                         //know no roundoff occurred, meaning the decimal places
>                         //were all zeros, and we're in business. Otherwise, throw
>                         //the exception
>                         Double d1 = new Double(origVal);
>                         short d1val = d1.shortValue();
>                         Double d2 = new Double(d1val);
>                         if (d1.equals(d2)) {
>                             return new Short(d1val);
>                         } else {
>                             throw e;
>                         }
>                     } catch (NumberFormatException e2) {
>                         //saw_040203.1 - initialize the exception with a message
>                         //throw new ParseException(e2);
>                         throw new ParseException(e2, "Value must be an integer");
>                     }
>                 }
>                 // ilc_022702.2_end
>             }
>             public Object [] getTypeArray(int size) {
>                 return new Short [size];
>             }
> 
>         };
> 
>     // Double type definition.
>     public static FormType DOUBLE = new FormType() {
>             public Class getFormClass() {
>                 return Double.class;
>             }
> 
>             public Object parse(String origVal, Locale locale) throws ParseException {
>                 // Eliminate the obvious.
>                 if (origVal==null)
>                     return null;
>                 
>                 try {
>                     return new Double(origVal);
>                 } catch (NumberFormatException e) {
>                     //saw_040203.1 - initialize the exception with a message
>                     //throw new ParseException(e);
>                     throw new ParseException(e, "Value must be a number");
>                 }
>             }
> 
>             public Object [] getTypeArray(int size) {
>                 return new Double [size];
>             }
> 
>         };
> 
>     // Float type definition.
>     public static FormType FLOAT = new FormType() {
>             public Class getFormClass() {
>                 return Float.class;
>             }
> 
>             public Object parse(String origVal, Locale locale) throws ParseException {
>                 // Eliminate the obvious.
>                 if (origVal==null)
>                     return null;
>                 
>                 try {
>                     return new Float(origVal);
>                 } catch (NumberFormatException e) {
>                     //saw_040203.1 - initialize the exception with a message
>                     //throw new ParseException(e);
>                     throw new ParseException(e, "Value must be a number");
>                 }
>             }
> 
>             public Object [] getTypeArray(int size) {
>                 return new Float [size];
>             }
> 
> 
>         };
> 
>     // BigDecimal type definition.
>     public static FormType BIG_DECIMAL = new FormType() {
>             public Class getFormClass() {
>                 return BigDecimal.class;
>             }
>                 
>             public Object parse(String origVal, Locale locale) throws ParseException {
>                 //csc_060702.1_start - I changed this to use the String constructor since
>                 //the javadocs say that using the Double constructor is unpredicatable. Note
>                 //that I also am stripping out the dollar sign if its there (probably still 
>                 //need to handle other currency symbols, based on locales)
>                 /*
>                   Object d = DOUBLE.parse(origVal, locale);
>                   if (d!=null) {
>                   return new BigDecimal(((Double)d).doubleValue());
>                   }
>                   return null;
>                 */          
>                 //csc_040203.2 - wrapped the logic in a block to catch NumberFormatExceptions...not sure why this hadn't been done originally!
>                 try {
>                     String s = origVal.trim();
>                     s = StringUtil.replace(s, "$","");  //strip off $ sign
>                     s = StringUtil.replace(s, "£","");  //strip off £ sign
>                     s = StringUtil.replace(s, ",","");  //strip off commas
>                     if (s.startsWith("(") && s.endsWith(")")) { //if its a debit (ie. in parenthesis), strip off parenthesis and add a - sign
>                         s = "-"+s.substring(1,s.length()-1);
>                     }
>                     return new BigDecimal(s);
>                 } catch (NumberFormatException e) {
>                     //saw_040203.1 - initialize the exception with a message
>                     //throw new ParseException(e);
>                     throw new ParseException(e, "Value must be a number");
>                 }
> 
> 
>                 //csc_060702.1_end 
>             }
> 
>             public Object [] getTypeArray(int size) {
>                 return new BigDecimal [size];
>             }
> 
> 
> 
>         };
> 
>     // Date type definition.
>     public static FormType DATE = new FormType() {
>             public Class getFormClass() {
>                 return java.util.Date.class;
>             }
> 
>             public Object parse(String origVal, Locale locale) throws ParseException {
>                 // Eliminate the obvious.
>                 if (origVal==null)
>                     return null;
> 
>                 if (locale==null)
>                     locale = Locale.getDefault();
>                 /*
>                 //rtl20010822 - start
>                 DateFormat df = DateFormat.getDateInstance();
>                 df.setLenient(false);
>                 val = df.parse(origVal);
>                 //rtl20010822 - end
>                 */
>                 //rtl20010822 - start new
>                 // try all the various forms of date format to cover more bases
>                 try {
>                     //dbr_011602.1  DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT);
>                     DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, locale); //dbr_011602.1
>                     df.setLenient(false);
>                     return df.parse(origVal);
>                 } catch (java.text.ParseException e1) {
>                     try {
>                         //dbr_011602.1      DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM);
>                         DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM, locale); //dbr_011602.1
>                         df.setLenient(false);
>                         return df.parse(origVal);
>                     } catch (java.text.ParseException e2) {
>                         try {
>                             //dbr_011602.1          DateFormat df = DateFormat.getDateInstance(DateFormat.LONG);
>                             DateFormat df = DateFormat.getDateInstance(DateFormat.LONG, locale); //dbr_011602.1
>                             df.setLenient(false);
>                             return df.parse(origVal);
>                         } catch (java.text.ParseException e3) {
>                             try {
>                                 //dbr_011602.1              DateFormat df = DateFormat.getDateInstance(DateFormat.FULL);
>                                 DateFormat df = DateFormat.getDateInstance(DateFormat.FULL, locale); //dbr_011602.1
>                                 df.setLenient(false);
>                                 return df.parse(origVal);
>                             } catch (java.text.ParseException e4) {
>                                 //saw_040203.1 - initialize the exception with a message
>                                 //throw new ParseException(e4, "Locale is " + locale.getCountry());
>                                 throw new ParseException(e4, "Value must be a date");
>                             }
>                         }
>                     }
>                     //rtl20010822 - end new
>                 }
>             }
> 
>             public Object [] getTypeArray(int size) {
>                 return new Date [size];
>             }
>         };
> 
>     /**
>      * Protected constructor to prevent external instantiation. Cannot be
>      * private because we would be unable to call the constructor from a
>      * sub-class.
>      */
>     protected FormType() { }
> 
>     /**
>      * Returns the class associated with this particular form type.
>      */
>     public abstract Class getFormClass();
> 
>     /**
>      * Parses an object based on the specific form type.
>      */
>     public Object parse(String origVal) throws ParseException {
>         return parse(origVal, null);
>     }
> 
>     /**
>      * Parses an object based on the specific form type.
>      */
>     public abstract Object parse(String origVal, Locale loc) throws ParseException;
> 
> 
>     /** create an array of the FormType's type - if heterogenous types
>      * are returned, an array of Object will be returned.
>      */
>     public abstract Object [] getTypeArray(int size);
> 
>     /**
>      * Returns a string representation of this particular formt type.
>      */
>     public String toString() {
>         return this.getFormClass().getName();
>     }
> 
> }
> 
> 
> 
> ------------------------------------------------------------------------
> 
> /*
>  * Enhydra Java Application Server Project
>  *
>  * The contents of this file are subject to the Enhydra Public License
>  * Version 1.1 (the "License"); you may not use this file except in
>  * compliance with the License. You may obtain a copy of the License on
>  * the Enhydra web site (http://www.enhydra.org/).
>  *
>  * Software distributed under the License is distributed on an "AS IS"
>  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
>  * the License for the specific terms governing rights and limitations
>  * under the License.
>  *
>  * The Initial Developer of the Enhydra Application Server is Lutris
>  * Technologies, Inc. The Enhydra Application Server and portions created
>  * by Lutris Technologies, Inc. are Copyright Lutris Technologies, Inc.
>  * All Rights Reserved.
>  *
>  * Contributor(s): Christian Cryder, Diez B. Roggisch, Jacob Kjome
>  *
>  * $Id: DefaultFormMap.java,v 1.24 2003/01/21 05:42:53 jacobk Exp $
>  */
> package org.enhydra.barracuda.core.forms;
> 
> import java.util.*;
> import java.text.*;
> import javax.servlet.*;
> import javax.servlet.http.*;
> 
> import org.apache.log4j.*;
> 
> import org.enhydra.barracuda.plankton.data.*;
> 
> /**
>  * <p>This class provides the default implementation of a FormMap.
>  *
>  * <p>A FormMap is used to provide a virtual representation of a
>  * form. It can contain any number of unique FormElements, and
>  * it can also be associated with FormValidators. The primary
>  * function of a form map is to:
>  *
>  * <ul>
>  *         <li>define the map (with its elements and validators)</li>
>  *         <li>actually populate the map (from either a ServletRequest
>  *            or a StateMap)</li>
>  *         <li>validate the map (by invoking all the validators associated
>  *            with the form and all its elements)</li>
>  *        <li>provide convenience methods to access the underlying values
>  *            of the form elements contained in this map</li>
>  * </ul>
>  *
>  * @author  Christian Cryder <[email protected]>
>  * @author  Diez B. Roggisch <[email protected]>
>  * @author  Jacob Kjome <[email protected]>
>  * @version %I%, %G%
>  * @since   1.0
>  */
> //public abstract class DefaultFormMap implements FormMap {
> public class DefaultFormMap implements FormMap {
> 
>     //public constants
>     protected static final Logger localLogger = Logger.getLogger(DefaultFormMap.class.getName());
> 
>     private static final String PARSE_EXCEPTION = "ParseException";
> 
>     //non-public vars
>     protected Map elements = new HashMap(10);
>     protected List validators = new ArrayList(5);
>     protected StateMap statemap = new DefaultStateMap();
>     protected static final Locale defaultLoc = Locale.getDefault();  //csc_031402.2
> 
>     //--------------- FormMap ------------------------------------
>     /**
>      * This defines an element to be mapped by this form, using
>      * the key from the FormElement. You would invoke this method
>      * for each element in the form.
>      *
>      * @param element a FormElement to be mapped by this form
>      */
>     public void defineElement(FormElement element) {
>         defineElement(element.getKey(), element);
>     }
> 
>     /**
>      * This defines an element to be mapped by this form.
>      * You would invoke this method for each element in the form.
>      *
>      * @param key the key which uniquely identifies this FormElement
>      * @param element a FormElement to be mapped by this form
>      */
>     public void defineElement(String key, FormElement element) {
>         if (localLogger.isDebugEnabled()) localLogger.debug("Defining FormElement: Key=["+key+"] Element=["+element+"]");
>         elements.put(key, element);
>     }
> 
>     /**
>      * This defines a validator for the entire form. This validator
>      * will be invoked prior to validating specific form element
>      * validators. Calling this method multiple times will result
>      * in multiple form validators being added to the form (they
>      * will be invoked in the order they were added)
>      *
>      * @param validator a form validator to be applied to the entire form
>      */
>     public void defineValidator(FormValidator validator) {
>         if (!validators.contains(validator)) {
>             if (localLogger.isDebugEnabled()) localLogger.debug("Defining validator: Validator=["+validator+"]");
>             validators.add(validator);
>         }
>     }
> 
>     /**
>      * This is where we actually take an incoming form (in
>      * the form of a ServletRequest) and map it using the
>      * definitions supplied by all the FormElements. If there
>      * are multiple parameters for a given key, the values
>      * will be mapped into List structures
>      *
>      * @param req the ServletRequest to map paramters from based on
>      *        all defined FormElements
>      * @return a reference to the FormMap (we do this so you can inline
>      *        map/validate requests if you desire: form.map(req).validate())
>      * @throws MappingException if for some reason the value cannot
>      *        be mapped successfully
>      */
>     public FormMap map(ServletRequest req) {
>         return map(req, null, null);
>     }
> 
>     /**
>      * This is where we actually take an incoming form (in
>      * the form of a ServletRequest) and map it using the
>      * definitions supplied by all the FormElements. If there
>      * are multiple parameters for a given key, the values
>      * will be mapped into List structures
>      *
>      * @param req the ServletRequest to map paramters from based on
>      *        all defined FormElements
>      * @param loc the locale to use when parsing Dates and other locale dependend
>      *        values.
>      * @return a reference to the FormMap (we do this so you can inline
>      *        map/validate requests if you desire: form.map(req).validate())
>      * @throws MappingException if for some reason the value cannot
>      *        be mapped successfully
>      */
>     public FormMap map(ServletRequest req, Locale loc) {
>         return map(req, null, loc);
>     }
> 
>     /**
>      * This is where we actually take an incoming form (in
>      * the form of a ServletRequest) and map it using the
>      * definitions supplied by all the FormElements. If there
>      * are multiple parameters for a given key, the values
>      * will be mapped into List structures
>      *
>      * @param req the ServletRequest to map paramters from based on
>      *        all defined FormElements
>      * @param prefix the prefix to use when mapping parameters
>      *
>      * @return a reference to the FormMap (we do this so you can inline
>      *        map/validate requests if you desire: form.map(req).validate())
>      * @throws MappingException if for some reason the value cannot
>      *        be mapped successfully
>      */
>     public FormMap map(ServletRequest req, String prefix) {
>         return map(req, prefix, null);
>     }
> 
>     /**
>      * This is where we actually take an incoming form (in
>      * the form of a ServletRequest) and map it using the
>      * definitions supplied by all the FormElements. If there
>      * are multiple parameters for a given key, the values
>      * will be mapped into List structures
>      *
>      * if a prefix is given, only the parameters which start with that prefix
>      * are mapped. <b>Important</b>: They are mapped to their name <b>without</b> that prefix.
>      *
>      * @param req the ServletRequest to map paramters from based on
>      *        all defined FormElements
>      * @param prefix the prefix to use when mapping parameters
>      *
>      * @param loc the locale to use when parsing Dates and other locale dependend
>      *        values.
>      * @return a reference to the FormMap (we do this so you can inline
>      *        map/validate requests if you desire: form.map(req).validate())
>      * @throws MappingException if for some reason the value cannot
>      *        be mapped successfully
>      */
>     //public FormMap map(ServletRequest req, Locale loc) {
>     public FormMap map(ServletRequest req, String prefix, Locale loc) {
>         // if we have a prefix, use it
>         // Otherwise, set it to empty string
>         prefix = prefix!=null ? prefix : "";
>         //csc_031402.2        if (loc==null) loc = Locale.getDefault();
>         if (loc==null) loc = defaultLoc;    //csc_031402.2
> 
>         if (localLogger.isInfoEnabled()) localLogger.info("Mapping ServletRequest to FormMap");
>         if (localLogger.isDebugEnabled()) {
>             localLogger.debug("ServletRequest parameters");
>             Map map = new ServletRequestParameterStateMap(req).getStateValues();
>             CollectionsUtil.printStackTrace(map, 0, localLogger, null);
>             localLogger.debug("Map elements");
>             CollectionsUtil.printStackTrace(elements, 0, localLogger, null);
>         }
> 
>         Iterator it = elements.values().iterator();
>         while (it.hasNext()) {
>             //get the next element, determine the original values
>             FormElement element = (FormElement) it.next();
>             if (localLogger.isDebugEnabled()) localLogger.debug("Next FormElement: "+element);
>             //String[] origVals = null;
>             //if (element.allowMultiples()) origVals = req.getParameterValues(element.getKey());
>             /*if (element.allowMultiples()) origVals = req.getParameterValues(prefix + element.getKey());
>             else {
>                 //String param = req.getParameter(element.getKey());
>                 String param = req.getParameter(prefix + element.getKey());
>                 if (param!=null) origVals = new String[]{param};
>             }*/
>             //jrk_020702.1 - The above check is totally unnecessary because both multiple *and*
>             //single parameter values are returned as an Array of String objects.  In the
>             //single value case, it is just an array with a length of 1 just like what is manually
>             //being built above.  Also, no need to pre-assign origVals to null because
>             //getParameterValues returns null if the parameter being requested doesn't exist
>             String[] origVals = req.getParameterValues(prefix + element.getKey());
> 
>             //now map the values. If there are multiple values for
>             //a given key, the values will be mapped into List structures
>             Object origVal = null;
>             Object val = null;
>             if (origVals!=null) {
>                 int max = origVals.length;
>                 if (max==1) {
>                     //if there's only one
>                     origVal = origVals[0];
>                     //val = mapElement(element, origVal);
>                     
>                     //saw_040203.1 start - an empty string original value should be interpreted as
>                     //  null so the mapping can be skipped
>                     //val = mapElement(element, origVal, loc);
>                     if (origVal.equals("")) val = null;
>                     else val = mapElement(element, origVal, loc);
>                     //saw_040203.1 end
>                 } else {
>                     //if there's multiple values
>                     origVal = new ArrayList();
>                     val = new ArrayList();
>                     List lorigVal = (List) origVal;
>                     List lval = (List) val;
>                     for (int i=0; i<max; i++) {
>                         lorigVal.add(origVals[i]);
>                         //lval.add(mapElement(element, origVals[i]));
>                         
>                         //saw_040203.1 start - an empty string original value should be interprested
>                         //  as null so the mapping can be skipped
>                         //lval.add(mapElement(element, origVals[i], loc));
>                         if (origVals[i].equals("")) lval.add(null);
>                         else lval.add(mapElement(element, origVals[i], loc));
>                         //saw_040203.1 end
>                     }
>                 }
>             } else {
>                 //val = mapElement(element, null);
>                 val = mapElement(element, null, loc);
>             }
> 
>             //place the values in the form element
>             element.setOrigVal(origVal);
>             element.setVal(val);
>         }
>         return this;
>     }
> 
>     /**
>      * This is where we actually take an incoming form (in
>      * the form of a StateMap) and map it using the definitions
>      * supplied by all the FormElements.
>      *
>      * @param map the StateMap to map properties from based on
>      *        all defined FormElements
>      * @return a reference to the FormMap (we do this so you can inline
>      *        map/validate requests if you desire: form.map(req).validate())
>      * @throws MappingException if for some reason the value cannot
>      *        be mapped successfully
>      */
>     public FormMap map(StateMap map) {
>         return map(map, null, null);
>     }
> 
>     /**
>      * This is where we actually take an incoming form (in
>      * the form of a StateMap) and map it using the definitions
>      * supplied by all the FormElements.
>      *
>      * @param map the StateMap to map properties from based on
>      *        all defined FormElements
>      * @param prefix the prefix to use when mapping parameters
>      *
>      * @return a reference to the FormMap (we do this so you can inline
>      *        map/validate requests if you desire: form.map(req).validate())
>      * @throws MappingException if for some reason the value cannot
>      *        be mapped successfully
>      */
>     public FormMap map(StateMap map, String prefix) {
>         return map(map, prefix, null);
>     }
> 
>     /**
>      * This is where we actually take an incoming form (in
>      * the form of a StateMap) and map it using the definitions
>      * supplied by all the FormElements.
>      *
>      * @param map the StateMap to map properties from based on
>      *        all defined FormElements
>      * @param loc the locale to use when parsing Dates and other locale dependend
>      *        values.
>      * @return a reference to the FormMap (we do this so you can inline
>      *        map/validate requests if you desire: form.map(req).validate())
>      * @throws MappingException if for some reason the value cannot
>      *        be mapped successfully
>      */
>     public FormMap map(StateMap map, Locale loc) {
>         return map(map, null, loc);
>     }
> 
>     /**
>      * This is where we actually take an incoming form (in
>      * the form of a StateMap) and map it using the definitions
>      * supplied by all the FormElements.
>      *
>      * @param map the StateMap to map properties from based on
>      *        all defined FormElements
>      * @param prefix the prefix to use when mapping parameters
>      *
>      * @param loc the locale to use when parsing Dates and other locale dependend
>      *        values.
>      * @return a reference to the FormMap (we do this so you can inline
>      *        map/validate requests if you desire: form.map(req).validate())
>      * @throws MappingException if for some reason the value cannot
>      *        be mapped successfully
>      */
>     //public FormMap map(StateMap map, Locale loc) {
>     public FormMap map(StateMap map, String prefix, Locale loc) {
>         // if we have a prefix, use it
>         // Otherwise, set it to empty string
>         prefix = prefix!=null ? prefix : "";
>         //csc_031402.2        if (loc==null) loc = Locale.getDefault();
>         if (loc==null) loc = defaultLoc;    //csc_031402.2
> 
>         if (localLogger.isInfoEnabled()) localLogger.info("Mapping StateMap to FormMap");
>         Iterator it = elements.values().iterator();
>         while (it.hasNext()) {
>             //get the next element, determine the original value
>             FormElement element = (FormElement) it.next();
>             //Object origVal = map.getState(element.getKey());
>             Object origVal = map.getState(prefix + element.getKey());
> 
>             //now map the element
>             //Object val = mapElement(element, origVal);
>             Object val = mapElement(element, origVal, loc);
> 
>             //place the values in the form element
>             element.setOrigVal(origVal);
>             element.setVal(val);
>         }
>         return this;
>     }
> 
>     //csc_031402.2_start
>     /**
>      * This allows you to map a single value (as opposed to passing in a
>      * whole statemap or request).
>      *
>      * @param key the name of the element we wish to map to
>      * @param origVal the original value to be mapped
>      * @return the newly mapped form element
>      */
>     public FormElement mapElement(String key, Object origVal) {
>         return mapElement(key, origVal, null);
>     }
> 
>     /**
>      * This allows you to map a single value (as opposed to passing in a
>      * whole statemap or request).
>      *
>      * @param key the name of the element we wish to map to
>      * @param origVal the original value to be mapped
>      * @param loc the locale to use when parsing Dates and other locale dependant values.
>      * @return the newly mapped form element
>      */
>     public FormElement mapElement(String key, Object origVal, Locale loc) {
>         //assign a default loc if need be
>         if (loc==null) loc = defaultLoc;
> 
>         //get the for element
>         FormElement element = getElement(key);
>         if (element!=null) {
>             //now map the element
>             Object val = mapElement(element, origVal, loc);
> 
>             //place the values in the form element
>             element.setOrigVal(origVal);
>             element.setVal(val);
>         }
>         return element;
>     }
>     //csc_031402.2_end
> 
>     /**
>      * This maps a form element and
>      *
>      * @param element a FormElement to be mapped by this form
>      * @param origVal the original value of the form element
>      * @param loc the locale to use when parsing Dates and other locale dependend
>      *        values.
>      * @return the original value of the form element, the default value
>      *         (if the original value is null) or null neither the original
>      *         value nor the default value can be determined
>      */
>     //private Object mapElement(FormElement element, Object origVal) {
>     private Object mapElement(FormElement element, Object origVal, Locale loc) {
>         //jrk_020702.2 - Note: I changed origVal from being a String to an Object
>         //because everything calling this had to call Object.toString() when sending
>         //in origVal and had to do a null check before doing that.  Having origVal be
>         //a generic object cleans that up.  Also, I change this method to be private
>         //since this was the only class using it.  If other classes start needing it,
>         //it can be changed back to protected or public (not likely).
>         if (localLogger.isInfoEnabled()) localLogger.info("Mapping Element: "+element.getKey()+"="+origVal);
>         Object val = null;
>         FormType type = element.getType();
> 
>         if (origVal!=null) {
>             //parse the value; catch any exceptions and use the default
>             //value instead
>             try {
>                 //val = type.parse(origVal.toString());
>                 // ilc_022702.1_start
>                 // don't need to parse if origVal is the expected type
>                 Class typeclass = type.getFormClass();
>                 if (typeclass.isInstance(origVal))
>                   val = origVal;
>                 else
>                 // ilc_022702.1_end
>                   val = type.parse(origVal.toString(), loc);
>             } catch (ParseException e) {
>                 if (localLogger.isDebugEnabled()) localLogger.debug("ParseException:", e);
>                 element.setParseException(e);
>             }
>         }
> 
>         if (val==null) {
>             if (localLogger.isDebugEnabled()) localLogger.debug("Using default val");
>             val = element.getDefaultVal();
>         }
> 
>         if (localLogger.isDebugEnabled()) localLogger.debug("Result: "+val);
>         return val;
>     }
> 
>     /**
>      * Validate the entire form (both form level and elements).
>      * We start by invoking form validators which apply to individual
>      * form elements, then we invoke any which apply to the entire form
>      *
>      * @param deferExceptions do we want to deferValidation exceptions
>      *        and attempt to validate all elements so that we can process
>      *        all the exceptions at once
>      * @return a reference to the FormMap (we do this so you can inline
>      *        map/validate requests if you desire: form.map(req).validate())
>      * @throws ValidationException if the form (or any element within it)
>      *        is invalid
>      */
>     public FormMap validate(boolean deferExceptions) throws ValidationException {
>         if (localLogger.isInfoEnabled()) localLogger.info("Validating FormMap (form & elements)");
>         ValidationException ve = null;
> 
>         try {
>             //validate each individual element
>             try {
>                 validateElements(deferExceptions);
>             } catch (DeferredValidationException dve) {
>                 if (ve==null) ve = new DeferredValidationException(dve.getSource(), "Validation err:"+dve);
>                 ve.addSubException(dve);
>             }
> 
>             //validate the entire form
>             try {
>                 validateForm(deferExceptions);
>             } catch (DeferredValidationException dve) {
>                 if (ve==null) ve = new DeferredValidationException(dve.getSource(), "Validation err:"+dve);
>                 ve.addSubException(dve);
>             }
>         } catch (ValidationException e) {
>             if (localLogger.isDebugEnabled()) localLogger.debug("Validation err! (immediate): ", e);
>             throw e;
>         }
> 
>         //now, if we have generated a ValidationExceptions,
>         //rethrow it
>         if (ve!=null) throw ve;
>         return this;
>     }
> 
>     /**
>      * Validate just the elements (not the form)
>      *
>      * @param deferExceptions do we want to deferValidation exceptions
>      *        and attempt to validate all elements so that we can process
>      *        all the exceptions at once
>      * @return a reference to the FormMap (we do this so you can inline
>      *        map/validate requests if you desire: form.map(req).validate())
>      * @throws ValidationException if the form (or any element within it)
>      *        is invalid
>      */
>     public FormMap validateElements(boolean deferExceptions) throws ValidationException {
>         if (localLogger.isInfoEnabled()) localLogger.info("Validating FormMap (elements)");
>         ValidationException ve = null;
> 
>         try {
>             //validate each individual element
>             if (localLogger.isDebugEnabled()) localLogger.debug("Validating individual elements...");
>             Iterator it = elements.values().iterator();
>             FormElement element = null;
>             while (it.hasNext()) {
>                 try {
>                     element = (FormElement) it.next();
>                     if (localLogger.isDebugEnabled()) localLogger.debug("Next FormElement: "+element);
>                     
>                     //saw_040203.1 start - a ValidationException should be thrown if the element
>                     //  contains a ParseException since any unparsable element should not be
>                     //  considered valid.
>                     ParseException pe = element.getParseException();
>                     if (pe != null) {
>                         if (localLogger.isDebugEnabled()) localLogger.debug("Element Invalid... has ParseException: "+pe);
>                         //create a new exception so that the exception contains a reference to the
>                         //FormElement as the source object
>                         if (deferExceptions) throw new DeferredValidationException(element, pe.getMessage());
>                         else throw new ValidationException(element, pe.getMessage());
>                     }
>                     //saw_040203.1 end
>                     
>                     FormValidator fv = element.getValidator();
>                     if (fv!=null) fv.validate(element, this, deferExceptions);
>                     if (localLogger.isDebugEnabled()) localLogger.debug("Element Valid!");
>                 } catch (DeferredValidationException dve) {
>                     if (localLogger.isDebugEnabled()) localLogger.debug("Element Invalid! (deferred): "+dve.getMessage());
>                     if (ve==null) ve = new DeferredValidationException(element, "Validation err:"+dve);
>                     ve.addSubException(dve);
>                 }
>             }
>         } catch (ValidationException e) {
>             if (localLogger.isDebugEnabled()) localLogger.debug("Validation err! (immediate): ", e);
>             throw e;
>         }
> 
>         //now, if we have generated a ValidationExceptions,
>         //rethrow it
>         if (ve!=null) throw ve;
>         return this;
>     }
> 
>     /**
>      * Validate just the form (not the individual elements)
>      *
>      * @param deferExceptions do we want to deferValidation exceptions
>      *        and attempt to validate all elements so that we can process
>      *        all the exceptions at once
>      * @return a reference to the FormMap (we do this so you can inline
>      *        map/validate requests if you desire: form.map(req).validate())
>      * @throws ValidationException if the form (or any element within it)
>      *        is invalid
>      */
>     public FormMap validateForm(boolean deferExceptions) throws ValidationException {
>         if (localLogger.isInfoEnabled()) localLogger.info("Validating FormMap (form)");
>         ValidationException ve = null;
> 
>         try {
>             //validate the entire form
>             if (localLogger.isDebugEnabled()) localLogger.debug("Validating entire form...");
>             try {
>                 Iterator it = validators.iterator();
>                 while (it.hasNext()) {
>                     Object obj = it.next();
>                     if (localLogger.isDebugEnabled()) localLogger.debug("Next obj:"+obj);
>                     FormValidator fv = (FormValidator) obj;
>                     if (localLogger.isDebugEnabled()) localLogger.debug("Next FormValidator: "+fv);
>                     fv.validate(null, this, deferExceptions);
>                     if (localLogger.isDebugEnabled()) localLogger.debug("Form Valid!");
>                 }
>             } catch (DeferredValidationException dve) {
>                 if (localLogger.isDebugEnabled()) localLogger.debug("Form Invalid! (deferred): ", dve);
>                 if (ve==null) ve = new DeferredValidationException(this, "Validation err:"+dve);
>                 ve.addSubException(dve);
>             }
>         } catch (ValidationException e) {
>             if (localLogger.isDebugEnabled()) localLogger.debug("Validation err! (immediate): ", e);
>             throw e;
>         }
> 
>         //now, if we have generated a ValidationExceptions,
>         //rethrow it
>         if (ve!=null) throw ve;
>         return this;
>     }
> 
> 
> 
>     //-------------------- StateMap ------------------------------
>     /**
>      * set a property in this StateMap
>      *
>      * @param key the state key object
>      * @param val the state value object
>      */
>     public void putState(Object key, Object val) {
>         statemap.putState(key,val);
>     }
> 
>     /**
>      * get a property in this StateMap
>      *
>      * @param key the state key object
>      * @return the value for the given key
>      */
>     public Object getState(Object key) {
>         return statemap.getState(key);
>     }
> 
>     /**
>      * remove a property in this StateMap
>      *
>      * @param key the key object
>      * @return the object which was removed
>      */
>     public Object removeState(Object key) {
>         return statemap.removeState(key);
>     }
> 
>     /**
>      * get a list of the keys for this StateMap
>      *
>      * @return a list the keys for this StateMap
>      */
>     public List getStateKeys() {
>         return statemap.getStateKeys();
>     }
> 
>     /**
>      * get a copy of the underlying Map
>      *
>      * @return a copy of the underlying state Map
>      */
>     public Map getStateValues() {
>         return statemap.getStateValues();
>     }
> 
> 
>     //--------------- Convenience methods ------------------------
>     /**
>      * Return true if an element exists and its value is not null
>      *
>      * @param key the key which uniquely identifies this FormElement
>      * @return true if an element exists (not null)
>      */
>     public boolean exists(String key) {
>         FormElement fel = (FormElement) elements.get(key);
>         if (fel==null) return false;
>         return (fel.getVal()!=null);
>     }
> 
>     /**
>      * Get an element by key
>      *
>      * @param key the key which uniquely identifies this FormElement
>      * @return the FormElement for this key (may be null)
>      */
>     public FormElement getElement(String key) {
>         return (FormElement) elements.get(key);
>     }
> 
>     /**
>      * return a map with containing all the elements in this form map
>      *
>      * @return a copy of the Map that backs this FormMap
>      */
>     public Map getElements() {
>         return new HashMap(elements);
>     }
> 
>     //csc_041602.1 - readded (seems to have gotten deleted from the previous revision)
>     /**
>      * Get a map with containing the values for all the elements in this form map
>      *
>      * @param key the key which uniquely identifies this FormElement
>      * @return the value for this key (may be null)
>      */
>     public Map getElementVals() {
>         Map valmap = new HashMap();
>         Iterator it = elements.keySet().iterator();
>         FormElement el = null;
>         while (it.hasNext()) {
>             String key = (String) it.next();
>             el = (FormElement) elements.get(key);
>             if (el==null) valmap.put(key, el);
>             else valmap.put(key, el.getVal());
>         }
>         return valmap;
>     }
> 
>     /**
>      * Manually set the value of an element. If an element does not
>      * exist for this key one will be created.
>      *
>      * @param key the key
>      * @param val the value for the key
>      */
>     public void setVal(String key, Object val) {
>         FormElement el = (FormElement) elements.get(key);
>         if (el==null) {
>             el = new DefaultFormElement(key);
>             defineElement(key, el);
>         }
>         el.setVal(val);
>     }
> 
>     /**
>      * Get the value for a given key. This is basically a convenience
>      * method. You could manually grab the FormElement using getElement
>      * and then retrieve the value that way as well. Note that if the
>      * particular FormElement supports multiple values, then this call
>      * will only return the first value in the array; to get all the values,
>      * use the getVals() function.
>      *
>      * @param key the key which uniquely identifies this FormElement
>      * @return the value for this key (may be null)
>      */
>     public Object getVal(String key) {
>         FormElement el = (FormElement) elements.get(key);
>         if (el==null) return null;
>         else return el.getVal();
>     }
> 
>     /**
>      * Get an array of values for a given key. This is basically a convenience
>      * method. You could manually grab the FormElement using getElement
>      * and then retrieve the value that way as well. You should only use this
>      * method if the particular FormElement has allowMultiples = true
>      *
>      * @param key the key which uniquely identifies this FormElement
>      * @return the value for this key (may be null)
>      */
>     public Object[] getVals(String key) {
>         FormElement el = (FormElement) elements.get(key);
>         if (el==null) return null;
>         else return el.getVals();
>     }
> 
>     /**
>      * Get a String value from the map
>      *
>      * @param key the form element key
>      * @return the value for the given key (may be null
>      *        if the value is not set or the key does not match
>      *        a known form element)
>      */
>     public String getStringVal(String key) {
>         FormElement el = (FormElement) elements.get(key);
>         if (el==null) return null;
>         else return (String) el.getVal();
>     }
> 
>     /**
>      * Get the value for a given key, defaulting accordingly if
>      * the value is null.
>      *
>      * @param key the key which uniquely identifies this FormElement
>      * @param dflt the default value to be used if the underlying value is null
>      * @return the value for this key (may be null)
>      */
>     public String getStringVal(String key, String dflt) {
>         String val = getStringVal(key);
>         return (val!=null ? val : dflt);
>     }
> 
>     /**
>      * Get an Boolean value from the map
>      *
>      * @param key the form element key
>      * @return the value for the given key (may be null
>      *        if the value is not set or the key does not match
>      *        a known form element)
>      */
>     public Boolean getBooleanVal(String key) {
>         FormElement el = (FormElement) elements.get(key);
>         if (el==null) return null;
>         else return (Boolean) el.getVal();
>     }
> 
>     /**
>      * Get the value for a given key, defaulting accordingly if
>      * the value is null.
>      *
>      * @param key the key which uniquely identifies this FormElement
>      * @param dflt the default value to be used if the underlying value is null
>      * @return the value for this key (may be null)
>      */
>     public Boolean getBooleanVal(String key, Boolean dflt) {
>         Boolean val = getBooleanVal(key);
>         return (val!=null ? val : dflt);
>     }
> 
>     /**
>      * Get an Integer value from the map
>      *
>      * @param key the form element key
>      * @return the value for the given key (may be null
>      *        if the value is not set or the key does not match
>      *        a known form element)
>      */
>     public Integer getIntegerVal(String key) {
>         FormElement el = (FormElement) elements.get(key);
>         if (el==null) return null;
>         else return (Integer) el.getVal();
>     }
> 
>     /**
>      * Get the value for a given key, defaulting accordingly if
>      * the value is null.
>      *
>      * @param key the key which uniquely identifies this FormElement
>      * @param dflt the default value to be used if the underlying value is null
>      * @return the value for this key (may be null)
>      */
>     public Integer getIntegerVal(String key, Integer dflt) {
>         Integer val = getIntegerVal(key);
>         return (val!=null ? val : dflt);
>     }
> 
>     /**
>      * Get an Date value from the map
>      *
>      * @param key the form element key
>      * @return the value for the given key (may be null
>      *        if the value is not set or the key does not match
>      *        a known form element)
>      */
>     public Date getDateVal(String key) {
>         FormElement el = (FormElement) elements.get(key);
>         if (el==null) return null;
>         else return (Date) el.getVal();
>     }
> 
>     /**
>      * Get the value for a given key, defaulting accordingly if
>      * the value is null.
>      *
>      * @param key the key which uniquely identifies this FormElement
>      * @param dflt the default value to be used if the underlying value is null
>      * @return the value for this key (may be null)
>      */
>     public Date getDateVal(String key, Date dflt) {
>         Date val = getDateVal(key);
>         return (val!=null ? val : dflt);
>     }
> 
>     /**
>      * Get an Long value from the map
>      *
>      * @param key the form element key
>      * @return the value for the given key (may be null
>      *        if the value is not set or the key does not match
>      *        a known form element)
>      */
>     public Long getLongVal(String key) {
>         FormElement el = (FormElement) elements.get(key);
>         if (el==null) return null;
>         else return (Long) el.getVal();
>     }
> 
>     /**
>      * Get the value for a given key, defaulting accordingly if
>      * the value is null.
>      *
>      * @param key the key which uniquely identifies this FormElement
>      * @param dflt the default value to be used if the underlying value is null
>      * @return the value for this key (may be null)
>      */
>     public Long getLongVal(String key, Long dflt) {
>         Long val = getLongVal(key);
>         return (val!=null ? val : dflt);
>     }
> 
>     /**
>      * Get an Short value from the map
>      *
>      * @param key the form element key
>      * @return the value for the given key (may be null
>      *        if the value is not set or the key does not match
>      *        a known form element)
>      */
>     public Short getShortVal(String key) {
>         FormElement el = (FormElement) elements.get(key);
>         if (el==null) return null;
>         else return (Short) el.getVal();
>     }
> 
>     /**
>      * Get the value for a given key, defaulting accordingly if
>      * the value is null.
>      *
>      * @param key the key which uniquely identifies this FormElement
>      * @param dflt the default value to be used if the underlying value is null
>      * @return the value for this key (may be null)
>      */
>     public Short getShortVal(String key, Short dflt) {
>         Short val = getShortVal(key);
>         return (val!=null ? val : dflt);
>     }
> 
>     /**
>      * Get an Double value from the map
>      *
>      * @param key the form element key
>      * @return the value for the given key (may be null
>      *        if the value is not set or the key does not match
>      *        a known form element)
>      */
>     public Double getDoubleVal(String key) {
>         FormElement el = (FormElement) elements.get(key);
>         if (el==null) return null;
>         else return (Double) el.getVal();
>     }
> 
>     /**
>      * Get the value for a given key, defaulting accordingly if
>      * the value is null.
>      *
>      * @param key the key which uniquely identifies this FormElement
>      * @param dflt the default value to be used if the underlying value is null
>      * @return the value for this key (may be null)
>      */
>     public Double getDoubleVal(String key, Double dflt) {
>         Double val = getDoubleVal(key);
>         return (val!=null ? val : dflt);
>     }
> 
>     /**
>      * Get an Float value from the map
>      *
>      * @param key the form element key
>      * @return the value for the given key (may be null
>      *        if the value is not set or the key does not match
>      *        a known form element)
>      */
>     public Float getFloatVal(String key) {
>         FormElement el = (FormElement) elements.get(key);
>         if (el==null) return null;
>         else return (Float) el.getVal();
>     }
> 
>     /**
>      * Get the value for a given key, defaulting accordingly if
>      * the value is null.
>      *
>      * @param key the key which uniquely identifies this FormElement
>      * @param dflt the default value to be used if the underlying value is null
>      * @return the value for this key (may be null)
>      */
>     public Float getFloatVal(String key, Float dflt) {
>         Float val = getFloatVal(key);
>         return (val!=null ? val : dflt);
>     }
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
> //I don't think these are needed if we go back to the older/terser naming convention
> 
>     /**
>      * Get the value for a given key. This is basically a convenience
>      * method. You could manually grab the FormElement using getElement
>      * and then retrieve the value that way as well.
>      *
>      * @param key the key which uniquely identifies this FormElement
>      * @return the value for this key (may be null)
>      */
> /*
>     public Object getSingleValue(String key) {
>         FormElement el = (FormElement) elements.get(key);
>         if (el==null) return null;
>         else return el.getSingleValue();
>     }
> */
>     /**
>      * Get the value for a given key. This is basically a convenience
>      * method. You could manually grab the FormElement using getElement
>      * and then retrieve the value that way as well.
>      *
>      * @param key the key which uniquely identifies this FormElement
>      * @return the value for this key (may be null)
>      */
> /*
>     public Object [] getMultipleValues(String key) {
>         FormElement el = (FormElement) elements.get(key);
>         if (el==null) return null;
>         else return el.getMultipleValues();
>     }
> */
>     /**
>      * Get a String value from the map
>      *
>      * @param key the form element key
>      * @return the value for the given key (may be null
>      *        if the value is not set or the key does not match
>      *        a known form element)
>      */
> /*
>     public String getSingleStringValue(String key) {
>         FormElement el = (FormElement) elements.get(key);
>         if (el==null) return null;
>         else return (String) el.getSingleValue();
>     }
> */
> 
>     /**
>      * Get the value for a given key, defaulting accordingly if
>      * the value is null.
>      *
>      * @param key the key which uniquely identifies this FormElement
>      * @param dflt the default value to be used if the underlying value is null
>      * @return the value for this key (may be null)
>      */
> /*
>     public String getSingleStringValue(String key, String dflt) {
>         String val = getSingleStringValue(key);
>         return (val!=null ? val : dflt);
>     }
> */
> 
>     /**
>      * Get an Boolean value from the map
>      *
>      * @param key the form element key
>      * @return the value for the given key (may be null
>      *        if the value is not set or the key does not match
>      *        a known form element)
>      */
> /*
>     public Boolean getSingleBooleanValue(String key) {
>         FormElement el = (FormElement) elements.get(key);
>         if (el==null) return null;
>         else return (Boolean) el.getSingleValue();
>     }
> */
> 
>     /**
>      * Get the value for a given key, defaulting accordingly if
>      * the value is null.
>      *
>      * @param key the key which uniquely identifies this FormElement
>      * @param dflt the default value to be used if the underlying value is null
>      * @return the value for this key (may be null)
>      */
> /*
>     public Boolean getSingleBooleanValue(String key, Boolean dflt) {
>         Boolean val = getSingleBooleanValue(key);
>         return (val!=null ? val : dflt);
>     }
> */
> 
>     /**
>      * Get an Integer value from the map
>      *
>      * @param key the form element key
>      * @return the value for the given key (may be null
>      *        if the value is not set or the key does not match
>      *        a known form element)
>      */
> /*
>     public Integer getSingleIntegerValue(String key) {
>         FormElement el = (FormElement) elements.get(key);
>         if (el==null) return null;
>         else return (Integer) el.getSingleValue();
>     }
> */
> 
>     /**
>      * Get the value for a given key, defaulting accordingly if
>      * the value is null.
>      *
>      * @param key the key which uniquely identifies this FormElement
>      * @param dflt the default value to be used if the underlying value is null
>      * @return the value for this key (may be null)
>      */
> /*
>     public Integer getSingleIntegerValue(String key, Integer dflt) {
>         Integer val = getSingleIntegerValue(key);
>         return (val!=null ? val : dflt);
>     }
> */
> 
>     /**
>      * Get an Date value from the map
>      *
>      * @param key the form element key
>      * @return the value for the given key (may be null
>      *        if the value is not set or the key does not match
>      *        a known form element)
>      */
> /*
>     public Date getSingleDateValue(String key) {
>         FormElement el = (FormElement) elements.get(key);
>         if (el==null) return null;
>         else return (Date) el.getSingleValue();
>     }
> */
> 
>     /**
>      * Get the value for a given key, defaulting accordingly if
>      * the value is null.
>      *
>      * @param key the key which uniquely identifies this FormElement
>      * @param dflt the default value to be used if the underlying value is null
>      * @return the value for this key (may be null)
>      */
> /*
>     public Date getSingleDateValue(String key, Date dflt) {
>         Date val = getSingleDateValue(key);
>         return (val!=null ? val : dflt);
>     }
> */
> 
>     /**
>      * Get an Long value from the map
>      *
>      * @param key the form element key
>      * @return the value for the given key (may be null
>      *        if the value is not set or the key does not match
>      *        a known form element)
>      */
> /*
>     public Long getSingleLongValue(String key) {
>         FormElement el = (FormElement) elements.get(key);
>         if (el==null) return null;
>         else return (Long) el.getSingleValue();
>     }
> */
> 
>     /**
>      * Get the value for a given key, defaulting accordingly if
>      * the value is null.
>      *
>      * @param key the key which uniquely identifies this FormElement
>      * @param dflt the default value to be used if the underlying value is null
>      * @return the value for this key (may be null)
>      */
> /*
>     public Long getSingleLongValue(String key, Long dflt) {
>         Long val = getSingleLongValue(key);
>         return (val!=null ? val : dflt);
>     }
> */
> 
>     /**
>      * Get an Short value from the map
>      *
>      * @param key the form element key
>      * @return the value for the given key (may be null
>      *        if the value is not set or the key does not match
>      *        a known form element)
>      */
> /*
>     public Short getSingleShortValue(String key) {
>         FormElement el = (FormElement) elements.get(key);
>         if (el==null) return null;
>         else return (Short) el.getSingleValue();
>     }
> */
> 
>     /**
>      * Get the value for a given key, defaulting accordingly if
>      * the value is null.
>      *
>      * @param key the key which uniquely identifies this FormElement
>      * @param dflt the default value to be used if the underlying value is null
>      * @return the value for this key (may be null)
>      */
> /*
>     public Short getSingleShortValue(String key, Short dflt) {
>         Short val = getSingleShortValue(key);
>         return (val!=null ? val : dflt);
>     }
> */
> 
>     /**
>      * Get an Double value from the map
>      *
>      * @param key the form element key
>      * @return the value for the given key (may be null
>      *        if the value is not set or the key does not match
>      *        a known form element)
>      */
> /*
>     public Double getSingleDoubleValue(String key) {
>         FormElement el = (FormElement) elements.get(key);
>         if (el==null) return null;
>         else return (Double) el.getSingleValue();
>     }
> */
> 
>     /**
>      * Get the value for a given key, defaulting accordingly if
>      * the value is null.
>      *
>      * @param key the key which uniquely identifies this FormElement
>      * @param dflt the default value to be used if the underlying value is null
>      * @return the value for this key (may be null)
>      */
> /*
>     public Double getSingleDoubleValue(String key, Double dflt) {
>         Double val = getSingleDoubleValue(key);
>         return (val!=null ? val : dflt);
>     }
> */
> 
>     /**
>      * Get an Float value from the map
>      *
>      * @param key the form element key
>      * @return the value for the given key (may be null
>      *        if the value is not set or the key does not match
>      *        a known form element)
>      */
> /*
>     public Float getSingleFloatValue(String key) {
>         FormElement el = (FormElement) elements.get(key);
>         if (el==null) return null;
>         else return (Float) el.getSingleValue();
>     }
> */
> 
>     /**
>      * Get the value for a given key, defaulting accordingly if
>      * the value is null.
>      *
>      * @param key the key which uniquely identifies this FormElement
>      * @param dflt the default value to be used if the underlying value is null
>      * @return the value for this key (may be null)
>      */
> /*
>     public Float getSingleFloatValue(String key, Float dflt) {
>         Float val = getSingleFloatValue(key);
>         return (val!=null ? val : dflt);
>     }
> */
> 
> }
>
FormType.java (text/plain, 17 KB)
/*
 * Enhydra Java Application Server Project
 *
 * The contents of this file are subject to the Enhydra Public License
 * Version 1.1 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License on
 * the Enhydra web site (http://www.enhydra.org/).
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
 * the License for the specific terms governing rights and limitations
 * under the License.
 *
 * The Initial Developer of the Enhydra Application Server is Lutris
 * Technologies, Inc. The Enhydra Application Server and portions created
 * by Lutris Technologies, Inc. are Copyright Lutris Technologies, Inc.
 * All Rights Reserved.
 *
 * Contributor(s): Chris Webb, Diez Roggisch, Iman L. Crawford, Christian Cryder, Jacob Kjome
 *
 * $Id: FormType.java,v 1.25 2003/04/02 15:57:30 christianc Exp $
 */
package org.enhydra.barracuda.core.forms;

import java.math.BigDecimal;
import java.text.*;
import java.util.*;

import org.enhydra.barracuda.plankton.*;

/**
 * This class defines all valid FormTypes. Currently we support:
 *
 * <ul>
 *        <li>String</li>
 *        <li>Boolean</li>
 *        <li>Integer</li>
 *        <li>Long</li>
 *        <li>Short</li>
 *        <li>Double</li>
 *        <li>Float</li>
 *        <li>BigDecimal</li>
 *        <li>Date</li>
 * </ul>
 * @author  Chris Webb <[email protected]>
 * @author  Diez Roggisch <[email protected]>
 * @author  Iman L. Crawford <[email protected]>
 * @author  Christian Cryder <[email protected]>
 * @author  Jacob Kjome <[email protected]>
 * @version %I%, %G%
 * @since   1.0
 */
public abstract class FormType {

    // String type definition.
    public static FormType STRING = new FormType() {
            public Class getFormClass() {
                return String.class;
            }

            public Object parse(String origVal, Locale locale) throws ParseException {
                return origVal;
            }

            public Object [] getTypeArray(int size) {
                return new String [size];
            }

        };

    // Boolean type definition.
    public static FormType BOOLEAN = new FormType() {
            public Class getFormClass() {
                return Boolean.class;
            }

            public Object parse(String origVal, Locale locale) throws ParseException {
                // Eliminate the obvious.
                if (origVal==null)
                    return null;

                String tval = origVal.trim().toLowerCase();
                //csc_061902.1            if (tval.equals("on") || tval.equals("yes") || tval.equals("true")) {
                if (tval.equals("on") || tval.equals("yes") || tval.equals("true") || tval.equals("y")) {   //csc_061902.1
                    origVal = "true";
                    //csc_061902.1            } else if (tval.equals("off") || tval.equals("no") || tval.equals("false")) {
                } else if (tval.equals("off") || tval.equals("no") || tval.equals("false") || tval.equals("n")) {   //csc_061902.1
                    origVal = "false";
                } else {
                    //saw_040203.1 - initialize the exception with a message
                    //throw new ParseException(origVal);
                    throw new ParseException(origVal, "Value must be a boolean");
                }
                return new Boolean(origVal);
            }

            public Object [] getTypeArray(int size) {
                return new Boolean [size];
            }

        };

    // Integer type definition.
    public static FormType INTEGER = new FormType() {
            public Class getFormClass() {
                return Integer.class;
            }

            public Object parse(String origVal, Locale locale) throws ParseException {
                // Eliminate the obvious.
                if (origVal==null)
                    return null;

                try {
                    return new Integer(origVal);
                } catch (NumberFormatException e) {
                    try {
                        //this basically handles the case where the user
                        //typed in an integer value like 123.00...we convert
                        //that value to a double, then to an int, and then form
                        //a new double from that. If the values are equal, we
                        //know no roundoff occurred, meaning the decimal places
                        //were all zeros, and we're in business. Otherwise, throw
                        //the exception
                        Double d1 = new Double(origVal);
                        int d1val = d1.intValue();
                        Double d2 = new Double(d1val);
                        if (d1.equals(d2)) {
                            return new Integer(d1val);
                        } else {
                            throw e;
                        }
                    } catch (NumberFormatException e2) {
                        //saw_040203.1 - initialize the exception with a message
                        //throw new ParseException(e2);
                        throw new ParseException(e2, "Value must be an integer");
                    }
                }
            }
            public Object [] getTypeArray(int size) {
                return new Integer [size];
            }


        };

    // Long type definition.
    public static FormType LONG = new FormType() {
            public Class getFormClass() {
                return Long.class;
            }

            public Object parse(String origVal, Locale locale) throws ParseException {
                // Eliminate the obvious.
                if (origVal==null)
                    return null;

                // ilc_022702.1_start
                // check for 0's after decimal place.
                // val = new Long(origVal);
                try {
                    return new Long(origVal);
                } catch (NumberFormatException e) {
                    try {
                        //this basically handles the case where the user
                        //typed in an integer value like 123.00...we convert
                        //that value to a double, then to an int, and then form
                        //a new double from that. If the values are equal, we
                        //know no roundoff occurred, meaning the decimal places
                        //were all zeros, and we're in business. Otherwise, throw
                        //the exception
                        Double d1 = new Double(origVal);
                        long d1val = d1.longValue();
                        Double d2 = new Double(d1val);
                        if (d1.equals(d2)) {
                            return new Long(d1val);
                        } else {
                            throw e;
                        }
                    } catch (NumberFormatException e2) {
                        //saw_040203.1 - initialize the exception with a message
                        //throw new ParseException(e2);
                        throw new ParseException(e2, "Value must be an integer");
                    }
                }
                // ilc_022702.1_end
            }

            public Object [] getTypeArray(int size) {
                return new Long [size];
            }

        };

    // Short type definition.
    public static FormType SHORT = new FormType() {
            public Class getFormClass() {
                return Short.class;
            }

            public Object parse(String origVal, Locale locale) throws ParseException {
                // Eliminate the obvious.
                if (origVal==null)
                    return null;

                // ilc_022702.2_start
                // check for 0's after decimal place.
                // val = new Short(origVal);
                try {
                    return new Short(origVal);
                } catch (NumberFormatException e) {
                    try {
                        //this basically handles the case where the user
                        //typed in an integer value like 123.00...we convert
                        //that value to a double, then to an int, and then form
                        //a new double from that. If the values are equal, we
                        //know no roundoff occurred, meaning the decimal places
                        //were all zeros, and we're in business. Otherwise, throw
                        //the exception
                        Double d1 = new Double(origVal);
                        short d1val = d1.shortValue();
                        Double d2 = new Double(d1val);
                        if (d1.equals(d2)) {
                            return new Short(d1val);
                        } else {
                            throw e;
                        }
                    } catch (NumberFormatException e2) {
                        //saw_040203.1 - initialize the exception with a message
                        //throw new ParseException(e2);
                        throw new ParseException(e2, "Value must be an integer");
                    }
                }
                // ilc_022702.2_end
            }
            public Object [] getTypeArray(int size) {
                return new Short [size];
            }

        };

    // Double type definition.
    public static FormType DOUBLE = new FormType() {
            public Class getFormClass() {
                return Double.class;
            }

            public Object parse(String origVal, Locale locale) throws ParseException {
                // Eliminate the obvious.
                if (origVal==null)
                    return null;
                
                try {
                    return new Double(origVal);
                } catch (NumberFormatException e) {
                    //saw_040203.1 - initialize the exception with a message
                    //throw new ParseException(e);
                    throw new ParseException(e, "Value must be a number");
                }
            }

            public Object [] getTypeArray(int size) {
                return new Double [size];
            }

        };

    // Float type definition.
    public static FormType FLOAT = new FormType() {
            public Class getFormClass() {
                return Float.class;
            }

            public Object parse(String origVal, Locale locale) throws ParseException {
                // Eliminate the obvious.
                if (origVal==null)
                    return null;
                
                try {
                    return new Float(origVal);
                } catch (NumberFormatException e) {
                    //saw_040203.1 - initialize the exception with a message
                    //throw new ParseException(e);
                    throw new ParseException(e, "Value must be a number");
                }
            }

            public Object [] getTypeArray(int size) {
                return new Float [size];
            }


        };

    // BigDecimal type definition.
    public static FormType BIG_DECIMAL = new FormType() {
            public Class getFormClass() {
                return BigDecimal.class;
            }
                
            public Object parse(String origVal, Locale locale) throws ParseException {
                //csc_060702.1_start - I changed this to use the String constructor since
                //the javadocs say that using the Double constructor is unpredicatable. Note
                //that I also am stripping out the dollar sign if its there (probably still 
                //need to handle other currency symbols, based on locales)
                /*
                  Object d = DOUBLE.parse(origVal, locale);
                  if (d!=null) {
                  return new BigDecimal(((Double)d).doubleValue());
                  }
                  return null;
                */          
                //csc_040203.2 - wrapped the logic in a block to catch NumberFormatExceptions...not sure why this hadn't been done originally!
                try {
                    String s = origVal.trim();
                    s = StringUtil.replace(s, "$","");  //strip off $ sign
                    s = StringUtil.replace(s, "£","");  //strip off £ sign
                    s = StringUtil.replace(s, ",","");  //strip off commas
                    if (s.startsWith("(") && s.endsWith(")")) { //if its a debit (ie. in parenthesis), strip off parenthesis and add a - sign
                        s = "-"+s.substring(1,s.length()-1);
                    }
                    return new BigDecimal(s);
                } catch (NumberFormatException e) {
                    //saw_040203.1 - initialize the exception with a message
                    //throw new ParseException(e);
                    throw new ParseException(e, "Value must be a number");
                }


                //csc_060702.1_end 
            }

            public Object [] getTypeArray(int size) {
                return new BigDecimal [size];
            }



        };

    // Date type definition.
    public static FormType DATE = new FormType() {
            public Class getFormClass() {
                return java.util.Date.class;
            }

            public Object parse(String origVal, Locale locale) throws ParseException {
                // Eliminate the obvious.
                if (origVal==null)
                    return null;

                if (locale==null)
                    locale = Locale.getDefault();
                /*
                //rtl20010822 - start
                DateFormat df = DateFormat.getDateInstance();
                df.setLenient(false);
                val = df.parse(origVal);
                //rtl20010822 - end
                */
                //rtl20010822 - start new
                // try all the various forms of date format to cover more bases
                try {
                    //dbr_011602.1  DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT);
                    DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, locale); //dbr_011602.1
                    df.setLenient(false);
                    return df.parse(origVal);
                } catch (java.text.ParseException e1) {
                    try {
                        //dbr_011602.1      DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM);
                        DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM, locale); //dbr_011602.1
                        df.setLenient(false);
                        return df.parse(origVal);
                    } catch (java.text.ParseException e2) {
                        try {
                            //dbr_011602.1          DateFormat df = DateFormat.getDateInstance(DateFormat.LONG);
                            DateFormat df = DateFormat.getDateInstance(DateFormat.LONG, locale); //dbr_011602.1
                            df.setLenient(false);
                            return df.parse(origVal);
                        } catch (java.text.ParseException e3) {
                            try {
                                //dbr_011602.1              DateFormat df = DateFormat.getDateInstance(DateFormat.FULL);
                                DateFormat df = DateFormat.getDateInstance(DateFormat.FULL, locale); //dbr_011602.1
                                df.setLenient(false);
                                return df.parse(origVal);
                            } catch (java.text.ParseException e4) {
                                //saw_040203.1 - initialize the exception with a message
                                //throw new ParseException(e4, "Locale is " + locale.getCountry());
                                throw new ParseException(e4, "Value must be a date");
                            }
                        }
                    }
                    //rtl20010822 - end new
                }
            }

            public Object [] getTypeArray(int size) {
                return new Date [size];
            }
        };

    /**
     * Protected constructor to prevent external instantiation. Cannot be
     * private because we would be unable to call the constructor from a
     * sub-class.
     */
    protected FormType() { }

    /**
     * Returns the class associated with this particular form type.
     */
    public abstract Class getFormClass();

    /**
     * Parses an object based on the specific form type.
     */
    public Object parse(String origVal) throws ParseException {
        return parse(origVal, null);
    }

    /**
     * Parses an object based on the specific form type.
     */
    public abstract Object parse(String origVal, Locale loc) throws ParseException;


    /** create an array of the FormType's type - if heterogenous types
     * are returned, an array of Object will be returned.
     */
    public abstract Object [] getTypeArray(int size);

    /**
     * Returns a string representation of this particular formt type.
     */
    public String toString() {
        return this.getFormClass().getName();
    }

}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.