KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > tapestry > valid > ValidationDelegate


1 // Copyright 2004, 2005 The Apache Software Foundation
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
// http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14

15 package org.apache.tapestry.valid;
16
17 import java.util.ArrayList JavaDoc;
18 import java.util.Collections JavaDoc;
19 import java.util.HashMap JavaDoc;
20 import java.util.Iterator JavaDoc;
21 import java.util.List JavaDoc;
22 import java.util.Map JavaDoc;
23
24 import org.apache.tapestry.IMarkupWriter;
25 import org.apache.tapestry.IRender;
26 import org.apache.tapestry.IRequestCycle;
27 import org.apache.tapestry.Tapestry;
28 import org.apache.tapestry.form.IFormComponent;
29
30 /**
31  * A base implementation of {@link IValidationDelegate}that can be used as a managed bean. This
32  * class is often subclassed, typically to override presentation details.
33  *
34  * @author Howard Lewis Ship
35  * @since 1.0.5
36  */

37
38 public class ValidationDelegate implements IValidationDelegate
39 {
40     private static final long serialVersionUID = 6215074338439140780L;
41
42     private transient IFormComponent _currentComponent;
43
44     /**
45      * A list of {@link IFieldTracking}.
46      */

47
48     private final List JavaDoc _trackings = new ArrayList JavaDoc();
49
50     /**
51      * A map of {@link IFieldTracking}, keyed on form element name.
52      */

53
54     private final Map JavaDoc _trackingMap = new HashMap JavaDoc();
55
56     public void clear()
57     {
58         _currentComponent = null;
59         _trackings.clear();
60         _trackingMap.clear();
61     }
62
63     /**
64      * If the form component is in error, places a <font color="red"< around it. Note: this
65      * will only work on the render phase after a rewind, and will be confused if components are
66      * inside any kind of loop.
67      */

68
69     public void writeLabelPrefix(IFormComponent component, IMarkupWriter writer, IRequestCycle cycle)
70     {
71         if (isInError(component))
72         {
73             writer.begin("font");
74             writer.attribute("color", "red");
75         }
76     }
77
78     /**
79      * Closes the <font> element,started by
80      * {@link #writeLabelPrefix(IFormComponent,IMarkupWriter,IRequestCycle)}, if the form component
81      * is in error.
82      */

83
84     public void writeLabelSuffix(IFormComponent component, IMarkupWriter writer, IRequestCycle cycle)
85     {
86         if (isInError(component))
87         {
88             writer.end();
89         }
90     }
91
92     /**
93      * Returns the {@link IFieldTracking}for the current component, if any. The
94      * {@link IFieldTracking}is usually created in {@link #record(String, ValidationConstraint)}or
95      * in {@link #record(IRender, ValidationConstraint)}.
96      * <p>
97      * Components may be rendered multiple times, with multiple names (provided by the
98      * {@link org.apache.tapestry.form.Form}, care must be taken that this method is invoked
99      * <em>after</em> the Form has provided a unique {@link IFormComponent#getName()}for the
100      * component.
101      *
102      * @see #setFormComponent(IFormComponent)
103      * @return the {@link FieldTracking}, or null if the field has no tracking.
104      */

105
106     protected FieldTracking getComponentTracking()
107     {
108         return (FieldTracking) _trackingMap.get(_currentComponent.getName());
109     }
110
111     public void setFormComponent(IFormComponent component)
112     {
113         _currentComponent = component;
114     }
115
116     public boolean isInError()
117     {
118         IFieldTracking tracking = getComponentTracking();
119
120         return tracking != null && tracking.isInError();
121     }
122
123     public String JavaDoc getFieldInputValue()
124     {
125         IFieldTracking tracking = getComponentTracking();
126
127         return tracking == null ? null : tracking.getInput();
128     }
129
130     /**
131      * Returns all the field trackings as an unmodifiable List.
132      */

133
134     public List JavaDoc getFieldTracking()
135     {
136         if (Tapestry.size(_trackings) == 0)
137             return null;
138
139         return Collections.unmodifiableList(_trackings);
140     }
141
142     /** @since 3.0.2 */
143     public IFieldTracking getCurrentFieldTracking()
144     {
145         return findCurrentTracking();
146     }
147
148     public void reset()
149     {
150         IFieldTracking tracking = getComponentTracking();
151
152         if (tracking != null)
153         {
154             _trackings.remove(tracking);
155             _trackingMap.remove(tracking.getFieldName());
156         }
157     }
158
159     /**
160      * Invokes {@link #record(String, ValidationConstraint)}, or
161      * {@link #record(IRender, ValidationConstraint)}if the
162      * {@link ValidatorException#getErrorRenderer() error renderer property}is not null.
163      */

164
165     public void record(ValidatorException ex)
166     {
167         IRender errorRenderer = ex.getErrorRenderer();
168
169         if (errorRenderer == null)
170             record(ex.getMessage(), ex.getConstraint());
171         else
172             record(errorRenderer, ex.getConstraint());
173     }
174
175     /**
176      * Invokes {@link #record(IRender, ValidationConstraint)}, after wrapping the message parameter
177      * in a {@link RenderString}.
178      */

179
180     public void record(String JavaDoc message, ValidationConstraint constraint)
181     {
182         record(new RenderString(message), constraint);
183     }
184
185     /**
186      * Records error information about the currently selected component, or records unassociated
187      * (with any field) errors.
188      * <p>
189      * Currently, you may have at most one error per <em>field</em> (note the difference between
190      * field and component), but any number of unassociated errors.
191      * <p>
192      * Subclasses may override the default error message (based on other factors, such as the field
193      * and constraint) before invoking this implementation.
194      *
195      * @since 1.0.9
196      */

197
198     public void record(IRender errorRenderer, ValidationConstraint constraint)
199     {
200         FieldTracking tracking = findCurrentTracking();
201
202         // Note that recording two errors for the same field is not advised; the
203
// second will override the first.
204

205         tracking.setErrorRenderer(errorRenderer);
206         tracking.setConstraint(constraint);
207     }
208
209     public void recordFieldInputValue(String JavaDoc input)
210     {
211         FieldTracking tracking = findCurrentTracking();
212
213         tracking.setInput(input);
214     }
215
216     /**
217      * Finds or creates the field tracking for the {@link #setFormComponent(IFormComponent)}
218      * &nbsp;current component. If no current component, an unassociated error is created and
219      * returned.
220      *
221      * @since 3.0
222      */

223
224     protected FieldTracking findCurrentTracking()
225     {
226         FieldTracking result = null;
227
228         if (_currentComponent == null)
229         {
230             result = new FieldTracking();
231
232             // Add it to the field trackings, but not to the
233
// map.
234

235             _trackings.add(result);
236         }
237         else
238         {
239             result = getComponentTracking();
240
241             if (result == null)
242             {
243                 String JavaDoc fieldName = _currentComponent.getName();
244
245                 result = new FieldTracking(fieldName, _currentComponent);
246
247                 _trackings.add(result);
248                 _trackingMap.put(fieldName, result);
249             }
250         }
251
252         return result;
253     }
254
255     /**
256      * Does nothing. Override in a subclass to decoreate fields.
257      */

258
259     public void writePrefix(IMarkupWriter writer, IRequestCycle cycle, IFormComponent component,
260             IValidator validator)
261     {
262     }
263
264     /**
265      * Does nothing. Override in a subclass to decorate fields.
266      */

267
268     public void writeAttributes(IMarkupWriter writer, IRequestCycle cycle,
269             IFormComponent component, IValidator validator)
270     {
271     }
272
273     /**
274      * Default implementation; if the current field is in error, then a suffix is written. The
275      * suffix is: <code>&amp;nbsp;&lt;font color="red"&gt;**&lt;/font&gt;</code>.
276      */

277
278     public void writeSuffix(IMarkupWriter writer, IRequestCycle cycle, IFormComponent component,
279             IValidator validator)
280     {
281         if (isInError())
282         {
283             writer.printRaw("&nbsp;");
284             writer.begin("font");
285             writer.attribute("color", "red");
286             writer.print("**");
287             writer.end();
288         }
289     }
290
291     public boolean getHasErrors()
292     {
293         return getFirstError() != null;
294     }
295
296     /**
297      * A convienience, as most pages just show the first error on the page.
298      * <p>
299      * As of release 1.0.9, this returns an instance of {@link IRender}, not a {@link String}.
300      */

301
302     public IRender getFirstError()
303     {
304         if (Tapestry.size(_trackings) == 0)
305             return null;
306
307         Iterator JavaDoc i = _trackings.iterator();
308
309         while (i.hasNext())
310         {
311             IFieldTracking tracking = (IFieldTracking) i.next();
312
313             if (tracking.isInError())
314                 return tracking.getErrorRenderer();
315         }
316
317         return null;
318     }
319
320     /**
321      * Checks to see if the field is in error. This will <em>not</em> work properly in a loop, but
322      * is only used by {@link FieldLabel}. Therefore, using {@link FieldLabel}in a loop (where the
323      * {@link IFormComponent}is renderred more than once) will not provide correct results.
324      */

325
326     protected boolean isInError(IFormComponent component)
327     {
328         // Get the name as most recently rendered.
329

330         String JavaDoc fieldName = component.getName();
331
332         IFieldTracking tracking = (IFieldTracking) _trackingMap.get(fieldName);
333
334         return tracking != null && tracking.isInError();
335     }
336
337     /**
338      * Returns a {@link List}of {@link IFieldTracking}s. This is the master list of trackings,
339      * except that it omits and trackings that are not associated with a particular field. May
340      * return an empty list, or null.
341      * <p>
342      * Order is not determined, though it is likely the order in which components are laid out on in
343      * the template (this is subject to change).
344      */

345
346     public List JavaDoc getAssociatedTrackings()
347     {
348         int count = Tapestry.size(_trackings);
349
350         if (count == 0)
351             return null;
352
353         List JavaDoc result = new ArrayList JavaDoc(count);
354
355         for (int i = 0; i < count; i++)
356         {
357             IFieldTracking tracking = (IFieldTracking) _trackings.get(i);
358
359             if (tracking.getFieldName() == null)
360                 continue;
361
362             result.add(tracking);
363         }
364
365         return result;
366     }
367
368     /**
369      * Like {@link #getAssociatedTrackings()}, but returns only the unassociated trackings.
370      * Unassociated trackings are new (in release 1.0.9), and are why interface
371      * {@link IFieldTracking}is not very well named.
372      * <p>
373      * The trackings are returned in an unspecified order, which (for the moment, anyway) is the
374      * order in which they were added (this could change in the future, or become more concrete).
375      */

376
377     public List JavaDoc getUnassociatedTrackings()
378     {
379         int count = Tapestry.size(_trackings);
380
381         if (count == 0)
382             return null;
383
384         List JavaDoc result = new ArrayList JavaDoc(count);
385
386         for (int i = 0; i < count; i++)
387         {
388             IFieldTracking tracking = (IFieldTracking) _trackings.get(i);
389
390             if (tracking.getFieldName() != null)
391                 continue;
392
393             result.add(tracking);
394         }
395
396         return result;
397     }
398
399     public List JavaDoc getErrorRenderers()
400     {
401         List JavaDoc result = new ArrayList JavaDoc();
402
403         Iterator JavaDoc i = _trackings.iterator();
404         while (i.hasNext())
405         {
406             IFieldTracking tracking = (IFieldTracking) i.next();
407
408             IRender errorRenderer = tracking.getErrorRenderer();
409
410             if (errorRenderer != null)
411                 result.add(errorRenderer);
412         }
413
414         return result;
415     }
416 }
Popular Tags