Save This Page
Home » hibernate-validator-src-20081106 » org.hibernate » validator » event » [javadoc | source]
    1   //$Id: ValidateEventListener.java 15133 2008-08-20 10:05:57Z hardy.ferentschik $
    2   package org.hibernate.validator.event;
    3   
    4   import java.io.Serializable;
    5   import java.util.ArrayList;
    6   import java.util.Collection;
    7   import java.util.HashMap;
    8   import java.util.Iterator;
    9   import java.util.List;
   10   import java.util.Map;
   11   
   12   import org.hibernate.AssertionFailure;
   13   import org.hibernate.EntityMode;
   14   import org.hibernate.HibernateException;
   15   import org.hibernate.cfg.Configuration;
   16   import org.hibernate.event.Initializable;
   17   import org.hibernate.event.PreInsertEvent;
   18   import org.hibernate.event.PreInsertEventListener;
   19   import org.hibernate.event.PreUpdateEvent;
   20   import org.hibernate.event.PreUpdateEventListener;
   21   import org.hibernate.mapping.Component;
   22   import org.hibernate.mapping.PersistentClass;
   23   import org.hibernate.mapping.Property;
   24   import org.hibernate.property.Getter;
   25   import org.hibernate.property.PropertyAccessor;
   26   import org.hibernate.property.PropertyAccessorFactory;
   27   import org.hibernate.annotations.common.reflection.ReflectionManager;
   28   import org.hibernate.annotations.common.reflection.java.JavaReflectionManager;
   29   import org.hibernate.util.ReflectHelper;
   30   import org.hibernate.util.StringHelper;
   31   import org.hibernate.validator.ClassValidator;
   32   import org.hibernate.validator.Environment;
   33   import org.hibernate.validator.InvalidStateException;
   34   import org.hibernate.validator.InvalidValue;
   35   import org.hibernate.validator.MessageInterpolator;
   36   
   37   /**
   38    * Before insert and update, executes the validator framework
   39    *
   40    * @author Emmanuel Bernard
   41    */
   42   public class ValidateEventListener implements PreInsertEventListener, PreUpdateEventListener, Initializable {
   43   	private boolean isInitialized;
   44   	private Map<Class, ValidatableElement> validators = new HashMap<Class, ValidatableElement>();
   45   
   46   	/**
   47   	 * initialize the validators, any non significant validators are not kept
   48   	 */
   49   	@SuppressWarnings( "unchecked" )
   50   	public synchronized void initialize(final Configuration cfg) {
   51   		if ( !isInitialized ) {
   52   			String interpolatorString = cfg.getProperty( Environment.MESSAGE_INTERPOLATOR_CLASS );
   53   			MessageInterpolator interpolator = null;
   54   			if ( StringHelper.isNotEmpty( interpolatorString ) ) {
   55   				try {
   56   					Class interpolatorClass = ReflectHelper.classForName( interpolatorString );
   57   					interpolator = (MessageInterpolator) interpolatorClass.newInstance();
   58   				}
   59   				catch (ClassNotFoundException e) {
   60   					throw new HibernateException( "Unable to find message interpolator: " + interpolatorString, e );
   61   				}
   62   				catch (IllegalAccessException e) {
   63   					throw new HibernateException( "Unable to instanciate message interpolator: " + interpolatorString,
   64   							e );
   65   				}
   66   				catch (InstantiationException e) {
   67   					throw new HibernateException( "Unable to instanciate message interpolator: " + interpolatorString,
   68   							e );
   69   				}
   70   				catch (ClassCastException e) {
   71   					throw new HibernateException( "Class does not implement "
   72   							+ MessageInterpolator.class.getName() + ": " + interpolatorString, e );
   73   				}
   74   			}
   75   			Iterator<PersistentClass> classes = (Iterator<PersistentClass>) cfg.getClassMappings();
   76   			ReflectionManager reflectionManager;
   77   			try {
   78   				//TODO introduce q ReflectionManagerHolder interface to avoid reflection
   79   				//I want to avoid hard link between HAN and Validator for usch a simple need
   80   				//reuse the existing reflectionManager one when possible
   81   				reflectionManager =
   82   						(ReflectionManager) cfg.getClass().getMethod( "getReflectionManager" ).invoke( cfg );
   83   
   84   			}
   85   			catch (Exception e) {
   86   				reflectionManager = new JavaReflectionManager();
   87   			}
   88   			while ( classes.hasNext() ) {
   89   				PersistentClass clazz = classes.next();
   90   				final Class mappedClass = clazz.getMappedClass();
   91   				ClassValidator validator =
   92   						new ClassValidator( mappedClass, null, interpolator, null, reflectionManager );
   93   				ValidatableElement element = new ValidatableElement( mappedClass, validator );
   94   				addSubElement( clazz.getIdentifierProperty(), element );
   95   				Iterator properties = clazz.getPropertyIterator();
   96   				while ( properties.hasNext() ) {
   97   					addSubElement( (Property) properties.next(), element );
   98   				}
   99   				if ( element.subElements.size() != 0 || element.validator.hasValidationRules() ) {
  100   					validators.put( mappedClass, element );
  101   				}
  102   			}
  103   			isInitialized = true;
  104   		}
  105   	}
  106   
  107   	@SuppressWarnings( "unchecked" )
  108   	private void addSubElement(Property property, ValidatableElement element) {
  109   		if ( property != null && property.isComposite() && !property.isBackRef() ) {
  110   			Component component = (Component) property.getValue();
  111   			if ( component.isEmbedded() ) return;
  112   			PropertyAccessor accessor = PropertyAccessorFactory.getPropertyAccessor( property, EntityMode.POJO );
  113   			Getter getter = accessor.getGetter( element.clazz, property.getName() );
  114   			ClassValidator validator = new ClassValidator( getter.getReturnType() );
  115   			ValidatableElement subElement = new ValidatableElement( getter.getReturnType(), validator, getter );
  116   			Iterator properties = component.getPropertyIterator();
  117   			while ( properties.hasNext() ) {
  118   				addSubElement( (Property) properties.next(), subElement );
  119   			}
  120   			if ( subElement.getSubElements().size() != 0 || subElement.validator.hasValidationRules() ) {
  121   				element.addSubElement( subElement );
  122   			}
  123   		}
  124   	}
  125   
  126   	@SuppressWarnings( "unchecked" )
  127   	protected void validate(Object entity, EntityMode mode) {
  128   		if ( entity == null || !EntityMode.POJO.equals( mode ) ) return;
  129   		ValidatableElement element;
  130   		if ( isInitialized ) {
  131   			element = validators.get( entity.getClass() );
  132   		}
  133   		else {
  134   			throw new AssertionFailure( "Validator event not initialized" );
  135   		}
  136   		if ( element == null ) return; //no validation to do
  137   		List<InvalidValue> consolidatedInvalidValues = new ArrayList<InvalidValue>();
  138   		validateSubElements( element, entity, consolidatedInvalidValues );
  139   		InvalidValue[] invalidValues = element.validator == null ?
  140   				null :
  141   				element.validator.getInvalidValues( entity );
  142   		if ( invalidValues != null ) {
  143   			for ( InvalidValue invalidValue : invalidValues ) {
  144   				consolidatedInvalidValues.add( invalidValue );
  145   			}
  146   		}
  147   		if ( consolidatedInvalidValues.size() > 0 ) {
  148   			throw new InvalidStateException(
  149   					consolidatedInvalidValues.toArray( new InvalidValue[consolidatedInvalidValues.size()] ),
  150   					entity.getClass().getName()
  151   			);
  152   		}
  153   	}
  154   
  155   	@SuppressWarnings( "unchecked" )
  156   	private void validateSubElements(
  157   			ValidatableElement element, Object entity, List<InvalidValue> consolidatedInvalidValues
  158   	) {
  159   		if ( element != null ) {
  160   			for ( ValidatableElement subElement : element.subElements ) {
  161   				Object component = subElement.getter.get( entity );
  162   				InvalidValue[] invalidValues = subElement.validator.getInvalidValues( component );
  163   				for ( InvalidValue invalidValue : invalidValues ) {
  164   					consolidatedInvalidValues.add( invalidValue );
  165   				}
  166   				validateSubElements( subElement, component, consolidatedInvalidValues );
  167   			}
  168   		}
  169   	}
  170   
  171   	public boolean onPreInsert(PreInsertEvent event) {
  172   		validate( event.getEntity(), event.getSource().getEntityMode() );
  173   		return false;
  174   	}
  175   
  176   	public boolean onPreUpdate(PreUpdateEvent event) {
  177   		validate( event.getEntity(), event.getSource().getEntityMode() );
  178   		return false;
  179   	}
  180   
  181   	private static class ValidatableElement implements Serializable {
  182   		private Class clazz;
  183   		private ClassValidator validator;
  184   		private Getter getter;
  185   		private Collection<ValidatableElement> subElements = new ArrayList<ValidatableElement>();
  186   
  187   		public ValidatableElement(Class clazz, ClassValidator validator) {
  188   			this.clazz = clazz;
  189   			this.validator = validator;
  190   		}
  191   
  192   		public ValidatableElement(Class clazz, ClassValidator validator, Getter getter) {
  193   			this( clazz, validator );
  194   			this.getter = getter;
  195   		}
  196   
  197   		public void addSubElement(ValidatableElement subValidatableElement) {
  198   			subElements.add( subValidatableElement );
  199   		}
  200   
  201   		public Collection<ValidatableElement> getSubElements() {
  202   			return this.subElements;
  203   		}
  204   	}
  205   }

Save This Page
Home » hibernate-validator-src-20081106 » org.hibernate » validator » event » [javadoc | source]