http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/validator/ValidationException.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/com/opensymphony/xwork2/validator/ValidationException.java 
b/core/src/main/java/com/opensymphony/xwork2/validator/ValidationException.java
new file mode 100644
index 0000000..2573b9f
--- /dev/null
+++ 
b/core/src/main/java/com/opensymphony/xwork2/validator/ValidationException.java
@@ -0,0 +1,44 @@
+/*
+ * 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 com.opensymphony.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);
+    }
+
+    public ValidationException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/validator/ValidationInterceptor.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/com/opensymphony/xwork2/validator/ValidationInterceptor.java
 
b/core/src/main/java/com/opensymphony/xwork2/validator/ValidationInterceptor.java
new file mode 100644
index 0000000..bbb25ed
--- /dev/null
+++ 
b/core/src/main/java/com/opensymphony/xwork2/validator/ValidationInterceptor.java
@@ -0,0 +1,281 @@
+/*
+ * 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 com.opensymphony.xwork2.validator;
+
+import com.opensymphony.xwork2.ActionInvocation;
+import com.opensymphony.xwork2.ActionProxy;
+import com.opensymphony.xwork2.Validateable;
+import com.opensymphony.xwork2.inject.Inject;
+import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
+import com.opensymphony.xwork2.interceptor.PrefixMethodInvocationUtil;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+/**
+ * <!-- 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 
com.opensymphony.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 com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor
+ */
+public class ValidationInterceptor extends MethodFilterInterceptor {
+
+    private boolean validateAnnotatedMethodOnly;
+    
+    private ActionValidatorManager actionValidatorManager;
+    
+    private static final Logger LOG = 
LogManager.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 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 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
+        //UPDATE:  see WW-3753
+        String context = this.getValidationContext(proxy);
+        String method = proxy.getMethod();
+
+        if (log.isDebugEnabled()) {
+            log.debug("Validating {}/{} with method {}.", 
invocation.getProxy().getNamespace(), invocation.getProxy().getActionName(), 
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;
+            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
+                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();
+    }
+    
+    /**
+     * Returns the context that will be used by the
+     * {@link ActionValidatorManager} to associate the action invocation with
+     * the appropriate {@link ValidatorConfig ValidatorConfigs}.
+     * <p>
+     * The context returned is used in the pattern
+     * <i>ActionClass-context-validation.xml</i>
+     * <p>
+     * The default context is the action name from the URL, but the method can
+     * be overridden to implement custom contexts.
+     * <p>
+     * This can be useful in cases in which a single action and a single model
+     * require vastly different validation based on some condition.
+     * 
+     * @return the Context
+     */
+    protected String getValidationContext(ActionProxy proxy) {
+        // This method created for WW-3753
+        return proxy.getActionName();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/validator/Validator.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/com/opensymphony/xwork2/validator/Validator.java 
b/core/src/main/java/com/opensymphony/xwork2/validator/Validator.java
new file mode 100644
index 0000000..1fcab44
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/validator/Validator.java
@@ -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 com.opensymphony.xwork2.validator;
+
+import com.opensymphony.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
+ *         "-//Apache Struts//XWork Validator 1.0.3//EN"
+ *        "http://struts.apache.org/dtds/xwork-validator-1.0.3.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);
+
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/validator/ValidatorConfig.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/com/opensymphony/xwork2/validator/ValidatorConfig.java 
b/core/src/main/java/com/opensymphony/xwork2/validator/ValidatorConfig.java
new file mode 100644
index 0000000..490f34e
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/validator/ValidatorConfig.java
@@ -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 com.opensymphony.xwork2.validator;
+
+import com.opensymphony.xwork2.util.location.Located;
+import com.opensymphony.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, Object> 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<>();
+    }
+
+    protected ValidatorConfig(ValidatorConfig orig) {
+        this.type = orig.type;
+        this.params = new LinkedHashMap<>(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, Object> 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, Object value) {
+            if (value != null && name != null) {
+                target.params.put(name, value);
+            }
+            return this;
+        }
+
+        public Builder addParams(Map<String,Object> 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;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/validator/ValidatorContext.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/com/opensymphony/xwork2/validator/ValidatorContext.java 
b/core/src/main/java/com/opensymphony/xwork2/validator/ValidatorContext.java
new file mode 100644
index 0000000..f795867
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/validator/ValidatorContext.java
@@ -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 com.opensymphony.xwork2.validator;
+
+import com.opensymphony.xwork2.LocaleProvider;
+import com.opensymphony.xwork2.TextProvider;
+import com.opensymphony.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);
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/validator/ValidatorFactory.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/com/opensymphony/xwork2/validator/ValidatorFactory.java 
b/core/src/main/java/com/opensymphony/xwork2/validator/ValidatorFactory.java
new file mode 100644
index 0000000..76bc3da
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/validator/ValidatorFactory.java
@@ -0,0 +1,239 @@
+package com.opensymphony.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
+ * com/opensymphony/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
+ * (com/opensymphony/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="com.opensymphony.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 "-//Apache Struts//XWork Validator 1.0.3//EN"
+               "http://struts.apache.org/dtds/xwork-validator-1.0.3.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$ $Id$
+ * @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);
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/validator/ValidatorFileParser.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/com/opensymphony/xwork2/validator/ValidatorFileParser.java 
b/core/src/main/java/com/opensymphony/xwork2/validator/ValidatorFileParser.java
new file mode 100644
index 0000000..2c9e39d
--- /dev/null
+++ 
b/core/src/main/java/com/opensymphony/xwork2/validator/ValidatorFileParser.java
@@ -0,0 +1,46 @@
+package com.opensymphony.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 com.opensymphony.xwork2.validator.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);
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/validator/annotations/ConditionalVisitorFieldValidator.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/com/opensymphony/xwork2/validator/annotations/ConditionalVisitorFieldValidator.java
 
b/core/src/main/java/com/opensymphony/xwork2/validator/annotations/ConditionalVisitorFieldValidator.java
new file mode 100644
index 0000000..29607ce
--- /dev/null
+++ 
b/core/src/main/java/com/opensymphony/xwork2/validator/annotations/ConditionalVisitorFieldValidator.java
@@ -0,0 +1,156 @@
+package com.opensymphony.xwork2.validator.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * <!-- START SNIPPET: description -->
+ * The validator allows you to forward validator to object properties of your 
action
+ * using the objects own validator 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 ConditionalVisitorFieldValidator can handle either simple Object 
properties, Collections of Objects, or Arrays.
+ * The error message for the ConditionalVisitorFieldValidator will be appended 
in front of validator messages added
+ * by the validations for the Object message.
+ * <!-- END SNIPPET: description -->
+ *
+ * <p/> <u>Annotation usage:</u>
+ *
+ * <!-- START SNIPPET: usage -->
+ * <p/>The annotation must be applied at method level.
+ * <!-- END SNIPPET: usage -->
+ *
+ * <p/> <u>Annotation parameters:</u>
+ *
+ * <!-- START SNIPPET: parameters -->
+ * <table class='confluenceTable'>
+ * <tr>
+ * <th class='confluenceTh'> Parameter </th>
+ * <th class='confluenceTh'> Required </th>
+ * <th class='confluenceTh'> Default </th>
+ * <th class='confluenceTh'> Notes </th>
+ * </tr>
+ * <tr>
+ * <td class='confluenceTd'>expression</td>
+ * <td class='confluenceTd'>yes</td>
+ * <td class='confluenceTd'>&nbsp;</td>
+ * <td class='confluenceTd'>Boolean conditional expression</td>
+ * </tr>
+ * <tr>
+ * <td class='confluenceTd'>message</td>
+ * <td class='confluenceTd'>yes</td>
+ * <td class='confluenceTd'>&nbsp;</td>
+ * <td class='confluenceTd'>field error message</td>
+ * </tr>
+ * <tr>
+ * <td class='confluenceTd'>key</td>
+ * <td class='confluenceTd'>no</td>
+ * <td class='confluenceTd'>&nbsp;</td>
+ * <td class='confluenceTd'>i18n key from language specific properties 
file.</td>
+ * </tr>
+ * <tr>
+ * <td class='confluenceTd'>messageParams</td>
+ * <td class='confluenceTd'>no</td>
+ * <td class='confluenceTd'>&nbsp;</td>
+ * <td class='confluenceTd'>Additional params to be used to customize message 
- will be evaluated against the Value Stack</td>
+ * </tr>
+ * <tr>
+ * <td class='confluenceTd'>fieldName</td>
+ * <td class='confluenceTd'>no</td>
+ * <td class='confluenceTd'>&nbsp;</td>
+ * <td class='confluenceTd'>&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td class='confluenceTd'>shortCircuit</td>
+ * <td class='confluenceTd'>no</td>
+ * <td class='confluenceTd'>false</td>
+ * <td class='confluenceTd'>If this validator should be used as 
shortCircuit.</td>
+ * </tr>
+ * <tr>
+ * <td class='confluenceTd'> context </td>
+ * <td class='confluenceTd'> no </td>
+ * <td class='confluenceTd'> action alias </td>
+ * <td class='confluenceTd'> Determines the context to use for validating the 
Object property. If not defined, the context of the Action validation is 
propagated to the Object property validation.  In the case of Action 
validation, this context is the Action alias.  </td>
+ * </tr>
+ * <tr>
+ * <td class='confluenceTd'> appendPrefix </td>
+ * <td class='confluenceTd'> no </td>
+ * <td class='confluenceTd'> true </td>
+ * <td class='confluenceTd'> Determines 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.  For example, suppose that 
the bean being validated has a "name" property.  If <em>appendPrefix</em> is 
true, then the field error will be stored under the field "bean.name".  If 
<em>appendPrefix</em> is false, then the field error will be stored under the 
field "name".  <br clear="all" /> <img class="emoticon" 
src="/images/icons/emoticons/warning.gif" height="16" width="16" 
align="absmiddle" alt="" border="0"/> If you are using the 
VisitorFieldValidator to validate the model from a ModelDriven Action, you 
should set <em>appendPrefix</em> to false unless you are using "model.name" to 
reference the properties on your model. </td>
+ * </tr>
+ * </table>
+ * <!-- END SNIPPET: parameters -->
+ *
+ * <p/> <u>Example code:</u>
+ *
+ * <pre>
+ * <!-- START SNIPPET: example -->
+ * &#64;ConditionalVisitorFieldValidator(expression="app.appid > 100",  
message = "Default message", key = "i18n.key", shortCircuit = true, context = 
"action alias", appendPrefix = true)
+ * <!-- END SNIPPET: example -->
+ * </pre>
+ *
+ * @author Matt Raible
+ */
+@Target({ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ConditionalVisitorFieldValidator {
+
+    /**
+     * Determines the context to use for validating the Object property.
+     * If not defined, the context of the Action validator is propogated to 
the Object property validator.
+     * In the case of Action validator, this context is the Action alias.
+     */
+    String context() default "";
+
+    /**
+     * Determines 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. For example, suppose that
+     * the bean being validated has a "name" property.
+     *
+     * If appendPrefix is true, then the field error will be stored under the 
field "bean.name".
+     * If appendPrefix is false, then the field error will be stored under the 
field "name".
+     *
+     * If you are using the ConditionalVisitorFieldValidator to validate the 
model from a ModelDriven Action,
+     * you should set appendPrefix to false unless you are using "model.name" 
to reference the properties
+     * on your model.
+     */
+    boolean appendPrefix() default true;
+
+    /**
+     * The conditional expression.
+     */
+    String expression();
+
+    /**
+     * The default error message for this validator.
+     * NOTE: It is required to set a message, if you are not using the message 
key for 18n lookup!
+     */
+    String message() default "";
+
+    /**
+     * The message key to lookup for i18n.
+     */
+    String key() default "";
+
+    /**
+     * Additional params to be used to customize message - will be evaluated 
against the Value Stack
+     */
+    String[] messageParams() default {};
+
+    /**
+     * The optional fieldName for SIMPLE validator types.
+     */
+    String fieldName() default "";
+
+    /**
+     * If this is activated, the validator will be used as short-circuit.
+     *
+     * Adds the short-circuit="true" attribute value if <tt>true</tt>.
+     *
+     */
+    boolean shortCircuit() default false;
+    
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/validator/annotations/ConversionErrorFieldValidator.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/com/opensymphony/xwork2/validator/annotations/ConversionErrorFieldValidator.java
 
b/core/src/main/java/com/opensymphony/xwork2/validator/annotations/ConversionErrorFieldValidator.java
new file mode 100644
index 0000000..9a6fc0a
--- /dev/null
+++ 
b/core/src/main/java/com/opensymphony/xwork2/validator/annotations/ConversionErrorFieldValidator.java
@@ -0,0 +1,139 @@
+/*
+ * 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 com.opensymphony.xwork2.validator.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * <!-- START SNIPPET: description -->
+ * This validator checks if there are any conversion errors for a field and 
applies them if they exist.
+ * See <a 
href="http://wiki.opensymphony.com/display/XW/Type+Conversion+Error+Handling";>Type
 Conversion Error Handling</a> for details.
+ * <!-- END SNIPPET: description -->
+ *
+ * <p/> <u>Annotation usage:</u>
+ *
+ * <!-- START SNIPPET: usage -->
+ * <p/>The ConversionErrorFieldValidator annotation must be applied at method 
level.
+ * <!-- END SNIPPET: usage -->
+ *
+ * <p/> <u>Annotation parameters:</u>
+ *
+ * <!-- START SNIPPET: parameters -->
+ * <table class='confluenceTable'>
+ * <tr>
+ * <th class='confluenceTh'> Parameter </th>
+ * <th class='confluenceTh'> Required </th>
+ * <th class='confluenceTh'> Default </th>
+ * <th class='confluenceTh'> Notes </th>
+ * </tr>
+ * <tr>
+ * <td class='confluenceTd'>message</td>
+ * <td class='confluenceTd'>yes</td>
+ * <td class='confluenceTd'>&nbsp;</td>
+ * <td class='confluenceTd'>field error message</td>
+ * </tr>
+ * <tr>
+ * <td class='confluenceTd'>key</td>
+ * <td class='confluenceTd'>no</td>
+ * <td class='confluenceTd'>&nbsp;</td>
+ * <td class='confluenceTd'>i18n key from language specific properties 
file.</td>
+ * </tr>
+ * <tr>
+ * <td class='confluenceTd'>messageParams</td>
+ * <td class='confluenceTd'>no</td>
+ * <td class='confluenceTd'>&nbsp;</td>
+ * <td class='confluenceTd'>Additional params to be used to customize message 
- will be evaluated against the Value Stack</td>
+ * </tr>
+ * <tr>
+ * <td class='confluenceTd'>fieldName</td>
+ * <td class='confluenceTd'>no</td>
+ * <td class='confluenceTd'>&nbsp;</td>
+ * <td class='confluenceTd'>&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td class='confluenceTd'>shortCircuit</td>
+ * <td class='confluenceTd'>no</td>
+ * <td class='confluenceTd'>false</td>
+ * <td class='confluenceTd'>If this validator should be used as 
shortCircuit.</td>
+ * </tr>
+ * <tr>
+ * <td class='confluenceTd'>type</td>
+ * <td class='confluenceTd'>yes</td>
+ * <td class='confluenceTd'>ValidatorType.FIELD</td>
+ * <td class='confluenceTd'>Enum value from ValidatorType. Either FIELD or 
SIMPLE can be used here.</td>
+ * </tr>
+ * </table>
+ * <!-- END SNIPPET: parameters -->
+ *
+ * <p/> <u>Example code:</u>
+ *
+ * <pre>
+ * <!-- START SNIPPET: example -->
+ * &#64;ConversionErrorFieldValidator(message = "Default message", key = 
"i18n.key", shortCircuit = true)
+ * <!-- END SNIPPET: example -->
+ * </pre>
+ *
+ * @author Rainer Hermanns
+ * @version $Id$
+ */
+@Target({ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ConversionErrorFieldValidator {
+
+    /**
+     * The default error message for this validator.
+     * NOTE: It is required to set a message, if you are not using the message 
key for 18n lookup!
+     */
+    String message() default "";
+
+    /**
+     * The message key to lookup for i18n.
+     */
+    String key() default "";
+
+    /**
+     * Additional params to be used to customize message - will be evaluated 
against the Value Stack
+     */
+    String[] messageParams() default {};
+
+    /**
+     * The optional fieldName for SIMPLE validator types.
+     */
+    String fieldName() default "";
+
+    /**
+     * If this is activated, the validator will be used as short-circuit.
+     *
+     * Adds the short-circuit="true" attribute value if <tt>true</tt>.
+     *
+     */
+    boolean shortCircuit() default false;
+
+    /**
+     * Defines to repopulate field or not after validation, default false
+     */
+    boolean repopulateField() default false;
+
+    /**
+     * The validation type for this field/method.
+     */
+    ValidatorType type() default ValidatorType.FIELD;
+
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/validator/annotations/CustomValidator.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/com/opensymphony/xwork2/validator/annotations/CustomValidator.java
 
b/core/src/main/java/com/opensymphony/xwork2/validator/annotations/CustomValidator.java
new file mode 100644
index 0000000..27d63b2
--- /dev/null
+++ 
b/core/src/main/java/com/opensymphony/xwork2/validator/annotations/CustomValidator.java
@@ -0,0 +1,124 @@
+/*
+ * 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 com.opensymphony.xwork2.validator.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * <!-- START SNIPPET: description -->
+ * This annotation can be used for custom validators. Use the 
ValidationParameter annotation to supply additional params.
+ * <!-- END SNIPPET: description -->
+ *
+ * <p/> <u>Annotation usage:</u>
+ *
+ * <!-- START SNIPPET: usage -->
+ * <p/>The annotation must be applied at method or type level.
+ * <!-- END SNIPPET: usage -->
+ *
+ * <p/> <u>Annotation parameters:</u>
+ *
+ * <!-- START SNIPPET: parameters -->
+ * <table class='confluenceTable'>
+ * <tr>
+ * <th class='confluenceTh'> Parameter </th>
+ * <th class='confluenceTh'> Required </th>
+ * <th class='confluenceTh'> Default </th>
+ * <th class='confluenceTh'> Notes </th>
+ * </tr>
+ * <tr>
+ * <td class='confluenceTd'>message</td>
+ * <td class='confluenceTd'>yes</td>
+ * <td class='confluenceTd'>&nbsp;</td>
+ * <td class='confluenceTd'>field error message</td>
+ * </tr>
+ * <tr>
+ * <td class='confluenceTd'>key</td>
+ * <td class='confluenceTd'>no</td>
+ * <td class='confluenceTd'>&nbsp;</td>
+ * <td class='confluenceTd'>i18n key from language specific properties 
file.</td>
+ * </tr>
+ * <tr>
+ * <td class='confluenceTd'>messageParams</td>
+ * <td class='confluenceTd'>no</td>
+ * <td class='confluenceTd'>&nbsp;</td>
+ * <td class='confluenceTd'>Additional params to be used to customize message 
- will be evaluated against the Value Stack</td>
+ * </tr>
+ * <tr>
+ * <td class='confluenceTd'>fieldName</td>
+ * <td class='confluenceTd'>no</td>
+ * <td class='confluenceTd'>&nbsp;</td>
+ * <td class='confluenceTd'>&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td class='confluenceTd'>shortCircuit</td>
+ * <td class='confluenceTd'>no</td>
+ * <td class='confluenceTd'>false</td>
+ * <td class='confluenceTd'>If this validator should be used as 
shortCircuit.</td>
+ * </tr>
+ * <tr>
+ * <td class='confluenceTd'>type</td>
+ * <td class='confluenceTd'>yes</td>
+ * <td class='confluenceTd'>name of validator</td>
+ * <td class='confluenceTd'>Simple string which identifies that validator 
among other</td>
+ * </tr>
+ * </table>
+ * <!-- END SNIPPET: parameters -->
+ *
+ * <p/> <u>Example code:</u>
+ *
+ * <pre>
+ * <!-- START SNIPPET: example -->
+ * &#64;CustomValidator(type ="customValidatorName", fieldName = "myField")
+ * <!-- END SNIPPET: example -->
+ * </pre>
+ *
+ * @author jepjep
+ * @author Rainer Hermanns
+ * @version $Id$
+ */
+@Target({ElementType.METHOD, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface CustomValidator {
+
+    String type();
+
+    /**
+     * The optional fieldName for SIMPLE validator types.
+     */
+    String fieldName() default "";
+
+    /**
+     * The default error message for this validator.
+     * NOTE: It is required to set a message, if you are not using the message 
key for 18n lookup!
+     */
+    String message() default "";
+
+    String key() default "";
+
+    /**
+     * Additional params to be used to customize message - will be evaluated 
against the Value Stack
+     */
+    String[] messageParams() default {};
+
+    public ValidationParameter[] parameters() default {};
+
+    boolean shortCircuit() default false;
+
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/validator/annotations/DateRangeFieldValidator.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/com/opensymphony/xwork2/validator/annotations/DateRangeFieldValidator.java
 
b/core/src/main/java/com/opensymphony/xwork2/validator/annotations/DateRangeFieldValidator.java
new file mode 100644
index 0000000..d6457d5
--- /dev/null
+++ 
b/core/src/main/java/com/opensymphony/xwork2/validator/annotations/DateRangeFieldValidator.java
@@ -0,0 +1,196 @@
+/*
+ * 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 com.opensymphony.xwork2.validator.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * <!-- START SNIPPET: description -->
+ * This validator checks that a date field has a value within a specified 
range.
+ * <!-- END SNIPPET: description -->
+ *
+ * <p/> <u>Annotation usage:</u>
+ *
+ * <!-- START SNIPPET: usage -->
+ * <p/>The annotation must be applied at method level.
+ * <!-- END SNIPPET: usage -->
+ *
+ * <p/> <u>Annotation parameters:</u>
+ *
+ * <!-- START SNIPPET: parameters -->
+ * <table class='confluenceTable'>
+ * <tr>
+ * <th class='confluenceTh'> Parameter </th>
+ * <th class='confluenceTh'> Required </th>
+ * <th class='confluenceTh'> Default </th>
+ * <th class='confluenceTh'> Notes </th>
+ * </tr>
+ * <tr>
+ * <td class='confluenceTd'>message</td>
+ * <td class='confluenceTd'>yes</td>
+ * <td class='confluenceTd'>&nbsp;</td>
+ * <td class='confluenceTd'>field error message</td>
+ * </tr>
+ * <tr>
+ * <td class='confluenceTd'>key</td>
+ * <td class='confluenceTd'>no</td>
+ * <td class='confluenceTd'>&nbsp;</td>
+ * <td class='confluenceTd'>i18n key from language specific properties 
file.</td>
+ * </tr>
+ * <tr>
+ * <td class='confluenceTd'>messageParams</td>
+ * <td class='confluenceTd'>no</td>
+ * <td class='confluenceTd'>&nbsp;</td>
+ * <td class='confluenceTd'>Additional params to be used to customize message 
- will be evaluated against the Value Stack</td>
+ * </tr>
+ * <tr>
+ * <td class='confluenceTd'>fieldName</td>
+ * <td class='confluenceTd'>no</td>
+ * <td class='confluenceTd'>&nbsp;</td>
+ * <td class='confluenceTd'>&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td class='confluenceTd'>shortCircuit</td>
+ * <td class='confluenceTd'>no</td>
+ * <td class='confluenceTd'>false</td>
+ * <td class='confluenceTd'>If this validator should be used as 
shortCircuit.</td>
+ * </tr>
+ * <tr>
+ * <td class='confluenceTd'>type</td>
+ * <td class='confluenceTd'>yes</td>
+ * <td class='confluenceTd'>ValidatorType.FIELD</td>
+ * <td class='confluenceTd'>Enum value from ValidatorType. Either FIELD or 
SIMPLE can be used here.</td>
+ * </tr>
+ * <tr>
+ * <td class='confluenceTd'> min </td>
+ * <td class='confluenceTd'> no </td>
+ * <td class='confluenceTd'>&nbsp;</td>
+ * <td class='confluenceTd'> Date property.  The minimum the date must be. 
</td>
+ * </tr>
+ * <tr>
+ * <td class='confluenceTd'>minExpression</td>
+ * <td class='confluenceTd'>no</td>
+ * <td class='confluenceTd'>&nbsp;</td>
+ * <td class='confluenceTd'>OGNL expression used to obtain the minimum the 
date must be.</td>
+ * </tr>
+ * <tr>
+ * <td class='confluenceTd'> max </td>
+ * <td class='confluenceTd'> no </td>
+ * <td class='confluenceTd'>&nbsp;</td>
+ * <td class='confluenceTd'> Date property.  The maximum date can be. </td>
+ * </tr>
+ * <tr>
+ * <td class='confluenceTd'>maxExpression</td>
+ * <td class='confluenceTd'>no</td>
+ * <td class='confluenceTd'>&nbsp;</td>
+ * <td class='confluenceTd'>OGNL expression used to obtain the maximum date 
can be.</td>
+ * </tr>
+ * <tr>
+ * <td class='confluenceTd'>maxExpression</td>
+ * <td class='confluenceTd'>no</td>
+ * <td class='confluenceTd'>&nbsp;</td>
+ * <td class='confluenceTd'>OGNL expression used to obtain the maximum date 
can be.</td>
+ * </tr>
+ * <tr>
+ * <td class='confluenceTd'>dateFormat</td>
+ * <td class='confluenceTd'>no</td>
+ * <td class='confluenceTd'>&nbsp;</td>
+ * <td class='confluenceTd'>Format used to parse min/max value.</td>
+ * </tr>
+ * </table>
+ *
+ * <p>If neither <em>min</em> nor <em>max</em> is set, nothing will be 
done.</p>
+ * <!-- END SNIPPET: parameters -->
+ *
+ * <p/> <u>Example code:</u>
+ *
+ * <pre>
+ * <!-- START SNIPPET: example -->
+ * &#64;DateRangeFieldValidator(message = "Default message", key = "i18n.key", 
shortCircuit = true, min = "2005/01/01", max = "2005/12/31")
+ * <!-- END SNIPPET: example -->
+ * </pre>
+ *
+ * @author Rainer Hermanns
+ * @version $Id$
+ */
+@Target({ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface DateRangeFieldValidator {
+
+    /**
+     *  Date property. The minimum the date must be.
+     */
+    String min() default "";
+
+    /**
+     * An expression which will be evaluated against the Value Stack to get 
the min value
+     */
+    String minExpression() default "";
+
+    /**
+     *  Date property. The maximum date can be.
+     */
+    String max() default "";
+
+    /**
+     * An expression which will be evaluated against the Value Stack to get 
the max value
+     */
+    String maxExpression() default "";
+
+    /**
+     * Date format used to parse min and max value
+     */
+    String dateFormat() default "";
+
+    /**
+     * The default error message for this validator.
+     * NOTE: It is required to set a message, if you are not using the message 
key for 18n lookup!
+     */
+    String message() default "";
+
+    /**
+     * The message key to lookup for i18n.
+     */
+    String key() default "";
+
+    /**
+     * Additional params to be used to customize message - will be evaluated 
against the Value Stack
+     */
+    String[] messageParams() default {};
+
+    /**
+     * The optional fieldName for SIMPLE validator types.
+     */
+    String fieldName() default "";
+
+    /**
+     * If this is activated, the validator will be used as short-circuit.
+     *
+     * Adds the short-circuit="true" attribute value if <tt>true</tt>.
+     *
+     */
+    boolean shortCircuit() default false;
+
+    /**
+     * The validation type for this field/method.
+     */
+    ValidatorType type() default ValidatorType.FIELD;
+
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/validator/annotations/DoubleRangeFieldValidator.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/com/opensymphony/xwork2/validator/annotations/DoubleRangeFieldValidator.java
 
b/core/src/main/java/com/opensymphony/xwork2/validator/annotations/DoubleRangeFieldValidator.java
new file mode 100644
index 0000000..5eb3049
--- /dev/null
+++ 
b/core/src/main/java/com/opensymphony/xwork2/validator/annotations/DoubleRangeFieldValidator.java
@@ -0,0 +1,225 @@
+/*
+ * 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 com.opensymphony.xwork2.validator.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * <!-- START SNIPPET: description -->
+ * This validator checks that a double field has a value within a specified 
range.
+ * If neither min nor max is set, nothing will be done.
+ * <!-- END SNIPPET: description -->
+ *
+ * <p/> <u>Annotation usage:</u>
+ *
+ * <!-- START SNIPPET: usage -->
+ * <p/>The annotation must be applied at method level.
+ * <!-- END SNIPPET: usage -->
+ *
+ * <p/> <u>Annotation parameters:</u>
+ *
+ * <!-- START SNIPPET: parameters -->
+ * <table class='confluenceTable'>
+ * <tr>
+ * <th class='confluenceTh'> Parameter </th>
+ * <th class='confluenceTh'> Required </th>
+ * <th class='confluenceTh'> Default </th>
+ * <th class='confluenceTh'> Notes </th>
+ * </tr>
+ * <tr>
+ * <td class='confluenceTd'>message</td>
+ * <td class='confluenceTd'>yes</td>
+ * <td class='confluenceTd'>&nbsp;</td>
+ * <td class='confluenceTd'>field error message</td>
+ * </tr>
+ * <tr>
+ * <td class='confluenceTd'>key</td>
+ * <td class='confluenceTd'>no</td>
+ * <td class='confluenceTd'>&nbsp;</td>
+ * <td class='confluenceTd'>i18n key from language specific properties 
file.</td>
+ * </tr>
+ * <tr>
+ * <td class='confluenceTd'>messageParams</td>
+ * <td class='confluenceTd'>no</td>
+ * <td class='confluenceTd'>&nbsp;</td>
+ * <td class='confluenceTd'>Additional params to be used to customize message 
- will be evaluated against the Value Stack</td>
+ * </tr>
+ * <tr>
+ * <td class='confluenceTd'>fieldName</td>
+ * <td class='confluenceTd'>no</td>
+ * <td class='confluenceTd'>&nbsp;</td>
+ * <td class='confluenceTd'>&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td class='confluenceTd'>shortCircuit</td>
+ * <td class='confluenceTd'>no</td>
+ * <td class='confluenceTd'>false</td>
+ * <td class='confluenceTd'>If this validator should be used as 
shortCircuit.</td>
+ * </tr>
+ * <tr>
+ * <td class='confluenceTd'>type</td>
+ * <td class='confluenceTd'>yes</td>
+ * <td class='confluenceTd'>ValidatorType.FIELD</td>
+ * <td class='confluenceTd'>Enum value from ValidatorType. Either FIELD or 
SIMPLE can be used here.</td>
+ * </tr>
+ * <tr>
+ * <td class='confluenceTd'> minInclusive </td>
+ * <td class='confluenceTd'> no </td>
+ * <td class='confluenceTd'>&nbsp;</td>
+ * <td class='confluenceTd'> Double property.  The inclusive minimum the 
number must be. </td>
+ * </tr>
+ * <tr>
+ * <td class='confluenceTd'>minInclusiveExpression</td>
+ * <td class='confluenceTd'>no</td>
+ * <td class='confluenceTd'>&nbsp;</td>
+ * <td class='confluenceTd'>OGNL expression used to obtain the inclusive 
minimum the number must be. </td>
+ * </tr>
+ * <tr>
+ * <td class='confluenceTd'> maxInclusive </td>
+ * <td class='confluenceTd'> no </td>
+ * <td class='confluenceTd'>&nbsp;</td>
+ * <td class='confluenceTd'> Double property.  The inclusive maximum number 
can be. </td>
+ * </tr>
+ * <tr>
+ * <td class='confluenceTd'> maxInclusiveExpression </td>
+ * <td class='confluenceTd'> no </td>
+ * <td class='confluenceTd'>&nbsp;</td>
+ * <td class='confluenceTd'>OGNL expression used to obtain the inclusive 
maximum number can be. </td>
+ * </tr>
+ * <tr>
+ * <td class='confluenceTd'> minExclusive </td>
+ * <td class='confluenceTd'> no </td>
+ * <td class='confluenceTd'>&nbsp;</td>
+ * <td class='confluenceTd'> Double property.  The exclusive minimum the 
number must be. </td>
+ * </tr>
+ * <tr>
+ * <td class='confluenceTd'> minExclusiveExpression </td>
+ * <td class='confluenceTd'> no </td>
+ * <td class='confluenceTd'>&nbsp;</td>
+ * <td class='confluenceTd'>OGNL expression used to obtain the exclusive 
minimum the number must be. </td>
+ * </tr>
+ * <tr>
+ * <td class='confluenceTd'> maxExclusive </td>
+ * <td class='confluenceTd'> no </td>
+ * <td class='confluenceTd'>&nbsp;</td>
+ * <td class='confluenceTd'> Double property.  The exclusive maximum number 
can be. </td>
+ * </tr>
+ * <tr>
+ * <td class='confluenceTd'> maxExclusiveExpression </td>
+ * <td class='confluenceTd'> no </td>
+ * <td class='confluenceTd'>&nbsp;</td>
+ * <td class='confluenceTd'>OGNL expression used to obtain the exclusive 
maximum number can be. </td>
+ * </tr>
+ * </table>
+ *
+ * <p>If neither <em>min</em> nor <em>max</em> is set, nothing will be 
done.</p>
+ *
+ * <p>The values for min and max must be inserted as String values so that "0" 
can be handled as a possible value.</p>
+ * <!-- END SNIPPET: parameters -->
+ *
+ * <p/> <u>Example code:</u>
+ *
+ * <pre>
+ * <!-- START SNIPPET: example -->
+ * &#64;DoubleRangeFieldValidator(message = "Default message", key = 
"i18n.key", shortCircuit = true, minInclusive = "0.123", maxInclusive = 
"99.987")
+ * <!-- END SNIPPET: example -->
+ * </pre>
+ *
+ * @author <a href="mailto:[email protected]";>Rainer Hermanns</a>
+ * @version $Id$
+ */
+@Target({ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface DoubleRangeFieldValidator {
+
+    /**
+     *  Double property. The inclusive minimum the number must be.
+     */
+    String minInclusive() default "";
+
+    /**
+     * The inclusive minimum the number must be defined as an expression
+     */
+    String minInclusiveExpression() default "";
+
+    /**
+     *  Double property. The inclusive minimum the number must be.
+     */
+    String maxInclusive() default "";
+
+    /**
+     *  The inclusive minimum the number must be defined as an expression
+     */
+    String maxInclusiveExpression() default "";
+
+    /**
+     *  Double property. The exclusive maximum number can be.
+     */
+    String minExclusive() default "";
+
+    /**
+     *  The exclusive maximum number can be defined as an expression
+     */
+    String minExclusiveExpression() default "";
+
+    /**
+     *  Double property. The exclusive maximum number can be.
+     */
+    String maxExclusive() default "";
+
+    /**
+     * The exclusive maximum number can be defined as an expression
+     */
+    String maxExclusiveExpression() default "";
+
+    /**
+     * The default error message for this validator.
+     * NOTE: It is required to set a message, if you are not using the message 
key for 18n lookup!
+     */
+    String message() default "";
+
+    /**
+     * The message key to lookup for i18n.
+     */
+    String key() default "";
+
+    /**
+     * Additional params to be used to customize message - will be evaluated 
against the Value Stack
+     */
+    String[] messageParams() default {};
+
+    /**
+     * The optional fieldName for SIMPLE validator types.
+     */
+    String fieldName() default "";
+
+    /**
+     * If this is activated, the validator will be used as short-circuit.
+     *
+     * Adds the short-circuit="true" attribute value if <tt>true</tt>.
+     *
+     */
+    boolean shortCircuit() default false;
+
+    /**
+     * The validation type for this field/method.
+     */
+    ValidatorType type() default ValidatorType.FIELD;
+}

Reply via email to