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}&nbsp;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}&nbsp;components and
052     * handle most of their validation internally (with the help of
053     * {@link IValidator}&nbsp;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}&nbsp;or
059     * {@link org.apache.tapestry.form.ListEdit}&nbsp;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 &lt;input&gt; 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 &lt;label&gt; 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}&nbsp;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    }