diff --git a/core/src/main/java/com/opensymphony/xwork2/validator/AbstractActionValidatorManager.java b/core/src/main/java/com/opensymphony/xwork2/validator/AbstractActionValidatorManager.java deleted file mode 100644 index 1fee8bd69..000000000 --- a/core/src/main/java/com/opensymphony/xwork2/validator/AbstractActionValidatorManager.java +++ /dev/null @@ -1,289 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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.FileManager; -import com.opensymphony.xwork2.FileManagerFactory; -import com.opensymphony.xwork2.TextProviderFactory; -import com.opensymphony.xwork2.inject.Inject; -import com.opensymphony.xwork2.util.ClassLoaderUtil; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.apache.struts2.StrutsConstants; - -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeSet; - -import static java.util.Collections.synchronizedMap; - -public abstract class AbstractActionValidatorManager implements ActionValidatorManager { - - /** - * The file suffix for any validation file. - */ - protected static final String VALIDATION_CONFIG_SUFFIX = "-validation.xml"; - - protected final Map> validatorCache = synchronizedMap(new HashMap<>()); - protected final Map> validatorFileCache = synchronizedMap(new HashMap<>()); - private static final Logger LOG = LogManager.getLogger(AbstractActionValidatorManager.class); - - protected ValidatorFactory validatorFactory; - protected ValidatorFileParser validatorFileParser; - protected FileManager fileManager; - protected boolean reloadingConfigs; - protected TextProviderFactory textProviderFactory; - - @Inject - public void setValidatorFactory(ValidatorFactory fac) { - this.validatorFactory = fac; - } - - @Inject - public void setValidatorFileParser(ValidatorFileParser parser) { - this.validatorFileParser = parser; - } - - @Inject - public void setFileManagerFactory(FileManagerFactory fileManagerFactory) { - this.fileManager = fileManagerFactory.getFileManager(); - } - - @Inject(value = StrutsConstants.STRUTS_CONFIGURATION_XML_RELOAD, required = false) - public void setReloadingConfigs(String reloadingConfigs) { - this.reloadingConfigs = Boolean.parseBoolean(reloadingConfigs); - } - - @Inject - public void setTextProviderFactory(TextProviderFactory textProviderFactory) { - this.textProviderFactory = textProviderFactory; - } - - @Override - public void validate(Object object, String context) throws ValidationException { - validate(object, context, (String) null); - } - - @Override - public void validate(Object object, String context, String method) throws ValidationException { - ValidatorContext validatorContext = new DelegatingValidatorContext(object, textProviderFactory); - validate(object, context, validatorContext, method); - } - - @Override - public void validate(Object object, String context, ValidatorContext validatorContext) throws ValidationException { - validate(object, context, validatorContext, null); - } - - @Override - public void validate(Object object, String context, ValidatorContext validatorContext, String method) throws ValidationException { - List validators = getValidators(object.getClass(), context, method); - Set shortcircuitedFields = null; - - for (Validator validator : validators) { - try { - validator.setValidatorContext(validatorContext); - - LOG.debug("Running validator: {} for object {} and method {}", validator, object, method); - - FieldValidator fValidator = null; - String fullFieldName = null; - - if (validator instanceof FieldValidator) { - fValidator = (FieldValidator) validator; - fullFieldName = fValidator.getValidatorContext().getFullFieldName(fValidator.getFieldName()); - - if ((shortcircuitedFields != null) && shortcircuitedFields.contains(fullFieldName)) { - LOG.debug("Short-circuited, skipping"); - continue; - } - } - - if (validator instanceof ShortCircuitableValidator && ((ShortCircuitableValidator) validator).isShortCircuit()) { - // get number of existing errors - List errs = null; - - if (fValidator != null) { - if (validatorContext.hasFieldErrors()) { - Collection fieldErrors = validatorContext.getFieldErrors().get(fullFieldName); - - if (fieldErrors != null) { - errs = new ArrayList<>(fieldErrors); - } - } - } else if (validatorContext.hasActionErrors()) { - Collection actionErrors = validatorContext.getActionErrors(); - - if (actionErrors != null) { - errs = new ArrayList<>(actionErrors); - } - } - - validator.validate(object); - - if (fValidator != null) { - if (validatorContext.hasFieldErrors()) { - Collection errCol = validatorContext.getFieldErrors().get(fullFieldName); - - if ((errCol != null) && !errCol.equals(errs)) { - LOG.debug("Short-circuiting on field validation"); - - if (shortcircuitedFields == null) { - shortcircuitedFields = new TreeSet<>(); - } - - shortcircuitedFields.add(fullFieldName); - } - } - } else if (validatorContext.hasActionErrors()) { - Collection errCol = validatorContext.getActionErrors(); - - if ((errCol != null) && !errCol.equals(errs)) { - LOG.debug("Short-circuiting"); - break; - } - } - - continue; - } - - validator.validate(object); - } finally { - validator.setValidatorContext(null); - } - - } - } - - /** - *

This method 'collects' all the validator configurations for a given - * action invocation.

- * - *

It will traverse up the class hierarchy looking for validators for every super class - * and directly implemented interface of the current action, as well as adding validators for - * any alias of this invocation. Nifty!

- * - *

Given the following class structure:

- *
-     *   interface Thing;
-     *   interface Animal extends Thing;
-     *   interface Quadraped extends Animal;
-     *   class AnimalImpl implements Animal;
-     *   class QuadrapedImpl extends AnimalImpl implements Quadraped;
-     *   class Dog extends QuadrapedImpl;
-     * 
- * - *

This method will look for the following config files for Dog:

- *
-     *   Animal
-     *   Animal-context
-     *   AnimalImpl
-     *   AnimalImpl-context
-     *   Quadraped
-     *   Quadraped-context
-     *   QuadrapedImpl
-     *   QuadrapedImpl-context
-     *   Dog
-     *   Dog-context
-     * 
- * - *

Note that the validation rules for Thing is never looked for because no class in the - * hierarchy directly implements Thing.

- * - * @param clazz the Class to look up validators for. - * @param context the context to use when looking up validators. - * @param checkFile true if the validation config file should be checked to see if it has been - * updated. - * @param checked the set of previously checked class-contexts, null if none have been checked - * @return a list of validator configs for the given class and context. - */ - protected List buildValidatorConfigs(Class clazz, String context, boolean checkFile, Set checked) { - List validatorConfigs = new ArrayList<>(); - - if (checked == null) { - checked = new TreeSet<>(); - } else if (checked.contains(clazz.getName())) { - return validatorConfigs; - } - - if (clazz.isInterface()) { - for (Class anInterface : clazz.getInterfaces()) { - validatorConfigs.addAll(buildValidatorConfigs(anInterface, context, checkFile, checked)); - } - } else { - if (!clazz.equals(Object.class)) { - validatorConfigs.addAll(buildValidatorConfigs(clazz.getSuperclass(), context, checkFile, checked)); - } - } - - // look for validators for implemented interfaces - for (Class anInterface1 : clazz.getInterfaces()) { - if (checked.contains(anInterface1.getName())) { - continue; - } - validatorConfigs.addAll(buildClassValidatorConfigs(anInterface1, checkFile)); - if (context != null) { - validatorConfigs.addAll(buildAliasValidatorConfigs(anInterface1, context, checkFile)); - } - checked.add(anInterface1.getName()); - } - - validatorConfigs.addAll(buildClassValidatorConfigs(clazz, checkFile)); - if (context != null) { - validatorConfigs.addAll(buildAliasValidatorConfigs(clazz, context, checkFile)); - } - checked.add(clazz.getName()); - - return validatorConfigs; - } - - protected abstract List buildAliasValidatorConfigs(Class aClass, String context, boolean checkFile); - - protected abstract List buildClassValidatorConfigs(Class aClass, boolean checkFile); - - protected List loadFile(String fileName, Class clazz, boolean checkFile) { - List retList = Collections.emptyList(); - - URL fileUrl = ClassLoaderUtil.getResource(fileName, clazz); - - if ((checkFile && fileManager.fileNeedsReloading(fileUrl)) || !validatorFileCache.containsKey(fileName)) { - try (InputStream is = fileManager.loadFile(fileUrl)) { - if (is != null) { - retList = new ArrayList<>(validatorFileParser.parseActionValidatorConfigs(validatorFactory, is, fileName)); - } - } catch (IOException e) { - LOG.error("Caught exception while closing file {}", fileName, e); - } - - validatorFileCache.put(fileName, retList); - } else { - retList = validatorFileCache.get(fileName); - } - - return retList; - } -} diff --git a/core/src/main/java/com/opensymphony/xwork2/validator/AnnotationActionValidatorManager.java b/core/src/main/java/com/opensymphony/xwork2/validator/AnnotationActionValidatorManager.java index bab8f6ce3..260c0c5e2 100644 --- a/core/src/main/java/com/opensymphony/xwork2/validator/AnnotationActionValidatorManager.java +++ b/core/src/main/java/com/opensymphony/xwork2/validator/AnnotationActionValidatorManager.java @@ -22,10 +22,7 @@ import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.ActionProxy; import com.opensymphony.xwork2.config.entities.ActionConfig; -import com.opensymphony.xwork2.util.ValueStack; import org.apache.commons.lang3.StringUtils; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; import java.util.ArrayList; import java.util.List; @@ -37,56 +34,9 @@ import java.util.List; * @author Rainer Hermanns * @author jepjep */ -public class AnnotationActionValidatorManager extends AbstractActionValidatorManager { - - private static final Logger LOG = LogManager.getLogger(AnnotationActionValidatorManager.class); +public class AnnotationActionValidatorManager extends DefaultActionValidatorManager { @Override - public List getValidators(Class clazz, String context) { - return getValidators(clazz, context, null); - } - - @Override - public List getValidators(Class clazz, String context, String method) { - String validatorKey = buildValidatorKey(clazz, context); - - if (validatorCache.containsKey(validatorKey)) { - if (reloadingConfigs) { - validatorCache.put(validatorKey, buildValidatorConfigs(clazz, context, true, null)); - } - } else { - validatorCache.put(validatorKey, buildValidatorConfigs(clazz, context, false, null)); - } - - // get the set of validator configs - List cfgs = new ArrayList<>(validatorCache.get(validatorKey)); - - ValueStack stack = ActionContext.getContext().getValueStack(); - - // create clean instances of the validators for the caller's use - ArrayList validators = new ArrayList<>(cfgs.size()); - for (ValidatorConfig cfg : cfgs) { - if (method == null || method.equals(cfg.getParams().get("methodName"))) { - Validator validator = validatorFactory.getValidator( - new ValidatorConfig.Builder(cfg) - .removeParam("methodName") - .build()); - validator.setValidatorType(cfg.getType()); - validator.setValueStack(stack); - validators.add(validator); - } - } - - return validators; - } - - /** - * Builds a key for validators - used when caching validators. - * - * @param clazz the action. - * @param context context - * @return a validator key which is the class name plus context. - */ protected String buildValidatorKey(Class clazz, String context) { ActionInvocation invocation = ActionContext.getContext().getActionInvocation(); ActionProxy proxy = invocation.getProxy(); @@ -98,20 +48,11 @@ public class AnnotationActionValidatorManager extends AbstractActionValidatorMan sb.append(config.getPackageName()); sb.append("/"); } - - // the key needs to use the name of the action from the config file, - // instead of the url, so wild card actions will have the same validator - // see WW-2996 - - // UPDATE: - // WW-3753 Using the config name instead of the context only for - // wild card actions to keep the flexibility provided - // by the original design (such as mapping different contexts - // to the same action and method if desired) - - // UPDATE: - // WW-4536 Using NameVariablePatternMatcher allows defines actions - // with patterns enclosed with '{}', it's similar case to WW-3753 + // WW-2996: key needs to use the name of the action from the config file, instead of the url, + // so wildcard actions will have the same validator + // WW-3753: Using the config name instead of the context only for wildcard actions to keep the flexibility + // provided by the original design (such as mapping different contexts to the same action and method if desired) + // WW-4536: Using NamedVariablePatternMatcher allows defines actions with patterns enclosed with '{}' String configName = config.getName(); if (configName.contains(ActionConfig.WILDCARD) || (configName.contains("{") && configName.contains("}"))) { sb.append(configName); @@ -120,7 +61,6 @@ public class AnnotationActionValidatorManager extends AbstractActionValidatorMan } else { sb.append(context); } - return sb.toString(); } diff --git a/core/src/main/java/com/opensymphony/xwork2/validator/DefaultActionValidatorManager.java b/core/src/main/java/com/opensymphony/xwork2/validator/DefaultActionValidatorManager.java index f37c1785b..3af54669e 100644 --- a/core/src/main/java/com/opensymphony/xwork2/validator/DefaultActionValidatorManager.java +++ b/core/src/main/java/com/opensymphony/xwork2/validator/DefaultActionValidatorManager.java @@ -19,12 +19,29 @@ package com.opensymphony.xwork2.validator; import com.opensymphony.xwork2.ActionContext; +import com.opensymphony.xwork2.FileManager; +import com.opensymphony.xwork2.FileManagerFactory; +import com.opensymphony.xwork2.TextProviderFactory; +import com.opensymphony.xwork2.inject.Inject; +import com.opensymphony.xwork2.util.ClassLoaderUtil; import com.opensymphony.xwork2.util.ValueStack; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.apache.struts2.StrutsConstants; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + +import static java.util.Collections.synchronizedMap; /** *

@@ -43,9 +60,102 @@ import java.util.List; * @author James House * @author Rainer Hermanns */ -public class DefaultActionValidatorManager extends AbstractActionValidatorManager { +public class DefaultActionValidatorManager implements ActionValidatorManager { - private final static Logger LOG = LogManager.getLogger(DefaultActionValidatorManager.class); + /** + * The file suffix for any validation file. + */ + protected static final String VALIDATION_CONFIG_SUFFIX = "-validation.xml"; + + protected final Map> validatorCache = synchronizedMap(new HashMap<>()); + protected final Map> validatorFileCache = synchronizedMap(new HashMap<>()); + private static final Logger LOG = LogManager.getLogger(DefaultActionValidatorManager.class); + + protected ValidatorFactory validatorFactory; + protected ValidatorFileParser validatorFileParser; + protected FileManager fileManager; + protected boolean reloadingConfigs; + protected TextProviderFactory textProviderFactory; + + @Inject + public void setValidatorFactory(ValidatorFactory fac) { + this.validatorFactory = fac; + } + + @Inject + public void setValidatorFileParser(ValidatorFileParser parser) { + this.validatorFileParser = parser; + } + + @Inject + public void setFileManagerFactory(FileManagerFactory fileManagerFactory) { + this.fileManager = fileManagerFactory.getFileManager(); + } + + @Inject(value = StrutsConstants.STRUTS_CONFIGURATION_XML_RELOAD, required = false) + public void setReloadingConfigs(String reloadingConfigs) { + this.reloadingConfigs = Boolean.parseBoolean(reloadingConfigs); + } + + @Inject + public void setTextProviderFactory(TextProviderFactory textProviderFactory) { + this.textProviderFactory = textProviderFactory; + } + + @Override + public void validate(Object object, String context) throws ValidationException { + validate(object, context, (String) null); + } + + @Override + public void validate(Object object, String context, String method) throws ValidationException { + ValidatorContext validatorContext = new DelegatingValidatorContext(object, textProviderFactory); + validate(object, context, validatorContext, method); + } + + @Override + public void validate(Object object, String context, ValidatorContext validatorContext) throws ValidationException { + validate(object, context, validatorContext, null); + } + + /** + * Builds a key for validators - used when caching validators. + * + * @param clazz the action. + * @param context context + * @return a validator key which is the class name plus context. + */ + protected String buildValidatorKey(Class clazz, String context) { + return clazz.getName() + "/" + context; + } + + protected Validator getValidatorFromValidatorConfig(ValidatorConfig config, ValueStack stack) { + Validator validator = validatorFactory.getValidator(config); + validator.setValidatorType(config.getType()); + validator.setValueStack(stack); + return validator; + } + + @Override + public synchronized List getValidators(Class clazz, String context, String method) { + String validatorKey = buildValidatorKey(clazz, context); + + if (!validatorCache.containsKey(validatorKey)) { + validatorCache.put(validatorKey, buildValidatorConfigs(clazz, context, false, null)); + } else if (reloadingConfigs) { + validatorCache.put(validatorKey, buildValidatorConfigs(clazz, context, true, null)); + } + + ValueStack stack = ActionContext.getContext().getValueStack(); + List configs = validatorCache.get(validatorKey); + List validators = new ArrayList<>(); + for (ValidatorConfig config : configs) { + if (method == null || method.equals(config.getParams().get("methodName"))) { + validators.add(getValidatorFromValidatorConfig(config, stack)); + } + } + return validators; + } @Override public synchronized List getValidators(Class clazz, String context) { @@ -53,54 +163,189 @@ public class DefaultActionValidatorManager extends AbstractActionValidatorManage } @Override - public synchronized List getValidators(Class clazz, String context, String method) { - String validatorKey = buildValidatorKey(clazz, context); + public void validate(Object object, String context, ValidatorContext validatorContext, String method) throws ValidationException { + List validators = getValidators(object.getClass(), context, method); + Set shortcircuitedFields = null; - if (validatorCache.containsKey(validatorKey)) { - if (reloadingConfigs) { - validatorCache.put(validatorKey, buildValidatorConfigs(clazz, context, true, null)); + for (Validator validator : validators) { + validator.setValidatorContext(validatorContext); + + LOG.debug("Running validator: {} for object {} and method {}", validator, object, method); + + FieldValidator fValidator = null; + String fullFieldName = null; + + if (validator instanceof FieldValidator) { + fValidator = (FieldValidator) validator; + fullFieldName = validatorContext.getFullFieldName(fValidator.getFieldName()); + + if ((shortcircuitedFields != null) && shortcircuitedFields.contains(fullFieldName)) { + LOG.debug("Short-circuited, skipping"); + continue; + } } - } else { - validatorCache.put(validatorKey, buildValidatorConfigs(clazz, context, false, null)); - } - ValueStack stack = ActionContext.getContext().getValueStack(); - // get the set of validator configs - List cfgs = validatorCache.get(validatorKey); + if (validator instanceof ShortCircuitableValidator && ((ShortCircuitableValidator) validator).isShortCircuit()) { + // get number of existing errors + List errs = null; - // create clean instances of the validators for the caller's use - ArrayList validators = new ArrayList<>(cfgs.size()); - for (ValidatorConfig cfg : cfgs) { - if (method == null || method.equals(cfg.getParams().get("methodName"))) { - Validator validator = validatorFactory.getValidator(cfg); - validator.setValidatorType(cfg.getType()); - validator.setValueStack(stack); - validators.add(validator); + if (fValidator != null) { + if (validatorContext.hasFieldErrors()) { + Collection fieldErrors = validatorContext.getFieldErrors().get(fullFieldName); + + if (fieldErrors != null) { + errs = new ArrayList<>(fieldErrors); + } + } + } else if (validatorContext.hasActionErrors()) { + Collection actionErrors = validatorContext.getActionErrors(); + + if (actionErrors != null) { + errs = new ArrayList<>(actionErrors); + } + } + + validator.validate(object); + + if (fValidator != null) { + if (validatorContext.hasFieldErrors()) { + Collection errCol = validatorContext.getFieldErrors().get(fullFieldName); + + if ((errCol != null) && !errCol.equals(errs)) { + LOG.debug("Short-circuiting on field validation"); + + if (shortcircuitedFields == null) { + shortcircuitedFields = new TreeSet<>(); + } + + shortcircuitedFields.add(fullFieldName); + } + } + } else if (validatorContext.hasActionErrors()) { + Collection errCol = validatorContext.getActionErrors(); + + if ((errCol != null) && !errCol.equals(errs)) { + LOG.debug("Short-circuiting"); + break; + } + } + continue; } + validator.validate(object); } - return validators; } /** - * Builds a key for validators - used when caching validators. + *

This method 'collects' all the validator configurations for a given + * action invocation.

* - * @param clazz the action. - * @param context the action's context. - * @return a validator key which is the class name plus context. + *

It will traverse up the class hierarchy looking for validators for every super class + * and directly implemented interface of the current action, as well as adding validators for + * any alias of this invocation. Nifty!

+ * + *

Given the following class structure:

+ *
+     *   interface Thing;
+     *   interface Animal extends Thing;
+     *   interface Quadraped extends Animal;
+     *   class AnimalImpl implements Animal;
+     *   class QuadrapedImpl extends AnimalImpl implements Quadraped;
+     *   class Dog extends QuadrapedImpl;
+     * 
+ * + *

This method will look for the following config files for Dog:

+ *
+     *   Animal
+     *   Animal-context
+     *   AnimalImpl
+     *   AnimalImpl-context
+     *   Quadraped
+     *   Quadraped-context
+     *   QuadrapedImpl
+     *   QuadrapedImpl-context
+     *   Dog
+     *   Dog-context
+     * 
+ * + *

Note that the validation rules for Thing is never looked for because no class in the + * hierarchy directly implements Thing.

+ * + * @param clazz the Class to look up validators for. + * @param context the context to use when looking up validators. + * @param checkFile true if the validation config file should be checked to see if it has been + * updated. + * @param checked the set of previously checked class-contexts, null if none have been checked + * @return a list of validator configs for the given class and context. */ - protected static String buildValidatorKey(Class clazz, String context) { - return clazz.getName() + "/" + context; + protected List buildValidatorConfigs(Class clazz, String context, boolean checkFile, Set checked) { + List validatorConfigs = new ArrayList<>(); + + if (checked == null) { + checked = new TreeSet<>(); + } else if (checked.contains(clazz.getName())) { + return validatorConfigs; + } + + if (clazz.isInterface()) { + for (Class anInterface : clazz.getInterfaces()) { + validatorConfigs.addAll(buildValidatorConfigs(anInterface, context, checkFile, checked)); + } + } else { + if (!clazz.equals(Object.class)) { + validatorConfigs.addAll(buildValidatorConfigs(clazz.getSuperclass(), context, checkFile, checked)); + } + } + + // look for validators for implemented interfaces + for (Class anInterface1 : clazz.getInterfaces()) { + if (checked.contains(anInterface1.getName())) { + continue; + } + validatorConfigs.addAll(buildClassValidatorConfigs(anInterface1, checkFile)); + if (context != null) { + validatorConfigs.addAll(buildAliasValidatorConfigs(anInterface1, context, checkFile)); + } + checked.add(anInterface1.getName()); + } + + validatorConfigs.addAll(buildClassValidatorConfigs(clazz, checkFile)); + if (context != null) { + validatorConfigs.addAll(buildAliasValidatorConfigs(clazz, context, checkFile)); + } + checked.add(clazz.getName()); + + return validatorConfigs; } - @Override protected List buildAliasValidatorConfigs(Class aClass, String context, boolean checkFile) { String fileName = aClass.getName().replace('.', '/') + "-" + context + VALIDATION_CONFIG_SUFFIX; return loadFile(fileName, aClass, checkFile); } - @Override protected List buildClassValidatorConfigs(Class aClass, boolean checkFile) { String fileName = aClass.getName().replace('.', '/') + VALIDATION_CONFIG_SUFFIX; return loadFile(fileName, aClass, checkFile); } + + protected List loadFile(String fileName, Class clazz, boolean checkFile) { + List retList = Collections.emptyList(); + + URL fileUrl = ClassLoaderUtil.getResource(fileName, clazz); + + if ((checkFile && fileManager.fileNeedsReloading(fileUrl)) || !validatorFileCache.containsKey(fileName)) { + try (InputStream is = fileManager.loadFile(fileUrl)) { + if (is != null) { + retList = new ArrayList<>(validatorFileParser.parseActionValidatorConfigs(validatorFactory, is, fileName)); + } + } catch (IOException e) { + LOG.error("Caught exception while closing file {}", fileName, e); + } + + validatorFileCache.put(fileName, retList); + } else { + retList = validatorFileCache.get(fileName); + } + + return retList; + } } diff --git a/core/src/test/java/com/opensymphony/xwork2/validator/DefaultActionValidatorManagerTest.java b/core/src/test/java/com/opensymphony/xwork2/validator/DefaultActionValidatorManagerTest.java index b320febc9..233952c89 100644 --- a/core/src/test/java/com/opensymphony/xwork2/validator/DefaultActionValidatorManagerTest.java +++ b/core/src/test/java/com/opensymphony/xwork2/validator/DefaultActionValidatorManagerTest.java @@ -44,7 +44,7 @@ import java.util.List; * DefaultActionValidatorManagerTest * * @author Jason Carreira - * @author tm_jee + * @author tm_jee * @version $Date$ $Id$ */ public class DefaultActionValidatorManagerTest extends XWorkTestCase { @@ -87,7 +87,7 @@ public class DefaultActionValidatorManagerTest extends XWorkTestCase { public void testBuildValidatorKey() { - String validatorKey = DefaultActionValidatorManager.buildValidatorKey(SimpleAction.class, alias); + String validatorKey = actionValidatorManager.buildValidatorKey(SimpleAction.class, alias); assertEquals(SimpleAction.class.getName() + "/" + alias, validatorKey); } @@ -239,7 +239,7 @@ public class DefaultActionValidatorManagerTest extends XWorkTestCase { user.setName("Mark"); // * mark both email to starts with mark to get pass the action-level validator, // so we could concentrate on testing the field-level validators (User-validation.xml) - // * make both email the same to pass the action-level validator at + // * make both email the same to pass the action-level validator at // UserMarker-validation.xml user.setEmail("mark_bad_email_for_field_val@foo.com"); user.setEmail2("mark_bad_email_for_field_val@foo.com"); @@ -255,51 +255,51 @@ public class DefaultActionValidatorManagerTest extends XWorkTestCase { assertEquals(1, l.size()); // because email-field-val is short-circuit assertEquals("Email not from the right company.", l.get(0)); - + // check action errors l = (List) context.getActionErrors(); assertFalse(context.hasActionErrors()); assertEquals(0, l.size()); - - + + } catch (ValidationException ex) { ex.printStackTrace(); fail("Validation error: " + ex.getMessage()); } } - + public void testActionLevelShortCircuit() throws Exception { - + List validatorList = actionValidatorManager.getValidators(User.class, null); assertEquals(10, validatorList.size()); - + User user = new User(); // all fields will trigger error, but sc of action-level, cause it to not appear - user.setName(null); + user.setName(null); user.setEmail("tmjee(at)yahoo.co.uk"); user.setEmail("tm_jee(at)yahoo.co.uk"); - + ValidatorContext context = new GenericValidatorContext(user); actionValidatorManager.validate(user, null, context); - + // check field level errors // shouldn't have any because action error prevents validation of anything else List l = (List) context.getFieldErrors().get("email2"); assertNull(l); - - + + // check action errors assertTrue(context.hasActionErrors()); l = (List) context.getActionErrors(); assertNotNull(l); // we only get one, because UserMarker-validation.xml action-level validator // already sc it :-) - assertEquals(1, l.size()); + assertEquals(1, l.size()); assertEquals("Email not the same as email2", l.get(0)); } - - + + public void testShortCircuitNoErrors() { // get validators List validatorList = actionValidatorManager.getValidators(User.class, null); @@ -319,65 +319,65 @@ public class DefaultActionValidatorManagerTest extends XWorkTestCase { fail("Validation error: " + ex.getMessage()); } } - + public void testFieldErrorsOrder() throws Exception { ValidationOrderAction action = new ValidationOrderAction(); actionValidatorManager.validate(action, "actionContext"); Map fieldErrors = action.getFieldErrors(); Iterator i = fieldErrors.entrySet().iterator(); - + assertNotNull(fieldErrors); assertEquals(fieldErrors.size(), 12); - - + + Map.Entry e = (Map.Entry) i.next(); assertEquals(e.getKey(), "username"); assertEquals(((List)e.getValue()).get(0), "username required"); - + e = (Map.Entry) i.next(); assertEquals(e.getKey(), "password"); assertEquals(((List)e.getValue()).get(0), "password required"); - + e = (Map.Entry) i.next(); assertEquals(e.getKey(), "confirmPassword"); assertEquals(((List)e.getValue()).get(0), "confirm password required"); - + e = (Map.Entry) i.next(); assertEquals(e.getKey(), "firstName"); assertEquals(((List)e.getValue()).get(0), "first name required"); - + e = (Map.Entry) i.next(); assertEquals(e.getKey(), "lastName"); assertEquals(((List)e.getValue()).get(0), "last name required"); - + e = (Map.Entry) i.next(); assertEquals(e.getKey(), "city"); assertEquals(((List)e.getValue()).get(0), "city is required"); - + e = (Map.Entry) i.next(); assertEquals(e.getKey(), "province"); assertEquals(((List)e.getValue()).get(0), "province is required"); - + e = (Map.Entry) i.next(); assertEquals(e.getKey(), "country"); assertEquals(((List)e.getValue()).get(0), "country is required"); - + e = (Map.Entry) i.next(); assertEquals(e.getKey(), "postalCode"); assertEquals(((List)e.getValue()).get(0), "postal code is required"); - + e = (Map.Entry) i.next(); assertEquals(e.getKey(), "email"); assertEquals(((List)e.getValue()).get(0), "email is required"); - + e = (Map.Entry) i.next(); assertEquals(e.getKey(), "website"); assertEquals(((List)e.getValue()).get(0), "website is required"); - + e = (Map.Entry) i.next(); assertEquals(e.getKey(), "passwordHint"); assertEquals(((List)e.getValue()).get(0), "password hint is required"); - + } */ }