View Javadoc

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