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