1 package org.apache.turbine.util.parser;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.beans.IndexedPropertyDescriptor;
23 import java.beans.Introspector;
24 import java.beans.PropertyDescriptor;
25 import java.io.UnsupportedEncodingException;
26 import java.lang.reflect.Method;
27 import java.math.BigDecimal;
28 import java.text.DateFormat;
29 import java.text.ParseException;
30 import java.util.Calendar;
31 import java.util.Collections;
32 import java.util.Date;
33 import java.util.Enumeration;
34 import java.util.GregorianCalendar;
35 import java.util.HashMap;
36 import java.util.Iterator;
37 import java.util.Map;
38 import java.util.Set;
39
40 import org.apache.commons.collections.iterators.ArrayIterator;
41 import org.apache.commons.lang.ArrayUtils;
42 import org.apache.commons.lang.StringUtils;
43 import org.apache.commons.logging.Log;
44 import org.apache.commons.logging.LogFactory;
45 import org.apache.torque.om.NumberKey;
46 import org.apache.torque.om.StringKey;
47 import org.apache.turbine.TurbineConstants;
48 import org.apache.turbine.util.DateSelector;
49 import org.apache.turbine.util.TimeSelector;
50 import org.apache.turbine.util.pool.RecyclableSupport;
51
52 /***
53 * BaseValueParser is a base class for classes that need to parse
54 * name/value Parameters, for example GET/POST data or Cookies
55 * (DefaultParameterParser and DefaultCookieParser).
56 *
57 * <p>It can also be used standalone, for an example see DataStreamParser.
58 *
59 * <p>NOTE: The name= portion of a name=value pair may be converted
60 * to lowercase or uppercase when the object is initialized and when
61 * new data is added. This behaviour is determined by the url.case.folding
62 * property in TurbineResources.properties. Adding a name/value pair may
63 * overwrite existing name=value pairs if the names match:
64 *
65 * <pre>
66 * ValueParser vp = new BaseValueParser();
67 * vp.add("ERROR",1);
68 * vp.add("eRrOr",2);
69 * int result = vp.getInt("ERROR");
70 * </pre>
71 *
72 * In the above example, result is 2.
73 *
74 * @author <a href="mailto:ilkka.priha@simsoft.fi">Ilkka Priha</a>
75 * @author <a href="mailto:jon@clearink.com">Jon S. Stevens</a>
76 * @author <a href="mailto:sean@informage.net">Sean Legassick</a>
77 * @author <a href="mailto:jvanzyl@periapt.com">Jason van Zyl</a>
78 * @author <a href="mailto:seade@backstagetech.com.au">Scott Eade</a>
79 * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
80 * @author <a href="mailto:quintonm@bellsouth.net">Quinton McCombs</a>
81 * @version $Id: BaseValueParser.java 534527 2007-05-02 16:10:59Z tv $
82 */
83 public class BaseValueParser
84 extends RecyclableSupport
85 implements ValueParser
86 {
87 /*** Logging */
88 private static Log log = LogFactory.getLog(BaseValueParser.class);
89
90 /***
91 * Random access storage for parameter data. The keys must always be
92 * Strings. The values will be arrays of Strings.
93 */
94 private Map parameters = new HashMap();
95
96 /*** The character encoding to use when converting to byte arrays */
97 private String characterEncoding = TurbineConstants.PARAMETER_ENCODING_DEFAULT;
98
99 /***
100 * A static version of the convert method, which
101 * trims the string data and applies the conversion specified in
102 * the property given by URL_CASE_FOLDING. It returns a new
103 * string so that it does not destroy the value data.
104 *
105 * @param value A String to be processed.
106 * @return A new String converted to lowercase and trimmed.
107 * @deprecated Use ParserUtils.convertAndTrim(value).
108 */
109 public static String convertAndTrim(String value)
110 {
111 return ParserUtils.convertAndTrim(value);
112 }
113
114 /***
115 * Default constructor
116 */
117 public BaseValueParser()
118 {
119 this(TurbineConstants.PARAMETER_ENCODING_DEFAULT);
120 }
121
122 /***
123 * Constructor that takes a character encoding
124 */
125 public BaseValueParser(String characterEncoding)
126 {
127 super();
128 setCharacterEncoding(characterEncoding);
129 }
130
131 /***
132 * Recycles the parser with a character encoding.
133 *
134 * @param characterEncoding the character encoding.
135 *
136 * @todo Is this method used anywhere? Does it make any sense at all?
137 */
138 public void recycle(String characterEncoding)
139 {
140 setCharacterEncoding(characterEncoding);
141 super.recycle();
142 }
143
144 /***
145 * Disposes the parser.
146 */
147 public void dispose()
148 {
149 clear();
150 super.dispose();
151 }
152
153 /***
154 * Clear all name/value pairs out of this object.
155 */
156 public void clear()
157 {
158 parameters.clear();
159 }
160
161 /***
162 * Set the character encoding that will be used by this ValueParser.
163 */
164 public void setCharacterEncoding(String s)
165 {
166 characterEncoding = s;
167 }
168
169 /***
170 * Get the character encoding that will be used by this ValueParser.
171 */
172 public String getCharacterEncoding()
173 {
174 return characterEncoding;
175 }
176
177 /***
178 * Add a name/value pair into this object.
179 *
180 * @param name A String with the name.
181 * @param value A double with the value.
182 */
183 public void add(String name, double value)
184 {
185 add(name, Double.toString(value));
186 }
187
188 /***
189 * Add a name/value pair into this object.
190 *
191 * @param name A String with the name.
192 * @param value An int with the value.
193 */
194 public void add(String name, int value)
195 {
196 add(name, Integer.toString(value));
197 }
198
199 /***
200 * Add a name/value pair into this object.
201 *
202 * @param name A String with the name.
203 * @param value An Integer with the value.
204 */
205 public void add(String name, Integer value)
206 {
207 if (value != null)
208 {
209 add(name, value.toString());
210 }
211 }
212
213 /***
214 * Add a name/value pair into this object.
215 *
216 * @param name A String with the name.
217 * @param value A long with the value.
218 */
219 public void add(String name, long value)
220 {
221 add(name, Long.toString(value));
222 }
223
224 /***
225 * Add a name/value pair into this object.
226 *
227 * @param name A String with the name.
228 * @param value A long with the value.
229 */
230 public void add(String name, String value)
231 {
232 if (value != null)
233 {
234 String [] items = getParam(name);
235 items = (String []) ArrayUtils.add(items, value);
236 putParam(name, items);
237 }
238 }
239
240 /***
241 * Add an array of Strings for a key. This
242 * is simply adding all the elements in the
243 * array one by one.
244 *
245 * @param name A String with the name.
246 * @param value A String Array.
247 */
248 public void add(String name, String [] value)
249 {
250
251
252 if (value != null)
253 {
254 for (int i = 0 ; i < value.length; i++)
255 {
256 if (value[i] != null)
257 {
258 add(name, value[i]);
259 }
260 }
261 }
262 }
263
264 /***
265 * Add a String parameters. If there are any Strings already
266 * associated with the name, append to the array. This is used
267 * for handling parameters from multipart POST requests.
268 *
269 * @param name A String with the name.
270 * @param value A String with the value.
271 *
272 * @deprecated Use add(name, value) instead.
273 */
274 public void append(String name, String value)
275 {
276 add(name, value);
277 }
278
279 /***
280 * Removes the named parameter from the contained hashtable. Wraps to the
281 * contained <code>Map.remove()</code>.
282 *
283 * @return The value that was mapped to the key (a <code>String[]</code>)
284 * or <code>null</code> if the key was not mapped.
285 */
286 public Object remove(String name)
287 {
288 return parameters.remove(convert(name));
289 }
290
291 /***
292 * Trims the string data and applies the conversion specified in
293 * the property given by URL_CASE_FOLDING. It returns a new
294 * string so that it does not destroy the value data.
295 *
296 * @param value A String to be processed.
297 * @return A new String converted to lowercase and trimmed.
298 */
299 public String convert(String value)
300 {
301 return ParserUtils.convertAndTrim(value);
302 }
303
304 /***
305 * Determine whether a given key has been inserted. All keys are
306 * stored in lowercase strings, so override method to account for
307 * this.
308 *
309 * @param key An Object with the key to search for.
310 * @return True if the object is found.
311 */
312 public boolean containsKey(Object key)
313 {
314 return parameters.containsKey(convert(String.valueOf(key)));
315 }
316
317 /***
318 * Check for existence of key_day, key_month and key_year
319 * parameters (as returned by DateSelector generated HTML).
320 *
321 * @param key A String with the selector name.
322 * @return True if keys are found.
323 */
324 public boolean containsDateSelectorKeys(String key)
325 {
326 return (containsKey(key + DateSelector.DAY_SUFFIX) &&
327 containsKey(key + DateSelector.MONTH_SUFFIX) &&
328 containsKey(key + DateSelector.YEAR_SUFFIX));
329 }
330
331 /***
332 * Check for existence of key_hour, key_minute and key_second
333 * parameters (as returned by TimeSelector generated HTML).
334 *
335 * @param key A String with the selector name.
336 * @return True if keys are found.
337 */
338 public boolean containsTimeSelectorKeys(String key)
339 {
340 return (containsKey(key + TimeSelector.HOUR_SUFFIX) &&
341 containsKey(key + TimeSelector.MINUTE_SUFFIX) &&
342 containsKey(key + TimeSelector.SECOND_SUFFIX));
343 }
344
345 /***
346 * Get an enumerator for the parameter keys.
347 *
348 * @return An <code>enumerator</code> of the keys.
349 * @deprecated use {@link #keySet} instead.
350 */
351 public Enumeration keys()
352 {
353 return Collections.enumeration(keySet());
354 }
355
356 /***
357 * Gets the set of keys
358 *
359 * @return A <code>Set</code> of the keys.
360 */
361 public Set keySet()
362 {
363 return parameters.keySet();
364 }
365
366 /***
367 * Returns all the available parameter names.
368 *
369 * @return A object array with the keys.
370 */
371 public Object[] getKeys()
372 {
373 return keySet().toArray();
374 }
375
376 /***
377 * Return a boolean for the given name. If the name does not
378 * exist, return defaultValue.
379 *
380 * @param name A String with the name.
381 * @param defaultValue The default value.
382 * @return A boolean.
383 */
384 public boolean getBoolean(String name, boolean defaultValue)
385 {
386 Boolean result = getBooleanObject(name);
387 return (result == null ? defaultValue : result.booleanValue());
388 }
389
390 /***
391 * Return a boolean for the given name. If the name does not
392 * exist, return false.
393 *
394 * @param name A String with the name.
395 * @return A boolean.
396 */
397 public boolean getBoolean(String name)
398 {
399 return getBoolean(name, false);
400 }
401
402 /***
403 * Returns a Boolean object for the given name. If the parameter
404 * does not exist or can not be parsed as a boolean, null is returned.
405 * <p>
406 * Valid values for true: true, on, 1, yes<br>
407 * Valid values for false: false, off, 0, no<br>
408 * <p>
409 * The string is compared without reguard to case.
410 *
411 * @param name A String with the name.
412 * @return A Boolean.
413 */
414 public Boolean getBooleanObject(String name)
415 {
416 Boolean result = null;
417 String value = getString(name);
418
419 if (StringUtils.isNotEmpty(value))
420 {
421 if (value.equals("1") ||
422 value.equalsIgnoreCase("true") ||
423 value.equalsIgnoreCase("yes") ||
424 value.equalsIgnoreCase("on"))
425 {
426 result = Boolean.TRUE;
427 }
428 else if (value.equals("0") ||
429 value.equalsIgnoreCase("false") ||
430 value.equalsIgnoreCase("no") ||
431 value.equalsIgnoreCase("off"))
432 {
433 result = Boolean.FALSE;
434 }
435 else
436 {
437 logConvertionFailure(name, value, "Boolean");
438 }
439 }
440 return result;
441 }
442
443 /***
444 * Returns a Boolean object for the given name. If the parameter
445 * does not exist or can not be parsed as a boolean, null is returned.
446 * <p>
447 * Valid values for true: true, on, 1, yes<br>
448 * Valid values for false: false, off, 0, no<br>
449 * <p>
450 * The string is compared without reguard to case.
451 *
452 * @param name A String with the name.
453 * @param defaultValue The default value.
454 * @return A Boolean.
455 */
456 public Boolean getBooleanObject(String name, Boolean defaultValue)
457 {
458 Boolean result = getBooleanObject(name);
459 return (result == null ? defaultValue : result);
460 }
461
462 /***
463 * Return a Boolean for the given name. If the name does not
464 * exist, return defaultValue.
465 *
466 * @param name A String with the name.
467 * @param defaultValue The default value.
468 * @return A Boolean.
469 * @deprecated use {@link #getBooleanObject} instead
470 */
471 public Boolean getBool(String name, boolean defaultValue)
472 {
473
474 return getBooleanObject(name, new Boolean(defaultValue));
475 }
476
477 /***
478 * Return a Boolean for the given name. If the name does not
479 * exist, return false.
480 *
481 * @param name A String with the name.
482 * @return A Boolean.
483 * @deprecated use {@link #getBooleanObject(String)} instead
484 */
485 public Boolean getBool(String name)
486 {
487 return getBooleanObject(name, Boolean.FALSE);
488 }
489
490 /***
491 * Return a double for the given name. If the name does not
492 * exist, return defaultValue.
493 *
494 * @param name A String with the name.
495 * @param defaultValue The default value.
496 * @return A double.
497 */
498 public double getDouble(String name, double defaultValue)
499 {
500 double result = defaultValue;
501 String value = getString(name);
502
503 if (StringUtils.isNotEmpty(value))
504 {
505 try
506 {
507 result = Double.parseDouble(StringUtils.trim(value));
508 }
509 catch (NumberFormatException e)
510 {
511 logConvertionFailure(name, value, "Double");
512 }
513 }
514 return result;
515 }
516
517 /***
518 * Return a double for the given name. If the name does not
519 * exist, return 0.0.
520 *
521 * @param name A String with the name.
522 * @return A double.
523 */
524 public double getDouble(String name)
525 {
526 return getDouble(name, 0.0);
527 }
528
529 /***
530 * Return an array of doubles for the given name. If the name does
531 * not exist, return null.
532 *
533 * @param name A String with the name.
534 * @return A double[].
535 */
536 public double[] getDoubles(String name)
537 {
538 double[] result = null;
539 String value[] = getParam(name);
540 if (value != null)
541 {
542 result = new double[value.length];
543 for (int i = 0; i < value.length; i++)
544 {
545 if (StringUtils.isNotEmpty(value[i]))
546 {
547 try
548 {
549 result[i] = Double.parseDouble(value[i]);
550 }
551 catch (NumberFormatException e)
552 {
553 logConvertionFailure(name, value[i], "Double");
554 }
555 }
556 }
557 }
558 return result;
559 }
560
561 /***
562 * Return a Double for the given name. If the name does not
563 * exist, return defaultValue.
564 *
565 * @param name A String with the name.
566 * @param defaultValue The default value.
567 * @return A double.
568 */
569 public Double getDoubleObject(String name, Double defaultValue)
570 {
571 Double result = getDoubleObject(name);
572 return (result == null ? defaultValue : result);
573 }
574
575 /***
576 * Return a Double for the given name. If the name does not
577 * exist, return null.
578 *
579 * @param name A String with the name.
580 * @return A double.
581 */
582 public Double getDoubleObject(String name)
583 {
584 Double result = null;
585 String value = getString(name);
586
587 if (StringUtils.isNotEmpty(value))
588 {
589 try
590 {
591 result = new Double(StringUtils.trim(value));
592 }
593 catch(NumberFormatException e)
594 {
595 logConvertionFailure(name, value, "Double");
596 }
597 }
598 return result;
599 }
600
601 /***
602 * Return an array of doubles for the given name. If the name does
603 * not exist, return null.
604 *
605 * @param name A String with the name.
606 * @return A double[].
607 */
608 public Double[] getDoubleObjects(String name)
609 {
610 Double[] result = null;
611 String value[] = getParam(name);
612 if (value != null)
613 {
614 result = new Double[value.length];
615 for (int i = 0; i < value.length; i++)
616 {
617 if (StringUtils.isNotEmpty(value[i]))
618 {
619 try
620 {
621 result[i] = Double.valueOf(value[i]);
622 }
623 catch (NumberFormatException e)
624 {
625 logConvertionFailure(name, value[i], "Double");
626 }
627 }
628 }
629 }
630 return result;
631 }
632
633 /***
634 * Return a float for the given name. If the name does not
635 * exist, return defaultValue.
636 *
637 * @param name A String with the name.
638 * @param defaultValue The default value.
639 * @return A float.
640 */
641 public float getFloat(String name, float defaultValue)
642 {
643 float result = defaultValue;
644 String value = getString(name);
645
646 if (StringUtils.isNotEmpty(value))
647 {
648 try
649 {
650 result = Float.parseFloat(StringUtils.trim(value));
651 }
652 catch (NumberFormatException e)
653 {
654 logConvertionFailure(name, value, "Float");
655 }
656 }
657 return result;
658 }
659
660 /***
661 * Return a float for the given name. If the name does not
662 * exist, return 0.0.
663 *
664 * @param name A String with the name.
665 * @return A float.
666 */
667 public float getFloat(String name)
668 {
669 return getFloat(name, 0.0f);
670 }
671
672 /***
673 * Return an array of floats for the given name. If the name does
674 * not exist, return null.
675 *
676 * @param name A String with the name.
677 * @return A float[].
678 */
679 public float[] getFloats(String name)
680 {
681 float[] result = null;
682 String value[] = getParam(name);
683 if (value != null)
684 {
685 result = new float[value.length];
686 for (int i = 0; i < value.length; i++)
687 {
688 if (StringUtils.isNotEmpty(value[i]))
689 {
690 try
691 {
692 result[i] = Float.parseFloat(value[i]);
693 }
694 catch (NumberFormatException e)
695 {
696 logConvertionFailure(name, value[i], "Float");
697 }
698 }
699 }
700 }
701 return result;
702 }
703
704 /***
705 * Return a Float for the given name. If the name does not
706 * exist, return defaultValue.
707 *
708 * @param name A String with the name.
709 * @param defaultValue The default value.
710 * @return A Float.
711 */
712 public Float getFloatObject(String name, Float defaultValue)
713 {
714 Float result = getFloatObject(name);
715 return (result == null ? defaultValue : result);
716 }
717
718 /***
719 * Return a float for the given name. If the name does not
720 * exist, return null.
721 *
722 * @param name A String with the name.
723 * @return A Float.
724 */
725 public Float getFloatObject(String name)
726 {
727 Float result = null;
728 String value = getString(name);
729
730 if (StringUtils.isNotEmpty(value))
731 {
732 try
733 {
734 result = new Float(StringUtils.trim(value));
735 }
736 catch(NumberFormatException e)
737 {
738 logConvertionFailure(name, value, "Float");
739 }
740 }
741
742 return result;
743 }
744
745 /***
746 * Return an array of floats for the given name. If the name does
747 * not exist, return null.
748 *
749 * @param name A String with the name.
750 * @return A float[].
751 */
752 public Float[] getFloatObjects(String name)
753 {
754 Float[] result = null;
755 String value[] = getParam(name);
756 if (value != null)
757 {
758 result = new Float[value.length];
759 for (int i = 0; i < value.length; i++)
760 {
761 if (StringUtils.isNotEmpty(value[i]))
762 {
763 try
764 {
765 result[i] = Float.valueOf(value[i]);
766 }
767 catch (NumberFormatException e)
768 {
769 logConvertionFailure(name, value[i], "Float");
770 }
771 }
772 }
773 }
774 return result;
775 }
776
777 /***
778 * Return a BigDecimal for the given name. If the name does not
779 * exist, return defaultValue.
780 *
781 * @param name A String with the name.
782 * @param defaultValue The default value.
783 * @return A BigDecimal.
784 */
785 public BigDecimal getBigDecimal(String name, BigDecimal defaultValue)
786 {
787 BigDecimal result = defaultValue;
788 String value = getString(name);
789
790 if (StringUtils.isNotEmpty(value))
791 {
792 try
793 {
794 result = new BigDecimal(StringUtils.trim(value));
795 }
796 catch (NumberFormatException e)
797 {
798 logConvertionFailure(name, value, "BigDecimal");
799 }
800 }
801
802 return result;
803 }
804
805 /***
806 * Return a BigDecimal for the given name. If the name does not
807 * exist, return 0.0.
808 *
809 * @param name A String with the name.
810 * @return A BigDecimal.
811 */
812 public BigDecimal getBigDecimal(String name)
813 {
814 return getBigDecimal(name, new BigDecimal(0.0));
815 }
816
817 /***
818 * Return an array of BigDecimals for the given name. If the name
819 * does not exist, return null.
820 *
821 * @param name A String with the name.
822 * @return A BigDecimal[].
823 */
824 public BigDecimal[] getBigDecimals(String name)
825 {
826 BigDecimal[] result = null;
827 String value[] = getParam(name);
828 if (value != null)
829 {
830 result = new BigDecimal[value.length];
831 for (int i = 0; i < value.length; i++)
832 {
833 if (StringUtils.isNotEmpty(value[i]))
834 {
835 try
836 {
837 result[i] = new BigDecimal(value[i]);
838 }
839 catch (NumberFormatException e)
840 {
841 logConvertionFailure(name, value[i], "BigDecimal");
842 }
843 }
844 }
845 }
846 return result;
847 }
848
849 /***
850 * Return an int for the given name. If the name does not exist,
851 * return defaultValue.
852 *
853 * @param name A String with the name.
854 * @param defaultValue The default value.
855 * @return An int.
856 */
857 public int getInt(String name, int defaultValue)
858 {
859 int result = defaultValue;
860 String value = getString(name);
861
862 if (StringUtils.isNotEmpty(value))
863 {
864 try
865 {
866 result = Integer.parseInt(StringUtils.trim(value));
867 }
868 catch (NumberFormatException e)
869 {
870 logConvertionFailure(name, value, "Integer");
871 }
872 }
873
874 return result;
875 }
876
877 /***
878 * Return an int for the given name. If the name does not exist,
879 * return 0.
880 *
881 * @param name A String with the name.
882 * @return An int.
883 */
884 public int getInt(String name)
885 {
886 return getInt(name, 0);
887 }
888
889 /***
890 * Return an Integer for the given name. If the name does not
891 * exist, return defaultValue.
892 *
893 * @param name A String with the name.
894 * @param defaultValue The default value.
895 * @return An Integer.
896 * @deprecated use {@link #getIntObject} instead
897 */
898 public Integer getInteger(String name, int defaultValue)
899 {
900 return getIntObject(name, new Integer(defaultValue));
901 }
902
903 /***
904 * Return an Integer for the given name. If the name does not
905 * exist, return defaultValue. You cannot pass in a null here for
906 * the default value.
907 *
908 * @param name A String with the name.
909 * @param def The default value.
910 * @return An Integer.
911 * @deprecated use {@link #getIntObject} instead
912 */
913 public Integer getInteger(String name, Integer def)
914 {
915 return getIntObject(name, def);
916 }
917
918 /***
919 * Return an Integer for the given name. If the name does not
920 * exist, return 0.
921 *
922 * @param name A String with the name.
923 * @return An Integer.
924 * @deprecated use {@link #getIntObject} instead
925 */
926 public Integer getInteger(String name)
927 {
928 return getIntObject(name, new Integer(0));
929 }
930
931 /***
932 * Return an array of ints for the given name. If the name does
933 * not exist, return null.
934 *
935 * @param name A String with the name.
936 * @return An int[].
937 */
938 public int[] getInts(String name)
939 {
940 int[] result = null;
941 String value[] = getParam(name);
942 if (value != null)
943 {
944 result = new int[value.length];
945 for (int i = 0; i < value.length; i++)
946 {
947 if (StringUtils.isNotEmpty(value[i]))
948 {
949 try
950 {
951 result[i] = Integer.parseInt(value[i]);
952 }
953 catch (NumberFormatException e)
954 {
955 logConvertionFailure(name, value[i], "Integer");
956 }
957 }
958 }
959 }
960 return result;
961 }
962
963 /***
964 * Return an Integer for the given name. If the name does not exist,
965 * return defaultValue.
966 *
967 * @param name A String with the name.
968 * @param defaultValue The default value.
969 * @return An Integer.
970 */
971 public Integer getIntObject(String name, Integer defaultValue)
972 {
973 Integer result = getIntObject(name);
974 return (result == null ? defaultValue : result);
975 }
976
977 /***
978 * Return an Integer for the given name. If the name does not exist,
979 * return null.
980 *
981 * @param name A String with the name.
982 * @return An Integer.
983 */
984 public Integer getIntObject(String name)
985 {
986 Integer result = null;
987 String value = getString(name);
988
989 if (StringUtils.isNotEmpty(value))
990 {
991 try
992 {
993 result = new Integer(StringUtils.trim(value));
994 }
995 catch(NumberFormatException e)
996 {
997 logConvertionFailure(name, value, "Integer");
998 }
999 }
1000
1001 return result;
1002 }
1003
1004 /***
1005 * Return an array of Integers for the given name. If the name
1006 * does not exist, return null.
1007 *
1008 * @param name A String with the name.
1009 * @return An Integer[].
1010 */
1011 public Integer[] getIntObjects(String name)
1012 {
1013 Integer[] result = null;
1014 String value[] = getParam(name);
1015 if (value != null)
1016 {
1017 result = new Integer[value.length];
1018 for (int i = 0; i < value.length; i++)
1019 {
1020 if (StringUtils.isNotEmpty(value[i]))
1021 {
1022 try
1023 {
1024 result[i] = Integer.valueOf(value[i]);
1025 }
1026 catch (NumberFormatException e)
1027 {
1028 logConvertionFailure(name, value[i], "Integer");
1029 }
1030 }
1031 }
1032 }
1033 return result;
1034 }
1035
1036 /***
1037 * Return an array of Integers for the given name. If the name
1038 * does not exist, return null.
1039 *
1040 * @param name A String with the name.
1041 * @return An Integer[].
1042 * @deprecated use {@link #getIntObjects} instead
1043 */
1044 public Integer[] getIntegers(String name)
1045 {
1046 return getIntObjects(name);
1047 }
1048
1049 /***
1050 * Return a long for the given name. If the name does not exist,
1051 * return defaultValue.
1052 *
1053 * @param name A String with the name.
1054 * @param defaultValue The default value.
1055 * @return A long.
1056 */
1057 public long getLong(String name, long defaultValue)
1058 {
1059 long result = defaultValue;
1060 String value = getString(name);
1061
1062 if (StringUtils.isNotEmpty(value))
1063 {
1064 try
1065 {
1066 result = Long.parseLong(StringUtils.trim(value));
1067 }
1068 catch (NumberFormatException e)
1069 {
1070 logConvertionFailure(name, value, "Long");
1071 }
1072 }
1073
1074 return result;
1075 }
1076
1077 /***
1078 * Return a long for the given name. If the name does not exist,
1079 * return 0.
1080 *
1081 * @param name A String with the name.
1082 * @return A long.
1083 */
1084 public long getLong(String name)
1085 {
1086 return getLong(name, 0);
1087 }
1088
1089 /***
1090 * Return an array of longs for the given name. If the name does
1091 * not exist, return null.
1092 *
1093 * @param name A String with the name.
1094 * @return A long[].
1095 */
1096 public long[] getLongs(String name)
1097 {
1098 long[] result = null;
1099 String value[] = getParam(name);
1100 if (value != null)
1101 {
1102 result = new long[value.length];
1103 for (int i = 0; i < value.length; i++)
1104 {
1105 if (StringUtils.isNotEmpty(value[i]))
1106 {
1107 try
1108 {
1109 result[i] = Long.parseLong(value[i]);
1110 }
1111 catch (NumberFormatException e)
1112 {
1113 logConvertionFailure(name, value[i], "Long");
1114 }
1115 }
1116 }
1117 }
1118 return result;
1119 }
1120
1121 /***
1122 * Return an array of Longs for the given name. If the name does
1123 * not exist, return null.
1124 *
1125 * @param name A String with the name.
1126 * @return A Long[].
1127 */
1128 public Long[] getLongObjects(String name)
1129 {
1130 Long[] result = null;
1131 String value[] = getParam(name);
1132 if (value != null)
1133 {
1134 result = new Long[value.length];
1135 for (int i = 0; i < value.length; i++)
1136 {
1137 if (StringUtils.isNotEmpty(value[i]))
1138 {
1139 try
1140 {
1141 result[i] = Long.valueOf(value[i]);
1142 }
1143 catch (NumberFormatException e)
1144 {
1145 logConvertionFailure(name, value[i], "Long");
1146 }
1147 }
1148 }
1149 }
1150 return result;
1151 }
1152
1153 /***
1154 * Return a Long for the given name. If the name does
1155 * not exist, return null.
1156 *
1157 * @param name A String with the name.
1158 * @return A Long.
1159 */
1160 public Long getLongObject(String name)
1161 {
1162 Long result = null;
1163 String value = getString(name);
1164
1165 if (StringUtils.isNotEmpty(value))
1166 {
1167 try
1168 {
1169 result = new Long(StringUtils.trim(value));
1170 }
1171 catch(NumberFormatException e)
1172 {
1173 logConvertionFailure(name, value, "Long");
1174 }
1175 }
1176
1177 return result;
1178 }
1179
1180 /***
1181 * Return a Long for the given name. If the name does
1182 * not exist, return the default value.
1183 *
1184 * @param name A String with the name.
1185 * @param defaultValue The default value.
1186 * @return A Long.
1187 */
1188 public Long getLongObject(String name, Long defaultValue)
1189 {
1190 Long result = getLongObject(name);
1191 return (result == null ? defaultValue : result);
1192 }
1193
1194 /***
1195 * Return a byte for the given name. If the name does not exist,
1196 * return defaultValue.
1197 *
1198 * @param name A String with the name.
1199 * @param defaultValue The default value.
1200 * @return A byte.
1201 */
1202 public byte getByte(String name, byte defaultValue)
1203 {
1204 byte result = defaultValue;
1205 String value = getString(name);
1206
1207 if (StringUtils.isNotEmpty(value))
1208 {
1209 try
1210 {
1211 result = Byte.parseByte(StringUtils.trim(value));
1212 }
1213 catch (NumberFormatException e)
1214 {
1215 logConvertionFailure(name, value, "Byte");
1216 }
1217 }
1218
1219 return result;
1220 }
1221
1222 /***
1223 * Return a byte for the given name. If the name does not exist,
1224 * return 0.
1225 *
1226 * @param name A String with the name.
1227 * @return A byte.
1228 */
1229 public byte getByte(String name)
1230 {
1231 return getByte(name, (byte) 0);
1232 }
1233
1234 /***
1235 * Return an array of bytes for the given name. If the name does
1236 * not exist, return null. The array is returned according to the
1237 * HttpRequest's character encoding.
1238 *
1239 * @param name A String with the name.
1240 * @return A byte[].
1241 * @exception UnsupportedEncodingException
1242 */
1243 public byte[] getBytes(String name)
1244 throws UnsupportedEncodingException
1245 {
1246 byte result[] = null;
1247 String value = getString(name);
1248 if (value != null)
1249 {
1250 result = value.getBytes(getCharacterEncoding());
1251 }
1252 return result;
1253 }
1254
1255 /***
1256 * Return a byte for the given name. If the name does not exist,
1257 * return defaultValue.
1258 *
1259 * @param name A String with the name.
1260 * @param defaultValue The default value.
1261 * @return A byte.
1262 */
1263 public Byte getByteObject(String name, Byte defaultValue)
1264 {
1265 Byte result = getByteObject(name);
1266 return (result == null ? defaultValue : result);
1267 }
1268
1269 /***
1270 * Return a byte for the given name. If the name does not exist,
1271 * return 0.
1272 *
1273 * @param name A String with the name.
1274 * @return A byte.
1275 */
1276 public Byte getByteObject(String name)
1277 {
1278 Byte result = null;
1279 String value = getString(name);
1280
1281 if (StringUtils.isNotEmpty(value))
1282 {
1283 try
1284 {
1285 result = new Byte(StringUtils.trim(value));
1286 }
1287 catch(NumberFormatException e)
1288 {
1289 logConvertionFailure(name, value, "Byte");
1290 }
1291 }
1292
1293 return result;
1294 }
1295
1296 /***
1297 * Return a String for the given name. If the name does not
1298 * exist, return null.
1299 *
1300 * @param name A String with the name.
1301 * @return A String or null if the key is unknown.
1302 */
1303 public String getString(String name)
1304 {
1305 String [] value = getParam(name);
1306
1307 return (value == null
1308 || value.length == 0)
1309 ? null : value[0];
1310 }
1311
1312 /***
1313 * Return a String for the given name. If the name does not
1314 * exist, return null. It is the same as the getString() method
1315 * however has been added for simplicity when working with
1316 * template tools such as Velocity which allow you to do
1317 * something like this:
1318 *
1319 * <code>$data.Parameters.form_variable_name</code>
1320 *
1321 * @param name A String with the name.
1322 * @return A String.
1323 */
1324 public String get(String name)
1325 {
1326 return getString(name);
1327 }
1328
1329 /***
1330 * Return a String for the given name. If the name does not
1331 * exist, return the defaultValue.
1332 *
1333 * @param name A String with the name.
1334 * @param defaultValue The default value.
1335 * @return A String.
1336 */
1337 public String getString(String name, String defaultValue)
1338 {
1339 String value = getString(name);
1340
1341 return (StringUtils.isEmpty(value) ? defaultValue : value );
1342 }
1343
1344 /***
1345 * Set a parameter to a specific value.
1346 *
1347 * This is useful if you want your action to override the values
1348 * of the parameters for the screen to use.
1349 * @param name The name of the parameter.
1350 * @param value The value to set.
1351 */
1352 public void setString(String name, String value)
1353 {
1354 if (value != null)
1355 {
1356 putParam(name, new String[]{value});
1357 }
1358 }
1359
1360 /***
1361 * Return an array of Strings for the given name. If the name
1362 * does not exist, return null.
1363 *
1364 * @param name A String with the name.
1365 * @return A String[].
1366 */
1367 public String[] getStrings(String name)
1368 {
1369 return getParam(name);
1370 }
1371
1372 /***
1373 * Return an array of Strings for the given name. If the name
1374 * does not exist, return the defaultValue.
1375 *
1376 * @param name A String with the name.
1377 * @param defaultValue The default value.
1378 * @return A String[].
1379 */
1380 public String[] getStrings(String name, String[] defaultValue)
1381 {
1382 String[] value = getParam(name);
1383
1384 return (value == null || value.length == 0)
1385 ? defaultValue : value;
1386 }
1387
1388 /***
1389 * Set a parameter to a specific value.
1390 *
1391 * This is useful if you want your action to override the values
1392 * of the parameters for the screen to use.
1393 * @param name The name of the parameter.
1394 * @param values The value to set.
1395 */
1396 public void setStrings(String name, String[] values)
1397 {
1398 if (values != null)
1399 {
1400 putParam(name, values);
1401 }
1402 }
1403
1404 /***
1405 * Return an Object for the given name. If the name does not
1406 * exist, return null.
1407 *
1408 * @param name A String with the name.
1409 * @return An Object.
1410 */
1411 public Object getObject(String name)
1412 {
1413 return getString(name);
1414 }
1415
1416 /***
1417 * Return an array of Objects for the given name. If the name
1418 * does not exist, return null.
1419 *
1420 * @param name A String with the name.
1421 * @return An Object[].
1422 */
1423 public Object[] getObjects(String name)
1424 {
1425 return getParam(name);
1426 }
1427
1428 /***
1429 * Returns a {@link java.util.Date} object. String is parsed by supplied
1430 * DateFormat. If the name does not exist or the value could not be
1431 * parsed into a date return the defaultValue.
1432 *
1433 * @param name A String with the name.
1434 * @param df A DateFormat.
1435 * @param defaultValue The default value.
1436 * @return A Date.
1437 */
1438 public Date getDate(String name, DateFormat df, Date defaultValue)
1439 {
1440 Date result = defaultValue;
1441 String value = getString(name);
1442
1443 if (StringUtils.isNotEmpty(value))
1444 {
1445 try
1446 {
1447
1448 df.setLenient(false);
1449 result = df.parse(value);
1450 }
1451 catch (ParseException e)
1452 {
1453 logConvertionFailure(name, value, "Date");
1454 }
1455 }
1456
1457 return result;
1458 }
1459
1460 /***
1461 * Returns a {@link java.util.Date} object. If there are DateSelector or
1462 * TimeSelector style parameters then these are used. If not and there
1463 * is a parameter 'name' then this is parsed by DateFormat. If the
1464 * name does not exist, return null.
1465 *
1466 * @param name A String with the name.
1467 * @return A Date.
1468 */
1469 public Date getDate(String name)
1470 {
1471 Date date = null;
1472
1473 if (containsDateSelectorKeys(name))
1474 {
1475 try
1476 {
1477 Calendar cal = new GregorianCalendar(
1478 getInt(name + DateSelector.YEAR_SUFFIX),
1479 getInt(name + DateSelector.MONTH_SUFFIX),
1480 getInt(name + DateSelector.DAY_SUFFIX));
1481
1482
1483 cal.setLenient(false);
1484 date = cal.getTime();
1485 }
1486 catch (IllegalArgumentException e)
1487 {
1488 logConvertionFailure(name, "n/a", "Date");
1489 }
1490 }
1491 else if (containsTimeSelectorKeys(name))
1492 {
1493 try
1494 {
1495 String ampm = getString(name + TimeSelector.AMPM_SUFFIX);
1496 int hour = getInt(name + TimeSelector.HOUR_SUFFIX);
1497
1498
1499 if (ampm != null)
1500 {
1501 if (hour == 12)
1502 {
1503 hour = (Integer.parseInt(ampm) == Calendar.PM) ? 12 : 0;
1504 }
1505 else if (Integer.parseInt(ampm) == Calendar.PM)
1506 {
1507 hour += 12;
1508 }
1509 }
1510 Calendar cal = new GregorianCalendar(1, 1, 1,
1511 hour,
1512 getInt(name + TimeSelector.MINUTE_SUFFIX),
1513 getInt(name + TimeSelector.SECOND_SUFFIX));
1514
1515
1516 cal.setLenient(false);
1517 date = cal.getTime();
1518 }
1519 catch (IllegalArgumentException e)
1520 {
1521 logConvertionFailure(name, "n/a", "Date");
1522 }
1523 }
1524 else
1525 {
1526 DateFormat df = DateFormat.getDateInstance();
1527 date = getDate(name, df, null);
1528 }
1529
1530 return date;
1531 }
1532
1533 /***
1534 * Returns a {@link java.util.Date} object. String is parsed by supplied
1535 * DateFormat. If the name does not exist, return null.
1536 *
1537 * @param name A String with the name.
1538 * @param df A DateFormat.
1539 * @return A Date.
1540 */
1541 public Date getDate(String name, DateFormat df)
1542 {
1543 return getDate(name, df, null);
1544 }
1545
1546 /***
1547 * Return an NumberKey for the given name. If the name does not
1548 * exist, return null.
1549 *
1550 * @param name A String with the name.
1551 * @return A NumberKey, or <code>null</code> if unparsable.
1552 * @deprecated no replacement
1553 */
1554 public NumberKey getNumberKey(String name)
1555 {
1556 NumberKey result = null;
1557 try
1558 {
1559 String value = getString(name);
1560 if (StringUtils.isNotEmpty(value))
1561 {
1562 result = new NumberKey(value);
1563 }
1564 }
1565 catch (ClassCastException e)
1566 {
1567 log.error("Parameter ("
1568 + name + ") could not be converted to a NumberKey", e);
1569 }
1570 return result;
1571 }
1572
1573 /***
1574 * Return an StringKey for the given name. If the name does not
1575 * exist, return null.
1576 *
1577 * @param name A String with the name.
1578 * @return A StringKey, or <code>null</code> if unparsable.
1579 * @deprecated no replacement
1580 */
1581 public StringKey getStringKey(String name)
1582 {
1583 StringKey result = null;
1584 try
1585 {
1586 String value = getString(name);
1587 if (StringUtils.isNotEmpty(value))
1588 {
1589 result = new StringKey(value);
1590 }
1591 }
1592 catch (ClassCastException e)
1593 {
1594 log.error("Parameter ("
1595 + name + ") could not be converted to a StringKey", e);
1596 }
1597 return result;
1598 }
1599
1600 /***
1601 * Uses bean introspection to set writable properties of bean from
1602 * the parameters, where a (case-insensitive) name match between
1603 * the bean property and the parameter is looked for.
1604 *
1605 * @param bean An Object.
1606 * @exception Exception a generic exception.
1607 */
1608 public void setProperties(Object bean) throws Exception
1609 {
1610 Class beanClass = bean.getClass();
1611 PropertyDescriptor[] props
1612 = Introspector.getBeanInfo(beanClass).getPropertyDescriptors();
1613
1614 for (int i = 0; i < props.length; i++)
1615 {
1616 String propname = props[i].getName();
1617 Method setter = props[i].getWriteMethod();
1618 if (setter != null &&
1619 (containsKey(propname) ||
1620 containsDateSelectorKeys(propname) ||
1621 containsTimeSelectorKeys(propname)))
1622 {
1623 setProperty(bean, props[i]);
1624 }
1625 }
1626 }
1627
1628 /***
1629 * Simple method that attempts to get a textual representation of
1630 * this object's name/value pairs. String[] handling is currently
1631 * a bit rough.
1632 *
1633 * @return A textual representation of the parsed name/value pairs.
1634 */
1635 public String toString()
1636 {
1637 StringBuffer sb = new StringBuffer();
1638 for (Iterator iter = keySet().iterator(); iter.hasNext();)
1639 {
1640 String name = (String) iter.next();
1641
1642 sb.append('{');
1643 sb.append(name);
1644 sb.append('=');
1645 Object [] params = getToStringParam(name);
1646
1647 if (params == null)
1648 {
1649 sb.append("unknown?");
1650 }
1651 else if (params.length == 0)
1652 {
1653 sb.append("empty");
1654 }
1655 else
1656 {
1657 sb.append('[');
1658 for (Iterator it = new ArrayIterator(params); it.hasNext(); )
1659 {
1660 sb.append(it.next());
1661 if (it.hasNext())
1662 {
1663 sb.append(", ");
1664 }
1665 }
1666 sb.append(']');
1667 }
1668 sb.append("}\n");
1669 }
1670
1671 return sb.toString();
1672 }
1673
1674 /***
1675 * This method is only used in toString() and can be used by
1676 * derived classes to add their local parameters to the toString()
1677
1678 * @param name A string with the name
1679 *
1680 * @return the value object array or null if not set
1681 */
1682 protected Object [] getToStringParam(final String name)
1683 {
1684 return getParam(name);
1685 }
1686
1687 /***
1688 * Set the property 'prop' in the bean to the value of the
1689 * corresponding parameters. Supports all types supported by
1690 * getXXX methods plus a few more that come for free because
1691 * primitives have to be wrapped before being passed to invoke
1692 * anyway.
1693 *
1694 * @param bean An Object.
1695 * @param prop A PropertyDescriptor.
1696 * @exception Exception a generic exception.
1697 */
1698 protected void setProperty(Object bean,
1699 PropertyDescriptor prop)
1700 throws Exception
1701 {
1702 if (prop instanceof IndexedPropertyDescriptor)
1703 {
1704 throw new Exception(prop.getName() +
1705 " is an indexed property (not supported)");
1706 }
1707
1708 Method setter = prop.getWriteMethod();
1709 if (setter == null)
1710 {
1711 throw new Exception(prop.getName() +
1712 " is a read only property");
1713 }
1714
1715 Class propclass = prop.getPropertyType();
1716 Object[] args = {null};
1717
1718 if (propclass == String.class)
1719 {
1720 args[0] = getString(prop.getName());
1721 }
1722 else if (propclass == Integer.class || propclass == Integer.TYPE)
1723 {
1724 args[0] = getIntObject(prop.getName());
1725 }
1726 else if (propclass == Long.class || propclass == Long.TYPE)
1727 {
1728 args[0] = new Long(getLong(prop.getName()));
1729 }
1730 else if (propclass == Boolean.class || propclass == Boolean.TYPE)
1731 {
1732 args[0] = getBooleanObject(prop.getName());
1733 }
1734 else if (propclass == Double.class || propclass == Double.TYPE)
1735 {
1736 args[0] = new Double(getDouble(prop.getName()));
1737 }
1738 else if (propclass == BigDecimal.class)
1739 {
1740 args[0] = getBigDecimal(prop.getName());
1741 }
1742 else if (propclass == String[].class)
1743 {
1744 args[0] = getStrings(prop.getName());
1745 }
1746 else if (propclass == Object.class)
1747 {
1748 args[0] = getObject(prop.getName());
1749 }
1750 else if (propclass == int[].class)
1751 {
1752 args[0] = getInts(prop.getName());
1753 }
1754 else if (propclass == Integer[].class)
1755 {
1756 args[0] = getIntObjects(prop.getName());
1757 }
1758 else if (propclass == Date.class)
1759 {
1760 args[0] = getDate(prop.getName());
1761 }
1762 else if (propclass == NumberKey.class)
1763 {
1764 args[0] = getNumberKey(prop.getName());
1765 }
1766 else if (propclass == StringKey.class)
1767 {
1768 args[0] = getStringKey(prop.getName());
1769 }
1770 else
1771 {
1772 throw new Exception("property "
1773 + prop.getName()
1774 + " is of unsupported type "
1775 + propclass.toString());
1776 }
1777
1778 setter.invoke(bean, args);
1779 }
1780
1781 /***
1782 * Writes a log message about a convertion failure.
1783 *
1784 * @param paramName name of the parameter which could not be converted
1785 * @param value value of the parameter
1786 * @param type target data type.
1787 */
1788 private void logConvertionFailure(String paramName,
1789 String value, String type)
1790 {
1791 if (log.isWarnEnabled())
1792 {
1793 log.warn("Parameter (" + paramName
1794 + ") with value of ("
1795 + value + ") could not be converted to a " + type);
1796 }
1797 }
1798
1799 /***
1800 * Puts a key into the parameters map. Makes sure that the name is always
1801 * mapped correctly. This method also enforces the usage of arrays for the
1802 * parameters.
1803 *
1804 * @param name A String with the name.
1805 * @param value An array of Objects with the values.
1806 *
1807 */
1808 protected void putParam(final String name, final String [] value)
1809 {
1810 String key = convert(name);
1811 if (key != null)
1812 {
1813 parameters.put(key, value);
1814 }
1815 }
1816
1817 /***
1818 * fetches a key from the parameters map. Makes sure that the name is
1819 * always mapped correctly.
1820 *
1821 * @param name A string with the name
1822 *
1823 * @return the value object array or null if not set
1824 */
1825 protected String [] getParam(final String name)
1826 {
1827 String key = convert(name);
1828
1829 return (key != null) ? (String []) parameters.get(key) : null;
1830 }
1831 }