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
015package org.apache.tapestry.valid;
016
017import java.io.Serializable;
018import java.util.List;
019
020import org.apache.tapestry.IMarkupWriter;
021import org.apache.tapestry.IRender;
022import org.apache.tapestry.IRequestCycle;
023import 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}&nbsp;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}&nbsp;components and handle most of their validation internally (with the help
049 * of {@link IValidator}&nbsp;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}&nbsp;or
054 * {@link org.apache.tapestry.form.ListEdit}&nbsp;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
079public 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 &lt;input&gt; 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 &lt;label&gt; 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}&nbsp;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}