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 | } |