1 package org.apache.turbine.services.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;
58 import org.apache.turbine.om.Retrievable;
59 import org.apache.turbine.services.intake.TurbineIntake;
60 import org.apache.turbine.services.intake.validator.InitableByConstraintMap;
61 import org.apache.turbine.services.intake.validator.ValidationException;
62 import org.apache.turbine.services.intake.validator.Validator;
63 import org.apache.turbine.services.intake.xmlmodel.Rule;
64 import org.apache.turbine.services.intake.xmlmodel.XmlField;
65 import org.apache.turbine.util.Log;
66 import org.apache.turbine.util.ParameterParser;
67 import org.apache.turbine.util.RunData;
68 import org.apache.turbine.util.TurbineException;
69
70 /***
71 * Base class for Intake generated input processing classes.
72 *
73 * @author <a href="mailto:jmcnally@collab.net>John McNally</a>
74 * @version $Id: Field.java,v 1.3 2002/07/11 16:53:27 mpoeschl Exp $
75 */
76 public abstract class Field
77 {
78 private static final String EMPTY = "";
79 private static final String VALUE_IF_ABSENT_KEY = "_vifa_";
80
81 // the following are set from the xml file and are permanent (final)
82 protected final String name;
83 protected final String key;
84 protected String displayName;
85 protected final String mapToObject;
86 protected Validator validator;
87 protected final Method getter;
88 protected final Method setter;
89 protected final String ifRequiredMessage;
90 protected final boolean isMultiValued;
91 protected final Group group;
92 protected boolean alwaysRequired;
93 protected Object onError;
94 protected Object defaultValue;
95
96 // these are reset when the Field is returned to the pool
97 protected boolean set_flag;
98 protected boolean valid_flag;
99 protected boolean required;
100 protected boolean initialized;
101 protected String message;
102 protected Retrievable retrievable;
103
104 private Object validValue;
105 private Object testValue;
106 private Object[] valArray; // for reflection
107
108 /*** The object containing the request data */
109 protected RunData data;
110
111 /***
112 * Constructs a field based on data in the xml specification
113 * and assigns it to a Group.
114 *
115 * @param field a <code>XmlField</code> value
116 * @param group a <code>Group</code> value
117 * @exception Exception if an error occurs
118 */
119 public Field(XmlField field, Group group)
120 throws Exception
121 {
122 this.group = group;
123 key = field.getKey();
124 name = field.getName();
125 displayName = field.getDisplayName();
126 isMultiValued = field.isMultiValued();
127 setDefaultValue(field.getDefaultValue());
128 String className = field.getValidator();
129 if ( className == null && field.getRules().size() > 0 )
130 {
131 className = getDefaultValidator();
132 }
133 else if ( className != null && className.indexOf('.') == -1 )
134 {
135 className = "org.apache.turbine.services.intake.validator."
136 + className;
137 }
138
139 if ( className != null )
140 {
141 validator = (Validator)Class.forName(className).newInstance();
142 // this should always be true for now
143 // (until bean property initialization is implemented)
144 if ( validator instanceof InitableByConstraintMap )
145 {
146 ((InitableByConstraintMap)validator).init(field.getRuleMap());
147 }
148
149 }
150
151 // field may have been declared as always required in the xml spec
152 Rule reqRule = (Rule)field.getRuleMap().get("required");
153 if ( reqRule != null )
154 {
155 alwaysRequired = new Boolean(reqRule.getValue()).booleanValue();
156 }
157
158 mapToObject = field.getMapToObject();
159 String propName = field.getMapToProperty();
160 Method tmpGetter = null;
161 Method tmpSetter = null;
162 if ( mapToObject != null && mapToObject.length() != 0)
163 {
164 tmpGetter = TurbineIntake.getFieldGetter(mapToObject, propName);
165 tmpSetter = TurbineIntake.getFieldSetter(mapToObject, propName);
166 }
167 getter = tmpGetter;
168 setter = tmpSetter;
169 ifRequiredMessage = field.getIfRequiredMessage();
170
171 valArray = new Object[1];
172 }
173
174
175 /***
176 * Method called when this field (the group it belongs to) is
177 * pulled from the pool. The request data is searched to determine
178 * if a value has been supplied for this field. if so, the value
179 * is validated.
180 *
181 * @param data a <code>RunData</code> value
182 * @return a <code>Field</code> value
183 * @exception TurbineException if an error occurs
184 */
185 public Field init(RunData data)
186 throws TurbineException
187 {
188 this.data = data;
189 valid_flag = true;
190
191 ParameterParser pp = data.getParameters();
192 if ( pp.containsKey(getKey()) && pp.getString(getKey()) != null )
193 {
194 set_flag = true;
195 if (validate(pp))
196 {
197 // iv.reconcileNotValid(pp);
198 }
199 }
200 else if ( pp.containsKey(getValueIfAbsent()) &&
201 pp.getString(getValueIfAbsent()) != null )
202 {
203 pp.add(getKey(), pp.getString(getValueIfAbsent()));
204 set_flag = true;
205 validate(pp);
206 }
207
208 initialized = true;
209 return this;
210 }
211
212 /***
213 * Method called when this field or the group it belongs to is
214 * pulled from the pool. The retrievable object can provide
215 * a default value for the field, or using setProperty the field's
216 * value can be transferred to the retrievable.
217 *
218 * @param obj a <code>Retrievable</code> value
219 * @return a <code>Field</code> value
220 */
221 public Field init(Retrievable obj)
222 {
223 if ( !initialized )
224 {
225 valid_flag = true;
226 }
227 retrievable = obj;
228 return this;
229 }
230
231
232 protected String getDefaultValidator()
233 {
234 return "org.apache.turbine.services.intake.validator.DefaultValidator";
235 }
236
237 public Validator getValidator()
238 {
239 return validator;
240 }
241
242 /***
243 * Flag to determine whether the field has been declared as required.
244 * @return value of required.
245 */
246 public boolean isRequired()
247 {
248 return alwaysRequired || required;
249 }
250
251 /***
252 * Set whether this field is required to have a value.
253 * @param v Value to assign to required.
254 */
255 public void setRequired(boolean v)
256 {
257 setRequired(v, ifRequiredMessage);
258 }
259
260 /***
261 * Set the value of required.
262 *
263 * @param v a <code>boolean</code> value
264 * @param message, override the value from intake.xml
265 */
266 public void setRequired(boolean v, String message)
267 {
268 this.required = v;
269 if (v && !set_flag)
270 {
271 valid_flag=false;
272 this.message = message;
273 }
274 }
275
276 /***
277 * Removes references to this group and its fields from the
278 * query parameters
279 */
280 public void removeFromRequest()
281 {
282 data.getParameters().remove(getKey());
283 }
284
285
286 /***
287 * Disposes the object after use. The method is called
288 * when the Group is returned to its pool.
289 * if overridden, super.dispose() should be called.
290 */
291 public void dispose()
292 {
293 data = null;
294 initialized = false;
295 set_flag = false;
296 valid_flag = false;
297 required = false;
298 message = null;
299 retrievable = null;
300
301 validValue = null;
302 testValue = null;
303 valArray[0] = null;
304 }
305
306 /***
307 * Get the key used to identify the field.
308 * @return the query data key.
309 */
310 public String getKey()
311 {
312 if ( group == null )
313 {
314 return key;
315 }
316 else
317 {
318 return group.getObjectKey() + key;
319 }
320 }
321
322 /***
323 * Use in a hidden field assign a default value in the event the
324 * field is absent from the query parameters. Used to track checkboxes,
325 * since they only show up if checked.
326 */
327 public String getValueIfAbsent()
328 {
329 return getKey() + VALUE_IF_ABSENT_KEY;
330 }
331
332 /***
333 * Flag set to true, if the test value met the constraints.
334 * Is also true, in the case the test value was not set,
335 * unless this field has been marked as required.
336 *
337 * @return a <code>boolean</code> value
338 */
339 public boolean isValid()
340 {
341 return valid_flag;
342 }
343
344 /***
345 * Flag set to true, if the test value has been set to
346 * anything other than an empty value.
347 *
348 * @return a <code>boolean</code> value
349 */
350 public boolean isSet()
351 {
352 return set_flag;
353 }
354
355 /***
356 * Get the display name of the field. Useful for building
357 * data entry forms. Returns name of field if no display
358 * name has been assigned to the field by xml input file
359 *
360 * @return a <code>String</code> value
361 */
362 public String getDisplayName()
363 {
364 return (displayName == null) ? name : displayName;
365 }
366
367 /***
368 * Set the display name of the field. Display names are
369 * used in building data entry forms and serve as a
370 * user friendly description of the data contained in
371 * the field.
372 */
373 public void setDisplayName(String newDisplayName)
374 {
375 displayName = newDisplayName;
376 }
377
378 /***
379 * Get any error message resulting from invalid input.
380 *
381 * @return a <code>String</code> value
382 */
383 public String getMessage()
384 {
385 if ( message == null )
386 {
387 return EMPTY;
388 }
389 return message;
390 }
391
392 /***
393 * Sets an error message. The field is also marked as invalid.
394 */
395 public void setMessage(String message)
396 {
397 this.message = message;
398 valid_flag = false;
399 }
400
401 /***
402 * Compares request data with constraints and sets the valid flag.
403 */
404 protected boolean validate(ParameterParser pp)
405 // throws TurbineException
406 {
407 if ( isMultiValued )
408 {
409 String[] ss = pp.getStrings(getKey());
410 // this definition of not set might need refined. But
411 // not sure the situation will arise.
412 if ( ss.length == 0 || (ss.length == 1 && ss[0].length() == 0) )
413 {
414 set_flag = false;
415 }
416
417 if ( validator != null )
418 {
419 for (int i=0; i<ss.length; i++)
420 {
421 try
422 {
423 validator.assertValidity(ss[i]);
424 }
425 catch (ValidationException ve)
426 {
427 setMessage(ve.getMessage());
428 }
429 }
430 }
431
432 if ( set_flag && valid_flag )
433 {
434 doSetValue(pp);
435 }
436
437 }
438 else
439 {
440 String s = pp.getString(getKey());
441 if ( s.length() == 0 )
442 {
443 set_flag = false;
444 }
445
446 if ( validator != null )
447 {
448 try
449 {
450 validator.assertValidity(s);
451
452 if ( set_flag )
453 {
454 doSetValue(pp);
455 }
456 }
457 catch (ValidationException ve)
458 {
459 setMessage(ve.getMessage());
460 }
461 }
462 else if ( set_flag )
463 {
464 doSetValue(pp);
465 }
466 }
467
468 return valid_flag;
469 }
470
471 /***
472 * Compares request data with constraints and sets the valid flag.
473 * To be implemented in subclasses
474 */
475 protected abstract void doSetValue(ParameterParser pp);
476
477 /***
478 * Set the default Value
479 */
480 protected abstract void setDefaultValue(String prop);
481
482
483 /***
484 * Set the value used as a default, in the event the field
485 * has not been set yet.
486 *
487 * @param obj an <code>Object</code> value
488 */
489 void setInitialValue(Object obj)
490 {
491 validValue = obj;
492 }
493
494 /***
495 * Get the value used as a default. If the initial value has
496 * not been set and a <code>Retrievable</code> object has
497 * been associated with this field, the objects property will
498 * be used as the initial value.
499 *
500 * @return an <code>Object</code> value
501 * @exception Exception if an error occurs
502 */
503 public Object getInitialValue()
504 throws Exception
505 {
506 if ( validValue == null)
507 {
508 if ( retrievable != null )
509 {
510 getProperty(retrievable);
511 }
512 else
513 {
514 getDefault();
515 }
516 }
517 return validValue;
518 }
519
520 /***
521 * Set the value input by a user that will be validated.
522 *
523 * @param obj an <code>Object</code> value
524 */
525 void setTestValue(Object obj)
526 {
527 testValue = obj;
528 }
529
530 /***
531 * Get the value input by a user that will be validated.
532 *
533 * @return an <code>Object</code> value
534 */
535 public Object getTestValue()
536 {
537 return testValue;
538 }
539
540 /***
541 * Get the value of the field. if a test value has been set, it
542 * will be returned as is, unless it is so badly formed that the
543 * validation could not parse it. In most cases the test value
544 * is returned even though invalid, so that it can be returned to
545 * the user to make modifications. if the test value is not set
546 * the initial value is returned.
547 *
548 * @return an <code>Object</code> value
549 */
550 public Object getValue()
551 {
552 Object val = null;
553 try
554 {
555 val = getInitialValue();
556 }
557 catch (Exception e)
558 {
559 Log.error(e);
560 }
561
562 if ( getTestValue() != null )
563 {
564 val = getTestValue();
565 }
566
567 if ( val == null )
568 {
569 val = onError;
570 }
571 return val;
572 }
573
574 /***
575 * Calls toString() on the object returned by getValue(),
576 * unless null; and then it returns "", the empty String.
577 *
578 * @return a <code>String</code> value
579 */
580 public String toString()
581 {
582 if ( getValue() != null )
583 {
584 return getValue().toString();
585 }
586 else
587 {
588 return EMPTY;
589 }
590 }
591
592 /***
593 * Loads the valid value from a bean
594 */
595 public void getProperty(Object obj)
596 throws Exception
597 {
598 validValue = getter.invoke(obj, null);
599 }
600
601 /***
602 * Loads the default value from the object
603 */
604
605 public void getDefault()
606 {
607 validValue = getDefaultValue();
608 }
609
610 /***
611 * Calls a setter method on obj, if this field has been set.
612 * @exception throws a TurbineException if called and the input
613 * was not valid.
614 */
615 public void setProperty(Object obj)
616 // public void setProperty($appData.BasePackage$field.MapToObject obj)
617 throws TurbineException
618 {
619 if (!isValid())
620 {
621 throw new TurbineException(
622 "Attempted to assign an invalid input.");
623 }
624 if (isSet())
625 {
626 try
627 {
628 valArray[0] = getTestValue();
629 setter.invoke(obj, valArray);
630 }
631 catch ( Exception e)
632 {
633 throw new TurbineException("An exception prevented the" +
634 " setting property "+name+" of " + obj + " to " +
635 valArray[0], e);
636 }
637 }
638 }
639
640 /***
641 * Get the default Value
642 */
643 public Object getDefaultValue()
644 {
645 return defaultValue;
646 }
647 }
This page was automatically generated by Maven