KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > fulcrum > intake > model > Field


1 package org.apache.fulcrum.intake.model;
2
3 /* ====================================================================
4  * The Apache Software License, Version 1.1
5  *
6  * Copyright (c) 2001 The Apache Software Foundation. All rights
7  * reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  *
16  * 2. Redistributions in binary form must reproduce the above copyright
17  * notice, this list of conditions and the following disclaimer in
18  * the documentation and/or other materials provided with the
19  * distribution.
20  *
21  * 3. The end-user documentation included with the redistribution,
22  * if any, must include the following acknowledgment:
23  * "This product includes software developed by the
24  * Apache Software Foundation (http://www.apache.org/)."
25  * Alternately, this acknowledgment may appear in the software itself,
26  * if and wherever such third-party acknowledgments normally appear.
27  *
28  * 4. The names "Apache" and "Apache Software Foundation" and
29  * "Apache Turbine" must not be used to endorse or promote products
30  * derived from this software without prior written permission. For
31  * written permission, please contact apache@apache.org.
32  *
33  * 5. Products derived from this software may not be called "Apache",
34  * "Apache Turbine", nor may "Apache" appear in their name, without
35  * prior written permission of the Apache Software Foundation.
36  *
37  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
41  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
44  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
47  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48  * SUCH DAMAGE.
49  * ====================================================================
50  *
51  * This software consists of voluntary contributions made by many
52  * individuals on behalf of the Apache Software Foundation. For more
53  * information on the Apache Software Foundation, please see
54  * <http://www.apache.org/>.
55  */

56
57 import java.lang.reflect.Method JavaDoc;
58 import java.util.Locale JavaDoc;
59
60 import org.apache.fulcrum.ServiceException;
61 import org.apache.fulcrum.TurbineServices;
62 import org.apache.fulcrum.intake.Retrievable;
63 import org.apache.fulcrum.intake.TurbineIntake;
64 import org.apache.fulcrum.intake.validator.InitableByConstraintMap;
65 import org.apache.fulcrum.intake.validator.ValidationException;
66 import org.apache.fulcrum.intake.validator.Validator;
67 import org.apache.fulcrum.intake.xmlmodel.Rule;
68 import org.apache.fulcrum.intake.xmlmodel.XmlField;
69 import org.apache.fulcrum.localization.LocalizationService;
70 import org.apache.fulcrum.parser.ParameterParser;
71 import org.apache.fulcrum.parser.ValueParser;
72 import org.apache.log4j.Category;
73 import org.apache.turbine.services.yaaficomponent.YaafiComponentService;
74
75 /**
76  * Base class for Intake generated input processing classes.
77  *
78  * @author <a HREF="mailto:jmcnally@collab.net>John McNally</a>
79  * @author <a HREF="mailto:dlr@finemaltcoding.com>Daniel Rall</a>
80  * @author <a HREF="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
81  * @version $Id: Field.java,v 1.1 2004/11/12 10:25:38 epugh Exp $
82  */

83 public abstract class Field
84 {
85     private static final String JavaDoc EMPTY = "";
86     private static final String JavaDoc VALUE_IF_ABSENT_KEY = "_vifa_";
87
88     // the following are set from the xml file and are permanent (final)
89
protected final String JavaDoc name;
90     protected final String JavaDoc key;
91     protected String JavaDoc displayName;
92     protected final String JavaDoc mapToObject;
93     protected Validator validator;
94     protected final Method JavaDoc getter;
95     protected final Method JavaDoc setter;
96     protected final String JavaDoc ifRequiredMessage;
97     protected final boolean isMultiValued;
98     protected final Group group;
99     protected boolean alwaysRequired;
100     protected Object JavaDoc onError;
101     protected Object JavaDoc defaultValue;
102
103     // these are reset when the Field is returned to the pool
104
protected boolean set_flag;
105     protected boolean valid_flag;
106     protected boolean required;
107     protected boolean initialized;
108     protected String JavaDoc message;
109     protected Retrievable retrievable;
110
111     private Locale JavaDoc locale;
112     private String JavaDoc stringValue;
113     private String JavaDoc[] stringValues;
114     private Object JavaDoc validValue;
115     private Object JavaDoc testValue;
116     private Object JavaDoc[] valArray; // for reflection
117

118     /**
119      * The object containing the field data.
120      * TODO: Rename to parser.
121      */

122     protected ValueParser pp;
123
124     /**
125      * Log4j category
126      */

127     Category category = Category.getInstance(getClass().getName());
128
129     /**
130      * Constructs a field based on data in the xml specification
131      * and assigns it to a Group.
132      *
133      * @param field a <code>XmlField</code> value
134      * @param group a <code>Group</code> value
135      * @param locale The locale
136      * @exception Exception if an error occurs
137      */

138     public Field(XmlField field, Group group)
139         throws Exception JavaDoc
140     {
141         this.group = group;
142         key = field.getKey();
143         name = field.getName();
144         displayName = field.getDisplayName();
145         isMultiValued = field.isMultiValued();
146         setDefaultValue(field.getDefaultValue());
147         String JavaDoc className = field.getValidator();
148         if ( className == null && field.getRules().size() > 0 )
149         {
150             className = getDefaultValidator();
151         }
152         else if ( className != null && className.indexOf('.') == -1 )
153         {
154             className = "org.apache.fulcrum.intake.validator."
155                 + className;
156         }
157
158         if ( className != null )
159         {
160             validator = (Validator)Class.forName(className).newInstance();
161             // this should always be true for now
162
// (until bean property initialization is implemented)
163
if ( validator instanceof InitableByConstraintMap )
164             {
165                 ((InitableByConstraintMap)validator).init(field.getRuleMap());
166             }
167
168         }
169
170         // field may have been declared as always required in the xml spec
171
Rule reqRule = (Rule)field.getRuleMap().get("required");
172         if ( reqRule != null )
173         {
174             alwaysRequired = new Boolean JavaDoc(reqRule.getValue()).booleanValue();
175         }
176
177         mapToObject = field.getMapToObject();
178         String JavaDoc propName = field.getMapToProperty();
179         Method JavaDoc tmpGetter = null;
180         Method JavaDoc tmpSetter = null;
181         if ( mapToObject != null && mapToObject.length() != 0)
182         {
183             tmpGetter = TurbineIntake.getFieldGetter(mapToObject, propName);
184             tmpSetter = TurbineIntake.getFieldSetter(mapToObject, propName);
185         }
186         getter = tmpGetter;
187         setter = tmpSetter;
188         ifRequiredMessage = field.getIfRequiredMessage();
189
190         valArray = new Object JavaDoc[1];
191     }
192
193
194     /**
195      * Method called when this field (the group it belongs to) is
196      * pulled from the pool. The request data is searched to determine
197      * if a value has been supplied for this field. if so, the value
198      * is validated.
199      *
200      * @param pp a <code>ValueParser</code> value
201      * @return a <code>Field</code> value
202      * @exception ServiceException if an error occurs
203      */

204     public Field init(ValueParser pp)
205         throws ServiceException
206     {
207         this.pp = pp;
208         valid_flag = true;
209
210         // If the parser is for a HTTP request, use the request it's
211
// associated with to grok the locale.
212
try {
213             LocalizationService localizationService = getLocalizationService();
214            // if (TurbineServices.getInstance()
215
// .isRegistered(LocalizationService.SERVICE_NAME))
216
// {
217
if (pp instanceof ParameterParser)
218                     {
219                         this.locale = localizationService.getLocale
220                             ( ((ParameterParser)pp).getRequest() );
221                     }
222                     else
223                     {
224                         this.locale = localizationService.getLocale((String JavaDoc)null);
225                     }
226                 //}
227
}
228         catch (Exception JavaDoc e){
229             System.out.println("localization service not registered");
230         }
231        
232
233         if ( pp.containsKey(getKey()) && pp.getString(getKey()) != null )
234         {
235             set_flag = true;
236             if (validate(pp))
237             {
238                 // iv.reconcileNotValid(pp);
239
}
240         }
241         else if ( pp.containsKey(getValueIfAbsent()) &&
242                   pp.getString(getValueIfAbsent()) != null )
243         {
244             pp.add(getKey(), pp.getString(getValueIfAbsent()));
245             set_flag = true;
246             validate(pp);
247         }
248
249         initialized = true;
250         return this;
251     }
252
253     /**
254      * Method called when this field or the group it belongs to is
255      * pulled from the pool. The retrievable object can provide
256      * a default value for the field, or using setProperty the field's
257      * value can be transferred to the retrievable.
258      *
259      * @param obj a <code>Retrievable</code> value
260      * @return a <code>Field</code> value
261      */

262     public Field init(Retrievable obj)
263     {
264         if ( !initialized )
265         {
266             valid_flag = true;
267         }
268         retrievable = obj;
269         return this;
270     }
271
272     /**
273      * Returns the <code>Locale</code> used when localizing data for
274      * this field, or <code>null</code> if unknown.
275      *
276      * @return Where to localize for.
277      */

278     protected Locale JavaDoc getLocale()
279     {
280         return locale;
281     }
282
283     /**
284      * Produces the fully qualified class name of the default validator.
285      */

286     protected String JavaDoc getDefaultValidator()
287     {
288         return "org.apache.fulcrum.intake.validator.DefaultValidator";
289     }
290
291     public Validator getValidator()
292     {
293         return validator;
294     }
295
296     /**
297      * Flag to determine whether the field has been declared as required.
298      * @return value of required.
299      */

300     public boolean isRequired()
301     {
302         return alwaysRequired || required;
303     }
304
305     /**
306      * Set whether this field is required to have a value.
307      * @param v Value to assign to required.
308      */

309     public void setRequired(boolean v)
310     {
311         setRequired(v, ifRequiredMessage);
312     }
313
314     /**
315      * Set the value of required.
316      *
317      * @param v a <code>boolean</code> value
318      * @param message, override the value from intake.xml
319      */

320     public void setRequired(boolean v, String JavaDoc message)
321     {
322         this.required = v;
323         if (v && !set_flag)
324         {
325             valid_flag=false;
326             this.message = message;
327         }
328     }
329
330     /**
331      * Removes references to this group and its fields from the
332      * query parameters
333      */

334     public void removeFromRequest()
335     {
336         pp.remove(getKey());
337     }
338
339
340     /**
341      * Disposes the object after use. The method is called
342      * when the Group is returned to its pool.
343      * if overridden, super.dispose() should be called.
344      */

345     public void dispose()
346     {
347         pp = null;
348         initialized = false;
349         set_flag = false;
350         valid_flag = false;
351         required = false;
352         message = null;
353         retrievable = null;
354
355         locale = null;
356         stringValue = null;
357         stringValues = null;
358         validValue = null;
359         testValue = null;
360         valArray[0] = null;
361     }
362
363     /**
364      * Get the key used to identify the field.
365      * @return the query data key.
366      */

367     public String JavaDoc getKey()
368     {
369         if ( group == null )
370         {
371             return key;
372         }
373         else
374         {
375             return group.getObjectKey() + key;
376         }
377     }
378
379     /**
380      * Use in a hidden field assign a default value in the event the
381      * field is absent from the query parameters. Used to track checkboxes,
382      * since they only show up if checked.
383      */

384     public String JavaDoc getValueIfAbsent()
385     {
386         return getKey() + VALUE_IF_ABSENT_KEY;
387     }
388
389     /**
390      * Flag set to true, if the test value met the constraints.
391      * Is also true, in the case the test value was not set,
392      * unless this field has been marked as required.
393      *
394      * @return a <code>boolean</code> value
395      */

396     public boolean isValid()
397     {
398         return valid_flag;
399     }
400
401     /**
402      * Flag set to true, if the test value has been set to
403      * anything other than an empty value.
404      *
405      * @return a <code>boolean</code> value
406      */

407     public boolean isSet()
408     {
409         return set_flag;
410     }
411
412     /**
413      * Get the display name of the field. Useful for building
414      * data entry forms. Returns name of field if no display
415      * name has been assigned to the field by xml input file
416      *
417      * @return a <code>String</code> value
418      */

419     public String JavaDoc getDisplayName()
420     {
421         return (displayName == null) ? name : displayName;
422     }
423
424     /**
425      * Set the display name of the field. Display names are
426      * used in building data entry forms and serve as a
427      * user friendly description of the data contained in
428      * the field.
429      */

430     public void setDisplayName(String JavaDoc newDisplayName)
431     {
432         displayName = newDisplayName;
433     }
434
435     /**
436      * Get any error message resulting from invalid input.
437      *
438      * @return a <code>String</code> value
439      */

440     public String JavaDoc getMessage()
441     {
442         if ( message == null )
443         {
444             return EMPTY;
445         }
446         return message;
447     }
448
449     /**
450      * Sets an error message. The field is also marked as invalid.
451      */

452     public void setMessage(String JavaDoc message)
453     {
454          this.message = message;
455          valid_flag = false;
456     }
457
458     /**
459      * @deprecated Call validate() instead (with no parameters).
460      */

461     protected boolean validate(ValueParser pp)
462     {
463         return validate();
464     }
465
466     /**
467      * Compares request data with constraints and sets the valid flag.
468      */

469     protected boolean validate()
470     // throws ServiceException
471
{
472         if ( isMultiValued )
473         {
474             stringValues = pp.getStrings(getKey());
475             // this definition of not set might need refined. But
476
// not sure the situation will arise.
477
if ( stringValues.length == 0 ||
478                  (stringValues.length == 1 && stringValues[0] == null) )
479             {
480                 set_flag = false;
481             }
482
483             if ( validator != null )
484             {
485                 // set the test value as a String[] which might be replaced by
486
// the correct type if the input is valid.
487
setTestValue(pp.getStrings(getKey()));
488                 for (int i=0; i<stringValues.length; i++)
489                 {
490                     try
491                     {
492                         validator.assertValidity(stringValues[i]);
493                     }
494                     catch (ValidationException ve)
495                     {
496                         setMessage(ve.getMessage());
497                     }
498                 }
499             }
500
501             if ( set_flag && valid_flag )
502             {
503                 doSetValue(pp);
504             }
505         }
506         else
507         {
508             stringValue = pp.getString(getKey());
509             if ( validator != null )
510             {
511                 // set the test value as a String which might be replaced by
512
// the correct type if the input is valid.
513
setTestValue(pp.getString(getKey()));
514
515                 try
516                 {
517                     validator.assertValidity(stringValue);
518
519                     if ( set_flag )
520                     {
521                         doSetValue(pp);
522                     }
523                 }
524                 catch (ValidationException ve)
525                 {
526                     setMessage(ve.getMessage());
527                 }
528             }
529             else if ( set_flag )
530             {
531                 doSetValue(pp);
532             }
533         }
534
535         return valid_flag;
536     }
537
538     /**
539      * Set the default Value
540      */

541     protected abstract void setDefaultValue(String JavaDoc prop);
542
543     /**
544      * @deprecated Use doSetValue() instead (with no parameters).
545      */

546     protected void doSetValue(ValueParser pp)
547     {
548         doSetValue();
549     }
550
551     /**
552      * Compares request data with constraints and sets the valid flag.
553      * To be implemented in subclasses
554      */

555     protected abstract void doSetValue();
556
557     /**
558      * Set the value used as a default, in the event the field
559      * has not been set yet.
560      *
561      * @param obj an <code>Object</code> value
562      */

563     void setInitialValue(Object JavaDoc obj)
564     {
565         validValue = obj;
566     }
567
568     /**
569      * Get the value used as a default. If the initial value has
570      * not been set and a <code>Retrievable</code> object has
571      * been associated with this field, the objects property will
572      * be used as the initial value.
573      *
574      * @return an <code>Object</code> value
575      * @exception Exception if an error occurs
576      */

577     public Object JavaDoc getInitialValue()
578         throws Exception JavaDoc
579     {
580         if ( validValue == null)
581         {
582             if ( retrievable != null )
583             {
584                 getProperty(retrievable);
585             }
586             else
587             {
588                 getDefault();
589             }
590         }
591         return validValue;
592     }
593
594     /**
595      * Set the value input by a user that will be validated.
596      *
597      * @param obj an <code>Object</code> value
598      */

599     void setTestValue(Object JavaDoc obj)
600     {
601         testValue = obj;
602     }
603
604     /**
605      * Get the value input by a user that will be validated.
606      *
607      * @return an <code>Object</code> value
608      */

609     public Object JavaDoc getTestValue()
610     {
611         return testValue;
612     }
613
614     /**
615      * Get the value of the field. if a test value has been set, it
616      * will be returned as is, unless it is so badly formed that the
617      * validation could not parse it. In most cases the test value
618      * is returned even though invalid, so that it can be returned to
619      * the user to make modifications. if the test value is not set
620      * the initial value is returned.
621      *
622      * @return an <code>Object</code> value
623      */

624     public Object JavaDoc getValue()
625     {
626         Object JavaDoc val = null;
627         try
628         {
629             val = getInitialValue();
630         }
631         catch (Exception JavaDoc e)
632         {
633             category.error(e);
634         }
635
636         if ( getTestValue() != null )
637         {
638             val = getTestValue();
639         }
640
641         if ( val == null )
642         {
643             val = onError;
644         }
645         return val;
646     }
647
648     /**
649      * Calls toString() on the object returned by getValue(),
650      * unless null; and then it returns "", the empty String.
651      *
652      * @return a <code>String</code> value
653      */

654     public String JavaDoc toString()
655     {
656         if ( stringValue != null )
657         {
658             return stringValue;
659         }
660         else if ( getValue() != null )
661         {
662             return getValue().toString();
663         }
664         else
665         {
666             return EMPTY;
667         }
668     }
669
670     /**
671      * Loads the valid value from a bean
672      */

673     public void getProperty(Object JavaDoc obj)
674         throws Exception JavaDoc
675     {
676         validValue = getter.invoke(obj, null);
677     }
678
679     /**
680      * Loads the default value from the object
681      */

682     
683     public void getDefault()
684     {
685         validValue = getDefaultValue();
686     }
687
688     /**
689      * Calls a setter method on obj, if this field has been set.
690      * @exception throws a ServiceException if called and the input
691      * was not valid.
692      */

693     public void setProperty(Object JavaDoc obj)
694     // public void setProperty($appData.BasePackage$field.MapToObject obj)
695
throws ServiceException
696     {
697         if (!isValid())
698         {
699             throw new ServiceException(
700                 "Attempted to assign an invalid input.");
701         }
702         if (isSet() && getTestValue() != null)
703         {
704             try
705             {
706                 valArray[0] = getTestValue();
707                 setter.invoke(obj, valArray);
708             }
709             catch ( Exception JavaDoc e)
710             {
711                 throw new ServiceException("An exception prevented the" +
712                     " setting property "+name+" of " + obj + " to " +
713                                            valArray[0], e);
714             }
715         }
716     }
717     
718     /**
719      * Get the default Value
720      */

721     public Object JavaDoc getDefaultValue()
722     {
723         return defaultValue;
724     }
725     
726     /**
727      * Utility method for accessing the service implementation.
728      * NOTE! Throw an exception in place of an isRegistered call
729      *
730      * @return a LocalizationService implementation instance
731      */

732     protected static LocalizationService getLocalizationService() throws Exception JavaDoc{
733         
734         YaafiComponentService yaafi = (YaafiComponentService) TurbineServices.getInstance().getService(
735                 YaafiComponentService.SERVICE_NAME);
736         return (LocalizationService) yaafi.lookup(LocalizationService.class.getName());
737         
738     }
739 }
740
Popular Tags