Package org.hibernate.cfg.beanvalidation

Source Code of org.hibernate.cfg.beanvalidation.BeanValidationIntegrator

/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, 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.jboss.logging.Logger;

import org.hibernate.HibernateException;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.event.service.spi.EventListenerRegistry;
import org.hibernate.integrator.spi.Integrator;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.metamodel.source.MetadataImplementor;
import org.hibernate.service.classloading.spi.ClassLoaderService;
import org.hibernate.service.spi.SessionFactoryServiceRegistry;

/**
* @author Steve Ebersole
*/
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 = "org.hibernate.cfg.beanvalidation.TypeSafeActivator";
  private static final String DDL_METHOD = "applyDDL";
  private static final String ACTIVATE_METHOD = "activateBeanValidation";
  private static final String VALIDATE_METHOD = "validateFactory";

  public static void validateFactory(Object object) {
    try {
      final Class activatorClass = BeanValidationIntegrator.class.getClassLoader().loadClass( ACTIVATOR_CLASS );
      try {
        final Method validateMethod = activatorClass.getMethod( VALIDATE_METHOD, Object.class );
        if ( ! validateMethod.isAccessible() ) {
          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(
      Configuration configuration,
      SessionFactoryImplementor sessionFactory,
      SessionFactoryServiceRegistry serviceRegistry) {
    // determine requested validation modes.
    final Set<ValidationMode> modes = ValidationMode.getModes( configuration.getProperties().get( MODE_PROPERTY ) );

    final ClassLoaderService classLoaderService = serviceRegistry.getService( ClassLoaderService.class );
        Dialect dialect = serviceRegistry.getService( JdbcServices.class ).getDialect();
    // try to locate a BV class to see if it is available on the classpath
    boolean isBeanValidationAvailable;
    try {
      classLoaderService.classForName( BV_CHECK_CLASS );
      isBeanValidationAvailable = true;
    }
    catch ( Exception e ) {
      isBeanValidationAvailable = false;
    }

    // locate the type safe activator class
    final Class typeSafeActivatorClass = loadTypeSafeActivatorClass( serviceRegistry );

    // todo : if this works out, probably better to simply alter TypeSafeActivator into a single method...
    applyRelationalConstraints(
        modes,
        isBeanValidationAvailable,
        typeSafeActivatorClass,
        configuration,
                dialect

    );
    applyHibernateListeners(
        modes,
        isBeanValidationAvailable,
        typeSafeActivatorClass,
        configuration,
        sessionFactory,
        serviceRegistry
    );
  }

  /**
   * {@inheritDoc}
   *
   * @see org.hibernate.integrator.spi.Integrator#integrate(org.hibernate.metamodel.source.MetadataImplementor, org.hibernate.engine.spi.SessionFactoryImplementor, org.hibernate.service.spi.SessionFactoryServiceRegistry)
   */
  @Override
  public void integrate( MetadataImplementor metadata,
                         SessionFactoryImplementor sessionFactory,
                         SessionFactoryServiceRegistry serviceRegistry ) {
//      Properties props = sessionFactory.getProperties();
//        final Set<ValidationMode> modes = ValidationMode.getModes(props.get(MODE_PROPERTY));
//        final ClassLoaderService classLoaderService = serviceRegistry.getService( ClassLoaderService.class );
//        // try to locate a BV class to see if it is available on the classpath
//        boolean isBeanValidationAvailable;
//        try {
//            classLoaderService.classForName( BV_CHECK_CLASS );
//            isBeanValidationAvailable = true;
//        } catch (Exception error) {
//            isBeanValidationAvailable = false;
//        }
//        // locate the type safe activator class
//        final Class typeSafeActivatorClass = loadTypeSafeActivatorClass(serviceRegistry);
//        // todo : if this works out, probably better to simply alter TypeSafeActivator into a single method...
//        applyRelationalConstraints(modes, isBeanValidationAvailable, typeSafeActivatorClass, props, metadata);
//        applyHibernateListeners(modes, isBeanValidationAvailable, typeSafeActivatorClass, sessionFactory, serviceRegistry);
  }

  private Class loadTypeSafeActivatorClass(SessionFactoryServiceRegistry serviceRegistry) {
    try {
      return serviceRegistry.getService( ClassLoaderService.class ).classForName( ACTIVATOR_CLASS );
    }
    catch (Exception e) {
      return null;
    }
  }

  private void applyRelationalConstraints(
      Set<ValidationMode> modes,
      boolean beanValidationAvailable,
      Class typeSafeActivatorClass,
      Configuration configuration,
            Dialect dialect) {
    if ( ! ConfigurationHelper.getBoolean( APPLY_CONSTRAINTS, configuration.getProperties(), true ) ){
      LOG.debug( "Skipping application of relational constraints from legacy Hibernate Validator" );
      return;
    }

    if ( ! ( modes.contains( ValidationMode.DDL ) || modes.contains( ValidationMode.AUTO ) ) ) {
      return;
    }

    if ( ! beanValidationAvailable ) {
      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 {
      Method applyDDLMethod = typeSafeActivatorClass.getMethod( DDL_METHOD, Collection.class, Properties.class, Dialect.class );
      try {
        applyDDLMethod.invoke(
            null,
            configuration.createMappings().getClasses().values(),
            configuration.getProperties(),
                        dialect
        );
      }
      catch (HibernateException e) {
        throw e;
      }
      catch (Exception e) {
        throw new HibernateException( "Error applying BeanValidation relational constraints", e );
      }
    }
    catch (HibernateException e) {
      throw e;
    }
    catch (Exception e) {
      throw new HibernateException( "Unable to locate TypeSafeActivator#applyDDL method", e );
    }
  }

//    private void applyRelationalConstraints( Set<ValidationMode> modes,
//                                             boolean beanValidationAvailable,
//                                             Class typeSafeActivatorClass,
//                                             Properties properties,
//                                             MetadataImplementor metadata ) {
//        if (!ConfigurationHelper.getBoolean(APPLY_CONSTRAINTS, properties, true)){
//            LOG.debug("Skipping application of relational constraints from legacy Hibernate Validator");
//            return;
//        }
//        if (!(modes.contains(ValidationMode.DDL) || modes.contains(ValidationMode.AUTO))) return;
//        if (!beanValidationAvailable) {
//            if (modes.contains(ValidationMode.DDL))
//                throw new HibernateException("Bean Validation not available in the class path but required in " + MODE_PROPERTY);
//            if(modes.contains(ValidationMode.AUTO)) return; //nothing to activate
//        }
//        try {
//            Method applyDDLMethod = typeSafeActivatorClass.getMethod(DDL_METHOD, Iterable.class, Properties.class, ClassLoaderService.class);
//            try {
//                applyDDLMethod.invoke(null, metadata.getEntityBindings(), properties,
//                                      metadata.getServiceRegistry().getService(ClassLoaderService.class));
//            } catch (HibernateException error) {
//                throw error;
//            } catch (Exception error) {
//                throw new HibernateException("Error applying BeanValidation relational constraints", error);
//            }
//        } catch (HibernateException error) {
//            throw error;
//        } catch (Exception error) {
//            throw new HibernateException("Unable to locate TypeSafeActivator#applyDDL method", error);
//        }
//    }

  private void applyHibernateListeners(
      Set<ValidationMode> modes,
      boolean beanValidationAvailable,
      Class typeSafeActivatorClass,
      Configuration configuration,
      SessionFactoryImplementor sessionFactory,
      SessionFactoryServiceRegistry serviceRegistry) {
    // de-activate not-null tracking at the core level when Bean Validation is present unless the user explicitly
    // asks for it
    if ( configuration.getProperty( Environment.CHECK_NULLABILITY ) == null ) {
      sessionFactory.getSettings().setCheckNullability( false );
    }

    if ( ! ( modes.contains( ValidationMode.CALLBACK ) || modes.contains( ValidationMode.AUTO ) ) ) {
      return;
    }

    if ( ! beanValidationAvailable ) {
      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;
      }
    }

    try {
      Method activateMethod = typeSafeActivatorClass.getMethod( ACTIVATE_METHOD, EventListenerRegistry.class, Configuration.class );
      try {
        activateMethod.invoke(
            null,
            serviceRegistry.getService( EventListenerRegistry.class ),
            configuration
        );
      }
      catch (HibernateException e) {
        throw e;
      }
      catch (Exception e) {
        throw new HibernateException( "Error applying BeanValidation relational constraints", e );
      }
    }
    catch (HibernateException e) {
      throw e;
    }
    catch (Exception e) {
      throw new HibernateException( "Unable to locate TypeSafeActivator#applyDDL method", e );
    }
  }

//    private void applyHibernateListeners( Set<ValidationMode> modes,
//                                          boolean beanValidationAvailable,
//                                          Class typeSafeActivatorClass,
//                                          SessionFactoryImplementor sessionFactory,
//                                          SessionFactoryServiceRegistry serviceRegistry ) {
//        // de-activate not-null tracking at the core level when Bean Validation is present unless the user explicitly
//        // asks for it
//        if (sessionFactory.getProperties().getProperty(Environment.CHECK_NULLABILITY) == null)
//            sessionFactory.getSettings().setCheckNullability( false );
//        if (!(modes.contains( ValidationMode.CALLBACK) || modes.contains(ValidationMode.AUTO))) return;
//        if (!beanValidationAvailable) {
//            if (modes.contains(ValidationMode.CALLBACK))
//                throw new HibernateException("Bean Validation not available in the class path but required in " + MODE_PROPERTY);
//            if (modes.contains(ValidationMode.AUTO)) return; //nothing to activate
//        }
//        try {
//            Method activateMethod = typeSafeActivatorClass.getMethod(ACTIVATE_METHOD, EventListenerRegistry.class);
//            try {
//                activateMethod.invoke(null, serviceRegistry.getService(EventListenerRegistry.class));
//            }
//            catch (HibernateException e) {
//                throw e;
//            }
//            catch (Exception e) {
//                throw new HibernateException( "Error applying BeanValidation relational constraints", e );
//            }
//        }
//        catch (HibernateException e) {
//            throw e;
//        }
//        catch (Exception e) {
//            throw new HibernateException( "Unable to locate TypeSafeActivator#applyDDL method", e );
//        }
//    }

  // Because the javax validation classes might not be on the runtime classpath
  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 );
        }
      }
    }
  }

  @Override
  public void disintegrate(SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) {
    // nothing to do here afaik
  }
}
TOP

Related Classes of org.hibernate.cfg.beanvalidation.BeanValidationIntegrator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.