Commits

Anonymous committed 46c403e

Cleaning validation classes, getting rid of statics, making validatorconfig immutable
XW-597

git-svn-id: http://svn.opensymphony.com/svn/xwork/trunk@1704e221344d-f017-0410-9bd5-d282ab1896d7

  • Participants
  • Parent commits 0f065fb

Comments (0)

Files changed (31)

File src/java/com/opensymphony/xwork2/config/entities/InterceptorConfig.java

             return this;
         }
 
-         public Builder addParam(String name, String value) {
+        public Builder addParam(String name, String value) {
             target.params.put(name, value);
             return this;
         }

File src/java/com/opensymphony/xwork2/config/providers/XWorkConfigurationProvider.java

 import com.opensymphony.xwork2.util.PatternMatcher;
 import com.opensymphony.xwork2.util.ValueStackFactory;
 import com.opensymphony.xwork2.util.WildcardHelper;
-import com.opensymphony.xwork2.validator.ActionValidatorManager;
-import com.opensymphony.xwork2.validator.AnnotationActionValidatorManager;
-import com.opensymphony.xwork2.validator.DefaultActionValidatorManager;
+import com.opensymphony.xwork2.validator.*;
 import com.opensymphony.xwork2.ognl.ObjectProxy;
 import com.opensymphony.xwork2.ognl.OgnlReflectionContextFactory;
 import com.opensymphony.xwork2.ognl.OgnlReflectionProvider;
                .factory(ObjectTypeDeterminer.class, DefaultObjectTypeDeterminer.class, Scope.SINGLETON)
                .factory(XWorkConverter.class, Scope.SINGLETON)
                .factory(ValueStackFactory.class, OgnlValueStackFactory.class, Scope.SINGLETON)
+               .factory(ValidatorFactory.class, DefaultValidatorFactory.class, Scope.SINGLETON)
+               .factory(ValidatorFileParser.class, DefaultValidatorFileParser.class, Scope.SINGLETON)
                .factory(PatternMatcher.class, WildcardHelper.class, Scope.SINGLETON)
                .factory(ReflectionProvider.class, OgnlReflectionProvider.class, Scope.SINGLETON)
                .factory(ReflectionContextFactory.class, OgnlReflectionContextFactory.class, Scope.SINGLETON)

File src/java/com/opensymphony/xwork2/config/providers/XmlConfigurationProvider.java

                     doc = DomHelper.parse(in, dtdMappings);
                 } catch (XWorkException e) {
                     if (includeElement != null) {
-                        throw new ConfigurationException(e, includeElement);
+                        throw new ConfigurationException("Unable to load "+url, e, includeElement);
                     } else {
-                        throw new ConfigurationException(e);
+                        throw new ConfigurationException("Unable to load "+url, e);
                     }
                 } catch (Exception e) {
                     final String s = "Caught exception while loading file " + fileName;

File src/java/com/opensymphony/xwork2/util/DomHelper.java

 
         factory.setValidating((dtdMappings != null));
         factory.setNamespaceAware(true);
-        
+
         SAXParser parser = null;
         try {
             parser = factory.newSAXParser();
         
         
         DOMBuilder builder = new DOMBuilder();
-        
+
         // Enhance the sax stream with location information
         ContentHandler locationHandler = new LocationAttributes.Pipe(builder);
         

File src/java/com/opensymphony/xwork2/util/XWorkTestCaseHelper.java

 
 import com.opensymphony.xwork2.ActionContext;
 import com.opensymphony.xwork2.ObjectFactory;
-import com.opensymphony.xwork2.config.Configuration;
-import com.opensymphony.xwork2.config.ConfigurationException;
-import com.opensymphony.xwork2.config.ConfigurationManager;
-import com.opensymphony.xwork2.config.ConfigurationProvider;
+import com.opensymphony.xwork2.config.*;
 import com.opensymphony.xwork2.config.providers.XWorkConfigurationProvider;
 import com.opensymphony.xwork2.config.providers.XmlConfigurationProvider;
 import com.opensymphony.xwork2.conversion.impl.XWorkConverter;
 
     public static ConfigurationManager setUp() throws Exception {
         ConfigurationManager configurationManager = new ConfigurationManager();
-        configurationManager.addConfigurationProvider(new XWorkConfigurationProvider());
+        configurationManager.addContainerProvider(new XWorkConfigurationProvider());
         Configuration config = configurationManager.getConfiguration();
         Container container = config.getContainer();
         
             throw new RuntimeException("Cannot clean old configuration", e);
         }
         configurationManager = new ConfigurationManager();
-        configurationManager.addConfigurationProvider(new ConfigurationProvider() {
+        configurationManager.addContainerProvider(new ContainerProvider() {
             public void destroy() {}
             public void init(Configuration configuration) throws ConfigurationException {}
-            public void loadPackages() throws ConfigurationException {}
             public boolean needsReload() { return false; }
 
             public void register(ContainerBuilder builder,
             }
             
         });
-        configurationManager.addConfigurationProvider(new XWorkConfigurationProvider());
+        configurationManager.addContainerProvider(new XWorkConfigurationProvider());
         for (ConfigurationProvider prov : providers) {
             if (prov instanceof XmlConfigurationProvider) {
                 ((XmlConfigurationProvider)prov).setThrowExceptionOnDuplicateBeans(false);

File src/java/com/opensymphony/xwork2/validator/AnnotationActionValidatorManager.java

 import java.util.TreeSet;
 
 import com.opensymphony.xwork2.ObjectFactory;
+import com.opensymphony.xwork2.ActionContext;
+import com.opensymphony.xwork2.inject.Inject;
 import com.opensymphony.xwork2.util.FileManager;
+import com.opensymphony.xwork2.util.ValueStack;
 import com.opensymphony.xwork2.util.logging.Logger;
 import com.opensymphony.xwork2.util.logging.LoggerFactory;
 
      */
     protected static final String VALIDATION_CONFIG_SUFFIX = "-validation.xml";
 
-    private static final Map<String, List<ValidatorConfig>> validatorCache = Collections.synchronizedMap(new HashMap<String, List<ValidatorConfig>>());
-    private static final Map<String, List<ValidatorConfig>> validatorFileCache = Collections.synchronizedMap(new HashMap<String, List<ValidatorConfig>>());
+    private final Map<String, List<ValidatorConfig>> validatorCache = Collections.synchronizedMap(new HashMap<String, List<ValidatorConfig>>());
+    private final Map<String, List<ValidatorConfig>> validatorFileCache = Collections.synchronizedMap(new HashMap<String, List<ValidatorConfig>>());
     private static final Logger LOG = LoggerFactory.getLogger(AnnotationActionValidatorManager.class);
 
+    private ValidatorFactory validatorFactory;
+    private ValidatorFileParser validatorFileParser;
+
+    @Inject
+    public void setValidatorFactory(ValidatorFactory fac) {
+        this.validatorFactory = fac;
+    }
+
+    @Inject
+    public void setValidatorFileParser(ValidatorFileParser parser) {
+        this.validatorFileParser = parser;
+    }
+
     public synchronized List<Validator> getValidators(Class clazz, String context) {
         return getValidators(clazz, context, null);
     }
         // get the set of validator configs
         List<ValidatorConfig> cfgs = validatorCache.get(validatorKey);
 
+        ValueStack stack = ActionContext.getContext().getValueStack();
+
         // create clean instances of the validators for the caller's use
         ArrayList<Validator> validators = new ArrayList<Validator>(cfgs.size());
         for (ValidatorConfig cfg : cfgs) {
             if (method == null || method.equals(cfg.getParams().get("methodName"))) {
-                cfg.getParams().remove("methodName");
-                Validator validator = ValidatorFactory.getValidator(cfg, ObjectFactory.getObjectFactory());
+                Validator validator = validatorFactory.getValidator(
+                        new ValidatorConfig.Builder(cfg)
+                            .removeParam("methodName")
+                            .build());
                 validator.setValidatorType(cfg.getType());
+                validator.setValueStack(stack);
                 validators.add(validator);
             }
         }
 
         List<ValidatorConfig> result = new ArrayList<ValidatorConfig>(loadFile(fileName, aClass, checkFile));
 
-        List<ValidatorConfig> annotationResult = new ArrayList<ValidatorConfig>(AnnotationValidationConfigurationBuilder.buildAnnotationClassValidatorConfigs(aClass));
+        AnnotationValidationConfigurationBuilder builder = new AnnotationValidationConfigurationBuilder(validatorFactory);
+
+        List<ValidatorConfig> annotationResult = new ArrayList<ValidatorConfig>(builder.buildAnnotationClassValidatorConfigs(aClass));
 
         result.addAll(annotationResult);
 
                 is = FileManager.loadFile(fileName, clazz);
 
                 if (is != null) {
-                    retList = new ArrayList<ValidatorConfig>(ValidatorFileParser.parseActionValidatorConfigs(is, fileName));
+                    retList = new ArrayList<ValidatorConfig>(validatorFileParser.parseActionValidatorConfigs(validatorFactory, is, fileName));
                 }
             } catch (Exception e) {
                 LOG.error("Caught exception while loading file " + fileName, e);

File src/java/com/opensymphony/xwork2/validator/AnnotationValidationConfigurationBuilder.java

     private static final Pattern SETTER_PATTERN = Pattern.compile("set([A-Z][A-Za-z0-9]*)$");
     private static final Pattern GETTER_PATTERN = Pattern.compile("(get|is|has)([A-Z][A-Za-z0-9]*)$");
 
+    private ValidatorFactory validatorFactory;
 
+    public AnnotationValidationConfigurationBuilder(ValidatorFactory fac) {
+        this.validatorFactory = fac;
+    }
 
-    private static List<ValidatorConfig> processAnnotations(Object o) {
+    private List<ValidatorConfig> processAnnotations(Object o) {
 
         List<ValidatorConfig> result = new ArrayList<ValidatorConfig>();
 
 
                 // Process collection of custom validations
                 if (a instanceof Validations) {
-                    processValidationAnnotation(a, fieldName, result);
+                    processValidationAnnotation(a, fieldName, methodName, result);
 
                 }
 
                     Validation v = (Validation) a;
                     if ( v.validations() != null ) {
                         for ( Validations val: v.validations()) {
-                            processValidationAnnotation(val , fieldName, result);
+                            processValidationAnnotation(val , fieldName, methodName, result);
                         }
                     }
 
                 // Process single custom validator
                 else if (a instanceof ExpressionValidator) {
                     ExpressionValidator v = (ExpressionValidator) a;
-                    ValidatorConfig temp = processExpressionValidatorAnnotation(v, fieldName);
+                    ValidatorConfig temp = processExpressionValidatorAnnotation(v, fieldName, methodName);
                     if (temp != null) {
                         result.add(temp);
                     }
                 // Process single custom validator
                 else if (a instanceof CustomValidator) {
                     CustomValidator v = (CustomValidator) a;
-                    ValidatorConfig temp = processCustomValidatorAnnotation(v, fieldName);
+                    ValidatorConfig temp = processCustomValidatorAnnotation(v, fieldName, methodName);
                     if (temp != null) {
                         result.add(temp);
                     }
                 // Process ConversionErrorFieldValidator
                 else if ( a instanceof ConversionErrorFieldValidator) {
                     ConversionErrorFieldValidator v = (ConversionErrorFieldValidator) a;
-                    ValidatorConfig temp = processConversionErrorFieldValidatorAnnotation(v, fieldName);
+                    ValidatorConfig temp = processConversionErrorFieldValidatorAnnotation(v, fieldName, methodName);
                     if ( temp != null) {
                         result.add(temp);
                     }
                 // Process DateRangeFieldValidator
                 else if ( a instanceof DateRangeFieldValidator) {
                     DateRangeFieldValidator v = (DateRangeFieldValidator) a;
-                    ValidatorConfig temp = processDateRangeFieldValidatorAnnotation(v, fieldName);
+                    ValidatorConfig temp = processDateRangeFieldValidatorAnnotation(v, fieldName, methodName);
                     if ( temp != null) {
                         result.add(temp);
                     }
                 // Process EmailValidator
                 else if ( a instanceof EmailValidator) {
                     EmailValidator v = (EmailValidator) a;
-                    ValidatorConfig temp = processEmailValidatorAnnotation(v, fieldName);
+                    ValidatorConfig temp = processEmailValidatorAnnotation(v, fieldName, methodName);
                     if ( temp != null) {
                         result.add(temp);
                     }
                 // Process FieldExpressionValidator
                 else if ( a instanceof FieldExpressionValidator) {
                     FieldExpressionValidator v = (FieldExpressionValidator) a;
-                    ValidatorConfig temp = processFieldExpressionValidatorAnnotation(v, fieldName);
+                    ValidatorConfig temp = processFieldExpressionValidatorAnnotation(v, fieldName, methodName);
                     if ( temp != null) {
                         result.add(temp);
                     }
                 // Process IntRangeFieldValidator
                 else if ( a instanceof IntRangeFieldValidator) {
                     IntRangeFieldValidator v = (IntRangeFieldValidator) a;
-                    ValidatorConfig temp = processIntRangeFieldValidatorAnnotation(v, fieldName);
+                    ValidatorConfig temp = processIntRangeFieldValidatorAnnotation(v, fieldName, methodName);
                     if ( temp != null) {
                         result.add(temp);
                     }
                 // Process DoubleRangeFieldValidator
                 else if ( a instanceof DoubleRangeFieldValidator) {
                     DoubleRangeFieldValidator v = (DoubleRangeFieldValidator) a;
-                    ValidatorConfig temp = processDoubleRangeFieldValidatorAnnotation(v, fieldName);
+                    ValidatorConfig temp = processDoubleRangeFieldValidatorAnnotation(v, fieldName, methodName);
                     if ( temp != null) {
                         result.add(temp);
                     }
                 // Process RequiredFieldValidator
                 else if ( a instanceof RequiredFieldValidator) {
                     RequiredFieldValidator v = (RequiredFieldValidator) a;
-                    ValidatorConfig temp = processRequiredFieldValidatorAnnotation(v, fieldName);
+                    ValidatorConfig temp = processRequiredFieldValidatorAnnotation(v, fieldName, methodName);
                     if ( temp != null) {
                         result.add(temp);
                     }
                 // Process RequiredStringValidator
                 else if ( a instanceof RequiredStringValidator) {
                     RequiredStringValidator v = (RequiredStringValidator) a;
-                    ValidatorConfig temp = processRequiredStringValidatorAnnotation(v, fieldName);
+                    ValidatorConfig temp = processRequiredStringValidatorAnnotation(v, fieldName, methodName);
                     if ( temp != null) {
                         result.add(temp);
                     }
                 // Process StringLengthFieldValidator
                 else if ( a instanceof StringLengthFieldValidator) {
                     StringLengthFieldValidator v = (StringLengthFieldValidator) a;
-                    ValidatorConfig temp = processStringLengthFieldValidatorAnnotation(v, fieldName);
+                    ValidatorConfig temp = processStringLengthFieldValidatorAnnotation(v, fieldName, methodName);
                     if ( temp != null) {
                         result.add(temp);
                     }
                 // Process UrlValidator
                 else if ( a instanceof UrlValidator) {
                     UrlValidator v = (UrlValidator) a;
-                    ValidatorConfig temp = processUrlValidatorAnnotation(v, fieldName);
+                    ValidatorConfig temp = processUrlValidatorAnnotation(v, fieldName, methodName);
                     if ( temp != null) {
                         result.add(temp);
                     }
                 // Process VisitorFieldValidator
                 else if ( a instanceof VisitorFieldValidator) {
                     VisitorFieldValidator v = (VisitorFieldValidator) a;
-                    ValidatorConfig temp = processVisitorFieldValidatorAnnotation(v, fieldName);
+                    ValidatorConfig temp = processVisitorFieldValidatorAnnotation(v, fieldName, methodName);
                     if ( temp != null) {
                         result.add(temp);
                     }
                 // Process RegexFieldValidator
                 else if ( a instanceof RegexFieldValidator) {
                     RegexFieldValidator v = (RegexFieldValidator) a;
-                    ValidatorConfig temp = processRegexFieldValidatorAnnotation(v, fieldName);
+                    ValidatorConfig temp = processRegexFieldValidatorAnnotation(v, fieldName, methodName);
                     if ( temp != null) {
                         result.add(temp);
                     }
 
                 }
             }
-            if (methodName != null) {
-                for (ValidatorConfig vc : result) {
-                    vc.getParams().put("methodName", methodName);
-                }
-            }
         }
         return result;
     }
 
-    private static void processValidationAnnotation(Annotation a, String fieldName, List<ValidatorConfig> result) {
+    private void processValidationAnnotation(Annotation a, String fieldName, String methodName, List<ValidatorConfig> result) {
         Validations validations = (Validations) a;
         CustomValidator[] cv = validations.customValidators();
         if ( cv != null ) {
             for (CustomValidator v : cv) {
-                ValidatorConfig temp = processCustomValidatorAnnotation(v, fieldName);
+                ValidatorConfig temp = processCustomValidatorAnnotation(v, fieldName, methodName);
                 if (temp != null) {
                     result.add(temp);
                 }
         ExpressionValidator[] ev = validations.expressions();
         if ( ev != null ) {
             for (ExpressionValidator v : ev) {
-                ValidatorConfig temp = processExpressionValidatorAnnotation(v, fieldName);
+                ValidatorConfig temp = processExpressionValidatorAnnotation(v, fieldName, methodName);
                 if (temp != null) {
                     result.add(temp);
                 }
         ConversionErrorFieldValidator[] cef = validations.conversionErrorFields();
         if ( cef != null ) {
             for (ConversionErrorFieldValidator v : cef) {
-                ValidatorConfig temp = processConversionErrorFieldValidatorAnnotation(v, fieldName);
+                ValidatorConfig temp = processConversionErrorFieldValidatorAnnotation(v, fieldName, methodName);
                 if (temp != null) {
                     result.add(temp);
                 }
         DateRangeFieldValidator[] drfv = validations.dateRangeFields();
         if ( drfv != null ) {
             for (DateRangeFieldValidator v : drfv) {
-                ValidatorConfig temp = processDateRangeFieldValidatorAnnotation(v, fieldName);
+                ValidatorConfig temp = processDateRangeFieldValidatorAnnotation(v, fieldName, methodName);
                 if (temp != null) {
                     result.add(temp);
                 }
         EmailValidator[] emv = validations.emails();
         if ( emv != null ) {
             for (EmailValidator v : emv) {
-                ValidatorConfig temp = processEmailValidatorAnnotation(v, fieldName);
+                ValidatorConfig temp = processEmailValidatorAnnotation(v, fieldName, methodName);
                 if (temp != null) {
                     result.add(temp);
                 }
         FieldExpressionValidator[] fev = validations.fieldExpressions();
         if ( fev != null ) {
             for (FieldExpressionValidator v : fev) {
-                ValidatorConfig temp = processFieldExpressionValidatorAnnotation(v, fieldName);
+                ValidatorConfig temp = processFieldExpressionValidatorAnnotation(v, fieldName, methodName);
                 if (temp != null) {
                     result.add(temp);
                 }
         IntRangeFieldValidator[] irfv = validations.intRangeFields();
         if ( irfv != null ) {
             for (IntRangeFieldValidator v : irfv) {
-                ValidatorConfig temp = processIntRangeFieldValidatorAnnotation(v, fieldName);
+                ValidatorConfig temp = processIntRangeFieldValidatorAnnotation(v, fieldName, methodName);
                 if (temp != null) {
                     result.add(temp);
                 }
         RegexFieldValidator[] rfv = validations.regexFields();
         if ( rfv != null ) {
             for (RegexFieldValidator v : rfv) {
-                ValidatorConfig temp = processRegexFieldValidatorAnnotation(v, fieldName);
+                ValidatorConfig temp = processRegexFieldValidatorAnnotation(v, fieldName, methodName);
                 if (temp != null) {
                     result.add(temp);
                 }
         RequiredFieldValidator[] rv = validations.requiredFields();
         if ( rv != null ) {
             for (RequiredFieldValidator v : rv) {
-                ValidatorConfig temp = processRequiredFieldValidatorAnnotation(v, fieldName);
+                ValidatorConfig temp = processRequiredFieldValidatorAnnotation(v, fieldName, methodName);
                 if (temp != null) {
                     result.add(temp);
                 }
         RequiredStringValidator[] rsv = validations.requiredStrings();
         if ( rsv != null ) {
             for (RequiredStringValidator v : rsv) {
-                ValidatorConfig temp = processRequiredStringValidatorAnnotation(v, fieldName);
+                ValidatorConfig temp = processRequiredStringValidatorAnnotation(v, fieldName, methodName);
                 if (temp != null) {
                     result.add(temp);
                 }
         StringLengthFieldValidator[] slfv = validations.stringLengthFields();
         if ( slfv != null ) {
             for (StringLengthFieldValidator v : slfv) {
-                ValidatorConfig temp = processStringLengthFieldValidatorAnnotation(v, fieldName);
+                ValidatorConfig temp = processStringLengthFieldValidatorAnnotation(v, fieldName, methodName);
                 if (temp != null) {
                     result.add(temp);
                 }
         UrlValidator[] uv = validations.urls();
         if ( uv != null ) {
             for (UrlValidator v : uv) {
-                ValidatorConfig temp = processUrlValidatorAnnotation(v, fieldName);
+                ValidatorConfig temp = processUrlValidatorAnnotation(v, fieldName, methodName);
                 if (temp != null) {
                     result.add(temp);
                 }
         VisitorFieldValidator[] vfv = validations.visitorFields();
         if ( vfv != null ) {
             for (VisitorFieldValidator v : vfv) {
-                ValidatorConfig temp = processVisitorFieldValidatorAnnotation(v, fieldName);
+                ValidatorConfig temp = processVisitorFieldValidatorAnnotation(v, fieldName, methodName);
                 if (temp != null) {
                     result.add(temp);
                 }
         }
     }
 
-    private static ValidatorConfig processExpressionValidatorAnnotation(ExpressionValidator v, String fieldName) {
+    private ValidatorConfig processExpressionValidatorAnnotation(ExpressionValidator v, String fieldName, String methodName) {
         String validatorType = "expression";
 
-        Map<String, Object> params = new HashMap<String, Object>();
+        Map<String, String> params = new HashMap<String, String>();
 
         if (fieldName != null) {
             params.put("fieldName", fieldName);
 
         params.put("expression", v.expression());
 
-        ValidatorFactory.lookupRegisteredValidatorType(validatorType);
-        ValidatorConfig vCfg = new ValidatorConfig(validatorType, params);
-        vCfg.setShortCircuit(v.shortCircuit());
-        vCfg.setDefaultMessage(v.message());
-
-        String key = v.key();
-
-        if ((key != null) && (key.trim().length() > 0)) {
-            vCfg.setMessageKey(key);
-        }
-
-        return vCfg;
+        validatorFactory.lookupRegisteredValidatorType(validatorType);
+        return new ValidatorConfig.Builder(validatorType)
+            .addParams(params)
+            .addParam("methodName", methodName)
+            .shortCircuit(v.shortCircuit())
+            .defaultMessage(v.message())
+            .messageKey(v.key())
+            .build();
 
     }
 
-    private static ValidatorConfig processCustomValidatorAnnotation(CustomValidator v, String fieldName) {
+    private ValidatorConfig processCustomValidatorAnnotation(CustomValidator v, String fieldName, String methodName) {
 
-        Map<String, Object> params = new HashMap<String, Object>();
+        Map<String, String> params = new HashMap<String, String>();
 
         if (fieldName != null) {
             params.put("fieldName", fieldName);
 
         String validatorType = v.type();
 
-        ValidatorFactory.lookupRegisteredValidatorType(validatorType);
+        validatorFactory.lookupRegisteredValidatorType(validatorType);
 
         Annotation[] recursedAnnotations = v.parameters();
 
             }
         }
 
-        ValidatorConfig vCfg = new ValidatorConfig(validatorType, params);
-        vCfg.setShortCircuit(v.shortCircuit());
-        vCfg.setDefaultMessage(v.message());
-
-        String key = v.key();
-
-        if ((key != null) && (key.trim().length() > 0)) {
-            vCfg.setMessageKey(key);
-        }
-
-        return vCfg;
+        return new ValidatorConfig.Builder(validatorType)
+            .addParams(params)
+            .addParam("methodName", methodName)
+            .shortCircuit(v.shortCircuit())
+            .defaultMessage(v.message())
+            .messageKey(v.key())
+            .build();
     }
 
-    private static ValidatorConfig processRegexFieldValidatorAnnotation(RegexFieldValidator v, String fieldName) {
+    private ValidatorConfig processRegexFieldValidatorAnnotation(RegexFieldValidator v, String fieldName, String methodName) {
         String validatorType = "regex";
 
-        Map<String, Object> params = new HashMap<String, Object>();
+        Map<String, String> params = new HashMap<String, String>();
 
         if (fieldName != null) {
             params.put("fieldName", fieldName);
 
         params.put("expression", v.expression());
 
-        ValidatorFactory.lookupRegisteredValidatorType(validatorType);
-        ValidatorConfig vCfg = new ValidatorConfig(validatorType, params);
-        vCfg.setShortCircuit(v.shortCircuit());
-        vCfg.setDefaultMessage(v.message());
-
-        String key = v.key();
-
-        if ((key != null) && (key.trim().length() > 0)) {
-            vCfg.setMessageKey(key);
-        }
-
-        return vCfg;
+        validatorFactory.lookupRegisteredValidatorType(validatorType);
+        return new ValidatorConfig.Builder(validatorType)
+            .addParams(params)
+            .addParam("methodName", methodName)
+            .shortCircuit(v.shortCircuit())
+            .defaultMessage(v.message())
+            .messageKey(v.key())
+            .build();
     }
 
-    private static ValidatorConfig processVisitorFieldValidatorAnnotation(VisitorFieldValidator v, String fieldName) {
+    private ValidatorConfig processVisitorFieldValidatorAnnotation(VisitorFieldValidator v, String fieldName, String methodName) {
 
         String validatorType = "visitor";
 
-        Map<String, Object> params = new HashMap<String, Object>();
+        Map<String, String> params = new HashMap<String, String>();
 
         if (fieldName != null) {
             params.put("fieldName", fieldName);
         }
 
         params.put("context", v.context());
-        params.put("appendPrefix", v.appendPrefix());
-
-        ValidatorFactory.lookupRegisteredValidatorType(validatorType);
-        ValidatorConfig vCfg = new ValidatorConfig(validatorType, params);
-        vCfg.setShortCircuit(v.shortCircuit());
-        vCfg.setDefaultMessage(v.message());
-
-        String key = v.key();
-
-        if ((key != null) && (key.trim().length() > 0)) {
-            vCfg.setMessageKey(key);
-        }
-
-        return vCfg;
+        params.put("appendPrefix", String.valueOf(v.appendPrefix()));
+
+        validatorFactory.lookupRegisteredValidatorType(validatorType);
+        return new ValidatorConfig.Builder(validatorType)
+            .addParams(params)
+            .addParam("methodName", methodName)
+            .shortCircuit(v.shortCircuit())
+            .defaultMessage(v.message())
+            .messageKey(v.key())
+            .build();
     }
 
-    private static ValidatorConfig processUrlValidatorAnnotation(UrlValidator v, String fieldName) {
+    private ValidatorConfig processUrlValidatorAnnotation(UrlValidator v, String fieldName, String methodName) {
         String validatorType = "url";
 
-        Map<String, Object> params = new HashMap<String, Object>();
+        Map<String, String> params = new HashMap<String, String>();
 
         if (fieldName != null) {
             params.put("fieldName", fieldName);
             params.put("fieldName", v.fieldName());
         }
 
-        ValidatorFactory.lookupRegisteredValidatorType(validatorType);
-        ValidatorConfig vCfg = new ValidatorConfig(validatorType, params);
-        vCfg.setShortCircuit(v.shortCircuit());
-        vCfg.setDefaultMessage(v.message());
-
-        String key = v.key();
-
-        if ((key != null) && (key.trim().length() > 0)) {
-            vCfg.setMessageKey(key);
-        }
-
-        return vCfg;
+        validatorFactory.lookupRegisteredValidatorType(validatorType);
+        return new ValidatorConfig.Builder(validatorType)
+            .addParams(params)
+            .addParam("methodName", methodName)
+            .shortCircuit(v.shortCircuit())
+            .defaultMessage(v.message())
+            .messageKey(v.key())
+            .build();
     }
 
-    private static ValidatorConfig processStringLengthFieldValidatorAnnotation(StringLengthFieldValidator v, String fieldName) {
+    private ValidatorConfig processStringLengthFieldValidatorAnnotation(StringLengthFieldValidator v, String fieldName, String methodName) {
         String validatorType = "stringlength";
 
-        Map<String, Object> params = new HashMap<String, Object>();
+        Map<String, String> params = new HashMap<String, String>();
 
         if (fieldName != null) {
             params.put("fieldName", fieldName);
         if ( v.minLength() != null && v.minLength().length() > 0) {
             params.put("minLength", v.minLength());
         }
-        params.put("trim", v.trim());
-
-        ValidatorFactory.lookupRegisteredValidatorType(validatorType);
-        ValidatorConfig vCfg = new ValidatorConfig(validatorType, params);
-        vCfg.setShortCircuit(v.shortCircuit());
-        vCfg.setDefaultMessage(v.message());
+        params.put("trim", String.valueOf(v.trim()));
 
-        String key = v.key();
-
-        if ((key != null) && (key.trim().length() > 0)) {
-            vCfg.setMessageKey(key);
-        }
-
-        return vCfg;
+        validatorFactory.lookupRegisteredValidatorType(validatorType);
+        return new ValidatorConfig.Builder(validatorType)
+            .addParams(params)
+            .addParam("methodName", methodName)
+            .shortCircuit(v.shortCircuit())
+            .defaultMessage(v.message())
+            .messageKey(v.key())
+            .build();
     }
 
-    private static Date parseDateString(String value) {
+    private Date parseDateString(String value) {
 
         SimpleDateFormat d1 = (SimpleDateFormat) DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.LONG, Locale.getDefault());
         SimpleDateFormat d2 = (SimpleDateFormat)DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM, Locale.getDefault());
 
     }
 
-    private static ValidatorConfig processRequiredStringValidatorAnnotation(RequiredStringValidator v, String fieldName) {
+    private ValidatorConfig processRequiredStringValidatorAnnotation(RequiredStringValidator v, String fieldName, String methodName) {
         String validatorType = "requiredstring";
 
-        Map<String, Object> params = new HashMap<String, Object>();
+        Map<String, String> params = new HashMap<String, String>();
 
         if (fieldName != null) {
             params.put("fieldName", fieldName);
             params.put("fieldName", v.fieldName());
         }
 
-        params.put("trim", v.trim());
-
-        ValidatorFactory.lookupRegisteredValidatorType(validatorType);
-        ValidatorConfig vCfg = new ValidatorConfig(validatorType, params);
-        vCfg.setShortCircuit(v.shortCircuit());
-        vCfg.setDefaultMessage(v.message());
-
-        String key = v.key();
+        params.put("trim", String.valueOf(v.trim()));
 
-        if ((key != null) && (key.trim().length() > 0)) {
-            vCfg.setMessageKey(key);
-        }
-
-        return vCfg;
+        validatorFactory.lookupRegisteredValidatorType(validatorType);
+        return new ValidatorConfig.Builder(validatorType)
+            .addParams(params)
+            .addParam("methodName", methodName)
+            .shortCircuit(v.shortCircuit())
+            .defaultMessage(v.message())
+            .messageKey(v.key())
+            .build();
     }
 
-    private static ValidatorConfig processRequiredFieldValidatorAnnotation(RequiredFieldValidator v, String fieldName) {
+    private ValidatorConfig processRequiredFieldValidatorAnnotation(RequiredFieldValidator v, String fieldName, String methodName) {
         String validatorType = "required";
 
-        Map<String, Object> params = new HashMap<String, Object>();
+        Map<String, String> params = new HashMap<String, String>();
 
         if (fieldName != null) {
             params.put("fieldName", fieldName);
             params.put("fieldName", v.fieldName());
         }
 
-        ValidatorFactory.lookupRegisteredValidatorType(validatorType);
-        ValidatorConfig vCfg = new ValidatorConfig(validatorType, params);
-        vCfg.setShortCircuit(v.shortCircuit());
-        vCfg.setDefaultMessage(v.message());
-
-        String key = v.key();
-
-        if ((key != null) && (key.trim().length() > 0)) {
-            vCfg.setMessageKey(key);
-        }
-
-        return vCfg;
+        validatorFactory.lookupRegisteredValidatorType(validatorType);
+        return new ValidatorConfig.Builder(validatorType)
+            .addParams(params)
+            .addParam("methodName", methodName)
+            .shortCircuit(v.shortCircuit())
+            .defaultMessage(v.message())
+            .messageKey(v.key())
+            .build();
     }
 
-    private static ValidatorConfig processIntRangeFieldValidatorAnnotation(IntRangeFieldValidator v, String fieldName) {
+    private ValidatorConfig processIntRangeFieldValidatorAnnotation(IntRangeFieldValidator v, String fieldName, String methodName) {
         String validatorType = "int";
 
-        Map<String, Object> params = new HashMap<String, Object>();
+        Map<String, String> params = new HashMap<String, String>();
 
         if (fieldName != null) {
             params.put("fieldName", fieldName);
             params.put("max", v.max());
         }
 
-        ValidatorFactory.lookupRegisteredValidatorType(validatorType);
-        ValidatorConfig vCfg = new ValidatorConfig(validatorType, params);
-        vCfg.setShortCircuit(v.shortCircuit());
-        vCfg.setDefaultMessage(v.message());
-
-        String key = v.key();
-
-        if ((key != null) && (key.trim().length() > 0)) {
-            vCfg.setMessageKey(key);
-        }
-
-        return vCfg;
+        validatorFactory.lookupRegisteredValidatorType(validatorType);
+        return new ValidatorConfig.Builder(validatorType)
+            .addParams(params)
+            .addParam("methodName", methodName)
+            .shortCircuit(v.shortCircuit())
+            .defaultMessage(v.message())
+            .messageKey(v.key())
+            .build();
     }
 
-    private static ValidatorConfig processDoubleRangeFieldValidatorAnnotation(DoubleRangeFieldValidator v, String fieldName) {
+    private ValidatorConfig processDoubleRangeFieldValidatorAnnotation(DoubleRangeFieldValidator v, String fieldName, String methodName) {
         String validatorType = "double";
 
-        Map<String, Object> params = new HashMap<String, Object>();
+        Map<String, String> params = new HashMap<String, String>();
 
         if (fieldName != null) {
             params.put("fieldName", fieldName);
             params.put("maxExclusive", v.maxExclusive());
         }
 
-        ValidatorFactory.lookupRegisteredValidatorType(validatorType);
-        ValidatorConfig vCfg = new ValidatorConfig(validatorType, params);
-        vCfg.setShortCircuit(v.shortCircuit());
-        vCfg.setDefaultMessage(v.message());
-
-        String key = v.key();
-
-        if ((key != null) && (key.trim().length() > 0)) {
-            vCfg.setMessageKey(key);
-        }
-
-        return vCfg;
+        validatorFactory.lookupRegisteredValidatorType(validatorType);
+        return new ValidatorConfig.Builder(validatorType)
+            .addParams(params)
+            .addParam("methodName", methodName)
+            .shortCircuit(v.shortCircuit())
+            .defaultMessage(v.message())
+            .messageKey(v.key())
+            .build();
     }
 
-    private static ValidatorConfig processFieldExpressionValidatorAnnotation(FieldExpressionValidator v, String fieldName) {
+    private ValidatorConfig processFieldExpressionValidatorAnnotation(FieldExpressionValidator v, String fieldName, String methodName) {
         String validatorType = "fieldexpression";
 
-        Map<String, Object> params = new HashMap<String, Object>();
+        Map<String, String> params = new HashMap<String, String>();
 
         if (fieldName != null) {
             params.put("fieldName", fieldName);
 
         params.put("expression", v.expression());
 
-        ValidatorFactory.lookupRegisteredValidatorType(validatorType);
-        ValidatorConfig vCfg = new ValidatorConfig(validatorType, params);
-        vCfg.setShortCircuit(v.shortCircuit());
-        vCfg.setDefaultMessage(v.message());
-
-        String key = v.key();
-
-        if ((key != null) && (key.trim().length() > 0)) {
-            vCfg.setMessageKey(key);
-        }
-
-        return vCfg;
+        validatorFactory.lookupRegisteredValidatorType(validatorType);
+        return new ValidatorConfig.Builder(validatorType)
+            .addParams(params)
+            .addParam("methodName", methodName)
+            .shortCircuit(v.shortCircuit())
+            .defaultMessage(v.message())
+            .messageKey(v.key())
+            .build();
     }
 
-    private static ValidatorConfig processEmailValidatorAnnotation(EmailValidator v, String fieldName) {
+    private ValidatorConfig processEmailValidatorAnnotation(EmailValidator v, String fieldName, String methodName) {
         String validatorType = "email";
 
-        Map<String, Object> params = new HashMap<String, Object>();
+        Map<String, String> params = new HashMap<String, String>();
 
         if (fieldName != null) {
             params.put("fieldName", fieldName);
             params.put("fieldName", v.fieldName());
         }
 
-        ValidatorFactory.lookupRegisteredValidatorType(validatorType);
-        ValidatorConfig vCfg = new ValidatorConfig(validatorType, params);
-        vCfg.setShortCircuit(v.shortCircuit());
-        vCfg.setDefaultMessage(v.message());
-
-        String key = v.key();
-
-        if ((key != null) && (key.trim().length() > 0)) {
-            vCfg.setMessageKey(key);
-        }
-
-        return vCfg;
+        validatorFactory.lookupRegisteredValidatorType(validatorType);
+        return new ValidatorConfig.Builder(validatorType)
+            .addParams(params)
+            .addParam("methodName", methodName)
+            .shortCircuit(v.shortCircuit())
+            .defaultMessage(v.message())
+            .messageKey(v.key())
+            .build();
     }
 
-    private static ValidatorConfig processDateRangeFieldValidatorAnnotation(DateRangeFieldValidator v, String fieldName) {
+    private ValidatorConfig processDateRangeFieldValidatorAnnotation(DateRangeFieldValidator v, String fieldName, String methodName) {
         String validatorType = "date";
 
-        Map<String, Object> params = new HashMap<String, Object>();
+        Map<String, String> params = new HashMap<String, String>();
 
         if (fieldName != null) {
             params.put("fieldName", fieldName);
         }
         if ( v.min() != null && v.min().length() > 0) {
              final Date minDate = parseDateString(v.min());
-             params.put("min", minDate == null ? v.min() : minDate);
+             params.put("min", String.valueOf(minDate == null ? v.min() : minDate));
         }
         if ( v.max() != null && v.max().length() > 0) {
              final Date maxDate = parseDateString(v.max());
-             params.put("max", maxDate == null ? v.max() : maxDate);
+             params.put("max", String.valueOf(maxDate == null ? v.max() : maxDate));
         }
 
-        ValidatorFactory.lookupRegisteredValidatorType(validatorType);
-        ValidatorConfig vCfg = new ValidatorConfig(validatorType, params);
-        vCfg.setShortCircuit(v.shortCircuit());
-        vCfg.setDefaultMessage(v.message());
-
-        String key = v.key();
-
-        if ((key != null) && (key.trim().length() > 0)) {
-            vCfg.setMessageKey(key);
-        }
-
-        return vCfg;
+        validatorFactory.lookupRegisteredValidatorType(validatorType);
+        return new ValidatorConfig.Builder(validatorType)
+            .addParams(params)
+            .addParam("methodName", methodName)
+            .shortCircuit(v.shortCircuit())
+            .defaultMessage(v.message())
+            .messageKey(v.key())
+            .build();
     }
 
-    private static ValidatorConfig processConversionErrorFieldValidatorAnnotation(ConversionErrorFieldValidator v, String fieldName) {
+    private ValidatorConfig processConversionErrorFieldValidatorAnnotation(ConversionErrorFieldValidator v, String fieldName, String methodName) {
         String validatorType = "conversion";
 
-        Map<String, Object> params = new HashMap<String, Object>();
+        Map<String, String> params = new HashMap<String, String>();
 
         if (fieldName != null) {
             params.put("fieldName", fieldName);
             params.put("fieldName", v.fieldName());
         }
 
-        ValidatorFactory.lookupRegisteredValidatorType(validatorType);
-        ValidatorConfig vCfg = new ValidatorConfig(validatorType, params);
-        vCfg.setShortCircuit(v.shortCircuit());
-        vCfg.setDefaultMessage(v.message());
-
-        String key = v.key();
-
-        if ((key != null) && (key.trim().length() > 0)) {
-            vCfg.setMessageKey(key);
-        }
-
-        return vCfg;
+        validatorFactory.lookupRegisteredValidatorType(validatorType);
+        return new ValidatorConfig.Builder(validatorType)
+            .addParams(params)
+            .addParam("methodName", methodName)
+            .shortCircuit(v.shortCircuit())
+            .defaultMessage(v.message())
+            .messageKey(v.key())
+            .build();
     }
 
-    public static List<ValidatorConfig> buildAnnotationClassValidatorConfigs(Class aClass) {
+    public List<ValidatorConfig> buildAnnotationClassValidatorConfigs(Class aClass) {
 
         List<ValidatorConfig> result = new ArrayList<ValidatorConfig>();
 
      * @param method The method to get the property name for.
      * @return the property name for given method; null if non could be resolved.
      */
-    public static String resolvePropertyName(Method method) {
+    public String resolvePropertyName(Method method) {
 
         Matcher matcher = SETTER_PATTERN.matcher(method.getName());
         if (matcher.matches() && method.getParameterTypes().length == 1) {

File src/java/com/opensymphony/xwork2/validator/DefaultActionValidatorManager.java

 import java.util.TreeSet;
 
 import com.opensymphony.xwork2.ObjectFactory;
+import com.opensymphony.xwork2.ActionContext;
+import com.opensymphony.xwork2.inject.Inject;
 import com.opensymphony.xwork2.util.FileManager;
+import com.opensymphony.xwork2.util.ValueStack;
 import com.opensymphony.xwork2.util.logging.Logger;
 import com.opensymphony.xwork2.util.logging.LoggerFactory;
 
     /** The file suffix for any validation file. */
     protected static final String VALIDATION_CONFIG_SUFFIX = "-validation.xml";
 
-    private static final Map<String, List<ValidatorConfig>> validatorCache = Collections.synchronizedMap(new HashMap<String, List<ValidatorConfig>>());
-    private static final Map<String, List<ValidatorConfig>> validatorFileCache = Collections.synchronizedMap(new HashMap<String, List<ValidatorConfig>>());
-    private static final Logger LOG = LoggerFactory.getLogger(DefaultActionValidatorManager.class);
-    private ObjectFactory objectFactory;
-    
+    private final Map<String, List<ValidatorConfig>> validatorCache = Collections.synchronizedMap(new HashMap<String, List<ValidatorConfig>>());
+    private final Map<String, List<ValidatorConfig>> validatorFileCache = Collections.synchronizedMap(new HashMap<String, List<ValidatorConfig>>());
+    private final Logger LOG = LoggerFactory.getLogger(DefaultActionValidatorManager.class);
+    private ValidatorFactory validatorFactory;
+    private ValidatorFileParser validatorFileParser;
+
+    @Inject
+    public void setValidatorFileParser(ValidatorFileParser parser) {
+        this.validatorFileParser = parser;
+    }
     
+    @Inject
+    public void setValidatorFactory(ValidatorFactory fac) {
+        this.validatorFactory = fac;
+    }
 
     public synchronized List<Validator> getValidators(Class clazz, String context) {
         return getValidators(clazz, context, null);
         } else {
             validatorCache.put(validatorKey, buildValidatorConfigs(clazz, context, false, null));
         }
+        ValueStack stack = ActionContext.getContext().getValueStack();
 
         // get the set of validator configs
         List<ValidatorConfig> cfgs = validatorCache.get(validatorKey);
         ArrayList<Validator> validators = new ArrayList<Validator>(cfgs.size());
         for (ValidatorConfig cfg : cfgs) {
             if (method == null || method.equals(cfg.getParams().get("methodName"))) {
-                Validator validator = ValidatorFactory.getValidator(cfg, ObjectFactory.getObjectFactory());
+                Validator validator = validatorFactory.getValidator(cfg);
                 validator.setValidatorType(cfg.getType());
+                validator.setValueStack(stack);
                 validators.add(validator);
             }
         }
                 is = FileManager.loadFile(fileName, clazz);
 
                 if (is != null) {
-                    retList = new ArrayList<ValidatorConfig>(ValidatorFileParser.parseActionValidatorConfigs(is, fileName));
+                    retList = new ArrayList<ValidatorConfig>(validatorFileParser.parseActionValidatorConfigs(validatorFactory, is, fileName));
                 }
             } finally {
                 if (is != null) {

File src/java/com/opensymphony/xwork2/validator/DefaultValidatorFactory.java

+/*
+ * Copyright (c) 2002-2006 by OpenSymphony
+ * All rights reserved.
+ */
+package com.opensymphony.xwork2.validator;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.InputStream;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.opensymphony.xwork2.ObjectFactory;
+import com.opensymphony.xwork2.XWorkException;
+import com.opensymphony.xwork2.inject.Inject;
+import com.opensymphony.xwork2.util.ClassLoaderUtil;
+import com.opensymphony.xwork2.util.logging.Logger;
+import com.opensymphony.xwork2.util.logging.LoggerFactory;
+
+
+/**
+ * Default validator factory
+ * 
+ * @version $Date$ $Id$
+ * @author Jason Carreira
+ * @author James House
+ */
+public class DefaultValidatorFactory implements ValidatorFactory {
+
+    protected Map<String, String> validators = new HashMap<String, String>();
+    private static Logger LOG = LoggerFactory.getLogger(DefaultValidatorFactory.class);
+    protected ObjectFactory objectFactory;
+    protected ValidatorFileParser validatorFileParser;
+
+    @Inject
+    public DefaultValidatorFactory(@Inject ObjectFactory objectFactory, @Inject ValidatorFileParser parser) {
+        this.objectFactory = objectFactory;
+        this.validatorFileParser = parser;
+        parseValidators();
+    }
+
+    public Validator getValidator(ValidatorConfig cfg) {
+
+        String className = lookupRegisteredValidatorType(cfg.getType());
+
+        Validator validator;
+
+        try {
+            // instantiate the validator, and set configured parameters
+            //todo - can this use the ThreadLocal?
+            validator = objectFactory.buildValidator(className, cfg.getParams(), null); // ActionContext.getContext().getContextMap());
+        } catch (Exception e) {
+            final String msg = "There was a problem creating a Validator of type " + className + " : caused by " + e.getMessage();
+            throw new XWorkException(msg, e, cfg);
+        }
+
+        // set other configured properties
+        validator.setMessageKey(cfg.getMessageKey());
+        validator.setDefaultMessage(cfg.getDefaultMessage());
+        if (validator instanceof ShortCircuitableValidator) {
+            ((ShortCircuitableValidator) validator).setShortCircuit(cfg.isShortCircuit());
+        }
+
+        return validator;
+    }
+
+    public void registerValidator(String name, String className) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Registering validator of class " + className + " with name " + name);
+        }
+
+        validators.put(name, className);
+    }
+
+    public String lookupRegisteredValidatorType(String name) {
+        // lookup the validator class mapped to the type name
+        String className = validators.get(name);
+
+        if (className == null) {
+            throw new IllegalArgumentException("There is no validator class mapped to the name " + name);
+        }
+
+        return className;
+    }
+
+    private void parseValidators() {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Loading validator definitions.");
+        }
+
+        // Get custom validator configurations via the classpath
+        URL u = ClassLoaderUtil.getResource("", DefaultValidatorFactory.class);
+        File[] files = null;
+        try {
+            File f = new File(u.toURI());
+            FilenameFilter filter = new FilenameFilter() {
+                public boolean accept(File file, String fileName) {
+                    return fileName.contains("-validators.xml");
+                }
+            };
+            files = f.listFiles(filter);
+        } catch (URISyntaxException e) {
+            // swallow
+        }
+
+        // Parse default validator configurations
+        String resourceName = "com/opensymphony/xwork2/validator/validators/default.xml";
+        retrieveValidatorConfiguration(resourceName);
+
+        // Overwrite and extend defaults with application specific validator configurations
+        resourceName = "validators.xml";
+        retrieveValidatorConfiguration(resourceName);
+
+        // Add custom (plugin) specific validator configurations
+        if ( files != null && files.length > 0 ) {
+            for (File file : files) {
+                retrieveValidatorConfiguration(file.getName());
+            }
+        }
+    }
+
+    private void retrieveValidatorConfiguration(String resourceName) {
+        InputStream is = ClassLoaderUtil.getResourceAsStream(resourceName, DefaultValidatorFactory.class);
+        if (is != null) {
+            validatorFileParser.parseValidatorDefinitions(validators, is, resourceName);
+        }
+    }
+}

File src/java/com/opensymphony/xwork2/validator/DefaultValidatorFileParser.java

+/*
+ * Copyright (c) 2002-2006 by OpenSymphony
+ * All rights reserved.
+ */
+package com.opensymphony.xwork2.validator;
+
+import com.opensymphony.xwork2.ObjectFactory;
+import com.opensymphony.xwork2.util.DomHelper;
+import com.opensymphony.xwork2.XWorkException;
+import com.opensymphony.xwork2.config.ConfigurationException;
+import com.opensymphony.xwork2.inject.Inject;
+import org.w3c.dom.*;
+import org.xml.sax.InputSource;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * Parse the validation file. (eg. MyAction-validation.xml, MyAction-actionAlias-validation.xml)
+ * to return a List of ValidatorConfig encapsulating the validator information.
+ *
+ * @author Jason Carreira
+ * @author James House
+ * @author tm_jee ( tm_jee (at) yahoo.co.uk )
+ * @author Rob Harrop
+ * @author Rene Gielen
+ *
+ * @see com.opensymphony.xwork2.validator.ValidatorConfig
+ */
+public class DefaultValidatorFileParser implements ValidatorFileParser {
+
+    static final String MULTI_TEXTVALUE_SEPARATOR = " ";
+    private ObjectFactory objectFactory;
+
+    @Inject
+    public void setObjectFactory(ObjectFactory fac) {
+        this.objectFactory = fac;
+    }
+
+    public List<ValidatorConfig> parseActionValidatorConfigs(ValidatorFactory validatorFactory, InputStream is, final String resourceName) {
+        List validatorCfgs = new ArrayList();
+        Document doc = null;
+
+        InputSource in = new InputSource(is);
+        in.setSystemId(resourceName);
+            
+        Map dtdMappings = new HashMap();
+        dtdMappings.put("-//OpenSymphony Group//XWork Validator 1.0//EN", "xwork-validator-1.0.dtd");
+        dtdMappings.put("-//OpenSymphony Group//XWork Validator 1.0.2//EN", "xwork-validator-1.0.2.dtd");
+        
+        doc = DomHelper.parse(in, dtdMappings);
+
+        if (doc != null) {
+            NodeList fieldNodes = doc.getElementsByTagName("field");
+
+            // BUG: xw-305: Let validator be parsed first and hence added to 
+            // the beginning of list and therefore evaluated first, so short-circuting
+            // it will not cause field-leve validator to be kicked off.
+            {NodeList validatorNodes = doc.getElementsByTagName("validator");
+            addValidatorConfigs(validatorFactory, validatorNodes, new HashMap(), validatorCfgs);}
+
+            for (int i = 0; i < fieldNodes.getLength(); i++) {
+                Element fieldElement = (Element) fieldNodes.item(i);
+                String fieldName = fieldElement.getAttribute("name");
+                Map extraParams = new HashMap();
+                extraParams.put("fieldName", fieldName);
+
+                NodeList validatorNodes = fieldElement.getElementsByTagName("field-validator");
+                addValidatorConfigs(validatorFactory, validatorNodes, extraParams, validatorCfgs);
+            }
+        }
+
+        return validatorCfgs;
+    }
+
+    
+    public void parseValidatorDefinitions(Map<String,String> validators, InputStream is, String resourceName) {
+
+        InputSource in = new InputSource(is);
+        in.setSystemId(resourceName);
+            
+        Map dtdMappings = new HashMap();
+        dtdMappings.put("-//OpenSymphony Group//XWork Validator Config 1.0//EN", "xwork-validator-config-1.0.dtd");
+
+        Document doc = DomHelper.parse(in, dtdMappings);
+
+        if (doc != null) {
+            NodeList nodes = doc.getElementsByTagName("validator");
+            
+            for (int i = 0; i < nodes.getLength(); i++) {
+                Element validatorElement = (Element) nodes.item(i);
+                String name = validatorElement.getAttribute("name");
+                String className = validatorElement.getAttribute("class");
+
+                try {
+                    // catch any problems here
+                    objectFactory.buildValidator(className, new HashMap(), null);
+                    validators.put(name, className);
+                } catch (Exception e) {
+                    throw new ConfigurationException("Unable to load validator class " + className, e, validatorElement);
+                }
+            }
+        }
+    }
+
+    /**
+     * Extract trimmed text value from the given DOM element, ignoring XML comments. Appends all CharacterData nodes
+     * and EntityReference nodes into a single String value, excluding Comment nodes.
+     * This method is based on a method originally found in DomUtils class of Springframework.
+     *
+     * @see org.w3c.dom.CharacterData
+     * @see org.w3c.dom.EntityReference
+     * @see org.w3c.dom.Comment
+     */
+    public static String getTextValue(Element valueEle) {
+        StringBuffer value = new StringBuffer();
+        NodeList nl = valueEle.getChildNodes();
+        boolean firstCDataFound = false;
+        for (int i = 0; i < nl.getLength(); i++) {
+            Node item = nl.item(i);
+            if ((item instanceof CharacterData && !(item instanceof Comment)) || item instanceof EntityReference) {
+                final String nodeValue = item.getNodeValue();
+                if (nodeValue != null) {
+                    if (firstCDataFound) {
+                        value.append(MULTI_TEXTVALUE_SEPARATOR);
+                    } else {
+                        firstCDataFound = true;
+                    }
+                    value.append(nodeValue.trim());
+                }
+            }
+        }
+        return value.toString().trim();
+    }
+
+    private void addValidatorConfigs(ValidatorFactory factory, NodeList validatorNodes, Map extraParams, List validatorCfgs) {
+        for (int j = 0; j < validatorNodes.getLength(); j++) {
+            Element validatorElement = (Element) validatorNodes.item(j);
+            String validatorType = validatorElement.getAttribute("type");
+            Map params = new HashMap(extraParams);
+            NodeList paramNodes = validatorElement.getElementsByTagName("param");
+
+            for (int k = 0; k < paramNodes.getLength(); k++) {
+                Element paramElement = (Element) paramNodes.item(k);
+                String paramName = paramElement.getAttribute("name");
+                params.put(paramName, getTextValue(paramElement));
+            }
+
+            // ensure that the type is valid...
+            try {
+                factory.lookupRegisteredValidatorType(validatorType);
+            } catch (IllegalArgumentException ex) {
+                throw new ConfigurationException("Invalid validation type: "+validatorType, validatorElement);
+            }
+
+            ValidatorConfig.Builder vCfg = new ValidatorConfig.Builder(validatorType)
+                    .addParams(params)
+                    .location(DomHelper.getLocationObject(validatorElement))
+                    .shortCircuit(Boolean.valueOf(validatorElement.getAttribute("short-circuit")).booleanValue());
+
+            NodeList messageNodes = validatorElement.getElementsByTagName("message");
+            Element messageElement = (Element) messageNodes.item(0);
+            String key = messageElement.getAttribute("key");
+
+
+            if ((key != null) && (key.trim().length() > 0)) {
+                vCfg.messageKey(key);
+            }
+
+            final Node defaultMessageNode = messageElement.getFirstChild();
+            String defaultMessage = (defaultMessageNode == null) ? "" : defaultMessageNode.getNodeValue();
+            vCfg.defaultMessage(defaultMessage);
+            validatorCfgs.add(vCfg.build());
+        }
+    }
+}

File src/java/com/opensymphony/xwork2/validator/Validator.java

  */
 package com.opensymphony.xwork2.validator;
 
+import com.opensymphony.xwork2.util.ValueStack;
+
 
 /**
  * <!-- START SNIPPET: validatorFlavours -->
      */
     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);
+
 }

File src/java/com/opensymphony/xwork2/validator/ValidatorConfig.java

 package com.opensymphony.xwork2.validator;
 
 import java.util.Map;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+
 import com.opensymphony.xwork2.util.location.Located;
+import com.opensymphony.xwork2.util.location.Location;
 
 /**
  * Holds the necessary information for configuring an instance of a Validator.
     private String messageKey;
     private boolean shortCircuit;
     
-    public ValidatorConfig() {
-    }
-    
     /**
      * @param validatorType
-     * @param params
      */
-    public ValidatorConfig(String validatorType, Map params) {
+    protected ValidatorConfig(String validatorType) {
         this.type = validatorType;
-        this.params = params;
+        params = new LinkedHashMap();
+    }
+
+    protected ValidatorConfig(ValidatorConfig orig) {
+        this.type = orig.type;
+        this.params = new LinkedHashMap<String,String>(orig.params);
+        this.defaultMessage = orig.defaultMessage;
+        this.messageKey = orig.messageKey;
+        this.shortCircuit = orig.shortCircuit;
     }
     
     /**
     }
     
     /**
-     * @param defaultMessage The defaultMessage to set on the validator.
-     */
-    public void setDefaultMessage(String defaultMessage) {
-        this.defaultMessage = defaultMessage;
-    }
-    
-    /**
      * @return Returns the messageKey for the validator.
      */
     public String getMessageKey() {
     }
     
     /**
-     * @param messageKey The messageKey to set on the validator.
-     */
-    public void setMessageKey(String messageKey) {
-        this.messageKey = messageKey;
-    }
-    
-    /**
      * @return Returns wether the shortCircuit flag should be set on the 
      * validator.
      */
     }
     
     /**
-     * @param shortCircuit Whether the validator's shortCircuit flag should 
-     * be set.
-     */
-    public void setShortCircuit(boolean shortCircuit) {
-        this.shortCircuit = shortCircuit;
-    }
-
-    /**
      * @return Returns the configured params to set on the validator. 
      */
     public Map getParams() {
     }
     
     /**
-     * @param params The configured params to set on the validator.
-     */
-    public void setParams(Map params) {
-        this.params = params;
-    }
-    
-    /**
      * @return Returns the type of validator to configure.
      */
     public String getType() {
         return type;
     }
-    
+
     /**
-     * @param validatorType The type of validator to configure.
+     * Builds a ValidatorConfig
      */
-    public void setType(String validatorType) {
-        this.type = validatorType;
+    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) {
+            target.defaultMessage = msg;
+            return this;
+        }
+
+        public Builder messageKey(String key) {
+            if ((key != null) && (key.trim().length() > 0)) {
+                target.messageKey = key;
+            }
+            return this;
+        }
+
+        public Builder addParam(String name, String value) {
+            if (value != null && name != null) {
+                target.params.put(name, value);
+            }
+            return this;
+        }
+
+        public Builder addParams(Map<String,String> params) {
+            target.params.putAll(params);
+            return this;
+        }
+
+        public Builder location(Location loc) {
+            target.location = loc;
+            return this;
+        }
+
+        public ValidatorConfig build() {
+            target.params = Collections.unmodifiableMap(target.params);
+            ValidatorConfig result = target;
+            target = new ValidatorConfig(target);
+            return result;
+        }
+
+        public Builder removeParam(String key) {
+            target.params.remove(key);
+            return this;
+        }
     }
 }

File src/java/com/opensymphony/xwork2/validator/ValidatorFactory.java

-/*
- * Copyright (c) 2002-2006 by OpenSymphony
- * All rights reserved.
- */
 package com.opensymphony.xwork2.validator;
 
-import java.io.File;
-import java.io.FilenameFilter;
-import java.io.InputStream;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.util.HashMap;
-import java.util.Map;
-
-import com.opensymphony.xwork2.ObjectFactory;
-import com.opensymphony.xwork2.XWorkException;
-import com.opensymphony.xwork2.util.ClassLoaderUtil;
-import com.opensymphony.xwork2.util.logging.Logger;
-import com.opensymphony.xwork2.util.logging.LoggerFactory;
-
+import com.opensymphony.xwork2.inject.Inject;
 
 /**
  * ValidatorFactory
  * <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 
+ * 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
  *    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>
  * @author Jason Carreira
  * @author James House
  */
-public class ValidatorFactory {
+public interface ValidatorFactory {
 
-    private static Map<String, String> validators = new HashMap<String, String>();
-    private static Logger LOG = LoggerFactory.getLogger(ValidatorFactory.class);
-
-    static {
-        parseValidators();
-    }
-
-    private ValidatorFactory() {
-    }
     /**