Browse Source

Refactor to allow IntrospectionManagers to query a shared Validator map.

Ben Alex 20 years ago
parent
commit
9b90df1812

+ 16 - 38
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
-     * <code>Validator</code> defined against the {@link #validators}.
+     * <code>Validator</code>.
      * 
      * <p>
      * Defaults to <code>true</code>. 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;
     }
 
     /**

+ 50 - 0
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;
+
+
+/**
+ * <code>ValidationRegistryManager</code> implementations are able to
+ * authoritatively return a <code>Validator</code> instance that is suitable
+ * for a given domain object.
+ * 
+ * <p>
+ * Implementations are free to implement their own strategy for maintaining the
+ * list of <code>Validator</code>s, or create them on-demand if preferred.
+ * This interface is non-prescriptive.
+ * </p>
+ *
+ * @author Matthew E. Porter
+ * @author Ben Alex
+ * @version $Id$
+ */
+public interface ValidationRegistryManager {
+    //~ Methods ================================================================
+
+    /**
+     * Obtains the <code>Validator</code> that applies for a given domain
+     * object class.
+     *
+     * @param domainClass that a <code>Validator</code> is required for
+     *
+     * @return the <code>Validator</code>, or <code>null</code> if no
+     *         <code>Validator</code> is known for the indicated
+     *         <code>domainClass</code>
+     */
+    public Validator findValidator(Class domainClass);
+}

+ 137 - 0
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}.
+ * 
+ * <p>
+ * Like <a
+ * href="http://java.sun.com/j2se/1.4.2/docs/api/java/beans/PropertyEditorManager.html">PropertyEditorManager</a>,
+ * this implementation uses three techniques for locating a
+ * <code>Validator</code> for a given domain object class:
+ * 
+ * <ol>
+ * <li>
+ * First, the {@link #registerValidator(Class, Class)} method allows a
+ * <code>Validator</code> to be expressly registered for a given domain object
+ * class.
+ * </li>
+ * <li>
+ * Second, an attempt will be made to find the <code>Validator</code> by
+ * concatenating "Validator" to the fully qualified domain object classname
+ * (eg "foo.bah.PersonValidator").
+ * </li>
+ * <li>
+ * 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.
+ * </li>
+ * </ol>
+ * </p>
+ *
+ * @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;
+    }
+}