org.acegisecurity.domain.validation.ValidationRegistryManagerImpl Maven / Gradle / Ivy
/* Copyright 2004, 2005, 2006 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 org.acegisecurity.domain.validation;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.util.Assert;
import org.springframework.validation.Validator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/**
* A basic implementation of {@link ValidationRegistryManager}.Locates Validator
s registered in
* bean factory.
* If more than one Validator
can support a given object, the supporting Validator
s
* will be iterated and their bean factory defined bean names will be used to attempt to select the "best matching"
* Validator
. The lowercase version of a given object's simplified class name will be searched within the
* bean names. If more than one Validator
contains this search criteria, an exception will be thrown as
* the actual intended Validator
is unidentifiable.
* For example, say you had a PartyValidator which could validate com.foo.Party, and also its subclass,
* com.foo.Person. There is also a PersonValidator which can only validate Person. PartyValidator and PersonValidator
* are registered in the bean container as "partyValidator" and "personValidator". When
* ValidationRegistryManagerImpl
is asked to return the Validator
for Person, it will locate
* the two matching Validator
s in the bean container. As there are two matching, it will look at the
* lowercase representation of the bean names and see if either contain the lower simplified class name of the object
* being search for (com.foo.Person thus becomes simply "person"). ValidationRegistryManagerImpl
will
* then correctly return the PersonValidator for Person. If the PartyValidator had been registered with an ambiguous
* bean name of say "personAndPartyValidator", both bean names would have matched and an exception would have been
* thrown.
*
* @author Matthew E. Porter
* @author Ben Alex
* @version $Id: ValidationRegistryManagerImpl.java 1496 2006-05-23 13:38:33Z benalex $
*/
public class ValidationRegistryManagerImpl implements ValidationRegistryManager, BeanFactoryAware {
//~ Instance fields ================================================================================================
private ListableBeanFactory bf;
private Map validatorMap = new HashMap();
//~ Methods ========================================================================================================
public Validator findValidator(Class domainClass) {
Assert.notNull(domainClass, "domainClass cannot be null");
if (validatorMap.containsKey(domainClass)) {
if (validatorMap.get(domainClass) == null) {
return null;
}
return (Validator) this.bf.getBean((String) validatorMap.get(domainClass), Validator.class);
}
// Attempt to find Validator via introspection
Map beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(bf, Validator.class, true, true);
// Search all Validators for those that support the class
Set candidateValidatorNames = new HashSet();
Iterator iter = beans.keySet().iterator();
while (iter.hasNext()) {
String beanName = iter.next();
Validator validator = beans.get(beanName);
if (validator.supports(domainClass)) {
candidateValidatorNames.add(beanName);
}
}
if (candidateValidatorNames.size() == 0) {
// No Validator found
this.validatorMap.put(domainClass, null);
return null;
} else if (candidateValidatorNames.size() == 1) {
// Only one Validator found, so return it
String validator = candidateValidatorNames.iterator().next();
this.validatorMap.put(domainClass, validator);
return beans.get(validator);
} else {
// Try to locate an entry with simple class name in it
StringBuffer sb = new StringBuffer();
Iterator iterCandidates = candidateValidatorNames.iterator();
String lastFound = null;
int numberFound = 0;
while (iterCandidates.hasNext()) {
String candidate = iterCandidates.next();
sb.append(candidate);
if (iterCandidates.hasNext()) {
sb.append(",");
}
if (candidate.toLowerCase().contains(domainClass.getSimpleName().toLowerCase())) {
numberFound++;
lastFound = candidate;
}
}
if (numberFound != 1) {
throw new IllegalArgumentException("More than one Validator found (" + sb.toString()
+ ") that supports '" + domainClass
+ "', but cannot determine the most specific Validator to use; give a hint by making bean name include the simple name of the target class ('"
+ domainClass.getSimpleName().toString() + "')");
}
this.validatorMap.put(domainClass, lastFound);
return beans.get(lastFound);
}
}
public void registerValidator(Class domainClass, String beanName) {
Assert.notNull(domainClass, "domainClass cannot be null");
Assert.notNull(beanName, "beanName cannot be null");
Assert.isTrue(this.bf.containsBean(beanName), "beanName not found in context");
Assert.isInstanceOf(Validator.class, this.bf.getBean(beanName),
"beanName '" + beanName + "' must be a Validator");
Assert.isTrue(((Validator) this.bf.getBean(beanName)).supports(domainClass),
"Validator does not support " + domainClass);
this.validatorMap.put(domainClass, beanName);
}
public void setBeanFactory(BeanFactory beanFactory)
throws BeansException {
Assert.isInstanceOf(ListableBeanFactory.class, beanFactory, "BeanFactory must be ListableBeanFactory");
this.bf = (ListableBeanFactory) beanFactory;
}
}