You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@struts.apache.org by lu...@apache.org on 2011/12/02 17:33:45 UTC

svn commit: r1209569 [32/50] - in /struts/struts2/branches/STRUTS_3_X: apps/blank/src/main/java/example/ apps/blank/src/test/java/example/ apps/jboss-blank/src/main/java/example/ apps/jboss-blank/src/test/java/example/ apps/mailreader/src/main/java/mai...

Added: struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/validator/DefaultValidatorFileParser.java
URL: http://svn.apache.org/viewvc/struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/validator/DefaultValidatorFileParser.java?rev=1209569&view=auto
==============================================================================
--- struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/validator/DefaultValidatorFileParser.java (added)
+++ struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/validator/DefaultValidatorFileParser.java Fri Dec  2 16:33:03 2011
@@ -0,0 +1,244 @@
+/*
+ * Copyright 2002-2006,2009 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.struts2.xwork2.validator;
+
+import org.apache.struts2.xwork2.ObjectFactory;
+import org.apache.struts2.xwork2.config.ConfigurationException;
+import org.apache.struts2.xwork2.config.providers.XmlHelper;
+import org.apache.struts2.xwork2.inject.Inject;
+import org.apache.struts2.xwork2.util.DomHelper;
+import org.apache.struts2.xwork2.util.logging.Logger;
+import org.apache.struts2.xwork2.util.logging.LoggerFactory;
+import org.w3c.dom.*;
+import org.xml.sax.InputSource;
+
+import java.io.InputStream;
+import java.util.*;
+
+
+/**
+ * Parse the validation file. (eg. MyAction-validation.xml, MyAction-actionAlias-validation.xml)
+ * to return a List of ValidatorConfig encapsulating the validator information.
+ *
+ * @author Jason Carreira
+ * @author James House
+ * @author tm_jee ( tm_jee (at) yahoo.co.uk )
+ * @author Rob Harrop
+ * @author Rene Gielen
+ * @author Martin Gilday
+ * 
+ * @see ValidatorConfig
+ */
+public class DefaultValidatorFileParser implements ValidatorFileParser {
+
+    private static Logger LOG = LoggerFactory.getLogger(DefaultValidatorFileParser.class);
+
+    static final String DEFAULT_MULTI_TEXTVALUE_SEPARATOR = " ";
+    static final String MULTI_TEXTVALUE_SEPARATOR_CONFIG_KEY = "xwork.validatorfileparser.multi_textvalue_separator";
+
+    private ObjectFactory objectFactory;
+    private String multiTextvalueSeparator=DEFAULT_MULTI_TEXTVALUE_SEPARATOR;
+
+    @Inject(value=MULTI_TEXTVALUE_SEPARATOR_CONFIG_KEY, required = false)
+    public void setMultiTextvalueSeparator(String type) {
+        multiTextvalueSeparator = type;
+    }
+
+    public String getMultiTextvalueSeparator() {
+        return multiTextvalueSeparator;
+    }
+
+    @Inject
+    public void setObjectFactory(ObjectFactory fac) {
+        this.objectFactory = fac;
+    }
+
+    public List<ValidatorConfig> parseActionValidatorConfigs(ValidatorFactory validatorFactory, InputStream is, final String resourceName) {
+        List<ValidatorConfig> validatorCfgs = new ArrayList<ValidatorConfig>();
+
+        InputSource in = new InputSource(is);
+        in.setSystemId(resourceName);
+
+        Map<String, String> dtdMappings = new HashMap<String, String>();
+        dtdMappings.put("-//Apache Struts//XWork Validator 1.0//EN", "xwork-validator-1.0.dtd");
+        dtdMappings.put("-//Apache Struts//XWork Validator 1.0.2//EN", "xwork-validator-1.0.2.dtd");
+        dtdMappings.put("-//Apache Struts//XWork Validator 1.0.3//EN", "xwork-validator-1.0.3.dtd");
+        dtdMappings.put("-//Apache Struts//XWork Validator Config 1.0//EN", "xwork-validator-config-1.0.dtd");
+
+        Document doc = DomHelper.parse(in, dtdMappings);
+
+        if (doc != null) {
+            NodeList fieldNodes = doc.getElementsByTagName("field");
+
+            // BUG: xw-305: Let validator be parsed first and hence added to 
+            // the beginning of list and therefore evaluated first, so short-circuting
+            // it will not cause field-level validator to be kicked off.
+            {
+                NodeList validatorNodes = doc.getElementsByTagName("validator");
+                addValidatorConfigs(validatorFactory, validatorNodes, new HashMap<String, String>(), validatorCfgs);
+            }
+
+            for (int i = 0; i < fieldNodes.getLength(); i++) {
+                Element fieldElement = (Element) fieldNodes.item(i);
+                String fieldName = fieldElement.getAttribute("name");
+                Map<String, String> extraParams = new HashMap<String, String>();
+                extraParams.put("fieldName", fieldName);
+
+                NodeList validatorNodes = fieldElement.getElementsByTagName("field-validator");
+                addValidatorConfigs(validatorFactory, validatorNodes, extraParams, validatorCfgs);
+            }
+        }
+
+        return validatorCfgs;
+    }
+
+
+    public void parseValidatorDefinitions(Map<String, String> validators, InputStream is, String resourceName) {
+
+        InputSource in = new InputSource(is);
+        in.setSystemId(resourceName);
+
+        Map<String, String> dtdMappings = new HashMap<String, String>();
+        dtdMappings.put("-//Apache Struts//XWork Validator Config 1.0//EN", "xwork-validator-config-1.0.dtd");
+
+        Document doc = DomHelper.parse(in, dtdMappings);
+
+        if (doc != null) {
+            NodeList nodes = doc.getElementsByTagName("validator");
+
+            for (int i = 0; i < nodes.getLength(); i++) {
+                Element validatorElement = (Element) nodes.item(i);
+                String name = validatorElement.getAttribute("name");
+                String className = validatorElement.getAttribute("class");
+
+                try {
+                    // catch any problems here
+                    objectFactory.buildValidator(className, new HashMap<String, String>(), null);
+                    validators.put(name, className);
+                } catch (Exception e) {
+                    throw new ConfigurationException("Unable to load validator class " + className, e, validatorElement);
+                }
+            }
+        }
+    }
+
+    /**
+     * Extract trimmed text value from the given DOM element, ignoring XML comments. Appends all CharacterData nodes
+     * and EntityReference nodes into a single String value, excluding Comment nodes.
+     * This method is based on a method originally found in DomUtils class of Springframework.
+     *
+     * @see org.w3c.dom.CharacterData
+     * @see org.w3c.dom.EntityReference
+     * @see org.w3c.dom.Comment
+     */
+    public String getTextValue(Element valueEle) {
+        StringBuilder value = new StringBuilder();
+        NodeList nl = valueEle.getChildNodes();
+        boolean firstCDataFound = false;
+        for (int i = 0; i < nl.getLength(); i++) {
+            Node item = nl.item(i);
+            if ((item instanceof CharacterData && !(item instanceof Comment)) || item instanceof EntityReference) {
+                final String nodeValue = item.getNodeValue();
+                if (nodeValue != null) {
+                    if (firstCDataFound) {
+                        value.append(getMultiTextvalueSeparator());
+                    } else {
+                        firstCDataFound = true;
+                    }
+                    value.append(nodeValue.trim());
+                }
+            }
+        }
+        return value.toString().trim();
+    }
+
+    private void addValidatorConfigs(ValidatorFactory factory, NodeList validatorNodes, Map<String, String> extraParams, List<ValidatorConfig> validatorCfgs) {
+        for (int j = 0; j < validatorNodes.getLength(); j++) {
+            Element validatorElement = (Element) validatorNodes.item(j);
+            String validatorType = validatorElement.getAttribute("type");
+            Map<String, String> params = new HashMap<String, String>(extraParams);
+
+            params.putAll(XmlHelper.getParams(validatorElement));
+
+            // ensure that the type is valid...
+            try {
+                factory.lookupRegisteredValidatorType(validatorType);
+            } catch (IllegalArgumentException ex) {
+                throw new ConfigurationException("Invalid validation type: " + validatorType, validatorElement);
+            }
+
+            ValidatorConfig.Builder vCfg = new ValidatorConfig.Builder(validatorType)
+                    .addParams(params)
+                    .location(DomHelper.getLocationObject(validatorElement))
+                    .shortCircuit(Boolean.valueOf(validatorElement.getAttribute("short-circuit")).booleanValue());
+
+            NodeList messageNodes = validatorElement.getElementsByTagName("message");
+            Element messageElement = (Element) messageNodes.item(0);
+
+            final Node defaultMessageNode = messageElement.getFirstChild();
+            String defaultMessage = (defaultMessageNode == null) ? "" : defaultMessageNode.getNodeValue();
+            vCfg.defaultMessage(defaultMessage);
+
+            Map<String, String> messageParams = XmlHelper.getParams(messageElement);
+            String key = messageElement.getAttribute("key");
+
+
+            if ((key != null) && (key.trim().length() > 0)) {
+                vCfg.messageKey(key);
+
+                // Get the default message when pattern 2 is used. We are only interested in the
+                // i18n message parameters when an i18n message key is specified.
+                // pattern 1:
+                // <message key="someKey">Default message</message>
+                // pattern 2:
+                // <message key="someKey">
+                //     <param name="1">'param1'</param>
+                //     <param name="2">'param2'</param>
+                //     <param name="defaultMessage>The Default Message</param>
+                // </message>
+
+                if (messageParams.containsKey("defaultMessage")) {
+                    vCfg.defaultMessage(messageParams.get("defaultMessage").toString());
+                }
+
+                // Sort the message param. those with keys as '1', '2', '3' etc. (numeric values)
+                // are i18n message parameter, others are excluded.
+                TreeMap<Integer, String> sortedMessageParameters = new TreeMap<Integer, String>();
+                for (Map.Entry<String, String> messageParamEntry : messageParams.entrySet()) {
+
+                    try {
+                        int _order = Integer.parseInt(messageParamEntry.getKey());
+                        sortedMessageParameters.put(Integer.valueOf(_order), messageParamEntry.getValue().toString());
+                    }
+                    catch (NumberFormatException e) {
+                        // ignore if its not numeric.
+                    }
+                }
+                vCfg.messageParams(sortedMessageParameters.values().toArray(new String[sortedMessageParameters.values().size()]));
+            } else {
+                if (messageParams != null && (messageParams.size() > 0)) {
+                    // we are i18n message parameters defined but no i18n message,
+                    // let's warn the user.
+                    if (LOG.isWarnEnabled()) {
+                	LOG.warn("validator of type ["+validatorType+"] have i18n message parameters defined but no i18n message key, it's parameters will be ignored");
+                    }
+                }
+            }
+
+            validatorCfgs.add(vCfg.build());
+        }
+    }
+}

Added: struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/validator/DelegatingValidatorContext.java
URL: http://svn.apache.org/viewvc/struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/validator/DelegatingValidatorContext.java?rev=1209569&view=auto
==============================================================================
--- struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/validator/DelegatingValidatorContext.java (added)
+++ struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/validator/DelegatingValidatorContext.java Fri Dec  2 16:33:03 2011
@@ -0,0 +1,316 @@
+/*
+ * Copyright 2002-2006,2009 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.struts2.xwork2.validator;
+
+import org.apache.struts2.xwork2.util.ValueStack;
+import org.apache.struts2.xwork2.util.logging.Logger;
+import org.apache.struts2.xwork2.util.logging.LoggerFactory;
+import org.apache.struts2.xwork2.ActionContext;
+import org.apache.struts2.xwork2.CompositeTextProvider;
+import org.apache.struts2.xwork2.LocaleProvider;
+import org.apache.struts2.xwork2.TextProvider;
+import org.apache.struts2.xwork2.TextProviderFactory;
+import org.apache.struts2.xwork2.TextProviderSupport;
+import org.apache.struts2.xwork2.ValidationAware;
+
+import java.util.*;
+
+
+/**
+ * A default implementation of the {@link ValidatorContext} interface.
+ *
+ * @author Jason Carreira
+ * @author Rainer Hermanns
+ */
+public class DelegatingValidatorContext implements ValidatorContext {
+
+    private LocaleProvider localeProvider;
+    private TextProvider textProvider;
+    private ValidationAware validationAware;
+
+    /**
+     * Creates a new validation context given a ValidationAware object, and a text and locale provider. These objects
+     * are used internally to set errors and get and set error text.
+     */
+    public DelegatingValidatorContext(ValidationAware validationAware, TextProvider textProvider,
+                                      LocaleProvider localeProvider) {
+        this.textProvider = textProvider;
+        this.validationAware = validationAware;
+        this.localeProvider = localeProvider;
+    }
+
+    /**
+     * Creates a new validation context given an object - usually an Action. The internal objects
+     * (validation aware instance and a locale and text provider) are created based on the given action.
+     *
+     * @param object the object to use for validation (usually an Action).
+     */
+    public DelegatingValidatorContext(Object object) {
+        this.localeProvider = makeLocaleProvider(object);
+        this.validationAware = makeValidationAware(object);
+        this.textProvider = makeTextProvider(object, localeProvider);
+    }
+
+    /**
+     * Create a new validation context given a Class definition. The locale provider, text provider and
+     * the validation context are created based on the class.
+     *
+     * @param clazz the class to initialize the context with.
+     */
+    public DelegatingValidatorContext(Class clazz) {
+        localeProvider = new ActionContextLocaleProvider();
+        textProvider = new TextProviderFactory().createInstance(clazz, localeProvider);
+        validationAware = new LoggingValidationAware(clazz);
+    }
+
+    public void setActionErrors(Collection<String> errorMessages) {
+        validationAware.setActionErrors(errorMessages);
+    }
+
+    public Collection<String> getActionErrors() {
+        return validationAware.getActionErrors();
+    }
+
+    public void setActionMessages(Collection<String> messages) {
+        validationAware.setActionMessages(messages);
+    }
+
+    public Collection<String> getActionMessages() {
+        return validationAware.getActionMessages();
+    }
+
+    public void setFieldErrors(Map<String, List<String>> errorMap) {
+        validationAware.setFieldErrors(errorMap);
+    }
+
+    public Map<String, List<String>> getFieldErrors() {
+        return validationAware.getFieldErrors();
+    }
+
+    public String getFullFieldName(String fieldName) {
+        return fieldName;
+    }
+
+    public Locale getLocale() {
+        return localeProvider.getLocale();
+    }
+
+    public boolean hasKey(String key) {
+    	return textProvider.hasKey(key);
+    }
+    
+    public String getText(String aTextName) {
+        return textProvider.getText(aTextName);
+    }
+
+    public String getText(String aTextName, String defaultValue) {
+        return textProvider.getText(aTextName, defaultValue);
+    }
+
+    public String getText(String aTextName, String defaultValue, String obj) {
+        return textProvider.getText(aTextName, defaultValue, obj);
+    }
+
+    public String getText(String aTextName, List<?> args) {
+        return textProvider.getText(aTextName, args);
+    }
+
+    public String getText(String key, String[] args) {
+        return textProvider.getText(key, args);
+    }
+
+    public String getText(String aTextName, String defaultValue, List<?> args) {
+        return textProvider.getText(aTextName, defaultValue, args);
+    }
+
+    public String getText(String key, String defaultValue, String[] args) {
+        return textProvider.getText(key, defaultValue, args);
+    }
+
+    public ResourceBundle getTexts(String aBundleName) {
+        return textProvider.getTexts(aBundleName);
+    }
+
+    public String getText(String key, String defaultValue, List<?> args, ValueStack stack) {
+        return textProvider.getText(key, defaultValue, args, stack);
+    }
+
+    public String getText(String key, String defaultValue, String[] args, ValueStack stack) {
+        return textProvider.getText(key, defaultValue, args, stack);
+    }
+
+    public ResourceBundle getTexts() {
+        return textProvider.getTexts();
+    }
+
+    public void addActionError(String anErrorMessage) {
+        validationAware.addActionError(anErrorMessage);
+    }
+
+    public void addActionMessage(String aMessage) {
+        validationAware.addActionMessage(aMessage);
+    }
+
+    public void addFieldError(String fieldName, String errorMessage) {
+        validationAware.addFieldError(fieldName, errorMessage);
+    }
+
+    public boolean hasActionErrors() {
+        return validationAware.hasActionErrors();
+    }
+
+    public boolean hasActionMessages() {
+        return validationAware.hasActionMessages();
+    }
+
+    public boolean hasErrors() {
+        return validationAware.hasErrors();
+    }
+
+    public boolean hasFieldErrors() {
+        return validationAware.hasFieldErrors();
+    }
+
+    public static TextProvider makeTextProvider(Object object, LocaleProvider localeProvider) {
+        // the object argument passed through here will most probably be an ActionSupport decendant which does
+        // implements TextProvider.
+        if ((object != null) && (object instanceof TextProvider)) {
+            return new CompositeTextProvider(new TextProvider[]{
+                    ((TextProvider) object),
+                    new TextProviderSupport(object.getClass(), localeProvider)
+            });
+        } else {
+            return new TextProviderFactory().createInstance(object.getClass(), localeProvider);
+        }
+    }
+
+    protected static LocaleProvider makeLocaleProvider(Object object) {
+        if (object instanceof LocaleProvider) {
+            return (LocaleProvider) object;
+        } else {
+            return new ActionContextLocaleProvider();
+        }
+    }
+
+    protected static ValidationAware makeValidationAware(Object object) {
+        if (object instanceof ValidationAware) {
+            return (ValidationAware) object;
+        } else {
+            return new LoggingValidationAware(object);
+        }
+    }
+
+    protected void setTextProvider(TextProvider textProvider) {
+        this.textProvider = textProvider;
+    }
+
+    protected TextProvider getTextProvider() {
+        return textProvider;
+    }
+
+    protected void setValidationAware(ValidationAware validationAware) {
+        this.validationAware = validationAware;
+    }
+
+    protected ValidationAware getValidationAware() {
+        return validationAware;
+    }
+
+    /**
+     * An implementation of LocaleProvider which gets the locale from the action context.
+     */
+    private static class ActionContextLocaleProvider implements LocaleProvider {
+        public Locale getLocale() {
+            return ActionContext.getContext().getLocale();
+        }
+    }
+
+    /**
+     * An implementation of ValidationAware which logs errors and messages.
+     */
+    private static class LoggingValidationAware implements ValidationAware {
+
+        private Logger log;
+
+        public LoggingValidationAware(Class clazz) {
+            log = LoggerFactory.getLogger(clazz);
+        }
+
+        public LoggingValidationAware(Object obj) {
+            log = LoggerFactory.getLogger(obj.getClass());
+        }
+
+        public void setActionErrors(Collection<String> errorMessages) {
+            for (Object errorMessage : errorMessages) {
+                String s = (String) errorMessage;
+                addActionError(s);
+            }
+        }
+
+        public Collection<String> getActionErrors() {
+            return null;
+        }
+
+        public void setActionMessages(Collection<String> messages) {
+            for (Object message : messages) {
+                String s = (String) message;
+                addActionMessage(s);
+            }
+        }
+
+        public Collection<String> getActionMessages() {
+            return null;
+        }
+
+        public void setFieldErrors(Map<String, List<String>> errorMap) {
+            for (Map.Entry<String, List<String>> entry : errorMap.entrySet()) {
+                addFieldError(entry.getKey(), entry.getValue().toString());
+            }
+        }
+
+        public Map<String, List<String>> getFieldErrors() {
+            return null;
+        }
+
+        public void addActionError(String anErrorMessage) {
+            log.error("Validation error: " + anErrorMessage);
+        }
+
+        public void addActionMessage(String aMessage) {
+            log.info("Validation Message: " + aMessage);
+        }
+
+        public void addFieldError(String fieldName, String errorMessage) {
+            log.error("Validation error for " + fieldName + ":" + errorMessage);
+        }
+
+        public boolean hasActionErrors() {
+            return false;
+        }
+
+        public boolean hasActionMessages() {
+            return false;
+        }
+
+        public boolean hasErrors() {
+            return false;
+        }
+
+        public boolean hasFieldErrors() {
+            return false;
+        }
+    }
+}

Added: struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/validator/FieldValidator.java
URL: http://svn.apache.org/viewvc/struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/validator/FieldValidator.java?rev=1209569&view=auto
==============================================================================
--- struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/validator/FieldValidator.java (added)
+++ struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/validator/FieldValidator.java Fri Dec  2 16:33:03 2011
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2002-2007,2009 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.struts2.xwork2.validator;
+
+/**
+ * The FieldValidator interface defines the methods to be implemented by FieldValidators.
+ * Which are used by the XWork validation framework to validate Action properties before
+ * executing the Action.
+ */
+public interface FieldValidator extends Validator {
+
+    /**
+     * Sets the field name to validate with this FieldValidator
+     *
+     * @param fieldName the field name
+     */
+    void setFieldName(String fieldName);
+
+    /**
+     * Gets the field name to be validated
+     *
+     * @return the field name
+     */
+    String getFieldName();
+
+}

Added: struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/validator/ShortCircuitableValidator.java
URL: http://svn.apache.org/viewvc/struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/validator/ShortCircuitableValidator.java?rev=1209569&view=auto
==============================================================================
--- struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/validator/ShortCircuitableValidator.java (added)
+++ struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/validator/ShortCircuitableValidator.java Fri Dec  2 16:33:03 2011
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2002-2007,2009 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.struts2.xwork2.validator;
+
+
+/**
+ * This interface should be implemented by validators that can short-circuit the validator queue
+ * that it is in.
+ *
+ * @author Mark Woon
+ */
+public interface ShortCircuitableValidator {
+
+    /**
+     * Sets whether this field validator should short circuit the validator queue
+     * it's in if validation fails.
+     *
+     * @param shortcircuit <tt>true</tt> if this field validator should short circuit on
+     *                     failure, <tt>false</tt> otherwise
+     */
+    public void setShortCircuit(boolean shortcircuit);
+
+    /**
+     * Gets whether this field validator should short circuit the validator queue
+     * it's in if validation fails.
+     *
+     * @return <tt>true</tt> if this field validator should short circuit on failure,
+     *         <tt>false</tt> otherwise
+     */
+    public boolean isShortCircuit();
+}

Added: struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/validator/ValidationException.java
URL: http://svn.apache.org/viewvc/struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/validator/ValidationException.java?rev=1209569&view=auto
==============================================================================
--- struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/validator/ValidationException.java (added)
+++ struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/validator/ValidationException.java Fri Dec  2 16:33:03 2011
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2002-2006,2009 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.struts2.xwork2.validator;
+
+
+/**
+ * ValidationException.
+ *
+ * @author Jason Carreira
+ */
+public class ValidationException extends Exception {
+
+    /**
+     * Constructs an <code>Exception</code> with no specified detail message.
+     */
+    public ValidationException() {
+    }
+
+    /**
+     * Constructs an <code>Exception</code> with the specified detail message.
+     *
+     * @param s the detail message.
+     */
+    public ValidationException(String s) {
+        super(s);
+    }
+}

Added: struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/validator/ValidationInterceptor.java
URL: http://svn.apache.org/viewvc/struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/validator/ValidationInterceptor.java?rev=1209569&view=auto
==============================================================================
--- struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/validator/ValidationInterceptor.java (added)
+++ struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/validator/ValidationInterceptor.java Fri Dec  2 16:33:03 2011
@@ -0,0 +1,267 @@
+/*
+ * Copyright 2002-2007,2009 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.struts2.xwork2.validator;
+
+import org.apache.struts2.xwork2.ActionInvocation;
+import org.apache.struts2.xwork2.ActionProxy;
+import org.apache.struts2.xwork2.Validateable;
+import org.apache.struts2.xwork2.inject.Inject;
+import org.apache.struts2.xwork2.interceptor.MethodFilterInterceptor;
+import org.apache.struts2.xwork2.interceptor.PrefixMethodInvocationUtil;
+import org.apache.struts2.xwork2.util.logging.Logger;
+import org.apache.struts2.xwork2.util.logging.LoggerFactory;
+
+/**
+ * <!-- START SNIPPET: description -->
+ *
+ * This interceptor runs the action through the standard validation framework, which in turn checks the action against
+ * any validation rules (found in files such as <i>ActionClass-validation.xml</i>) and adds field-level and action-level
+ * error messages (provided that the action implements {@link org.apache.struts2.xwork2.ValidationAware}). This interceptor
+ * is often one of the last (or second to last) interceptors applied in a stack, as it assumes that all values have
+ * already been set on the action.
+ *
+ * <p/>This interceptor does nothing if the name of the method being invoked is specified in the <b>excludeMethods</b>
+ * parameter. <b>excludeMethods</b> accepts a comma-delimited list of method names. For example, requests to
+ * <b>foo!input.action</b> and <b>foo!back.action</b> will be skipped by this interceptor if you set the
+ * <b>excludeMethods</b> parameter to "input, back".
+ * 
+ * </ol>
+ * 
+ * <p/> The workflow of the action request does not change due to this interceptor. Rather,
+ * this interceptor is often used in conjuction with the <b>workflow</b> interceptor.
+ *
+ * <p/>
+ * 
+ * <b>NOTE:</b> As this method extends off MethodFilterInterceptor, it is capable of
+ * deciding if it is applicable only to selective methods in the action class. See
+ * <code>MethodFilterInterceptor</code> for more info.
+ *
+ * <!-- END SNIPPET: description -->
+ *
+ * <p/> <u>Interceptor parameters:</u>
+ *
+ * <!-- START SNIPPET: parameters -->
+ *
+ * <ul>
+ *
+ * <li>alwaysInvokeValidate - Defaults to true. If true validate() method will always
+ * be invoked, otherwise it will not.</li>
+ *
+ * <li>programmatic - Defaults to true. If true and the action is Validateable call validate(),
+ * and any method that starts with "validate".
+ * </li>
+ * 
+ * <li>declarative - Defaults to true. Perform validation based on xml or annotations.</li>
+ * 
+ * </ul>
+ *
+ * <!-- END SNIPPET: parameters -->
+ *
+ * <p/> <u>Extending the interceptor:</u>
+ *
+ * <p/>
+ *
+ * <!-- START SNIPPET: extending -->
+ *
+ * There are no known extension points for this interceptor.
+ *
+ * <!-- END SNIPPET: extending -->
+ *
+ * <p/> <u>Example code:</u>
+ *
+ * <pre>
+ * <!-- START SNIPPET: example -->
+ * 
+ * &lt;action name="someAction" class="com.examples.SomeAction"&gt;
+ *     &lt;interceptor-ref name="params"/&gt;
+ *     &lt;interceptor-ref name="validation"/&gt;
+ *     &lt;interceptor-ref name="workflow"/&gt;
+ *     &lt;result name="success"&gt;good_result.ftl&lt;/result&gt;
+ * &lt;/action&gt;
+ * 
+ * &lt;-- in the following case myMethod of the action class will not
+ *        get validated --&gt;
+ * &lt;action name="someAction" class="com.examples.SomeAction"&gt;
+ *     &lt;interceptor-ref name="params"/&gt;
+ *     &lt;interceptor-ref name="validation"&gt;
+ *         &lt;param name="excludeMethods"&gt;myMethod&lt;/param&gt;
+ *     &lt;/interceptor-ref&gt;
+ *     &lt;interceptor-ref name="workflow"/&gt;
+ *     &lt;result name="success"&gt;good_result.ftl&lt;/result&gt;
+ * &lt;/action&gt;
+ * 
+ * &lt;-- in the following case only annotated methods of the action class will
+ *        be validated --&gt;
+ * &lt;action name="someAction" class="com.examples.SomeAction"&gt;
+ *     &lt;interceptor-ref name="params"/&gt;
+ *     &lt;interceptor-ref name="validation"&gt;
+ *         &lt;param name="validateAnnotatedMethodOnly"&gt;true&lt;/param&gt;
+ *     &lt;/interceptor-ref&gt;
+ *     &lt;interceptor-ref name="workflow"/&gt;
+ *     &lt;result name="success"&gt;good_result.ftl&lt;/result&gt;
+ * &lt;/action&gt;
+ *
+ *
+ * <!-- END SNIPPET: example -->
+ * </pre>
+ *
+ * @author Jason Carreira
+ * @author Rainer Hermanns
+ * @author <a href='mailto:the_mindstorm[at]evolva[dot]ro'>Alexandru Popescu</a>
+ * @see ActionValidatorManager
+ * @see org.apache.struts2.xwork2.interceptor.DefaultWorkflowInterceptor
+ */
+public class ValidationInterceptor extends MethodFilterInterceptor {
+
+    private boolean validateAnnotatedMethodOnly;
+    
+    private ActionValidatorManager actionValidatorManager;
+    
+    private static final Logger LOG = LoggerFactory.getLogger(ValidationInterceptor.class);
+    
+    private final static String VALIDATE_PREFIX = "validate";
+    private final static String ALT_VALIDATE_PREFIX = "validateDo";
+    
+    private boolean alwaysInvokeValidate = true;
+    private boolean programmatic = true;
+    private boolean declarative = true;
+
+    @Inject
+    public void setActionValidatorManager(ActionValidatorManager mgr) {
+        this.actionValidatorManager = mgr;
+    }
+    
+    /**
+     * Determines if {@link org.apache.struts2.xwork2.Validateable}'s <code>validate()</code> should be called,
+     * as well as methods whose name that start with "validate". Defaults to "true".
+     * 
+     * @param programmatic <tt>true</tt> then <code>validate()</code> is invoked.
+     */
+    public void setProgrammatic(boolean programmatic) {
+        this.programmatic = programmatic;
+    }
+
+    /**
+     * Determines if validation based on annotations or xml should be performed. Defaults 
+     * to "true".
+     * 
+     * @param declarative <tt>true</tt> then perform validation based on annotations or xml.
+     */
+    public void setDeclarative(boolean declarative) {
+        this.declarative = declarative;
+    }
+
+    /**
+     * Determines if {@link org.apache.struts2.xwork2.Validateable}'s <code>validate()</code> should always
+     * be invoked. Default to "true".
+     * 
+     * @param alwaysInvokeValidate <tt>true</tt> then <code>validate()</code> is always invoked.
+     */
+    public void setAlwaysInvokeValidate(String alwaysInvokeValidate) {
+            this.alwaysInvokeValidate = Boolean.parseBoolean(alwaysInvokeValidate);
+    }
+
+    /**
+     * Gets if <code>validate()</code> should always be called or only per annotated method.
+     *
+     * @return <tt>true</tt> to only validate per annotated method, otherwise <tt>false</tt> to always validate.
+     */
+    public boolean isValidateAnnotatedMethodOnly() {
+        return validateAnnotatedMethodOnly;
+    }
+
+    /**
+     * Determine if <code>validate()</code> should always be called or only per annotated method.
+     * Default to <tt>false</tt>.
+     *
+     * @param validateAnnotatedMethodOnly  <tt>true</tt> to only validate per annotated method, otherwise <tt>false</tt> to always validate.
+     */
+    public void setValidateAnnotatedMethodOnly(boolean validateAnnotatedMethodOnly) {
+        this.validateAnnotatedMethodOnly = validateAnnotatedMethodOnly;
+    }
+
+    /**
+     * Gets the current action and its context and delegates to {@link ActionValidatorManager} proper validate method.
+     *
+     * @param invocation  the execution state of the Action.
+     * @throws Exception if an error occurs validating the action.
+     */
+    protected void doBeforeInvocation(ActionInvocation invocation) throws Exception {
+        Object action = invocation.getAction();
+        ActionProxy proxy = invocation.getProxy();
+
+        //the action name has to be from the url, otherwise validators that use aliases, like
+        //MyActio-someaction-validator.xml will not be found, see WW-3194
+        String context = proxy.getActionName();
+        String method = proxy.getMethod();
+
+        if (log.isDebugEnabled()) {
+            log.debug("Validating "
+                    + invocation.getProxy().getNamespace() + "/" + invocation.getProxy().getActionName() + " with method "+ method +".");
+        }
+        
+
+        if (declarative) {
+           if (validateAnnotatedMethodOnly) {
+               actionValidatorManager.validate(action, context, method);
+           } else {
+               actionValidatorManager.validate(action, context);
+           }
+       }    
+        
+        if (action instanceof Validateable && programmatic) {
+            // keep exception that might occured in validateXXX or validateDoXXX
+            Exception exception = null; 
+            
+            Validateable validateable = (Validateable) action;
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("Invoking validate() on action "+validateable);
+            }
+            
+            try {
+                PrefixMethodInvocationUtil.invokePrefixMethod(
+                                invocation, 
+                                new String[] { VALIDATE_PREFIX, ALT_VALIDATE_PREFIX });
+            }
+            catch(Exception e) {
+                // If any exception occurred while doing reflection, we want 
+                // validate() to be executed
+                if (LOG.isWarnEnabled()) {
+                    LOG.warn("an exception occured while executing the prefix method", e);
+                }
+                exception = e;
+            }
+            
+            
+            if (alwaysInvokeValidate) {
+                validateable.validate();
+            }
+            
+            if (exception != null) { 
+                // rethrow if something is wrong while doing validateXXX / validateDoXXX 
+                throw exception;
+            }
+        }
+    }
+
+    @Override
+    protected String doIntercept(ActionInvocation invocation) throws Exception {
+        doBeforeInvocation(invocation);
+        
+        return invocation.invoke();
+    }
+
+}

Added: struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/validator/Validator.java
URL: http://svn.apache.org/viewvc/struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/validator/Validator.java?rev=1209569&view=auto
==============================================================================
--- struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/validator/Validator.java (added)
+++ struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/validator/Validator.java Fri Dec  2 16:33:03 2011
@@ -0,0 +1,490 @@
+/*
+ * Copyright 2002-2007,2009 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.struts2.xwork2.validator;
+
+import org.apache.struts2.xwork2.util.ValueStack;
+
+
+/**
+ * <!-- START SNIPPET: validatorFlavours -->
+ * <p>The validators supplied by the XWork distribution (and any validators you
+ * might write yourself) come in two different flavors:</p>
+ * <p/>
+ * <ol>
+ * <li> Plain Validators / Non-Field validators </li>
+ * <li> FieldValidators </li>
+ * </ol>
+ * <p/>
+ * <p>Plain Validators (such as the ExpressionValidator) perform validation checks
+ * that are not inherently tied to a single specified field. When you declare a
+ * plain Validator in your -validation.xml file you do not associate a fieldname
+ * attribute with it. (You should avoid using plain Validators within the
+ * <field-validator> syntax described below.)</p>
+ * <p/>
+ * <p>FieldValidators (such as the EmailValidator) are designed to perform
+ * validation checks on a single field. They require that you specify a fieldname
+ * attribute in your -validation.xml file. There are two different (but equivalent)
+ * XML syntaxes you can use to declare FieldValidators (see "<validator> vs.
+ * <field-Validator> syntax" below).</p>
+ * <p/>
+ * <p>There are two places where the differences between the two validator flavors
+ * are important to keep in mind:</p>
+ * <p/>
+ * <ol>
+ * <li> when choosing the xml syntax used for declaring a validator
+ * (either <validator> or <field-validator>)</li>
+ * <li> when using the short-circuit capability</li>
+ * </ol>
+ * <p/>
+ * <p><b>NOTE:</b>Note that you do not declare what "flavor" of validator you are
+ * using in your -validation.xml file, you just declare the name of the validator
+ * to use and Struts will know whether it's a "plain Validator" or a "FieldValidator"
+ * by looking at the validation class that the validator's programmer chose
+ * to implement.</p>
+ * <!-- END SNIPPET: validatorFlavours -->
+ * <p/>
+ * <p/>
+ * <p/>
+ * <p/>
+ * <!-- START SNIPPET: validationRules -->
+ * <p>To define validation rules for an Action, create a file named ActionName-validation.xml
+ * in the same package as the Action. You may also create alias-specific validation rules which
+ * add to the default validation rules defined in ActionName-validation.xml by creating
+ * another file in the same directory named ActionName-aliasName-validation.xml. In both
+ * cases, ActionName is the name of the Action class, and aliasName is the name of the
+ * Action alias defined in the xwork.xml configuration for the Action.</p>
+ * <p/>
+ * <p>The framework will also search up the inheritance tree of the Action to
+ * find validation rules for directly implemented interfaces and parent classes of the Action.
+ * This is particularly powerful when combined with ModelDriven Actions and the VisitorFieldValidator.
+ * Here's an example of how validation rules are discovered. Given the following class structure:</p>
+ * <p/>
+ * <ul>
+ * <li>interface Animal;</li>
+ * <li>interface Quadraped extends Animal;</li>
+ * <li>class AnimalImpl implements Animal;</li>
+ * <li>class QuadrapedImpl extends AnimalImpl implements Quadraped;</li>
+ * <li>class Dog extends QuadrapedImpl;</li>
+ * </ul>
+ * <p/>
+ * <p>The framework method will look for the following config files if Dog is to be validated:</p>
+ * <p/>
+ * <ul>
+ * <li>Animal</li>
+ * <li>Animal-aliasname</li>
+ * <li>AnimalImpl</li>
+ * <li>AnimalImpl-aliasname</li>
+ * <li>Quadraped</li>
+ * <li>Quadraped-aliasname</li>
+ * <li>QuadrapedImpl</li>
+ * <li>QuadrapedImpl-aliasname</li>
+ * <li>Dog</li>
+ * <li>Dog-aliasname</li>
+ * </ul>
+ * <p/>
+ * <p>While this process is similar to what the XW:Localization framework does
+ * when finding messages, there are some subtle differences. The most important
+ * difference is that validation rules are discovered from the parent downwards.
+ * </p>
+ * <p/>
+ * <p><b>NOTE:</b>Child's *-validation.xml will add on to parent's *-validation.xml
+ * according to the class hierarchy defined above. With this feature, one could have
+ * more generic validation rule at the parent and more specific validation rule at
+ * the child.</p>
+ * <p/>
+ * <!-- END SNIPPET: validationRules -->
+ * <p/>
+ * <p/>
+ * <!-- START SNIPPET: validatorVsFieldValidators1 -->
+ * <p>There are two ways you can define validators in your -validation.xml file:</p>
+ * <ol>
+ * <li> &lt;validator&gt; </li>
+ * <li> &lt;field-validator&gt; </li>
+ * </ol>
+ * <p>Keep the following in mind when using either syntax:</p>
+ * <p/>
+ * <p><b>Non-Field-Validator</b>
+ * The &lt;validator&gt; element allows you to declare both types of validators
+ * (either a plain Validator a field-specific FieldValidator).</p>
+ * <!-- END SNIPPET: validatorVsFieldValidators1 -->
+ * <p/>
+ * <pre>
+ * <!-- START SNIPPET: nonFieldValidatorUsingValidatorSyntax -->
+ *    &lt;!-- Declaring a plain Validator using the &lt;validator&gt; syntax: --&gt;
+ * <p/>
+ *    &lt;validator type="expression&gt;
+ *          &lt;param name="expression">foo gt bar&lt;/param&gt;
+ *          &lt;message&gt;foo must be great than bar.&lt;/message&gt;
+ *    &lt;/validator&gt;
+ * <!-- END SNIPPET: nonFieldValidatorUsingValidatorSyntax -->
+ * </pre>
+ * <p/>
+ * <pre>
+ * <!-- START SNIPPET: fieldValidatorUsingValidatorSyntax -->
+ *    &lt;!-- Declaring a field validator using the &lt;validator&gt; syntax; --&gt;
+ * <p/>
+ *    &lt;validator type="required"&gt;
+ *         &lt;param name="fieldName"&gt;bar&lt;/param&gt;
+ *         &lt;message&gt;You must enter a value for bar.&lt;/message&gt;
+ *    &lt/validator&gt;
+ * <!-- END SNIPPET: fieldValidatorUsingValidatorSyntax -->
+ * </pre>
+ * <p/>
+ * <p/>
+ * <!-- START SNIPPET: validatorVsFieldValidators2 -->
+ * <p><b>field-validator</b>
+ * The &lt;field-validator&gt; elements are basically the same as the &lt;validator&gt; elements
+ * except that they inherit the fieldName attribute from the enclosing &lt;field&gt; element.
+ * FieldValidators defined within a &lt;field-validator&gt; element will have their fieldName
+ * automatically filled with the value of the parent &lt;field&gt; element's fieldName
+ * attribute. The reason for this structure is to conveniently group the validators
+ * for a particular field under one element, otherwise the fieldName attribute
+ * would have to be repeated, over and over, for each individual &lt;validator&gt;.</p>
+ * <p/>
+ * <p><b>HINT:</b>
+ * It is always better to defined field-validator inside a &lt;field&gt; tag instead of
+ * using a &lt;validator&gt; tag and supplying fieldName as its param as the xml code itself
+ * is clearer (grouping of field is clearer)</p>
+ * <p/>
+ * <p><b>NOTE:</b>
+ * Note that you should only use FieldValidators (not plain Validators) within a
+ * <field-validator> block. A plain Validator inside a &lt;field&gt; will not be
+ * allowed and would generate error when parsing the xml, as it is not allowed in
+ * the defined dtd (xwork-validator-1.0.2.dtd)</p>
+ * <!-- END SNIPPET: validatorVsFieldValidators2 -->
+ * <p/>
+ * <pre>
+ * <!-- START SNIPPET: fieldValidatorUsingFieldValidatorSyntax -->
+ * Declaring a FieldValidator using the &lt;field-validator&gt; syntax:
+ * <p/>
+ * &lt;field name="email_address"&gt;
+ *   &lt;field-validator type="required"&gt;
+ *       &lt;message&gt;You cannot leave the email address field empty.&lt;/message&gt;
+ *   &lt;/field-validator&gt;
+ *   &lt;field-validator type="email"&gt;
+ *       &lt;message&gt;The email address you entered is not valid.&lt;/message&gt;
+ *   &lt;/field-validator&gt;
+ * &lt;/field&gt;
+ * <!-- END SNIPPET: fieldValidatorUsingFieldValidatorSyntax -->
+ * </pre>
+ * <p/>
+ * <p/>
+ * <!-- START SNIPPET: validatorVsFieldValidators3 -->
+ * <p>The choice is yours. It's perfectly legal to only use <validator> elements
+ * without the <field> elements and set the fieldName attribute for each of them.
+ * The following are effectively equal:</P>
+ * <!-- END SNIPPET: validatorVsFieldValidators3 -->
+ * <p/>
+ * <pre>
+ * <!-- START SNIPPET: similarVaidatorDeclaredInDiffSyntax -->
+ * &lt;field name="email_address"&gt;
+ *   &lt;field-validator type="required"&gt;
+ *       &lt;message&gt;You cannot leave the email address field empty.&lt;/message&gt;
+ *   &lt;/field-validator&gt;
+ *   &lt;field-validator type="email"&gt;
+ *       &lt;message&gt;The email address you entered is not valid.&lt;/message&gt;
+ *   &lt;/field-validator&gt;
+ * &lt;/field&gt;
+ * <p/>
+ * <p/>
+ * &lt;validator type="required"&gt;
+ *   &lt;param name="fieldName"&gt;email_address&lt;/param&gt;
+ *   &lt;message&gt;You cannot leave the email address field empty.&lt;/message&gt;
+ * &lt;/validator&gt;
+ * &lt;validator type="email"&gt;
+ *   &lt;param name="fieldName"&gt;email_address&lt;/param&gt;
+ *   &lt;message&gt;The email address you entered is not valid.&lt;/message&gt;
+ * &lt;/validator&gt;
+ * <!-- END SNIPPET: similarVaidatorDeclaredInDiffSyntax -->
+ * </pre>
+ * <p/>
+ * <p/>
+ * <!-- START SNIPPET: shortCircuitingValidators1 -->
+ * <p>It is possible to short-circuit a stack of validators.
+ * Here is another sample config file containing validation rules from the
+ * Xwork test cases: Notice that some of the &lt;field-validator&gt; and
+ * &lt;validator&gt; elements have the short-circuit attribute set to true.</p>
+ * <!-- END SNIPPET : shortCircuitingValidators1 -->
+ * <p/>
+ * <pre>
+ * &lt;!-- START SNIPPET: exShortCircuitingValidators --&gt;
+ * &lt;!DOCTYPE validators PUBLIC
+ *         "-//OpenSymphony Group//XWork Validator 1.0.2//EN"
+ *         "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd"&gt;
+ * &lt;validators&gt;
+ *   &lt;!-- Field Validators for email field --&gt;
+ *   &lt;field name="email"&gt;
+ *       &lt;field-validator type="required" short-circuit="true"&gt;
+ *           &lt;message&gt;You must enter a value for email.&lt;/message&gt;
+ *       &lt;/field-validator&gt;
+ *       &lt;field-validator type="email" short-circuit="true"&gt;
+ *           &lt;message&gt;Not a valid e-mail.&lt;/message&gt;
+ *       &lt;/field-validator&gt;
+ *   &lt;/field&gt;
+ *   &lt;!-- Field Validators for email2 field --&gt;
+ *   &lt;field name="email2"&gt;
+ *      &lt;field-validator type="required"&gt;
+ *           &lt;message&gt;You must enter a value for email2.&lt;/message&gt;
+ *       &lt;/field-validator&gt;
+ *      &lt;field-validator type="email"&gt;
+ *           &lt;message&gt;Not a valid e-mail2.&lt;/message&gt;
+ *       &lt;/field-validator&gt;
+ *   &lt;/field&gt;
+ *   &lt;!-- Plain Validator 1 --&gt;
+ *   &lt;validator type="expression"&gt;
+ *       &lt;param name="expression"&gt;email.equals(email2)&lt;/param&gt;
+ *       &lt;message&gt;Email not the same as email2&lt;/message&gt;
+ *   &lt;/validator&gt;
+ *   &lt;!-- Plain Validator 2 --&gt;
+ *   &lt;validator type="expression" short-circuit="true"&gt;
+ *       &lt;param name="expression"&gt;email.startsWith('mark')&lt;/param&gt;
+ *       &lt;message&gt;Email does not start with mark&lt;/message&gt;
+ *   &lt;/validator&gt;
+ * &lt;/validators&gt;
+ * &lt;!-- END SNIPPET: exShortCircuitingValidators --&gt;
+ * </pre>
+ * <p/>
+ * <!-- START SNIPPET:shortCircuitingValidators2  -->
+ * <p><b>short-circuiting and Validator flavors</b></p>
+ * <p>Plain validator takes precedence over field-validator. They get validated
+ * first in the order they are defined and then the field-validator in the order
+ * they are defined. Failure of a particular validator marked as short-circuit
+ * will prevent the evaluation of subsequent validators and an error (action
+ * error or field error depending on the type of validator) will be added to
+ * the ValidationContext of the object being validated.</p>
+ * <p/>
+ * <p>In the example above, the actual execution of validator would be as follows:</p>
+ * <p/>
+ * <ol>
+ * <li> Plain Validator 1</li>
+ * <li> Plain Validator 2</li>
+ * <li> Field Validators for email field</li>
+ * <li> Field Validators for email2 field</li>
+ * </ol>
+ * <p/>
+ * <p>Since Plain Validator 2 is short-circuited, if its validation failed,
+ * it will causes Field validators for email field and Field validators for email2
+ * field to not be validated as well.</p>
+ * <p/>
+ * <p><b>Usefull Information:</b>
+ * More complicated validation should probably be done in the validate()
+ * method on the action itself (assuming the action implements Validatable
+ * interface which ActionSupport already does).</p>
+ * <p/>
+ * <p>
+ * A plain Validator (non FieldValidator) that gets short-circuited will
+ * completely break out of the validation stack. No other validators will be
+ * evaluated and plain validators takes precedence over field validators meaning
+ * that they get evaluated in the order they are defined before field validators
+ * get a chance to be evaluated.
+ * </p>
+ * <!-- END SNIPPET: shortCircuitingValidators2 -->
+ * <p/>
+ * <p/>
+ * <!-- START SNIPPET: scAndValidatorFlavours1 -->
+ * <p><b>Short cuircuiting and validator flavours</b></p>
+ * <p>A FieldValidator that gets short-circuited will only prevent other
+ * FieldValidators for the same field from being evaluated. Note that this
+ * "same field" behavior applies regardless of whether the <validator> or
+ * <field-validator> syntax was used to declare the validation rule.
+ * By way of example, given this -validation.xml file:</p>
+ * <!-- END SNIPPET: scAndValidatorFlavours1 -->
+ * <p/>
+ * <pre>
+ * <!-- START SNIPPET: exScAndValidatorFlavours -->
+ * &lt;validator type="required" short-circuit="true"&gt;
+ *   &lt;param name="fieldName"&gt;bar&lt;/param&gt;
+ *   &lt;message&gt;You must enter a value for bar.&lt;/message&gt;
+ * &lt;/validator&gt;
+ * <p/>
+ * &lt;validator type="expression"&gt;
+ *   &lt;param name="expression">foo gt bar&lt;/param&gt;
+ *   &lt;message&gt;foo must be great than bar.&lt;/message&gt;
+ * &lt;/validator&gt;
+ * <!-- END SNIPPET: exScAndValidatorFlavours -->
+ * </pre>
+ * <p/>
+ * <!-- START SNIPPET: scAndValidatorFlavours2 -->
+ * <p>both validators will be run, even if the "required" validator short-circuits.
+ * "required" validators are FieldValidator's and will not short-circuit the plain
+ * ExpressionValidator because FieldValidators only short-circuit other checks on
+ * that same field. Since the plain Validator is not field specific, it is
+ * not short-circuited.</p>
+ * <!-- END SNIPPET: scAndValidatorFlavours2 -->
+ * <p/>
+ * <p/>
+ * <!-- START SNIPPET: howXworkFindsValidatorForAction -->
+ * <p>As mentioned above, the framework will also search up the inheritance tree
+ * of the action to find default validations for interfaces and parent classes of
+ * the Action. If you are using the short-circuit attribute and relying on
+ * default validators higher up in the inheritance tree, make sure you don't
+ * accidentally short-circuit things higher in the tree that you really want!</p>
+ * <p>
+ * The effect of having common validators on both
+ * </p>
+ * <ul>
+ * 	<li>&lt;actionClass&gt;-validation.xml</li>
+ *     <li>&lt;actionClass&gt;-&lt;actionAlias&gt;-validation.xml</li>
+ * </ul>
+ * <p>
+ * It should be noted that the nett effect will be validation on both the validators available
+ * in both validation configuration file. For example if we have 'requiredstring' validators defined
+ * in both validation xml file for field named 'address', we will see 2 validation error indicating that
+ * the the address cannot be empty (assuming validation failed). This is due to WebWork
+ * will merge validators found in both validation configuration files.
+ * </p>
+ * <p>
+ * The logic behind this design decision is such that we could have common validators in
+ * &lt;actionClass&gt;-validation.xml and more context specific validators to be located
+ * in &lt;actionClass&gt;-&lt;actionAlias&gt;-validation.xml
+ * </p>
+ * <!-- END SNIPPET: howXworkFindsValidatorForAction -->
+ *
+ * <p/>
+ * <!-- START SNIPPET: i18n -->
+ * Validator's validation messages could be internatinalized. For example,
+ * <pre>
+ *   &lt;field-validator type="required"&gt;
+ *      &lt;message key="required.field" /&gt;
+ *   &lt;/field-validator&gt;
+ * </pre>
+ * or
+ * <pre>
+ *   &lt;validator type="expression"&gt;
+ *      &lt;param name="expression"&gt;email.startsWith('Mark')&lt;/param&gt;
+ *      &lt;message key="email.invalid" /&gt;
+ *   &lt;/validator&gt;
+ * </pre>
+ * In the first case, WebWork would look for i18n with key 'required.field' as the validation error message if
+ * validation fails, and 'email.invalid' in the second case.
+ * <p/>
+ * We could also provide a default message such that if validation failed and the i18n key for the message
+ * cannot be found, WebWork would fall back and use the default message. An example would be as follows :-
+ * <pre>
+ *   &lt;field-validator type="required"&gt;
+ *      &lt;message key="required.field"&gt;This field is required.&lt;/message&gt;
+ *   &lt;/field-validator&gt;
+ * </pre>
+ * or
+ * <pre>
+ *   &lt;validator type="expression"&gt;
+ *      &lt;param name="expression"&gt;email.startsWith('Mark')&lt;/param&gt;
+ *      &lt;message key="email.invalid"&gt;Email needs with starts with Mark&lt;/message&gt;
+ *   &lt;/validator&gt;
+ * </pre>
+ *
+ *
+ * <!-- END SNIPPET: i18n -->
+ * @author Jason Carreira
+ */
+public interface Validator<T> {
+
+    /**
+     * Sets the default message to use for validation failure
+     *
+     * @param message the default message
+     */
+    void setDefaultMessage(String message);
+
+    /**
+     * Gets the default message used for validation failures
+     *
+     * @return the default message
+     */
+    String getDefaultMessage();
+
+    /**
+     * Gets the validation failure message for the given object
+     *
+     * @param object object being validated (eg. a domain model object)
+     * @return the validation failure message
+     */
+    String getMessage(Object object);
+
+    /**
+     * Sets a resource bundle key to be used for lookup of validation failure message
+     *
+     * @param key the resource bundle key
+     */
+    void setMessageKey(String key);
+
+    /**
+     * Gets the resource bundle key used for lookup of validation failure message
+     *
+     * @return the resource bundle key
+     */
+    String getMessageKey();
+
+    /**
+     * Sets the messsage parameters to be used when parsing i18n messages
+     *
+     * @param messageParameters  the messsage parameters
+     */
+    void setMessageParameters(String[] messageParameters);
+
+    /**
+     * Gets the messsage parameters to be used when parsing i18n messages
+     *
+     * @return the messsage parameters
+     */
+    String[] getMessageParameters();
+
+    /**
+     * This method will be called before validate with a non-null ValidatorContext.
+     *
+     * @param validatorContext the validation context to use.
+     */
+    void setValidatorContext(ValidatorContext validatorContext);
+
+    /**
+     * Gets the validation context used
+     *
+     * @return the validation context
+     */
+    ValidatorContext getValidatorContext();
+
+    /**
+     * The validation implementation must guarantee that setValidatorContext will
+     * be called with a non-null ValidatorContext before validate is called.
+     *
+     * @param object the object to be validated.
+     * @throws ValidationException is thrown if there is validation error(s).
+     */
+    void validate(Object object) throws ValidationException;
+
+    /**
+     * Sets the validator type to use (see class javadoc).
+     *
+     * @param type the type to use.
+     */
+    void setValidatorType(String type);
+
+    /**
+     * Gets the vaildator type used (see class javadoc).
+     *
+     * @return the type used
+     */
+    String getValidatorType();
+
+    /**
+     * Sets the value stack to use to resolve values and parameters
+     *
+     * @param stack The value stack for the request
+     * @since 2.1.1
+     */
+    void setValueStack(ValueStack stack);
+
+}

Added: struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/validator/ValidatorConfig.java
URL: http://svn.apache.org/viewvc/struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/validator/ValidatorConfig.java?rev=1209569&view=auto
==============================================================================
--- struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/validator/ValidatorConfig.java (added)
+++ struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/validator/ValidatorConfig.java Fri Dec  2 16:33:03 2011
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2002-2006,2009 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.struts2.xwork2.validator;
+
+import org.apache.struts2.xwork2.util.location.Located;
+import org.apache.struts2.xwork2.util.location.Location;
+
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * Holds the necessary information for configuring an instance of a Validator.
+ * 
+ * 
+ * @author James House
+ * @author Rainer Hermanns
+ * @author tm_jee
+ * @author Martin Gilday 
+ */
+public class ValidatorConfig extends Located {
+
+    private String type;
+    private Map<String,String> params;
+    private String defaultMessage;
+    private String messageKey;
+    private boolean shortCircuit;
+    private String[] messageParams;
+    
+    /**
+     * @param validatorType
+     */
+    protected ValidatorConfig(String validatorType) {
+        this.type = validatorType;
+        params = new LinkedHashMap<String, String>();
+    }
+
+    protected ValidatorConfig(ValidatorConfig orig) {
+        this.type = orig.type;
+        this.params = new LinkedHashMap<String,String>(orig.params);
+        this.defaultMessage = orig.defaultMessage;
+        this.messageKey = orig.messageKey;
+        this.shortCircuit = orig.shortCircuit;
+        this.messageParams = orig.messageParams;
+    }
+    
+    /**
+     * @return Returns the defaultMessage for the validator.
+     */
+    public String getDefaultMessage() {
+        return defaultMessage;
+    }
+    
+    /**
+     * @return Returns the messageKey for the validator.
+     */
+    public String getMessageKey() {
+        return messageKey;
+    }
+    
+    /**
+     * @return Returns wether the shortCircuit flag should be set on the 
+     * validator.
+     */
+    public boolean isShortCircuit() {
+        return shortCircuit;
+    }
+    
+    /**
+     * @return Returns the configured params to set on the validator. 
+     */
+    public Map<String, String> getParams() {
+        return params;
+    }
+    
+    /**
+     * @return Returns the type of validator to configure.
+     */
+    public String getType() {
+        return type;
+    }
+
+    /**
+     * @return The i18n message parameters/arguments to be used.
+     */
+    public String[] getMessageParams() {
+        return messageParams;
+    }
+
+    /**
+     * Builds a ValidatorConfig
+     */
+    public static final class Builder {
+        private ValidatorConfig target;
+
+        public Builder(String validatorType) {
+            target = new ValidatorConfig(validatorType);
+        }
+
+        public Builder(ValidatorConfig config) {
+            target = new ValidatorConfig(config);
+        }
+
+        public Builder shortCircuit(boolean shortCircuit) {
+            target.shortCircuit = shortCircuit;
+            return this;
+        }
+
+        public Builder defaultMessage(String msg) {
+            if ((msg != null) && (msg.trim().length() > 0)) {
+                target.defaultMessage = msg;
+            }
+            return this;
+        }
+
+        public Builder messageParams(String[] msgParams) {
+            target.messageParams = msgParams;
+            return this;
+        }
+
+        public Builder messageKey(String key) {
+            if ((key != null) && (key.trim().length() > 0)) {
+                target.messageKey = key;
+            }
+            return this;
+        }
+
+        public Builder addParam(String name, String value) {
+            if (value != null && name != null) {
+                target.params.put(name, value);
+            }
+            return this;
+        }
+
+        public Builder addParams(Map<String,String> params) {
+            target.params.putAll(params);
+            return this;
+        }
+
+        public Builder location(Location loc) {
+            target.location = loc;
+            return this;
+        }
+
+        public ValidatorConfig build() {
+            target.params = Collections.unmodifiableMap(target.params);
+            ValidatorConfig result = target;
+            target = new ValidatorConfig(target);
+            return result;
+        }
+
+        public Builder removeParam(String key) {
+            target.params.remove(key);
+            return this;
+        }
+    }
+}

Added: struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/validator/ValidatorContext.java
URL: http://svn.apache.org/viewvc/struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/validator/ValidatorContext.java?rev=1209569&view=auto
==============================================================================
--- struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/validator/ValidatorContext.java (added)
+++ struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/validator/ValidatorContext.java Fri Dec  2 16:33:03 2011
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2002-2006,2009 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.struts2.xwork2.validator;
+
+import org.apache.struts2.xwork2.LocaleProvider;
+import org.apache.struts2.xwork2.TextProvider;
+import org.apache.struts2.xwork2.ValidationAware;
+
+
+/**
+ * The context for validation. This interface extends others to provide methods for reporting
+ * errors and messages as well as looking up error messages in a resource bundle using a specific locale.
+ *
+ * @author Jason Carreira
+ */
+public interface ValidatorContext extends ValidationAware, TextProvider, LocaleProvider {
+
+    /**
+     * Translates a simple field name into a full field name in OGNL syntax.
+     *
+     * @param fieldName the field name to lookup.
+     * @return the full field name in OGNL syntax.
+     */
+    String getFullFieldName(String fieldName);
+}

Added: struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/validator/ValidatorFactory.java
URL: http://svn.apache.org/viewvc/struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/validator/ValidatorFactory.java?rev=1209569&view=auto
==============================================================================
--- struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/validator/ValidatorFactory.java (added)
+++ struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/validator/ValidatorFactory.java Fri Dec  2 16:33:03 2011
@@ -0,0 +1,239 @@
+package org.apache.struts2.xwork2.validator;
+
+/**
+ * ValidatorFactory
+ *
+ * <p>
+ * <!-- START SNIPPET: javadoc -->
+ * Validation rules are handled by validators, which must be registered with
+ * the ValidatorFactory (using the registerValidator method). The simplest way to do so is to add a file name
+ * validators.xml in the root of the classpath (/WEB-INF/classes) that declares
+ * all the validators you intend to use.
+ * <!-- END SNIPPET: javadoc -->
+ * </p>
+ *
+ *
+ * <p>
+ * <b>INFORMATION</b>
+ * <!-- START SNIPPET: information -->
+ * validators.xml if being defined should be available in the classpath. However
+ * this is not necessary, if no custom validator is needed. Predefined sets of validators
+ * will automatically be picked up when defined in
+ * org/apache/struts2/xwork2/validator/validators/default.xml packaged in
+ * in the xwork jar file. See ValidatorFactory static block for details.
+ * <!-- END SNIPPET: information -->
+ * </p>
+ *
+ * <p>
+ * <b>WARNING</b>
+ * <!-- START SNIPPET: warning -->
+ * If custom validator is being defined and a validators.xml is created and
+ * place in the classpath, do remember to copy all the other pre-defined validators
+ * that is needed into the validators.xml as if not they will not be registered.
+ * Once a validators.xml is detected in the classpath, the default one
+ * (org/apache/struts2/xwork2/validator/validators/default.xml) will not be loaded.
+ * It is only loaded when a custom validators.xml cannot be found in the classpath.
+ *  Be careful.
+ * <!-- END SNIPPET: warning -->
+ * </p>
+ *
+ * <p><b>Note:</b>
+ * <!-- START SNIPPET: turningOnValidators -->
+ * The default validationWorkflowStack already includes this.<br/>
+ * All that is required to enable validation for an Action is to put the
+ * ValidationInterceptor in the interceptor refs of the action (see xwork.xml) like so:
+ * <!-- END SNIPPET: turningOnValidators -->
+ * </p>
+ *
+ * <pre>
+ * <!-- START SNIPPET: exTurnOnValidators -->
+ *     &lt;interceptor name="validator" class="org.apache.struts2.xwork2.validator.ValidationInterceptor"/&gt;
+ * <!-- END SNIPPET: exTurnOnValidators -->
+ * </pre>
+ *
+ * <p><b>Field Validators</b>
+ * <!-- START SNIPPET: fieldValidators -->
+ * Field validators, as the name indicate, act on single fields accessible through an action.
+ * A validator, in contrast, is more generic and can do validations in the full action context,
+ * involving more than one field (or even no field at all) in validation rule.
+ * Most validations can be defined on per field basis. This should be preferred over
+ * non-field validation wherever possible, as field validator messages are bound to the
+ * related field and will be presented next to the corresponding input element in the
+ * respecting view.
+ * <!-- END SNIPPET: fieldValidators -->
+ * </p>
+ *
+ * <p><b>Non Field Validators</b>
+ * <!-- START SNIPPET: nonFieldValidators -->
+ * Non-field validators only add action level messages. Non-field validators
+ * are mostly domain specific and therefore offer custom implementations.
+ * The most important standard non-field validator provided by XWork
+ * is ExpressionValidator.
+ * <!-- END SNIPPET: nonFieldValidators -->
+ * </p>
+ *
+ * <p><b>NOTE:</b>
+ * <!-- START SNIPPET: validatorsNote -->
+ * Non-field validators takes precedence over field validators
+ * regardless of the order they are defined in *-validation.xml. If a non-field
+ * validator is short-circuited, it will causes its non-field validator to not
+ * being executed. See validation framework documentation for more info.
+ * <!-- END SNIPPET: validatorsNote -->
+ * </p>
+ *
+ * <p><b>VALIDATION RULES:</b>
+ * <!-- START SNIPPET: validationRules1 -->
+ * Validation rules can be specified:
+ * <ol>
+ *  <li> Per Action class: in a file named ActionName-validation.xml</li>
+ *  <li> Per Action alias: in a file named ActionName-alias-validation.xml</li>
+ *  <li> Inheritance hierarchy and interfaces implemented by Action class:
+ *  XWork searches up the inheritance tree of the action to find default
+ *  validations for parent classes of the Action and interfaces implemented</li>
+ * </ol>
+ * Here is an example for SimpleAction-validation.xml:
+ * <!-- END SNIPPET: validationRules1 -->
+ * <p>
+ *
+ * <pre>
+ * <!-- START SNIPPET: exValidationRules1 -->
+ * &lt;!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//EN"
+ *        "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd"&gt;
+ * &lt;validators&gt;
+ *   &lt;field name="bar"&gt;
+ *       &lt;field-validator type="required"&gt;
+ *           &lt;message&gt;You must enter a value for bar.&lt;/message&gt;
+ *       &lt;/field-validator&gt;
+ *       &lt;field-validator type="int"&gt;
+ *           &lt;param name="min">6&lt;/param&gt;
+ *           &lt;param name="max"&gt;10&lt;/param&gt;
+ *           &lt;message&gt;bar must be between ${min} and ${max}, current value is ${bar}.&lt;/message&gt;
+ *       &lt;/field-validator&gt;
+ *   &lt;/field&gt;
+ *   &lt;field name="bar2"&gt;
+ *       &lt;field-validator type="regex"&gt;
+ *           &lt;param name="expression"&gt;[0-9],[0-9]&lt;/param&gt;
+ *           &lt;message&gt;The value of bar2 must be in the format "x, y", where x and y are between 0 and 9&lt;/message&gt;
+ *      &lt;/field-validator&gt;
+ *   &lt;/field&gt;
+ *   &lt;field name="date"&gt;
+ *       &lt;field-validator type="date"&gt;
+ *           &lt;param name="min"&gt;12/22/2002&lt;/param&gt;
+ *           &lt;param name="max"&gt;12/25/2002&lt;/param&gt;
+ *           &lt;message&gt;The date must be between 12-22-2002 and 12-25-2002.&lt;/message&gt;
+ *       &lt;/field-validator&gt;
+ *   &lt;/field&gt;
+ *   &lt;field name="foo"&gt;
+ *       &lt;field-validator type="int"&gt;
+ *           &lt;param name="min"&gt;0&lt;/param&gt;
+ *           &lt;param name="max"&gt;100&lt;/param&gt;
+ *           &lt;message key="foo.range"&gt;Could not find foo.range!&lt;/message&gt;
+ *       &lt;/field-validator&gt;
+ *   &lt;/field&gt;
+ *   &lt;validator type="expression"&gt;
+ *       &lt;param name="expression"&gt;foo lt bar &lt;/param&gt;
+ *       &lt;message&gt;Foo must be greater than Bar. Foo = ${foo}, Bar = ${bar}.&lt;/message&gt;
+ *   &lt;/validator&gt;
+ * &lt;/validators&gt;
+ * <!-- END SNIPPET: exValidationRules1 -->
+ * </pre>
+ *
+ *
+ * <p>
+ * <!-- START SNIPPET: validationRules2 -->
+ * Here we can see the configuration of validators for the SimpleAction class.
+ * Validators (and field-validators) must have a type attribute, which refers
+ * to a name of an Validator registered with the ValidatorFactory as above.
+ * Validator elements may also have &lt;param&gt; elements with name and value attributes
+ * to set arbitrary parameters into the Validator instance. See below for discussion
+ * of the message element.
+ * <!-- END SNIPPET: validationRules2 -->
+ * </p>
+ *
+ *
+ *
+ * <!-- START SNIPPET: validationRules3 -->
+ * <p>Each Validator or Field-Validator element must define one message element inside
+ * the validator element body. The message element has 1 attributes, key which is not
+ * required. The body of the message tag is taken as the default message which should
+ * be added to the Action if the validator fails. Key gives a message key to look up
+ * in the Action's ResourceBundles using getText() from LocaleAware if the Action
+ * implements that interface (as ActionSupport does). This provides for Localized
+ * messages based on the Locale of the user making the request (or whatever Locale
+ * you've set into the LocaleAware Action). After either retrieving the message from
+ * the ResourceBundle using the Key value, or using the Default message, the current
+ * Validator is pushed onto the ValueStack, then the message is parsed for \$\{...\}
+ * sections which are replaced with the evaluated value of the string between the
+ * \$\{ and \}. This allows you to parameterize your messages with values from the
+ * Validator, the Action, or both.</p>
+ *
+ *
+ * <p>If the validator fails, the validator is pushed onto the ValueStack and the
+ * message - either the default or the locale-specific one if the key attribute is
+ * defined (and such a message exists) - is parsed for ${...} sections which are
+ * replaced with the evaluated value of the string between the ${ and }. This
+ * allows you to parameterize your messages with values from the validator, the
+ * Action, or both. </p>
+ *
+ * <p><b>NOTE:</b> Since validation rules are in an XML file, you must make sure
+ * you escape special characters. For example, notice that in the expression
+ * validator rule above we use "&amp;gt;" instead of "&gt;". Consult a resource on XML
+ * for the full list of characters that must be escaped. The most commonly used
+ * characters that must be escaped are: &amp; (use &amp;amp;), &gt; (user &amp;gt;), and &lt; (use &amp;lt;).</p>
+ *
+ * <p>Here is an example of a parameterized message:</p>
+ * <p>This will pull the min and max parameters from the IntRangeFieldValidator and
+ * the value of bar from the Action.</p>
+ * <!-- END SNIPPET: validationRules3 -->
+ *
+ * <pre>
+ * <!-- START SNIPPET: exValidationRules3 -->
+ *    bar must be between ${min} and ${max}, current value is ${bar}.
+ * <!-- END SNIPPET: exValidationRules3 -->
+ * </pre>
+ *
+ * <!-- START SNIPPET: validationRules4 -->
+ * <p>Another notable fact is that the provided message value is capable of containing OGNL expressions.
+ * Keeping this in mind, it is possible to construct quite sophisticated messages.</p>
+ * <p>See the following example to get an impression:</p>
+ *
+ * <!-- END SNIPPET: validationRules4 -->
+ *
+ * <pre>
+ * <!-- START SNIPPET: exValidationRules4 -->
+ *    <message>${getText("validation.failednotice")}! ${getText("reason")}: ${getText("validation.inputrequired")}</message>
+ * <!-- END SNIPPET: exValidationRules4 -->
+ * </pre>
+ *
+ * @version $Date: 2011-12-02 12:24:48 +0100 (Fri, 02 Dec 2011) $ $Id: ValidatorFactory.java 1209415 2011-12-02 11:24:48Z lukaszlenart $
+ * @author Jason Carreira
+ * @author James House
+ */
+public interface ValidatorFactory {
+
+    /**
+     * Get a Validator that matches the given configuration.
+     *
+     * @param cfg  the configurator.
+     * @return  the validator.
+     */
+    Validator getValidator(ValidatorConfig cfg);
+
+    /**
+     * Registers the given validator to the existing map of validators.
+     * This will <b>add</b> to the existing list.
+     *
+     * @param name    name of validator to add.
+     * @param className   the FQ classname of the validator.
+     */
+    void registerValidator(String name, String className);
+
+    /**
+     * Lookup to get the FQ classname of the given validator name.
+     *
+     * @param name   name of validator to lookup.
+     * @return  the found FQ classname
+     * @throws IllegalArgumentException is thrown if the name is not found.
+     */
+    String lookupRegisteredValidatorType(String name);
+}

Added: struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/validator/ValidatorFileParser.java
URL: http://svn.apache.org/viewvc/struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/validator/ValidatorFileParser.java?rev=1209569&view=auto
==============================================================================
--- struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/validator/ValidatorFileParser.java (added)
+++ struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/validator/ValidatorFileParser.java Fri Dec  2 16:33:03 2011
@@ -0,0 +1,46 @@
+package org.apache.struts2.xwork2.validator;
+
+import java.io.InputStream;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This class serves 2 purpose :
+ * <ul>
+ * <li>
+ * Parse the validation config file. (eg. MyAction-validation.xml, MyAction-actionAlias-validation.xml)
+  * to return a List of ValidatorConfig encapsulating the validator information.
+ * </li>
+ * <li>
+ * Parse the validator definition file, (eg. validators.xml) that defines the {@link Validator}s
+ * registered with XWork.
+ * </li>
+ * </ul>
+ *
+ * @author Jason Carreira
+ * @author James House
+ * @author tm_jee ( tm_jee (at) yahoo.co.uk )
+ * @author Rob Harrop
+ * @author Rene Gielen
+ *
+ * @see ValidatorConfig
+ */
+public interface ValidatorFileParser {
+    /**
+     * Parse resource for a list of ValidatorConfig objects (configuring which validator(s) are
+     * being applied to a particular field etc.)
+     *
+     * @param is input stream to the resource
+     * @param resourceName file name of the resource
+     * @return List list of ValidatorConfig
+     */
+    List<ValidatorConfig> parseActionValidatorConfigs(ValidatorFactory validatorFactory, InputStream is, String resourceName);
+
+    /**
+     * Parses validator definitions (register various validators with XWork).
+     *
+     * @param is The input stream
+     * @param resourceName The location of the input stream
+     */
+    void parseValidatorDefinitions(Map<String,String> validators, InputStream is, String resourceName);
+}