/* * Hibernate, Relational Persistence for Idiomatic Java * * Copyright (c) 2010, Red Hat Inc. or third-party contributors as * indicated by the @author tags or express copyright attribution * statements applied by the authors. All third-party contributions are * distributed under license by Red Hat Inc. * * This copyrighted material is made available to anyone wishing to use, modify, * copy, or redistribute it subject to the terms and conditions of the GNU * Lesser General Public License, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this distribution; if not, write to: * Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ package org.hibernate.cfg.beanvalidation; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Collection; import java.util.HashSet; import java.util.Properties; import java.util.Set; import org.hibernate.HibernateException; import org.hibernate.cfg.Environment; import org.hibernate.event.EventListeners; import org.hibernate.mapping.PersistentClass; import org.hibernate.util.ReflectHelper; /** * This class has no hard dependency on Bean Validation APIs * It must use reflection every time BV is required. * @author Emmanuel Bernard */ public class BeanValidationActivator { private static final String BV_DISCOVERY_CLASS = "javax.validation.Validation"; private static final String TYPE_SAFE_ACTIVATOR_CLASS = "org.hibernate.cfg.beanvalidation.TypeSafeActivator"; private static final String TYPE_SAFE_DDL_METHOD = "applyDDL"; private static final String TYPE_SAFE_ACTIVATOR_METHOD = "activateBeanValidation"; private static final String MODE_PROPERTY = "javax.persistence.validation.mode"; public static void activateBeanValidation(EventListeners eventListeners, Properties properties) { Set<ValidationMode> modes = ValidationMode.getModes( properties.get( MODE_PROPERTY ) ); try { //load Validation ReflectHelper.classForName( BV_DISCOVERY_CLASS, BeanValidationActivator.class ); } catch ( ClassNotFoundException e ) { if ( modes.contains( ValidationMode.CALLBACK ) ) { throw new HibernateException( "Bean Validation not available in the class path but required in " + MODE_PROPERTY ); } else if (modes.contains( ValidationMode.AUTO ) ) { //nothing to activate return; } } //de-activate not-null tracking at the core level when Bean Validation // is present unless the user really asks for it //Note that if BV is not present, the behavior is backward compatible if ( properties.getProperty( Environment.CHECK_NULLABILITY ) == null ) { properties.setProperty( Environment.CHECK_NULLABILITY, "false" ); } if ( ! ( modes.contains( ValidationMode.CALLBACK ) || modes.contains( ValidationMode.AUTO ) ) ) return; try { Class<?> activator = ReflectHelper.classForName( TYPE_SAFE_ACTIVATOR_CLASS, BeanValidationActivator.class ); Method activateBeanValidation = activator.getMethod( TYPE_SAFE_ACTIVATOR_METHOD, EventListeners.class, Properties.class ); activateBeanValidation.invoke( null, eventListeners, properties ); } catch ( NoSuchMethodException e ) { throw new HibernateException( "Unable to get the default Bean Validation factory", e); } catch ( IllegalAccessException e ) { throw new HibernateException( "Unable to get the default Bean Validation factory", e); } catch ( InvocationTargetException e ) { throw new HibernateException( "Unable to get the default Bean Validation factory", e); } catch ( ClassNotFoundException e ) { throw new HibernateException( "Unable to get the default Bean Validation factory", e); } } public static void applyDDL(Collection<PersistentClass> persistentClasses, Properties properties) { Set<ValidationMode> modes = ValidationMode.getModes( properties.get( MODE_PROPERTY ) ); if ( ! ( modes.contains( ValidationMode.DDL ) || modes.contains( ValidationMode.AUTO ) ) ) return; try { //load Validation ReflectHelper.classForName( BV_DISCOVERY_CLASS, BeanValidationActivator.class ); } catch ( ClassNotFoundException e ) { if ( modes.contains( ValidationMode.DDL ) ) { throw new HibernateException( "Bean Validation not available in the class path but required in " + MODE_PROPERTY ); } else if (modes.contains( ValidationMode.AUTO ) ) { //nothing to activate return; } } try { Class<?> activator = ReflectHelper.classForName( TYPE_SAFE_ACTIVATOR_CLASS, BeanValidationActivator.class ); Method applyDDL = activator.getMethod( TYPE_SAFE_DDL_METHOD, Collection.class, Properties.class ); applyDDL.invoke( null, persistentClasses, properties ); } catch ( NoSuchMethodException e ) { throw new HibernateException( "Unable to get the default Bean Validation factory", e); } catch ( IllegalAccessException e ) { throw new HibernateException( "Unable to get the default Bean Validation factory", e); } catch ( InvocationTargetException e ) { throw new HibernateException( "Unable to get the default Bean Validation factory", e); } catch ( ClassNotFoundException e ) { throw new HibernateException( "Unable to get the default Bean Validation factory", e); } } private static enum ValidationMode { AUTO, CALLBACK, NONE, DDL; public static Set<ValidationMode> getModes(Object modeProperty) { Set<ValidationMode> modes = new HashSet<ValidationMode>(3); if (modeProperty == null) { modes.add(ValidationMode.AUTO); } else { final String[] modesInString = modeProperty.toString().split( "," ); for ( String modeInString : modesInString ) { modes.add( getMode(modeInString) ); } } if ( modes.size() > 1 && ( modes.contains( ValidationMode.AUTO ) || modes.contains( ValidationMode.NONE ) ) ) { StringBuilder message = new StringBuilder( "Incompatible validation modes mixed: " ); for (ValidationMode mode : modes) { message.append( mode ).append( ", " ); } throw new HibernateException( message.substring( 0, message.length() - 2 ) ); } return modes; } private static ValidationMode getMode(String modeProperty) { if (modeProperty == null || modeProperty.length() == 0) { return AUTO; } else { try { return valueOf( modeProperty.trim().toUpperCase() ); } catch ( IllegalArgumentException e ) { throw new HibernateException( "Unknown validation mode in " + MODE_PROPERTY + ": " + modeProperty.toString() ); } } } } }