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 <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} 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} components and handle most of their validation internally (with the help 049 * of {@link IValidator} 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} or 054 * {@link org.apache.tapestry.form.ListEdit} 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 079 public 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 <input> 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 <label> 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} 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 }