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