/*
* Copyright (c) 2002-2006 by OpenSymphony
* All rights reserved.
*/
package com.opensymphony.xwork2.validator.validators;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.inject.Inject;
import com.opensymphony.xwork2.util.ValueStack;
import com.opensymphony.xwork2.validator.ActionValidatorManager;
import com.opensymphony.xwork2.validator.DelegatingValidatorContext;
import com.opensymphony.xwork2.validator.ValidationException;
import com.opensymphony.xwork2.validator.ValidatorContext;
import java.util.Collection;
/**
* <!-- START SNIPPET: javadoc -->
* The VisitorFieldValidator allows you to forward validation to object
* properties of your action using the object's own validation files. This
* allows you to use the ModelDriven development pattern and manage your
* validations for your models in one place, where they belong, next to your
* model classes. The VisitorFieldValidator can handle either simple Object
* properties, Collections of Objects, or Arrays.
* <!-- END SNIPPET: javadoc -->
* <p/>
*
* <!-- START SNIPPET: parameters -->
* <ul>
* <li>fieldName - field name if plain-validator syntax is used, not needed if field-validator syntax is used</li>
* <li>context - the context of which validation should take place. Optional</li>
* <li>appendPrefix - the prefix to be added to field. Optional </li>
* </ul>
* <!-- END SNIPPET: parameters -->
*
* <pre>
* <!-- START SNIPPET: example -->
* <validators>
* <!-- Plain Validator Syntax -->
* <validator type="visitor">
* <param name="fieldName">user</param>
* <param name="context">myContext</param>
* <param name="appendPrefix">true</param>
* </validator>
*
* <!-- Field Validator Syntax -->
* <field name="user">
* <field-validator type="visitor">
* <param name="context">myContext</param>
* <param name="appendPrefix">true</param>
* </field-validator>
* </field>
* </validators>
* <!-- END SNIPPET: example -->
* </pre>
*
* <!-- START SNIPPET: explanation -->
* <p>In the example above, if the acion's getUser() method return User object, XWork
* will look for User-myContext-validation.xml for the validators. Since appednPrefix is true,
* every field name will be prefixed with 'user' such that if the actual field name for 'name' is
* 'user.name' </p>
* <!-- END SNIPPET: explanation -->
*
* @author Jason Carreira
* @author Rainer Hermanns
* @version $Date: 2008-06-21 11:29:39 +0200 (Sa, 21 Jun 2008) $ $Id: VisitorFieldValidator.java 1833 2008-06-21 09:29:39Z rainerh $
*/
public class VisitorFieldValidator extends FieldValidatorSupport {
private String context;
private boolean appendPrefix = true;
private ActionValidatorManager actionValidatorManager;
@Inject
public void setActionValidatorManager(ActionValidatorManager mgr) {
this.actionValidatorManager = mgr;
}
/**
* Sets whether the field name of this field validator should be prepended to the field name of
* the visited field to determine the full field name when an error occurs. The default is
* true.
*/
public void setAppendPrefix(boolean appendPrefix) {
this.appendPrefix = appendPrefix;
}
/**
* Flags whether the field name of this field validator should be prepended to the field name of
* the visited field to determine the full field name when an error occurs. The default is
* true.
*/
public boolean isAppendPrefix() {
return appendPrefix;
}
public void setContext(String context) {
this.context = context;
}
public String getContext() {
return context;
}
public void validate(Object object) throws ValidationException {
String fieldName = getFieldName();
Object value = this.getFieldValue(fieldName, object);
if (value == null) {
log.warn("The visited object is null, VisitorValidator will not be able to handle validation properly. Please make sure the visited object is not null for VisitorValidator to function properly");
return;
}
ValueStack stack = ActionContext.getContext().getValueStack();
stack.push(object);
String visitorContext = (context == null) ? ActionContext.getContext().getName() : context;
if (value instanceof Collection) {
Collection coll = (Collection) value;
Object[] array = coll.toArray();
validateArrayElements(array, fieldName, visitorContext);
} else if (value instanceof Object[]) {
Object[] array = (Object[]) value;
validateArrayElements(array, fieldName, visitorContext);
} else {
validateObject(fieldName, value, visitorContext);
}
stack.pop();
}
private void validateArrayElements(Object[] array, String fieldName, String visitorContext) throws ValidationException {
if (array == null) {
return;
}
for (int i = 0; i < array.length; i++) {
Object o = array[i];
if (o != null) {
validateObject(fieldName + "[" + i + "]", o, visitorContext);
}
}
}
private void validateObject(String fieldName, Object o, String visitorContext) throws ValidationException {
ValueStack stack = ActionContext.getContext().getValueStack();
stack.push(o);
ValidatorContext validatorContext;
if (appendPrefix) {
validatorContext = new AppendingValidatorContext(getValidatorContext(), o, fieldName, getMessage(o));
} else {
ValidatorContext parent = getValidatorContext();
validatorContext = new DelegatingValidatorContext(parent, DelegatingValidatorContext.makeTextProvider(o, parent), parent);
}
actionValidatorManager.validate(o, visitorContext, validatorContext);
stack.pop();
}
public static class AppendingValidatorContext extends DelegatingValidatorContext {
private String field;
private String message;
private ValidatorContext parent;
public AppendingValidatorContext(ValidatorContext parent, Object object, String field, String message) {
super(parent, makeTextProvider(object, parent), parent);
this.field = field;
this.message = message;
this.parent = parent;
}
/**
* Translates a simple field name into a full field name in Ognl syntax
*
* @param fieldName field name in OGNL syntax
* @return field name in OGNL syntax
*/
@Override
public String getFullFieldName(String fieldName) {
return field + "." + fieldName;
}
public String getFullFieldNameFromParent(String fieldName) {
return parent.getFullFieldName(field + "." + fieldName);
}
@Override
public void addActionError(String anErrorMessage) {
super.addFieldError(getFullFieldName(field), message + anErrorMessage);
}
@Override
public void addFieldError(String fieldName, String errorMessage) {
super.addFieldError(getFullFieldName(fieldName), message + errorMessage);
}
}
}
|