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