package org.hibernate.cfg.beanvalidation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Set;
import org.hibernate.HibernateException;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.cfg.Configuration;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.integrator.spi.Integrator;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.metamodel.source.MetadataImplementor;
import org.hibernate.service.spi.SessionFactoryServiceRegistry;
import org.jboss.logging.Logger;
public class BeanValidationIntegrator implements Integrator {
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
CoreMessageLogger.class,
BeanValidationIntegrator.class.getName()
);
public static final String APPLY_CONSTRAINTS = "hibernate.validator.apply_to_ddl";
public static final String BV_CHECK_CLASS = "javax.validation.Validation";
public static final String MODE_PROPERTY = "javax.persistence.validation.mode";
private static final String ACTIVATOR_CLASS_NAME = "org.hibernate.cfg.beanvalidation.TypeSafeActivator";
private static final String VALIDATE_SUPPLIED_FACTORY_METHOD_NAME = "validateSuppliedFactory";
private static final String ACTIVATE_METHOD_NAME = "activate";
@SuppressWarnings("unchecked")
public static void validateFactory(Object object) {
try {
final Class activatorClass = BeanValidationIntegrator.class.getClassLoader().loadClass( ACTIVATOR_CLASS_NAME );
try {
final Method validateMethod = activatorClass.getMethod( VALIDATE_SUPPLIED_FACTORY_METHOD_NAME, Object.class );
validateMethod.setAccessible( true );
try {
validateMethod.invoke( null, object );
}
catch (InvocationTargetException e) {
if ( e.getTargetException() instanceof HibernateException ) {
throw (HibernateException) e.getTargetException();
}
throw new HibernateException( "Unable to check validity of passed ValidatorFactory", e );
}
catch (IllegalAccessException e) {
throw new HibernateException( "Unable to check validity of passed ValidatorFactory", e );
}
}
catch (HibernateException e) {
throw e;
}
catch (Exception e) {
throw new HibernateException( "Could not locate method needed for ValidatorFactory validation", e );
}
}
catch (HibernateException e) {
throw e;
}
catch (Exception e) {
throw new HibernateException( "Could not locate TypeSafeActivator class", e );
}
}
@Override
public void integrate(
final Configuration configuration,
final SessionFactoryImplementor sessionFactory,
final SessionFactoryServiceRegistry serviceRegistry) {
final Set<ValidationMode> modes = ValidationMode.getModes( configuration.getProperties().get( MODE_PROPERTY ) );
if ( modes.size() > 1 ) {
LOG.multipleValidationModes( ValidationMode.loggable( modes ) );
}
if ( modes.size() == 1 && modes.contains( ValidationMode.NONE ) ) {
return;
}
final ClassLoaderService classLoaderService = serviceRegistry.getService( ClassLoaderService.class );
if ( isBeanValidationApiAvailable( classLoaderService ) ) {
try {
final Class typeSafeActivatorClass = loadTypeSafeActivatorClass( classLoaderService );
@SuppressWarnings("unchecked")
final Method activateMethod = typeSafeActivatorClass.getMethod( ACTIVATE_METHOD_NAME, ActivationContext.class );
final ActivationContext activationContext = new ActivationContext() {
@Override
public Set<ValidationMode> getValidationModes() {
return modes;
}
@Override
public Configuration getConfiguration() {
return configuration;
}
@Override
public SessionFactoryImplementor getSessionFactory() {
return sessionFactory;
}
@Override
public SessionFactoryServiceRegistry getServiceRegistry() {
return serviceRegistry;
}
};
try {
activateMethod.invoke( null, activationContext );
}
catch (InvocationTargetException e) {
if ( HibernateException.class.isInstance( e.getTargetException() ) ) {
throw ( (HibernateException) e.getTargetException() );
}
throw new IntegrationException( "Error activating Bean Validation integration", e.getTargetException() );
}
catch (Exception e) {
throw new IntegrationException( "Error activating Bean Validation integration", e );
}
}
catch (NoSuchMethodException e) {
throw new HibernateException( "Unable to locate TypeSafeActivator#activate method", e );
}
}
else {
validateMissingBeanValidationApi( modes );
}
}
private boolean isBeanValidationApiAvailable(ClassLoaderService classLoaderService) {
try {
classLoaderService.classForName( BV_CHECK_CLASS );
return true;
}
catch (Exception e) {
return false;
}
}
private void validateMissingBeanValidationApi(Set<ValidationMode> modes) {
if ( modes.contains( ValidationMode.CALLBACK ) ) {
throw new IntegrationException( "Bean Validation API was not available, but 'callback' validation was requested" );
}
if ( modes.contains( ValidationMode.DDL ) ) {
throw new IntegrationException( "Bean Validation API was not available, but 'ddl' validation was requested" );
}
}
private Class loadTypeSafeActivatorClass(ClassLoaderService classLoaderService) {
try {
return classLoaderService.classForName( ACTIVATOR_CLASS_NAME );
}
catch (Exception e) {
throw new HibernateException( "Unable to load TypeSafeActivator class", e );
}
}
@Override
public void integrate(
MetadataImplementor metadata,
SessionFactoryImplementor sessionFactory,
SessionFactoryServiceRegistry serviceRegistry ) {
}
@Override
public void disintegrate(SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) {
}
}