Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
IValidationDelegate |
|
| 1.0;1 |
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 org.apache.tapestry.IMarkupWriter; | |
18 | import org.apache.tapestry.IRender; | |
19 | import org.apache.tapestry.IRequestCycle; | |
20 | import org.apache.tapestry.form.IFormComponent; | |
21 | import org.apache.tapestry.form.TextField; | |
22 | ||
23 | import java.io.Serializable; | |
24 | import java.util.List; | |
25 | ||
26 | /** | |
27 | * Interface used to track validation errors in forms and | |
28 | * {@link IFormComponent form element component}s (including | |
29 | * {@link TextField} and its subclasses). | |
30 | * <p> | |
31 | * In addition, controls how fields that are in error are presented (they can be | |
32 | * <em>decorated</em> in various ways by the delegate; the default | |
33 | * implementation adds two red asterisks to the right of the field). | |
34 | * <p> | |
35 | * Each {@link org.apache.tapestry.form.Form} must have its own validation | |
36 | * delegate instance. | |
37 | * <p> | |
38 | * Starting with release 1.0.8, this interface was extensively revised (in a | |
39 | * non-backwards compatible way) to move the tracking of errors and invalid | |
40 | * values (during a request cycle) to the delegate. It has evolved from a | |
41 | * largely stateless conduit for error messages into a very stateful tracker of | |
42 | * field state. | |
43 | * <p> | |
44 | * Starting with release 1.0.9, this interface was <em>again</em> reworked, to | |
45 | * allow tracking of errors in {@link IFormComponent form components}, and to | |
46 | * allow unassociated errors to be tracked. Unassociated errors are "global", | |
47 | * they don't apply to any particular field. | |
48 | * <p> | |
49 | * <b>Fields vs. Form Element Components </b> <br> | |
50 | * For most simple forms, these terms are pretty much synonymous. Your form will | |
51 | * render normally, and each form element component will render only once. Some | |
52 | * of your form components will be {@link ValidField} components and | |
53 | * handle most of their validation internally (with the help of | |
54 | * {@link IValidator} objects). In addition, your form listener may do | |
55 | * additional validation and notify the validation delegate of additional | |
56 | * errors, some of which are associated with a particular field, some of which | |
57 | * are unassociated with any particular field. | |
58 | * <p> | |
59 | * But what happens if you use a {@link org.apache.tapestry.components.ForBean} or | |
60 | * {@link org.apache.tapestry.form.ListEdit} inside your form? Some of | |
61 | * your components will render multiple times. In this case you will have | |
62 | * multiple <em>fields</em>. Each field will have a unique field name (the | |
63 | * {@link org.apache.tapestry.form.FormSupport#getElementId(IFormComponent) element id}, | |
64 | * which you can see this in the generated HTML). It is this field name that the | |
65 | * delegate keys off of, which means that some fields generated by a component | |
66 | * may have errors and some may not, it all works fine (with one exception). | |
67 | * <p> | |
68 | * <b>The Exception </b> <br> | |
69 | * The problem is that a component doesn't know its field name until its | |
70 | * <code>render()</code> method is invoked (at which point, it allocates a | |
71 | * unique field name from the | |
72 | * {@link org.apache.tapestry.IForm#getElementId(org.apache.tapestry.form.IFormComponent)}. | |
73 | * This is not a problem for the field or its {@link IValidator}, but screws | |
74 | * things up for the {@link FieldLabel}. | |
75 | * <p> | |
76 | * Typically, the label is rendered <em>before</em> the corresponding form | |
77 | * component. Form components leave their last assigned field name in their | |
78 | * {@link IFormComponent#getName() name property}. So if the form component is | |
79 | * in any kind of loop, the {@link FieldLabel}will key its name, | |
80 | * {@link IFormComponent#getDisplayName() display name} and error status off of | |
81 | * its last renderred value. So the moral of the story is don't use | |
82 | * {@link FieldLabel}in this situation. | |
83 | * | |
84 | * @author Howard Lewis Ship | |
85 | */ | |
86 | ||
87 | public interface IValidationDelegate extends Serializable | |
88 | { | |
89 | ||
90 | /** | |
91 | * Invoked before other methods to configure the delegate for the given form | |
92 | * component. Sets the current field based on the | |
93 | * {@link IFormComponent#getName() name} of the form component. | |
94 | * <p> | |
95 | * The caller should invoke this with a parameter of null to record | |
96 | * unassociated global errors (errors not associated with any particular | |
97 | * field). | |
98 | * | |
99 | * @since 1.0.8 | |
100 | */ | |
101 | ||
102 | void setFormComponent(IFormComponent component); | |
103 | ||
104 | /** | |
105 | * Returns true if the current field is in error (that is, had bad input | |
106 | * submitted by the end user). | |
107 | * | |
108 | * @since 1.0.8 | |
109 | */ | |
110 | ||
111 | boolean isInError(); | |
112 | ||
113 | /** | |
114 | * Returns the string submitted by the client as the value for the current | |
115 | * field. | |
116 | * | |
117 | * @since 1.0.8 | |
118 | */ | |
119 | ||
120 | String getFieldInputValue(); | |
121 | ||
122 | /** | |
123 | * Returns a {@link List} of {@link IFieldTracking}, in default order (the | |
124 | * order in which fields are renderred). A caller should not change the | |
125 | * values (the List is immutable). May return null if no fields are in | |
126 | * error. | |
127 | * | |
128 | * @since 1.0.8 | |
129 | */ | |
130 | ||
131 | List getFieldTracking(); | |
132 | ||
133 | /** | |
134 | * Resets any tracking information for the current field. This will clear | |
135 | * the field's inError flag, and set its error message and invalid input | |
136 | * value to null. | |
137 | * | |
138 | * @since 1.0.8 | |
139 | */ | |
140 | ||
141 | void reset(); | |
142 | ||
143 | /** | |
144 | * Clears all tracking information. | |
145 | * | |
146 | * @since 1.0.10 | |
147 | */ | |
148 | ||
149 | void clear(); | |
150 | ||
151 | /** | |
152 | * Clears all errors, but maintains user input. This is useful when a form | |
153 | * has been submitted for a semantic other than "process this data". A | |
154 | * common example of this is a dependent drop down list; selecting an option | |
155 | * in one drop down list forces a refresh submit of the form, to repopulate | |
156 | * the options in a second, dependent drop down list. | |
157 | * <p> | |
158 | * In these cases, the user input provided in the request is maintained, but | |
159 | * any errors should be cleared out (to prevent unwanted error messages and | |
160 | * decorations). | |
161 | * | |
162 | * @since 3.0.1 | |
163 | */ | |
164 | ||
165 | void clearErrors(); | |
166 | ||
167 | /** | |
168 | * Records the user's input for the current form component. Input should be | |
169 | * recorded even if there isn't an explicit error, since later form-wide | |
170 | * validations may discover an error in the field. | |
171 | * | |
172 | * @since 3.0 | |
173 | */ | |
174 | ||
175 | void recordFieldInputValue(String input); | |
176 | ||
177 | /** | |
178 | * The error notification method, invoked during the rewind phase (that is, | |
179 | * while HTTP parameters are being extracted from the request and assigned | |
180 | * to various object properties). | |
181 | * <p> | |
182 | * Typically, the delegate simply invokes | |
183 | * {@link #record(String, ValidationConstraint)}or | |
184 | * {@link #record(IRender, ValidationConstraint)}, but special delegates | |
185 | * may override this behavior to provide (in some cases) different error | |
186 | * messages or more complicated error renderers. | |
187 | */ | |
188 | ||
189 | void record(ValidatorException ex); | |
190 | ||
191 | /** | |
192 | * Records an error in the current field, or an unassociated error if there | |
193 | * is no current field. | |
194 | * | |
195 | * @param message | |
196 | * message to display (@see RenderString} | |
197 | * @param constraint | |
198 | * the constraint that was violated, or null if not known | |
199 | * @since 1.0.9 | |
200 | */ | |
201 | ||
202 | void record(String message, ValidationConstraint constraint); | |
203 | ||
204 | /** | |
205 | * Convienience for recording a standard string messages against a field. | |
206 | * | |
207 | * @param field | |
208 | * the field to record the error message against, or null to | |
209 | * record an unassociated error | |
210 | * @param message | |
211 | * the error message to record | |
212 | * @since 4.0 | |
213 | */ | |
214 | ||
215 | void record(IFormComponent field, String message); | |
216 | ||
217 | /** | |
218 | * Records an error in the current component, or an unassociated error. The | |
219 | * maximum flexibility recorder. | |
220 | * | |
221 | * @param errorRenderer | |
222 | * object that will render the error message (@see RenderString} | |
223 | * @param constraint | |
224 | * the constraint that was violated, or null if not known | |
225 | */ | |
226 | ||
227 | void record(IRender errorRenderer, ValidationConstraint constraint); | |
228 | ||
229 | /** | |
230 | * Invoked before the field is rendered. If the field is in error, the | |
231 | * delegate may decorate the field in some way (to highlight its error | |
232 | * state). | |
233 | * | |
234 | * @param writer | |
235 | * the writer to which output should be sent | |
236 | * @param cycle | |
237 | * the active request cycle | |
238 | * @param component | |
239 | * the component being decorated | |
240 | * @param validator | |
241 | * the validator for the component, or null if the component does | |
242 | * have (or doesn't support) a validator | |
243 | */ | |
244 | ||
245 | void writePrefix(IMarkupWriter writer, IRequestCycle cycle, | |
246 | IFormComponent component, IValidator validator); | |
247 | ||
248 | /** | |
249 | * Invoked just before the <input> element is closed. The delegate can | |
250 | * write additional attributes. This is often used to set the CSS class of | |
251 | * the field so that it can be displayed differently, if in error (or | |
252 | * required). * | |
253 | * | |
254 | * @param writer | |
255 | * the writer to which output should be sent | |
256 | * @param cycle | |
257 | * the active request cycle | |
258 | * @param component | |
259 | * the component being decorated | |
260 | * @param validator | |
261 | * the validator for the component, or null if the component does | |
262 | * have (or doesn't support) a validator | |
263 | * @since 1.0.5 | |
264 | */ | |
265 | ||
266 | void writeAttributes(IMarkupWriter writer, IRequestCycle cycle, | |
267 | IFormComponent component, IValidator validator); | |
268 | ||
269 | /** | |
270 | * Invoked after the form component is rendered, so that the delegate may | |
271 | * decorate the form component (if it is in error). * | |
272 | * | |
273 | * @param writer | |
274 | * the writer to which output should be sent | |
275 | * @param cycle | |
276 | * the active request cycle | |
277 | * @param component | |
278 | * the component being decorated | |
279 | * @param validator | |
280 | * the validator for the component, or null if the component does | |
281 | * have (or doesn't support) a validator | |
282 | */ | |
283 | ||
284 | void writeSuffix(IMarkupWriter writer, IRequestCycle cycle, | |
285 | IFormComponent component, IValidator validator); | |
286 | ||
287 | /** | |
288 | * Invoked by a {@link FieldLabel} just before writing the name of the form | |
289 | * component. | |
290 | */ | |
291 | ||
292 | void writeLabelPrefix(IFormComponent component, | |
293 | IMarkupWriter writer, IRequestCycle cycle); | |
294 | ||
295 | /** | |
296 | * Invoked just before the <label> element is closed. The delegate can | |
297 | * write additional attributes. This is often used to set the CSS class of | |
298 | * the label so that it can be displayed differently, if in error (or | |
299 | * required). Any attributes written here will be overriden by any informal | |
300 | * parameters specified in the {@link FieldLabel} implementation. | |
301 | * | |
302 | * @param writer | |
303 | * the writer to which output should be sent | |
304 | * @param cycle | |
305 | * the active request cycle | |
306 | * @param component | |
307 | * the component field that label decorates | |
308 | * @since 4.0.1 | |
309 | */ | |
310 | ||
311 | void writeLabelAttributes(IMarkupWriter writer, IRequestCycle cycle, | |
312 | IFormComponent component); | |
313 | ||
314 | /** | |
315 | * Invoked just before the actual field label text is written, right after all attributes and | |
316 | * informal parameters are done being printed on the <code><label></code> tag. | |
317 | * | |
318 | * <p> | |
319 | * Example, writing content would go here: | |
320 | * </p> | |
321 | * <p> | |
322 | * <label class="error"> >>here<< LABEL TEXT </label> | |
323 | * </p> | |
324 | * | |
325 | * @param writer | |
326 | * The writer to use. | |
327 | * @param cycle | |
328 | * Current request cycle. | |
329 | * @param component | |
330 | * Field label is bound to. | |
331 | */ | |
332 | void beforeLabelText(IMarkupWriter writer, IRequestCycle cycle, IFormComponent component); | |
333 | ||
334 | /** | |
335 | * Invoked just before the closing <code></label></code> tag is written. | |
336 | * | |
337 | * <p> | |
338 | * Example, writing content would go here: | |
339 | * </p> | |
340 | * <p> | |
341 | * <label class="error"> LABEL TEXT >>here<< </label> | |
342 | * </p> | |
343 | * | |
344 | * @param writer | |
345 | * The writer to use. | |
346 | * @param cycle | |
347 | * Current request cycle. | |
348 | * @param component | |
349 | * Field label is bound to. | |
350 | */ | |
351 | void afterLabelText(IMarkupWriter writer, IRequestCycle cycle, IFormComponent component); | |
352 | ||
353 | /** | |
354 | * Invoked by a {@link FieldLabel} just after writing the name of the form | |
355 | * component. | |
356 | */ | |
357 | ||
358 | void writeLabelSuffix(IFormComponent component, IMarkupWriter writer, IRequestCycle cycle); | |
359 | ||
360 | /** | |
361 | * Returns true if any form component has errors. | |
362 | */ | |
363 | ||
364 | boolean getHasErrors(); | |
365 | ||
366 | /** | |
367 | * Returns the {@link IFieldTracking} for the current component, if | |
368 | * any. Useful when displaying error messages for individual fields. | |
369 | * | |
370 | * @since 3.0.2 | |
371 | */ | |
372 | IFieldTracking getCurrentFieldTracking(); | |
373 | ||
374 | /** | |
375 | * Returns a list of {@link org.apache.tapestry.IRender} objects, each of | |
376 | * which will render an error message for a field tracked by the delegate, | |
377 | * plus any unassociated errors (for which no specific field is identified). | |
378 | * These objects can be rendered or converted to a string (via toString()). | |
379 | * | |
380 | * @return non-empty List of {@link org.apache.tapestry.IRender}. | |
381 | */ | |
382 | ||
383 | List getErrorRenderers(); | |
384 | ||
385 | /** | |
386 | * Registers a field for automatic focus. The goal is for the first field | |
387 | * that is in error to get focus; failing that, the first required field; | |
388 | * failing that, any field. | |
389 | * | |
390 | * @param field | |
391 | * the field requesting focus | |
392 | * @param priority | |
393 | * a priority level used to determine whether the registered | |
394 | * field becomes the focus field. Constants for this purpose are | |
395 | * defined in {@link ValidationConstants}. | |
396 | * @since 4.0 | |
397 | */ | |
398 | ||
399 | void registerForFocus(IFormComponent field, int priority); | |
400 | ||
401 | /** | |
402 | * Returns the field to focus upon, based on prior calls to | |
403 | * {@link #registerForFocus(IFormComponent, int)}. | |
404 | * | |
405 | * @return the field name, or null if no field should receive focus. | |
406 | * @since 4.0 | |
407 | */ | |
408 | String getFocusField(); | |
409 | ||
410 | } |