blob: e4a6baf74fac81d983c1c9947ce2fe0d02eafece [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}
* @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();
}