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 2015/06/17 23:09:29 UTC

[29/57] [partial] struts git commit: Merges xwork packages into struts

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:hermanns@aixcept.de">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;
+}