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    }