blob: c869537d7a8a9b015e47a405c0e4ee30d94eb5e9 [file] [log] [blame]
// Copyright 2004 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package org.apache.tapestry.valid;
import java.util.List;
import org.apache.tapestry.IMarkupWriter;
import org.apache.tapestry.IRender;
import org.apache.tapestry.IRequestCycle;
import org.apache.tapestry.form.IFormComponent;
/**
* Interface used to track validation errors in forms and {@link IFormComponent}s (including
* {@link org.apache.tapestry.form.AbstractTextField}and its subclasses).
* <p>
* In addition, controls how fields that are in error are presented (they can be marked in various
* ways by the delegate; the default implementation adds two red asterisks to the right of the
* field).
* <p>
* The interface is designed so that a single instance can be shared with many instances of
* {@link IFormComponent}.
* <p>
* Starting with release 1.0.8, this interface was extensively revised (in a non-backwards
* compatible way) to move the tracking of errors and invalid values (during a request cycle) to the
* delegate. It has evolved from a largely stateless conduit for error messages into a very stateful
* tracker of field state.
* <p>
* Starting with release 1.0.9, this interface was <em>again</em> reworked, to allow tracking of
* errors in {@link IFormComponent form components}, and to allow unassociated (with any field)
* errors to be tracked.
* <p>
* <b>Fields vs. Form Components </b> <br>
* For most simple forms, these terms are pretty much synonymous. Your form will render normally,
* and each form component will render only once. Some of your form components will be
* {@link ValidField}components and handle most of their validation internally (with the help of
* {@link IValidator}objects). In addition, your form listener may do additional validation and
* notify the validation delegate of additional errors, some of which are associated with a
* particular field, some of which are unassociated with any particular field.
* <p>
* But what happens if you use a {@link org.apache.tapestry.components.Foreach}or
* {@link org.apache.tapestry.form.ListEdit}inside your form? Some of your components will render
* multiple times. In this case you will have multiple <em>fields</em>. Each field will have a
* unique field name (you can see this in the generated HTML). It is this field name that the
* delegate keys off of, which means that some fields generated by a component may have errors and
* some may not, it all works fine (with one exception).
* <p>
* <b>The Exception </b> <br>
* The problem is that a component doesn't know its field name until its <code>render()</code>
* method is invoked (at which point, it allocates a unique field name from the
* {@link org.apache.tapestry.IForm#getElementId(org.apache.tapestry.form.IFormComponent)}. This is
* not a problem for the field or its {@link IValidator}, but screws things up for the
* {@link FieldLabel}.
* <p>
* Typically, the label is rendered <em>before</em> the corresponding form component. Form
* components leave their last assigned field name in their
* {@link IFormComponent#getName() name property}. So if the form component is in any kind of loop,
* the {@link FieldLabel}will key its name, {@link IFormComponent#getDisplayName() display name}
* and error status off of its last renderred value. So the moral of the story is don't use
* {@link FieldLabel}in this situation.
*
* @author Howard Lewis Ship
*/
public interface IValidationDelegate
{
/**
* Invoked before other methods to configure the delegate for the given form component. Sets the
* current field based on the {@link IFormComponent#getName() name}of the form component (which
* is almost always a {@link ValidField}).
* <p>
* The caller should invoke this with a parameter of null to record unassociated global errors
* (errors not associated with any particular field).
*
* @since 1.0.8
*/
public void setFormComponent(IFormComponent component);
/**
* Returns true if the current component is in error (that is, had bad input submitted by the
* end user).
*
* @since 1.0.8
*/
public boolean isInError();
/**
* Returns the string submitted by the client as the value for the current field.
*
* @since 1.0.8
*/
public String getFieldInputValue();
/**
* Returns a {@link List}of {@link IFieldTracking}, in default order (the order in which
* fields are renderred). A caller should not change the values (the List is immutable). May
* return null if no fields are in error.
*
* @since 1.0.8
*/
public List getFieldTracking();
/**
* Resets any tracking information for the current field. This will clear the field's inError
* flag, and set its error message and invalid input value to null.
*
* @since 1.0.8
*/
public void reset();
/**
* Clears all tracking information.
*
* @since 1.0.10
*/
public void clear();
/**
* Clears all errors, but maintains user input. This is useful when a form has been submitted
* for a semantic other than "process this data". A common example of this is a dependent drop
* down list; selecting an option in one drop down list forces a submit to repopulate the
* options in a second, dependent drop down list.
* <p>
* In these cases, the user input provided in the request is maintained, but any errors should
* be cleared out (to prevent unwanted error messages and decorations).
*
* @since 3.0.1
*/
public void clearErrors();
/**
* Records the user's input for the current form component. Input should be recorded even if
* there isn't an explicit error, since later form-wide validations may discover an error in the
* field.
*
* @since 3.0
*/
public void recordFieldInputValue(String input);
/**
* The error notification method, invoked during the rewind phase (that is, while HTTP
* parameters are being extracted from the request and assigned to various object properties).
* <p>
* Typically, the delegate simply invokes {@link #record(String, ValidationConstraint)}or
* {@link #record(IRender, ValidationConstraint)}, but special delegates may override this
* behavior to provide (in some cases) different error messages or more complicated error
* renderers.
*/
public void record(ValidatorException ex);
/**
* Records an error in the current field, or an unassociated error if there is no current field.
*
* @param message
* message to display (@see RenderString}
* @param constraint
* the constraint that was violated, or null if not known
* @since 1.0.9
*/
public void record(String message, ValidationConstraint constraint);
/**
* Records an error in the current component, or an unassociated error. The maximum flexibility
* recorder.
*
* @param errorRenderer
* object that will render the error message (@see RenderString}. The object should
* implement a reasonable <code>toString()</code> as well, to allow the error
* message to be rendered using an Insert component, or used where full markup is not
* allowed.
* @param constraint
* the constraint that was violated, or null if not known
*/
public void record(IRender errorRenderer, ValidationConstraint constraint);
/**
* Invoked before the field is rendered. If the field is in error, the delegate may decorate the
* field in some way (to highlight its error state).
*/
public void writePrefix(IMarkupWriter writer, IRequestCycle cycle, IFormComponent component,
IValidator validator);
/**
* Invoked just before the &lt;input&gt; element is closed. The delegate can write additional
* attributes. This is often used to set the CSS class of the field so that it can be displayed
* differently, if in error (or required).
*
* @since 1.0.5
*/
public void writeAttributes(IMarkupWriter writer, IRequestCycle cycle,
IFormComponent component, IValidator validator);
/**
* Invoked after the form component is rendered, so that the delegate may decorate the form
* component (if it is in error).
*/
public void writeSuffix(IMarkupWriter writer, IRequestCycle cycle, IFormComponent component,
IValidator validator);
/**
* Invoked by a {@link FieldLabel}just before writing the name of the form component.
*/
public void writeLabelPrefix(IFormComponent component, IMarkupWriter writer, IRequestCycle cycle);
/**
* Invoked by a {@link FieldLabel}just after writing the name of the form component.
*/
public void writeLabelSuffix(IFormComponent component, IMarkupWriter writer, IRequestCycle cycle);
/**
* Returns true if any form component has errors.
*/
public boolean getHasErrors();
/**
* Returns the {@link IFieldTracking}for the current component, if any. Useful when displaying
* error messages for individual fields.
*
* @since 3.0.2
*/
public IFieldTracking getCurrentFieldTracking();
}