001 // Copyright 2004, 2005 The Apache Software Foundation
002 //
003 // Licensed under the Apache License, Version 2.0 (the "License");
004 // you may not use this file except in compliance with the License.
005 // You may obtain a copy of the License at
006 //
007 // http://www.apache.org/licenses/LICENSE-2.0
008 //
009 // Unless required by applicable law or agreed to in writing, software
010 // distributed under the License is distributed on an "AS IS" BASIS,
011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012 // See the License for the specific language governing permissions and
013 // limitations under the License.
014
015 package org.apache.tapestry.valid;
016
017 import java.io.Serializable;
018 import java.util.List;
019
020 import org.apache.tapestry.IMarkupWriter;
021 import org.apache.tapestry.IRender;
022 import org.apache.tapestry.IRequestCycle;
023 import org.apache.tapestry.form.IFormComponent;
024
025 /**
026 * Interface used to track validation errors in forms and
027 * {@link IFormComponent form element component}s (including
028 * {@link org.apache.tapestry.form.AbstractTextField} and its subclasses).
029 * <p>
030 * In addition, controls how fields that are in error are presented (they can be
031 * <em>decorated</em> in various ways by the delegate; the default
032 * implementation adds two red asterisks to the right of the field).
033 * <p>
034 * Each {@link org.apache.tapestry.form.Form} must have its own validation
035 * delegate instance.
036 * <p>
037 * Starting with release 1.0.8, this interface was extensively revised (in a
038 * non-backwards compatible way) to move the tracking of errors and invalid
039 * values (during a request cycle) to the delegate. It has evolved from a
040 * largely stateless conduit for error messages into a very stateful tracker of
041 * field state.
042 * <p>
043 * Starting with release 1.0.9, this interface was <em>again</em> reworked, to
044 * allow tracking of errors in {@link IFormComponent form components}, and to
045 * allow unassociated errors to be tracked. Unassociated errors are "global",
046 * they don't apply to any particular field.
047 * <p>
048 * <b>Fields vs. Form Element Components </b> <br>
049 * For most simple forms, these terms are pretty much synonymous. Your form will
050 * render normally, and each form element component will render only once. Some
051 * of your form components will be {@link ValidField} components and
052 * handle most of their validation internally (with the help of
053 * {@link IValidator} objects). In addition, your form listener may do
054 * additional validation and notify the validation delegate of additional
055 * errors, some of which are associated with a particular field, some of which
056 * are unassociated with any particular field.
057 * <p>
058 * But what happens if you use a {@link org.apache.tapestry.components.Foreach} or
059 * {@link org.apache.tapestry.form.ListEdit} inside your form? Some of
060 * your components will render multiple times. In this case you will have
061 * multiple <em>fields</em>. Each field will have a unique field name (the
062 * {@link org.apache.tapestry.form.FormSupport#getElementId(IFormComponent) element id},
063 * which you can see this in the generated HTML). It is this field name that the
064 * delegate keys off of, which means that some fields generated by a component
065 * may have errors and some may not, it all works fine (with one exception).
066 * <p>
067 * <b>The Exception </b> <br>
068 * The problem is that a component doesn't know its field name until its
069 * <code>render()</code> method is invoked (at which point, it allocates a
070 * unique field name from the
071 * {@link org.apache.tapestry.IForm#getElementId(org.apache.tapestry.form.IFormComponent)}.
072 * This is not a problem for the field or its {@link IValidator}, but screws
073 * things up for the {@link FieldLabel}.
074 * <p>
075 * Typically, the label is rendered <em>before</em> the corresponding form
076 * component. Form components leave their last assigned field name in their
077 * {@link IFormComponent#getName() name property}. So if the form component is
078 * in any kind of loop, the {@link FieldLabel}will key its name,
079 * {@link IFormComponent#getDisplayName() display name} and error status off of
080 * its last renderred value. So the moral of the story is don't use
081 * {@link FieldLabel}in this situation.
082 *
083 * @author Howard Lewis Ship
084 */
085
086 public interface IValidationDelegate extends Serializable
087 {
088
089 /**
090 * Invoked before other methods to configure the delegate for the given form
091 * component. Sets the current field based on the
092 * {@link IFormComponent#getName() name} of the form component.
093 * <p>
094 * The caller should invoke this with a parameter of null to record
095 * unassociated global errors (errors not associated with any particular
096 * field).
097 *
098 * @since 1.0.8
099 */
100
101 void setFormComponent(IFormComponent component);
102
103 /**
104 * Returns true if the current field is in error (that is, had bad input
105 * submitted by the end user).
106 *
107 * @since 1.0.8
108 */
109
110 boolean isInError();
111
112 /**
113 * Returns the string submitted by the client as the value for the current
114 * field.
115 *
116 * @since 1.0.8
117 */
118
119 String getFieldInputValue();
120
121 /**
122 * Returns a {@link List} of {@link IFieldTracking}, in default order (the
123 * order in which fields are renderred). A caller should not change the
124 * values (the List is immutable). May return null if no fields are in
125 * error.
126 *
127 * @since 1.0.8
128 */
129
130 List getFieldTracking();
131
132 /**
133 * Resets any tracking information for the current field. This will clear
134 * the field's inError flag, and set its error message and invalid input
135 * value to null.
136 *
137 * @since 1.0.8
138 */
139
140 void reset();
141
142 /**
143 * Clears all tracking information.
144 *
145 * @since 1.0.10
146 */
147
148 void clear();
149
150 /**
151 * Clears all errors, but maintains user input. This is useful when a form
152 * has been submitted for a semantic other than "process this data". A
153 * common example of this is a dependent drop down list; selecting an option
154 * in one drop down list forces a refresh submit of the form, to repopulate
155 * the options in a second, dependent drop down list.
156 * <p>
157 * In these cases, the user input provided in the request is maintained, but
158 * any errors should be cleared out (to prevent unwanted error messages and
159 * decorations).
160 *
161 * @since 3.0.1
162 */
163
164 void clearErrors();
165
166 /**
167 * Records the user's input for the current form component. Input should be
168 * recorded even if there isn't an explicit error, since later form-wide
169 * validations may discover an error in the field.
170 *
171 * @since 3.0
172 */
173
174 void recordFieldInputValue(String input);
175
176 /**
177 * The error notification method, invoked during the rewind phase (that is,
178 * while HTTP parameters are being extracted from the request and assigned
179 * to various object properties).
180 * <p>
181 * Typically, the delegate simply invokes
182 * {@link #record(String, ValidationConstraint)}or
183 * {@link #record(IRender, ValidationConstraint)}, but special delegates
184 * may override this behavior to provide (in some cases) different error
185 * messages or more complicated error renderers.
186 */
187
188 void record(ValidatorException ex);
189
190 /**
191 * Records an error in the current field, or an unassociated error if there
192 * is no current field.
193 *
194 * @param message
195 * message to display (@see RenderString}
196 * @param constraint
197 * the constraint that was violated, or null if not known
198 * @since 1.0.9
199 */
200
201 void record(String message, ValidationConstraint constraint);
202
203 /**
204 * Convienience for recording a standard string messages against a field.
205 *
206 * @param field
207 * the field to record the error message against, or null to
208 * record an unassociated error
209 * @param message
210 * the error message to record
211 * @since 4.0
212 */
213
214 void record(IFormComponent field, String message);
215
216 /**
217 * Records an error in the current component, or an unassociated error. The
218 * maximum flexibility recorder.
219 *
220 * @param errorRenderer
221 * object that will render the error message (@see RenderString}
222 * @param constraint
223 * the constraint that was violated, or null if not known
224 */
225
226 void record(IRender errorRenderer, ValidationConstraint constraint);
227
228 /**
229 * Invoked before the field is rendered. If the field is in error, the
230 * delegate may decorate the field in some way (to highlight its error
231 * state).
232 *
233 * @param writer
234 * the writer to which output should be sent
235 * @param cycle
236 * the active request cycle
237 * @param component
238 * the component being decorated
239 * @param validator
240 * the validator for the component, or null if the component does
241 * have (or doesn't support) a validator
242 */
243
244 void writePrefix(IMarkupWriter writer, IRequestCycle cycle,
245 IFormComponent component, IValidator validator);
246
247 /**
248 * Invoked just before the <input> element is closed. The delegate can
249 * write additional attributes. This is often used to set the CSS class of
250 * the field so that it can be displayed differently, if in error (or
251 * required). *
252 *
253 * @param writer
254 * the writer to which output should be sent
255 * @param cycle
256 * the active request cycle
257 * @param component
258 * the component being decorated
259 * @param validator
260 * the validator for the component, or null if the component does
261 * have (or doesn't support) a validator
262 * @since 1.0.5
263 */
264
265 void writeAttributes(IMarkupWriter writer, IRequestCycle cycle,
266 IFormComponent component, IValidator validator);
267
268 /**
269 * Invoked after the form component is rendered, so that the delegate may
270 * decorate the form component (if it is in error). *
271 *
272 * @param writer
273 * the writer to which output should be sent
274 * @param cycle
275 * the active request cycle
276 * @param component
277 * the component being decorated
278 * @param validator
279 * the validator for the component, or null if the component does
280 * have (or doesn't support) a validator
281 */
282
283 void writeSuffix(IMarkupWriter writer, IRequestCycle cycle,
284 IFormComponent component, IValidator validator);
285
286 /**
287 * Invoked by a {@link FieldLabel} just before writing the name of the form
288 * component.
289 */
290
291 void writeLabelPrefix(IFormComponent component,
292 IMarkupWriter writer, IRequestCycle cycle);
293
294 /**
295 * Invoked just before the <label> element is closed. The delegate can
296 * write additional attributes. This is often used to set the CSS class of
297 * the label so that it can be displayed differently, if in error (or
298 * required). Any attributes written here will be overriden by any informal
299 * parameters specified in the {@link FieldLabel} implementation.
300 *
301 * @param writer
302 * the writer to which output should be sent
303 * @param cycle
304 * the active request cycle
305 * @param component
306 * the component field that label decorates
307 * @since 4.0.1
308 */
309
310 void writeLabelAttributes(IMarkupWriter writer, IRequestCycle cycle,
311 IFormComponent component);
312
313 /**
314 * Invoked by a {@link FieldLabel} just after writing the name of the form
315 * component.
316 */
317
318 void writeLabelSuffix(IFormComponent component,
319 IMarkupWriter writer, IRequestCycle cycle);
320
321 /**
322 * Returns true if any form component has errors.
323 */
324
325 boolean getHasErrors();
326
327 /**
328 * Returns the {@link IFieldTracking} for the current component, if
329 * any. Useful when displaying error messages for individual fields.
330 *
331 * @since 3.0.2
332 */
333 IFieldTracking getCurrentFieldTracking();
334
335 /**
336 * Returns a list of {@link org.apache.tapestry.IRender} objects, each of
337 * which will render an error message for a field tracked by the delegate,
338 * plus any unassociated errors (for which no specific field is identified).
339 * These objects can be rendered or converted to a string (via toString()).
340 *
341 * @return non-empty List of {@link org.apache.tapestry.IRender}.
342 */
343
344 List getErrorRenderers();
345
346 /**
347 * Registers a field for automatic focus. The goal is for the first field
348 * that is in error to get focus; failing that, the first required field;
349 * failing that, any field.
350 *
351 * @param field
352 * the field requesting focus
353 * @param priority
354 * a priority level used to determine whether the registered
355 * field becomes the focus field. Constants for this purpose are
356 * defined in {@link ValidationConstants}.
357 * @since 4.0
358 */
359
360 void registerForFocus(IFormComponent field, int priority);
361
362 /**
363 * Returns the field to focus upon, based on prior calls to
364 * {@link #registerForFocus(IFormComponent, int)}.
365 *
366 * @return the field name, or null if no field should receive focus.
367 * @since 4.0
368 */
369 String getFocusField();
370
371 }