For my application, I wanted to use a central
properties file for the validation messages. As
oppposed to overriding all the validators, I made
changes to AbstractValidator to allow the setting of a
global or instance based strategy object for creating
the messages. As it might be useful or might
generate some discussion, I've attached it to this
message. I thinks its backward compatible, but its
mostly untested (that will change over the next couple
of days). I won't be offended if you decide its
worthless :)
BTW, I was wondering about the dom4j dependancy. The
only place its used is in
wicket.util.string.Strings.toString() as follows:
else if (object instanceof Node)
{
return ((Node)object).getText();
}
Is this just an artifact? I'm trying to keep my
application size to a minimum so I end up just
commenting it out so I can exclude the dom4j.jar. Any
chance you might get rid of it or is there some future
plans for it? I just can't be bothered have to
comment it out each time I grab a new release :)
-Brad
/*
* $Id: AbstractValidator.java,v 1.28 2005/07/19 11:33:41 eelco12 Exp $
* $Revision: 1.28 $ $Date: 2005/07/19 11:33:41 $
*
* ==============================================================================
* 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 wicket.markup.html.form.validation;
import java.util.HashMap;
import java.util.Map;
import wicket.Localizer;
import wicket.markup.html.form.FormComponent;
import wicket.model.IModel;
import wicket.model.Model;
import wicket.util.lang.Classes;
/**
* Base class for form component validators. This class is thread-safe and
* therefore it is safe to share validators across sessions/threads.
* <p>
* Error messages can be registered on a component by calling one of the error()
* overloads. The error message will be retrieved using the Localizer for the
* form component. Normally, this localizer will find the error message in a
* string resource bundle (properties file) associated with the page in which
* this validator is contained. The resource key must be of the form:
* [form-name].[component-name].[validator-class]. For example:
* <p>
* MyForm.name.RequiredValidator=A name is required.
* <p>
* Error message string resources can contain optional ognl variable
* interpolations from the component, such as:
* <p>
* editBook.name.LengthValidator='${input}' is too short a name.
* <p>
* Available variables for interpolation are:
* <ul>
* <li>${input} - The user's input</li>
* <li>${name} - The name of the component</li>
* </ul>
* but specific validator subclasses may add more values.
* </p>
*
* @author Jonathan Locke
* @author Eelco Hillenius
*/
public abstract class AbstractValidator implements IValidator
{
/** The form component being validated */
private FormComponent formComponent;
/**
* the validator's resource key. will be used when it was explicitly set by a user or
* extending validator.
*/
private String resourceKey = null;
/** The global default strategy for determining messages. */
private static IValidatorMessageStrategy defaultMessageStrategy = new DefaultMessageStrategy();
/** The message strategy for determining messages. */
private IValidatorMessageStrategy messageStrategy = defaultMessageStrategy;
/** Default implementation of the strategy for determining messages. */
private static final class DefaultMessageStrategy implements IValidatorMessageStrategy
{
/* (non-Javadoc)
* @see wicket.markup.html.form.validation.IValidatorMessageStrategy#getMessage(java.lang.String, wicket.markup.html.form.FormComponent, wicket.model.IModel)
*/
public String getMessage(String resourceKey, FormComponent formComponent, IModel resourceModel)
{
Localizer localizer = formComponent.getLocalizer();
return localizer.getString(resourceKey, formComponent, resourceModel);
}
/* (non-Javadoc)
* @see wicket.markup.html.form.validation.IValidatorMessageStrategy#getDefaultResourceKey(wicket.markup.html.form.validation.IValidator, wicket.markup.html.form.FormComponent)
*/
public String getDefaultResourceKey(IValidator validator, FormComponent formComponent)
{
// Resource key must be <form-id>.<component-name>.<validator-class>
return formComponent.getForm().getId() + "." + formComponent.getId() + "."
+ Classes.name(validator.getClass());
}
}
/**
* Globally set the message strategy for determining how messages are formatted.
*/
public static void setDefaultMessageStrategy(IValidatorMessageStrategy messageStrategy) {
defaultMessageStrategy = messageStrategy;
}
/**
* Set the message strategy for determining how messages are formatted for this validator.
*/
public AbstractValidator setMessageStrategy(IValidatorMessageStrategy messageStrategy)
{
this.messageStrategy = messageStrategy;
return this;
}
/**
* Get the message strategy for determining how messages are formatted for this validator.
*/
public IValidatorMessageStrategy getMessageStrategy()
{
return this.messageStrategy;
}
/**
* Sets an error on the component being validated using the map returned by
* messageModel() for variable interpolations.
* <p>
* See class comments for details about how error messages are loaded and
* formatted.
*/
public void error()
{
error(messageModel());
}
/**
* Returns a formatted validation error message for a given component. The
* error message is retrieved from a message bundle associated with the page
* in which this validator is contained using the given resource key. The
* resourceModel is used for variable interpolation.
*
* @param resourceKey
* The resource key to use
* @param resourceModel
* The model for variable interpolation
*/
public void error(final String resourceKey, final IModel resourceModel)
{
// Return formatted error message
String message = messageStrategy.getMessage(resourceKey, formComponent, resourceModel);
formComponent.error(message);
}
/**
* Sets an error on the component being validated using the given map for
* variable interpolations.
*
* @param resourceKey
* The resource key to use
* @param map
* The model for variable interpolation
*/
public void error(final String resourceKey, final Map map)
{
error(resourceKey, Model.valueOf(map));
}
/**
* Sets an error on the component being validated using the given map for
* variable interpolations.
*
* @param map
* The model for variable interpolation
*/
public void error(final Map map)
{
error(resourceKey(), Model.valueOf(map));
}
/**
* @return Returns the component.
*/
public FormComponent getFormComponent()
{
return formComponent;
}
/**
* @return The string value being validated
*/
public String getInput()
{
return formComponent.getInput();
}
/**
* Explicitly set the resource key that should be used.
* WARNING: as resourceKey() is overrable, setting this parameter does not guarantee
* that extending validators honor using it.
* @param resourceKey the resource key
*/
public final void setResourceKey(String resourceKey)
{
this.resourceKey = resourceKey;
}
/**
* Returns the explicitly set resource key. When no resource key was explictly set
* (and the validator thus falls back on the <code>[form-name].[component-name].[validator-class]</code>)
* schema, this method returns null
* @return the explicitly set resource key or null
*/
protected final String getResourceKey()
{
if (resourceKey == null) {
resourceKey = messageStrategy.getDefaultResourceKey(this, formComponent);
}
return resourceKey;
}
/**
* Implemented by subclasses to validate component
*/
public abstract void onValidate();
/**
* @see wicket.markup.html.form.validation.IValidator#validate(wicket.markup.html.form.FormComponent)
*/
public synchronized final void validate(final FormComponent formComponent)
{
// Save component
this.formComponent = formComponent;
// Cause validation to happen
onValidate();
}
/**
* Gets the default variables for interpolation. These are:
* <ul>
* <li>${input}: the user's input</li>
* <li>${name}: the name of the component</li>
* </ul>
*
* @return a map with the variables for interpolation
*/
protected Map messageModel()
{
final Map resourceModel = new HashMap(4);
resourceModel.put("input", getInput());
resourceModel.put("name", formComponent.getId());
return resourceModel;
}
/**
* Gets the resource key based on the form component. It will have the form:
* <code>[form-name].[component-name].[validator-class]</code>
*
* @return the resource key based on the form component
* @deprecated use getResourceKey()
*/
protected String resourceKey()
{
return getResourceKey();
}
}
package wicket.markup.html.form.validation;
import wicket.markup.html.form.FormComponent;
import wicket.model.IModel;
/**
* Strategy pattern used by AbstractValidator for replacing the algorithm for
* determining a validation message.
*/
public interface IValidatorMessageStrategy {
/**
* Returns a formatted validation error message for a given component.
*
* @param resourceKey
* The resource key to use
* @param formComponent
* The component on which validation is being performed.
* @param resourceModel
* The model for variable interpolation
*/
public String getMessage(String resourceKey, FormComponent formComponent, IModel resourceModel);
/**
* Return the default resourceKey for this formComponent.
*
* @param validator
* The validator instance that will use the resourceKey if its not explicitly set.
* @param formComponent
* The component on which validation is being performed.
*/
public String getDefaultResourceKey(IValidator validator, FormComponent formComponent);
}