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 org.apache.tapestry.IMarkupWriter;
018    import org.apache.tapestry.IRender;
019    import org.apache.tapestry.IRequestCycle;
020    import org.apache.tapestry.form.IFormComponent;
021    import org.apache.tapestry.form.TextField;
022    
023    import java.io.Serializable;
024    import java.util.List;
025    
026    /**
027     * Interface used to track validation errors in forms and
028     * {@link IFormComponent form element component}s (including
029     * {@link TextField} and its subclasses).
030     * <p>
031     * In addition, controls how fields that are in error are presented (they can be
032     * <em>decorated</em> in various ways by the delegate; the default
033     * implementation adds two red asterisks to the right of the field).
034     * <p>
035     * Each {@link org.apache.tapestry.form.Form}&nbsp;must have its own validation
036     * delegate instance.
037     * <p>
038     * Starting with release 1.0.8, this interface was extensively revised (in a
039     * non-backwards compatible way) to move the tracking of errors and invalid
040     * values (during a request cycle) to the delegate. It has evolved from a
041     * largely stateless conduit for error messages into a very stateful tracker of
042     * field state.
043     * <p>
044     * Starting with release 1.0.9, this interface was <em>again</em> reworked, to
045     * allow tracking of errors in {@link IFormComponent form components}, and to
046     * allow unassociated errors to be tracked. Unassociated errors are "global",
047     * they don't apply to any particular field.
048     * <p>
049     * <b>Fields vs. Form Element Components </b> <br>
050     * For most simple forms, these terms are pretty much synonymous. Your form will
051     * render normally, and each form element component will render only once. Some
052     * of your form components will be {@link ValidField}&nbsp;components and
053     * handle most of their validation internally (with the help of
054     * {@link IValidator}&nbsp;objects). In addition, your form listener may do
055     * additional validation and notify the validation delegate of additional
056     * errors, some of which are associated with a particular field, some of which
057     * are unassociated with any particular field.
058     * <p>
059     * But what happens if you use a {@link org.apache.tapestry.components.ForBean}&nbsp;or
060     * {@link org.apache.tapestry.form.ListEdit}&nbsp;inside your form? Some of
061     * your components will render multiple times. In this case you will have
062     * multiple <em>fields</em>. Each field will have a unique field name (the
063     * {@link org.apache.tapestry.form.FormSupport#getElementId(IFormComponent) element id},
064     * which you can see this in the generated HTML). It is this field name that the
065     * delegate keys off of, which means that some fields generated by a component
066     * may have errors and some may not, it all works fine (with one exception).
067     * <p>
068     * <b>The Exception </b> <br>
069     * The problem is that a component doesn't know its field name until its
070     * <code>render()</code> method is invoked (at which point, it allocates a
071     * unique field name from the
072     * {@link org.apache.tapestry.IForm#getElementId(org.apache.tapestry.form.IFormComponent)}.
073     * This is not a problem for the field or its {@link IValidator}, but screws
074     * things up for the {@link FieldLabel}.
075     * <p>
076     * Typically, the label is rendered <em>before</em> the corresponding form
077     * component. Form components leave their last assigned field name in their
078     * {@link IFormComponent#getName() name property}. So if the form component is
079     * in any kind of loop, the {@link FieldLabel}will key its name,
080     * {@link IFormComponent#getDisplayName() display name} and error status off of
081     * its last renderred value. So the moral of the story is don't use
082     * {@link FieldLabel}in this situation.
083     * 
084     * @author Howard Lewis Ship
085     */
086    
087    public interface IValidationDelegate extends Serializable
088    {
089    
090        /**
091         * Invoked before other methods to configure the delegate for the given form
092         * component. Sets the current field based on the
093         * {@link IFormComponent#getName() name} of the form component.
094         * <p>
095         * The caller should invoke this with a parameter of null to record
096         * unassociated global errors (errors not associated with any particular
097         * field).
098         * 
099         * @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 &lt;input&gt; 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 &lt;label&gt; 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>&lt;label&gt;</code> tag. 
317         * 
318         * <p>
319         *  Example, writing content would go here:
320         * </p>
321         * <p>
322         *  &lt;label class="error"&gt &gt;&gt;here&lt;&lt; LABEL TEXT &lt;/label&gt;
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>&lt;/label&gt;</code> tag is written.
336         * 
337         * <p>
338         *  Example, writing content would go here:
339         * </p>
340         * <p>
341         *  &lt;label class="error"&gt LABEL TEXT  &gt;&gt;here&lt;&lt;  &lt;/label&gt;
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}&nbsp;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    }