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(); } }