1 package org.apache.turbine.services.intake.model;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.lang.reflect.InvocationTargetException;
23 import java.lang.reflect.Method;
24 import java.util.Locale;
25
26 import org.apache.commons.lang.StringUtils;
27 import org.apache.commons.logging.Log;
28 import org.apache.commons.logging.LogFactory;
29 import org.apache.turbine.om.Retrievable;
30 import org.apache.turbine.services.intake.IntakeException;
31 import org.apache.turbine.services.intake.TurbineIntake;
32 import org.apache.turbine.services.intake.validator.DefaultValidator;
33 import org.apache.turbine.services.intake.validator.InitableByConstraintMap;
34 import org.apache.turbine.services.intake.validator.ValidationException;
35 import org.apache.turbine.services.intake.validator.Validator;
36 import org.apache.turbine.services.intake.xmlmodel.Rule;
37 import org.apache.turbine.services.intake.xmlmodel.XmlField;
38 import org.apache.turbine.util.SystemError;
39 import org.apache.turbine.util.parser.ValueParser;
40
41 /***
42 * Base class for Intake generated input processing classes.
43 *
44 * @author <a href="mailto:jmcnally@collab.net">John McNally</a>
45 * @author <a href="mailto:dlr@finemaltcoding.com>Daniel Rall</a>
46 * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
47 * @author <a href="mailto:quintonm@bellsouth.net">Quinton McCombs</a>
48 * @author <a href="mailto:jh@byteaction.de">Jürgen Hoffmann</a>
49 * @author <a href="mailto:tv@apache.org">Thomas Vandahl</a>
50 * @version $Id: Field.java 645969 2008-04-08 15:12:38Z tv $
51 */
52 public abstract class Field
53 {
54 /*** Empty Value */
55 private static final String EMPTY = "";
56
57 /*** CGI Key for "value if absent" */
58 private static final String VALUE_IF_ABSENT_KEY = "_vifa_";
59
60 /*** Default Validator Package */
61 public static final String defaultValidatorPackage = "org.apache.turbine.services.intake.validator.";
62
63 /*** Default Field Package */
64 public static final String defaultFieldPackage = "org.apache.turbine.services.intake.model.";
65
66
67
68 /*** Name of the field. */
69 protected final String name;
70
71 /*** Key used to identify the field in the parser */
72 protected final String key;
73
74 /*** Display name of the field to be used on data entry forms... */
75 protected String displayName;
76
77 /*** Class name of the object to which the field is mapped */
78 protected final String mapToObject;
79
80 /*** Used to validate the contents of the field */
81 protected Validator validator;
82
83 /*** Getter method in the mapped object used to populate the field */
84 protected final Method getter;
85
86 /*** Setter method in the mapped object used to store the value of field */
87 protected final Method setter;
88
89 /*** Error message set on the field if required and not set by parser */
90 protected String ifRequiredMessage;
91
92 /*** Does this field accept multiple values? */
93 protected final boolean isMultiValued;
94
95 /*** Group to which the field belongs */
96 protected final Group group;
97
98 /*** Is this field always required? This is only set through the XML file */
99 protected boolean alwaysRequired;
100
101 /***
102 * Value of the field if an error occurs while getting
103 * the value from the mapped object
104 */
105 protected Object onError;
106
107 /*** Default value of the field */
108 protected Object defaultValue;
109
110 /*** Value of the field to use if the mapped parameter is empty or non-existant */
111 protected Object emptyValue;
112
113 /*** Display size of the field */
114 private String displaySize;
115
116 /*** Max size of the field */
117 private String maxSize;
118
119
120
121 /*** Has the field has been set from the parser? */
122 protected boolean setFlag;
123
124 /*** Has the field passed the validation test? */
125 protected boolean validFlag;
126
127 /*** Has the field been validated? */
128 protected boolean validated;
129
130 /*** Does the field require a value? */
131 protected boolean required;
132
133 /*** Has the field has been set from the parser? */
134 protected boolean initialized;
135
136 /*** Error message, is any, resulting from validation */
137 protected String message;
138
139 /*** Mapped object used to set the initial field value */
140 protected Retrievable retrievable;
141
142 private Locale locale;
143 /*** String value of the field */
144 private String stringValue;
145 /*** String valuess of the field if isMultiValued=true */
146 private String[] stringValues;
147 /*** Stores the value of the field from the Retrievable object */
148 private Object validValue;
149 /*** Stores the value of the field from the parser */
150 private Object testValue;
151 /*** Used to pass testValue to the setter mathod through reflection */
152 private Object[] valArray;
153 /*** The object containing the field data. */
154 protected ValueParser parser;
155
156 /*** Logging */
157 protected Log log = LogFactory.getLog(this.getClass());
158 protected boolean isDebugEnabled = false;
159
160 /***
161 * Constructs a field based on data in the xml specification
162 * and assigns it to a Group.
163 *
164 * @param field a <code>XmlField</code> value
165 * @param group a <code>Group</code> value
166 * @throws IntakeException indicates the validator was not valid or
167 * could not be loaded.
168 * @throws SystemError only occurs is the Validation object does not
169 * extend InitableByConstraintMap
170 */
171 public Field(XmlField field, Group group) throws IntakeException
172 {
173 isDebugEnabled = log.isDebugEnabled();
174
175 this.group = group;
176 key = field.getKey();
177 name = field.getName();
178 displayName = field.getDisplayName();
179 displaySize = field.getDisplaySize();
180 isMultiValued = field.isMultiValued();
181
182 try
183 {
184 setDefaultValue(field.getDefaultValue());
185 }
186 catch (RuntimeException e)
187 {
188 log.error("Could not set default value of " +
189 this.getDisplayName() + " to "
190 + field.getDefaultValue(), e);
191 }
192
193 try
194 {
195 setEmptyValue(field.getEmptyValue());
196 }
197 catch (RuntimeException e)
198 {
199 log.error("Could not set empty value of " +
200 this.getDisplayName() + " to "
201 + field.getEmptyValue(), e);
202 }
203
204 String validatorClassName = field.getValidator();
205 if (validatorClassName == null)
206 {
207 validatorClassName = getDefaultValidator();
208 }
209 else if (validatorClassName != null
210 && validatorClassName.indexOf('.') == -1)
211 {
212 validatorClassName = defaultValidatorPackage + validatorClassName;
213 }
214
215 if (validatorClassName != null)
216 {
217 try
218 {
219 validator = (Validator)
220 Class.forName(validatorClassName).newInstance();
221 }
222 catch (InstantiationException e)
223 {
224 throw new IntakeException(
225 "Could not create new instance of Validator("
226 + validatorClassName + ")", e);
227 }
228 catch (IllegalAccessException e)
229 {
230 throw new IntakeException(
231 "Could not create new instance of Validator("
232 + validatorClassName + ")", e);
233 }
234 catch (ClassNotFoundException e)
235 {
236 throw new IntakeException(
237 "Could not load Validator class("
238 + validatorClassName + ")", e);
239 }
240
241
242 if (validator instanceof InitableByConstraintMap)
243 {
244 ((InitableByConstraintMap) validator).init(field.getRuleMap());
245 }
246 else
247 {
248 throw new SystemError(
249 "All Validation objects must be subclasses of "
250 + "InitableByConstraintMap");
251 }
252 }
253
254
255 Rule reqRule = (Rule) field.getRuleMap().get("required");
256 if (reqRule != null)
257 {
258 alwaysRequired = Boolean.valueOf(reqRule.getValue()).booleanValue();
259 ifRequiredMessage = reqRule.getMessage();
260 }
261
262 Rule maxLengthRule = (Rule) field.getRuleMap().get("maxLength");
263 if (maxLengthRule != null)
264 {
265 maxSize = maxLengthRule.getValue();
266 }
267
268
269 mapToObject = field.getMapToObject();
270 String propName = field.getMapToProperty();
271 Method tmpGetter = null;
272 Method tmpSetter = null;
273 if (StringUtils.isNotEmpty(mapToObject)
274 && StringUtils.isNotEmpty(propName))
275 {
276 try
277 {
278 tmpGetter = TurbineIntake.getFieldGetter(mapToObject, propName);
279 }
280 catch (Exception e)
281 {
282 log.error("IntakeService could not map the getter for field "
283 + this.getDisplayName() + " in group "
284 + this.group.getIntakeGroupName()
285 + " to the property " + propName + " in object "
286 + mapToObject, e);
287 }
288 try
289 {
290 tmpSetter = TurbineIntake.getFieldSetter(mapToObject, propName);
291 }
292 catch (Exception e)
293 {
294 log.error("IntakeService could not map the setter for field "
295 + this.getDisplayName() + " in group "
296 + this.group.getIntakeGroupName()
297 + " to the property " + propName + " in object "
298 + mapToObject, e);
299 }
300 }
301 getter = tmpGetter;
302 setter = tmpSetter;
303
304 valArray = new Object[1];
305 }
306
307 /***
308 * Method called when this field (the group it belongs to) is
309 * pulled from the pool. The request data is searched to determine
310 * if a value has been supplied for this field. If so, the value
311 * is validated.
312 *
313 * @param pp a <code>ValueParser</code> value
314 * @return a <code>Field</code> value
315 * @throws IntakeException this exception is only thrown by subclasses
316 * overriding this implementation.
317 */
318 public Field init(ValueParser pp)
319 throws IntakeException
320 {
321 this.parser = pp;
322 validFlag = true;
323 validated = false;
324
325 this.locale = pp.getLocale();
326
327 if (pp.containsKey(getKey()))
328 {
329 if (isDebugEnabled)
330 {
331 log.debug(name + ": Found our Key in the request, setting Value");
332 }
333 if (pp.getString(getKey()) != null)
334 {
335 setFlag = true;
336 }
337
338 }
339 else if (pp.containsKey(getValueIfAbsent()) &&
340 pp.getString(getValueIfAbsent()) != null)
341 {
342 pp.add(getKey(), pp.getString(getValueIfAbsent()));
343 setFlag = true;
344
345 }
346
347 initialized = true;
348 return this;
349 }
350
351 /***
352 * Method called when this field or the group it belongs to is
353 * pulled from the pool. The retrievable object can provide
354 * a default value for the field, or using setProperty the field's
355 * value can be transferred to the retrievable.
356 *
357 * @param obj a <code>Retrievable</code> value
358 * @return a <code>Field</code> value
359 */
360 public Field init(Retrievable obj)
361 {
362 if (!initialized)
363 {
364 validFlag = true;
365 validated = false;
366 }
367 retrievable = obj;
368 return this;
369 }
370
371 /***
372 * Returns the <code>Group</code> this field belongs to
373 * or <code>null</code> if unknown.
374 *
375 * @return The group this field belongs to.
376 */
377 public Group getGroup()
378 {
379 return group;
380 }
381
382 /***
383 * Returns the <code>Locale</code> used when localizing data for
384 * this field, or <code>null</code> if unknown.
385 *
386 * @return Where to localize for.
387 */
388 public Locale getLocale()
389 {
390 return locale;
391 }
392
393 /***
394 * Produces the fully qualified class name of the default validator.
395 *
396 * @return class name of the default validator
397 */
398 protected String getDefaultValidator()
399 {
400 return DefaultValidator.class.getName();
401 }
402
403 /***
404 * Gets the Validator object for this field.
405 * @return a <code>Validator</code> object
406 */
407 public Validator getValidator()
408 {
409 return validator;
410 }
411
412 /***
413 * Flag to determine whether the field has been declared as multi-valued.
414 *
415 * @return value of isMultiValued.
416 */
417 public boolean isMultiValued()
418 {
419 return isMultiValued;
420 }
421
422 /***
423 * Flag to determine whether the field has been declared as required.
424 *
425 * @return value of required.
426 */
427 public boolean isRequired()
428 {
429 return alwaysRequired || required;
430 }
431
432 /***
433 * Set whether this field is required to have a value. If the field
434 * is already required due to a setting in the XML file, this method
435 * can not set it to false.
436 *
437 * @param v Value to assign to required.
438 */
439 public void setRequired(boolean v)
440 {
441 setRequired(v, ifRequiredMessage);
442 }
443
444 /***
445 * Set the value of required.
446 *
447 * @param v a <code>boolean</code> value
448 * @param message override the value from intake.xml
449 */
450 public void setRequired(boolean v, String message)
451 {
452 this.required = v;
453 if (v && (!setFlag || null == getTestValue()))
454 {
455 validFlag = false;
456 this.message = message;
457 }
458 }
459
460 /***
461 * Removes references to this group and its fields from the
462 * query parameters
463 */
464 public void removeFromRequest()
465 {
466 parser.remove(getKey());
467 parser.remove(getKey()+ VALUE_IF_ABSENT_KEY);
468 }
469
470 /***
471 * Disposes the object after use. The method is called
472 * when the Group is returned to its pool.
473 * if overridden, super.dispose() should be called.
474 */
475 public void dispose()
476 {
477 parser = null;
478 initialized = false;
479 setFlag = false;
480 validFlag = false;
481 validated = false;
482 required = false;
483 message = null;
484 retrievable = null;
485
486 locale = null;
487 stringValue = null;
488 stringValues = null;
489 validValue = null;
490 testValue = null;
491 valArray[0] = null;
492 }
493
494 /***
495 * Get the key used to identify the field.
496 *
497 * @return the query data key.
498 */
499 public String getKey()
500 {
501 return (group == null) ? key : group.getObjectKey() + key;
502 }
503
504 /***
505 * Use in a hidden field assign a default value in the event the
506 * field is absent from the query parameters. Used to track checkboxes,
507 * since they only show up if checked.
508 */
509 public String getValueIfAbsent()
510 {
511 return getKey() + VALUE_IF_ABSENT_KEY;
512 }
513
514 /***
515 * Flag set to true, if the test value met the constraints.
516 * Is also true, in the case the test value was not set,
517 * unless this field has been marked as required.
518 *
519 * @return a <code>boolean</code> value
520 */
521 public boolean isValid()
522 {
523 return validFlag;
524 }
525
526 /***
527 * Flag to determine whether the field has been validated.
528 *
529 * @return value of validated.
530 */
531 public boolean isValidated()
532 {
533 return validated;
534 }
535
536 /***
537 * Flag set to true, if the test value has been set by the parser (even to
538 * an empty value, so don't used this to determine if the field contains a
539 * non-empty value). Validation will only be executed for fields that have
540 * been set in this manner.
541 *
542 * @return a <code>boolean</code> value
543 */
544 public boolean isSet()
545 {
546 return setFlag;
547 }
548
549 /***
550 * Get the display name of the field. Useful for building
551 * data entry forms. Returns name of field if no display
552 * name has been assigned to the field by xml input file.
553 *
554 * @return a <code>String</code> value
555 */
556 public String getDisplayName()
557 {
558 return (displayName == null) ? name : displayName;
559 }
560
561 /***
562 * Set the display name of the field. Display names are
563 * used in building data entry forms and serve as a
564 * user friendly description of the data contained in
565 * the field.
566 */
567 public void setDisplayName(String newDisplayName)
568 {
569 displayName = newDisplayName;
570 }
571
572 /***
573 * Get any error message resulting from invalid input.
574 *
575 * @return a <code>String</code> value
576 */
577 public String getMessage()
578 {
579 return (message == null) ? EMPTY : message;
580 }
581
582 /***
583 * Sets an error message. The field is also marked as invalid.
584 */
585 public void setMessage(String message)
586 {
587 this.message = message;
588 validFlag = false;
589 }
590
591 /***
592 * @deprecated Call validate() instead (with no parameters).
593 */
594 protected boolean validate(ValueParser pp)
595 {
596 return validate();
597 }
598
599 /***
600 * Compares request data with constraints and sets the valid flag.
601 */
602 public boolean validate()
603 {
604 log.debug(name + ": validate()");
605
606 if (isMultiValued)
607 {
608 stringValues = parser.getStrings(getKey());
609
610 if (isDebugEnabled)
611 {
612 log.debug(name + ": Multi-Valued, Value is " + stringValue);
613 if (stringValues != null)
614 {
615 for (int i = 0; i < stringValues.length; i++)
616 {
617 log.debug(name + ": " + i + ". Value: " + stringValues[i]);
618 }
619 }
620 }
621
622 if (validator != null)
623 {
624
625
626 setTestValue(stringValues);
627
628 try
629 {
630 validator.assertValidity(this);
631 }
632 catch (ValidationException ve)
633 {
634 setMessage(ve.getMessage());
635 }
636 }
637
638 if (validFlag)
639 {
640 doSetValue();
641 }
642 }
643 else
644 {
645 stringValue = parser.getString(getKey());
646
647 if (isDebugEnabled)
648 {
649 log.debug(name + ": Single Valued, Value is " + stringValue);
650 }
651
652 if (validator != null)
653 {
654
655
656 setTestValue(parser.getString(getKey()));
657
658 try
659 {
660 validator.assertValidity(this);
661 log.debug(name + ": Value is ok");
662 doSetValue();
663 }
664 catch (ValidationException ve)
665 {
666 log.debug(name + ": Value failed validation!");
667 setMessage(ve.getMessage());
668 }
669 }
670 else
671 {
672 doSetValue();
673 }
674 }
675
676 validated = true;
677
678 return validFlag;
679 }
680
681 /***
682 * Set the default Value. This value is used if
683 * Intake should map this field to a new object.
684 *
685 * @param prop The value to use if the field is mapped to a new object.
686 */
687 public abstract void setDefaultValue(String prop);
688
689 /***
690 * Set the empty Value. This value is used if Intake
691 * maps a field to a parameter returned by the user and
692 * the corresponding field is either empty (empty string)
693 * or non-existant.
694 *
695 * @param prop The value to use if the field is empty.
696 */
697 public abstract void setEmptyValue(String prop);
698
699 /***
700 * @deprecated Use doSetValue() instead (with no parameters).
701 */
702 protected void doSetValue(ValueParser pp)
703 {
704 doSetValue();
705 }
706
707 /***
708 * Sets the value of the field from data in the parser.
709 */
710 protected abstract void doSetValue();
711
712 /***
713 * Set the value used as a default, in the event the field
714 * has not been set yet.
715 *
716 * @param obj an <code>Object</code> value
717 */
718 void setInitialValue(Object obj)
719 {
720 validValue = obj;
721 }
722
723 /***
724 * Get the value used as a default. If the initial value has
725 * not been set and a <code>Retrievable</code> object has
726 * been associated with this field, the objects property will
727 * be used as the initial value.
728 *
729 * @return an <code>Object</code> value
730 * @exception IntakeException indicates the value could not be
731 * returned from the mapped object
732 */
733 public Object getInitialValue() throws IntakeException
734 {
735 if (validValue == null)
736 {
737 if (retrievable != null)
738 {
739 getProperty(retrievable);
740 }
741 else
742 {
743 getDefault();
744 }
745 }
746 return validValue;
747 }
748
749 /***
750 * Set the value input by a user that will be validated.
751 *
752 * @param obj an <code>Object</code> value
753 */
754 void setTestValue(Object obj)
755 {
756 testValue = obj;
757 }
758
759 /***
760 * Get the value input by a user that will be validated.
761 *
762 * @return an <code>Object</code> value
763 */
764 public Object getTestValue()
765 {
766 return testValue;
767 }
768
769 /***
770 * Get the value of the field. if a test value has been set, it
771 * will be returned as is, unless it is so badly formed that the
772 * validation could not parse it. In most cases the test value
773 * is returned even though invalid, so that it can be returned to
774 * the user to make modifications. If the test value is not set
775 * the initial value is returned.
776 *
777 * @return an <code>Object</code> value
778 */
779 public Object getValue()
780 {
781 Object val = null;
782 try
783 {
784 val = getInitialValue();
785 }
786 catch (IntakeException e)
787 {
788 log.error("Could not get intial value of " + this.getDisplayName() +
789 " in group " + this.group.getIntakeGroupName(), e);
790 }
791
792 if (getTestValue() != null)
793 {
794 val = getTestValue();
795 }
796
797 if (val == null)
798 {
799 val = onError;
800 }
801 return val;
802 }
803
804 /***
805 * Calls toString() on the object returned by getValue(),
806 * unless null; and then it returns "", the empty String.
807 *
808 * @return a <code>String</code> value
809 */
810 public String toString()
811 {
812 String res = EMPTY;
813
814 if (stringValue != null)
815 {
816 res = stringValue;
817 }
818 else if (getValue() != null)
819 {
820 res = getValue().toString();
821 }
822 return res;
823 }
824
825 /***
826 * Calls toString() on the object returned by getValue(),
827 * unless null; and then it returns "", the empty String.
828 * Escapes " characters to be able to display these
829 * in HTML form fields.
830 *
831 * @return a <code>String</code> value
832 */
833 public String getHTMLString()
834 {
835 String res = toString();
836 return StringUtils.replace(res, "\"", """);
837 }
838
839 /***
840 * Loads the valid value from a bean
841 *
842 * @throws IntakeException indicates a problem during the execution of the
843 * object's getter method
844 */
845 public void getProperty(Object obj)
846 throws IntakeException
847 {
848 try
849 {
850 validValue = getter.invoke(obj, (Object[])null);
851 }
852 catch (IllegalAccessException e)
853 {
854 throwSetGetException("getter", obj, this.getDisplayName(),
855 this.group.getIntakeGroupName(), e);
856 }
857 catch (IllegalArgumentException e)
858 {
859 throwSetGetException("getter", obj, this.getDisplayName(),
860 this.group.getIntakeGroupName(), e);
861 }
862 catch (InvocationTargetException e)
863 {
864 throwSetGetException("getter", obj, this.getDisplayName(),
865 this.group.getIntakeGroupName(), e);
866 }
867 }
868
869 /***
870 * Loads the default value from the object
871 */
872
873 public void getDefault()
874 {
875 validValue = getDefaultValue();
876 }
877
878 /***
879 * Calls a setter method on obj, if this field has been set.
880 *
881 * @throws IntakeException indicates a problem during the execution of the
882 * object's setter method
883 */
884 public void setProperty(Object obj) throws IntakeException
885 {
886 if (isDebugEnabled)
887 {
888 log.debug(name + ".setProperty(" + obj.getClass().getName() + ")");
889 }
890
891 if (!isValid())
892 {
893 throw new IntakeException(
894 "Attempted to assign an invalid input.");
895 }
896 if (isSet() && null != getTestValue())
897 {
898 valArray[0] = getTestValue();
899 if (isDebugEnabled)
900 {
901 log.debug(name + ": Property is set, value is " + valArray[0]);
902 }
903 }
904 else
905 {
906 valArray[0] = getSafeEmptyValue();
907 if (isDebugEnabled)
908 {
909 log.debug(name + ": Property is not set, using emptyValue " + valArray[0]);
910 }
911 }
912
913 try
914 {
915
916
917
918
919
920
921 if(setter != null)
922 {
923 setter.invoke(obj, valArray);
924 }
925 else if (isDebugEnabled)
926 {
927 log.debug(name + ": has a null setter for the mapToProperty"
928 + " Attribute, although all Fields should be mapped"
929 + " to " + mapToObject + ". If this is unwanted, you"
930 + " should double check the mapToProperty Attribute, and"
931 + " consult the logs. The Turbine Intake Service will"
932 + " have logged a detailed Message with the error.");
933 }
934 }
935 catch (IllegalAccessException e)
936 {
937 throwSetGetException("setter", obj, this.getDisplayName(),
938 this.group.getIntakeGroupName(), e);
939 }
940 catch (IllegalArgumentException e)
941 {
942 throwSetGetException("setter", obj, this.getDisplayName(),
943 this.group.getIntakeGroupName(), e);
944 }
945 catch (InvocationTargetException e)
946 {
947 throwSetGetException("setter", obj, this.getDisplayName(),
948 this.group.getIntakeGroupName(), e);
949 }
950 }
951
952 /***
953 * Used to throw an IntakeException when an error occurs execuing the
954 * get/set method of the mapped persistent object.
955 *
956 * @param type Type of method. (setter/getter)
957 * @param fieldName Name of the field
958 * @param groupName Name of the group
959 * @param e Exception that was thrown
960 * @throws IntakeException New exception with formatted message
961 */
962 private void throwSetGetException(String type, Object obj,
963 String fieldName, String groupName,
964 Exception e)
965 throws IntakeException
966 {
967 throw new IntakeException("Could not execute " + type
968 + " method for " + fieldName + " in group " + groupName
969 + " on " + obj.getClass().getName(), e);
970
971 }
972
973 /***
974 * Get the default Value
975 *
976 * @return the default value
977 */
978 public Object getDefaultValue()
979 {
980 return defaultValue;
981 }
982
983 /***
984 * Get the Value to use if the field is empty
985 *
986 * @return the value to use if the field is empty.
987 */
988 public Object getEmptyValue()
989 {
990 return emptyValue;
991 }
992
993 /***
994 * Provides access to emptyValue such that the value returned will be
995 * acceptable as an argument parameter to Method.invoke. Subclasses
996 * that deal with primitive types should ensure that they return an
997 * appropriate value wrapped in the object wrapper class for the
998 * primitive type.
999 *
1000 * @return the value to use when the field is empty or an Object that
1001 * wraps the empty value for primitive types.
1002 */
1003 protected Object getSafeEmptyValue()
1004 {
1005 return getEmptyValue();
1006 }
1007
1008 /***
1009 * Gets the name of the field.
1010 *
1011 * @return name of the field as specified in the XML file.
1012 */
1013 public String getName()
1014 {
1015 return name;
1016 }
1017
1018 /***
1019 * Gets the diplay size of the field. This is useful when
1020 * building the HTML input tag. If no displaySize was set,
1021 * an empty string is returned.
1022 */
1023 public String getDisplaySize()
1024 {
1025 return (StringUtils.isEmpty(displaySize) ? "" : displaySize);
1026 }
1027
1028 /***
1029 * Gets the maximum size of the field. This is useful when
1030 * building the HTML input tag. The maxSize is set with the maxLength
1031 * rule. If this rul was not set, an enmpty string is returned.
1032 */
1033 public String getMaxSize()
1034 {
1035 return (StringUtils.isEmpty(maxSize) ? "" : maxSize);
1036 }
1037
1038 /***
1039 * Gets the String representation of the Value. This is basically a wrapper
1040 * method for the toString method which doesn't seem to show anything on
1041 * screen if accessed from Template. Name is also more in line with getValue
1042 * method which returns the actual Object.
1043 * This is useful for displaying correctly formatted data such as dates,
1044 * such as 18/11/1968 instead of the toString dump of a Date Object.
1045 *
1046 * @return the String Value
1047 */
1048 public String getStringValue()
1049 {
1050 return this.toString();
1051 }
1052
1053 }