From 9b90df1812421817702230cc51d6e00a69d47aed Mon Sep 17 00:00:00 2001 From: Ben Alex Date: Wed, 6 Apr 2005 06:37:42 +0000 Subject: [PATCH] Refactor to allow IntrospectionManagers to query a shared Validator map. --- .../validation/ValidationManagerImpl.java | 54 ++----- .../validation/ValidationRegistryManager.java | 50 +++++++ .../ValidationRegistryManagerImpl.java | 137 ++++++++++++++++++ 3 files changed, 203 insertions(+), 38 deletions(-) create mode 100644 domain/src/main/java/org/acegisecurity/domain/validation/ValidationRegistryManager.java create mode 100644 domain/src/main/java/org/acegisecurity/domain/validation/ValidationRegistryManagerImpl.java diff --git a/domain/src/main/java/org/acegisecurity/domain/validation/ValidationManagerImpl.java b/domain/src/main/java/org/acegisecurity/domain/validation/ValidationManagerImpl.java index 6011c64a16..fce5fd8128 100644 --- a/domain/src/main/java/org/acegisecurity/domain/validation/ValidationManagerImpl.java +++ b/domain/src/main/java/org/acegisecurity/domain/validation/ValidationManagerImpl.java @@ -35,6 +35,7 @@ import java.util.Vector; * Default implementation of {@link ValidationManager}. * * @author Ben Alex + * @author Matthew E. Porter * @version $Id$ */ public class ValidationManagerImpl implements InitializingBean, @@ -43,7 +44,7 @@ public class ValidationManagerImpl implements InitializingBean, protected final Log logger = LogFactory.getLog(getClass()); private IntrospectionManager introspectionManager; - private List validators; + private ValidationRegistryManager validationRegistryManager = new ValidationRegistryManagerImpl(); private boolean strictValidation = true; //~ Methods ================================================================ @@ -60,7 +61,7 @@ public class ValidationManagerImpl implements InitializingBean, /** * Indicates whether a {@link ValidatorNotFoundException} should be thrown * if any domain object does not have a corresponding - * Validator defined against the {@link #validators}. + * Validator. * *

* Defaults to true. This is a reasonable default, as callers @@ -80,37 +81,18 @@ public class ValidationManagerImpl implements InitializingBean, return strictValidation; } - /** - * Sets the {@link Validator} objects to be used. - * - * @param newList that should be used for validation. - */ - public void setValidators(List newList) { - Assert.notNull(newList, "A list of Validators is required"); - Assert.isTrue(newList.size() > 0, - "At least one Validator must be defined"); - - Iterator iter = newList.iterator(); - - while (iter.hasNext()) { - Object currentObject = null; - currentObject = iter.next(); - Assert.isInstanceOf(Validator.class, currentObject, - "Validator '" + currentObject - + "' must be an instance of Validator"); - } - - this.validators = newList; + public void setValidationRegistryManager( + ValidationRegistryManager validationRegistryManager) { + this.validationRegistryManager = validationRegistryManager; } - public List getValidators() { - return this.validators; + public ValidationRegistryManager getValidationRegistryManager() { + return validationRegistryManager; } public void afterPropertiesSet() throws Exception { - Assert.notNull(validators, "A list of Validators is required"); - Assert.isTrue(validators.size() > 0, - "At least one Validator must be defined"); + Assert.notNull(validationRegistryManager, + "A ValidationRegistryManager is required"); Assert.notNull(introspectionManager, "An IntrospectionManager is required"); } @@ -133,7 +115,7 @@ public class ValidationManagerImpl implements InitializingBean, Assert.notNull(domainObject, "Cannot validate a null domain object, as unable to getClass()"); - // Construct a list of objects to be validated and add self + // Construct a list of objects to be validated and adds self List allObjects = new Vector(); allObjects.add(domainObject); @@ -197,18 +179,14 @@ public class ValidationManagerImpl implements InitializingBean, throws ValidatorNotFoundException { Assert.notNull(clazz, "Class cannot be null"); - Iterator iter = validators.iterator(); + Validator validator = this.validationRegistryManager.findValidator(clazz); - while (iter.hasNext()) { - Validator validator = (Validator) iter.next(); - - if (validator.supports(clazz)) { - return validator; - } + if (validator == null) { + throw new ValidatorNotFoundException( + "No Validator found for class '" + clazz + "'"); } - throw new ValidatorNotFoundException("No Validator found for class '" - + clazz + "'"); + return validator; } /** diff --git a/domain/src/main/java/org/acegisecurity/domain/validation/ValidationRegistryManager.java b/domain/src/main/java/org/acegisecurity/domain/validation/ValidationRegistryManager.java new file mode 100644 index 0000000000..85467d96a2 --- /dev/null +++ b/domain/src/main/java/org/acegisecurity/domain/validation/ValidationRegistryManager.java @@ -0,0 +1,50 @@ +/* Copyright 2004, 2005 Acegi Technology Pty Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.sf.acegisecurity.domain.validation; + +import org.springframework.validation.Validator; + + +/** + * ValidationRegistryManager implementations are able to + * authoritatively return a Validator instance that is suitable + * for a given domain object. + * + *

+ * Implementations are free to implement their own strategy for maintaining the + * list of Validators, or create them on-demand if preferred. + * This interface is non-prescriptive. + *

+ * + * @author Matthew E. Porter + * @author Ben Alex + * @version $Id$ + */ +public interface ValidationRegistryManager { + //~ Methods ================================================================ + + /** + * Obtains the Validator that applies for a given domain + * object class. + * + * @param domainClass that a Validator is required for + * + * @return the Validator, or null if no + * Validator is known for the indicated + * domainClass + */ + public Validator findValidator(Class domainClass); +} diff --git a/domain/src/main/java/org/acegisecurity/domain/validation/ValidationRegistryManagerImpl.java b/domain/src/main/java/org/acegisecurity/domain/validation/ValidationRegistryManagerImpl.java new file mode 100644 index 0000000000..a3ca6b415e --- /dev/null +++ b/domain/src/main/java/org/acegisecurity/domain/validation/ValidationRegistryManagerImpl.java @@ -0,0 +1,137 @@ +/* Copyright 2004, 2005 Acegi Technology Pty Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.sf.acegisecurity.domain.validation; + +import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; + +import org.springframework.validation.Validator; + +import java.util.HashMap; +import java.util.Map; + + +/** + * A basic implementation of {@link ValidationRegistryManager}. + * + *

+ * Like PropertyEditorManager, + * this implementation uses three techniques for locating a + * Validator for a given domain object class: + * + *

    + *
  1. + * First, the {@link #registerValidator(Class, Class)} method allows a + * Validator to be expressly registered for a given domain object + * class. + *
  2. + *
  3. + * Second, an attempt will be made to find the Validator by + * concatenating "Validator" to the fully qualified domain object classname + * (eg "foo.bah.PersonValidator"). + *
  4. + *
  5. + * Third, it takes the domain object's simple classname (without the package + * name), adds "Validator" to it, then looks in the {@link + * #validatorSearchPath} for the validator. + *
  6. + *
+ *

+ * + * @author Matthew E. Porter + * @author Ben Alex + * @version $Id$ + */ +public class ValidationRegistryManagerImpl implements ValidationRegistryManager { + //~ Static fields/initializers ============================================= + + private static final String VALIDATOR_SUFFIX = "Validator"; + + //~ Instance fields ======================================================== + + private Map validatorMap = new HashMap(); + private String[] validatorSearchPath; + + //~ Methods ================================================================ + + public void setValidatorSearchPath(String[] validatorSearchPath) { + this.validatorSearchPath = validatorSearchPath; + } + + public String[] getValidatorSearchPath() { + return validatorSearchPath; + } + + public Validator findValidator(Class domainClass) { + Assert.notNull(domainClass, "domainClass cannot be null"); + + Class validatorClass = null; + Validator validator = null; + + if (validatorMap.containsKey(domainClass)) { + // already known to our Map + validatorClass = (Class) validatorMap.get(domainClass); + } else { + validatorClass = this.findValidatorClass(domainClass.getName() + + VALIDATOR_SUFFIX); + + if (validatorClass == null) { + String suffix = "." + ClassUtils.getShortName(domainClass) + + VALIDATOR_SUFFIX; + + for (int i = 0; + (i < validatorSearchPath.length) + && (validatorClass == null); i++) { + validatorClass = this.findValidatorClass(validatorSearchPath[i] + + suffix); + } + } + + // register the Validator in our Map, to speed up next retrieval + this.registerValidator(domainClass, validatorClass); + } + + // Attempt to create an instance of the Validator + try { + validator = (Validator) validatorClass.newInstance(); + } catch (ClassCastException cce) {} + catch (InstantiationException ie) {} + catch (IllegalAccessException ile) {} + + return validator; + } + + public void registerValidator(Class domainClass, Class validatorClass) { + Assert.notNull(domainClass, "domainClass cannot be null"); + Assert.notNull(validatorClass, "validatorClass cannot be null"); + Assert.isTrue(Validator.class.isAssignableFrom(validatorClass), + "validatorClass must be an implementation of Validator"); + this.validatorMap.put(domainClass, validatorClass); + } + + private Class findValidatorClass(String validatorClassName) { + Class validatorClass = null; + + try { + ClassLoader contextClassLoader = Thread.currentThread() + .getContextClassLoader(); + validatorClass = Class.forName(validatorClassName); + } catch (ClassNotFoundException e) {} + + return validatorClass; + } +}