HHH-5913 - Implement set of event listeners as a service

This commit is contained in:
Steve Ebersole 2011-03-27 14:07:23 -05:00
parent 42c609cfdd
commit e3a0525fb1
9 changed files with 540 additions and 626 deletions

View File

@ -35,8 +35,6 @@ import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.io.StringReader;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
@ -50,7 +48,6 @@ import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Properties;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TreeMap;
@ -83,7 +80,6 @@ import org.hibernate.annotations.common.reflection.ReflectionManager;
import org.hibernate.annotations.common.reflection.XClass;
import org.hibernate.annotations.common.reflection.java.JavaReflectionManager;
import org.hibernate.cfg.annotations.reflection.JPAMetadataProvider;
import org.hibernate.cfg.beanvalidation.BeanValidationActivator;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.MySQLDialect;
import org.hibernate.dialect.function.SQLFunction;
@ -92,10 +88,6 @@ import org.hibernate.engine.Mapping;
import org.hibernate.engine.NamedQueryDefinition;
import org.hibernate.engine.NamedSQLQueryDefinition;
import org.hibernate.engine.ResultSetMappingDefinition;
import org.hibernate.event.EventListenerRegistration;
import org.hibernate.event.EventType;
import org.hibernate.event.PreInsertEventListener;
import org.hibernate.event.PreUpdateEventListener;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.id.IdentifierGeneratorAggregator;
import org.hibernate.id.PersistentIdentifierGenerator;
@ -138,11 +130,7 @@ import org.hibernate.mapping.UniqueKey;
import org.hibernate.proxy.EntityNotFoundDelegate;
import org.hibernate.secure.JACCConfiguration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.StandardServiceInitiators;
import org.hibernate.service.classloading.spi.ClassLoaderService;
import org.hibernate.service.event.spi.EventListenerRegistry;
import org.hibernate.service.internal.BasicServiceRegistryImpl;
import org.hibernate.service.spi.ServiceRegistryImplementor;
import org.hibernate.tool.hbm2ddl.DatabaseMetadata;
import org.hibernate.tool.hbm2ddl.IndexMetadata;
import org.hibernate.tool.hbm2ddl.TableMetadata;
@ -1378,8 +1366,6 @@ public class Configuration implements Serializable {
buildUniqueKeyFromColumnNames( table, keyName, holder.getColumns() );
}
}
applyConstraintsToDDL();
}
private void processSecondPassesOfType(Class<? extends SecondPass> type) {
@ -1577,68 +1563,6 @@ public class Configuration implements Serializable {
}
}
private void applyConstraintsToDDL() {
boolean applyOnDdl = getProperties().getProperty(
"hibernate.validator.apply_to_ddl",
"true"
)
.equalsIgnoreCase( "true" );
if ( !applyOnDdl ) {
return; // nothing to do in this case
}
applyHibernateValidatorLegacyConstraintsOnDDL();
applyBeanValidationConstraintsOnDDL();
}
@SuppressWarnings({ "unchecked" })
private void applyHibernateValidatorLegacyConstraintsOnDDL() {
//TODO search for the method only once and cache it?
Constructor validatorCtr = null;
Method applyMethod = null;
try {
Class classValidator = ReflectHelper.classForName(
"org.hibernate.validator.ClassValidator", this.getClass()
);
Class messageInterpolator = ReflectHelper.classForName(
"org.hibernate.validator.MessageInterpolator", this.getClass()
);
validatorCtr = classValidator.getDeclaredConstructor(
Class.class, ResourceBundle.class, messageInterpolator, Map.class, ReflectionManager.class
);
applyMethod = classValidator.getMethod( "apply", PersistentClass.class );
}
catch ( ClassNotFoundException e ) {
if (!isValidatorNotPresentLogged) LOG.validatorNotFound();
isValidatorNotPresentLogged = true;
}
catch ( NoSuchMethodException e ) {
throw new AnnotationException( e );
}
if ( applyMethod != null ) {
for ( PersistentClass persistentClazz : classes.values() ) {
//integrate the validate framework
String className = persistentClazz.getClassName();
if ( StringHelper.isNotEmpty( className ) ) {
try {
Object validator = validatorCtr.newInstance(
ReflectHelper.classForName( className ), null, null, null, reflectionManager
);
applyMethod.invoke( validator, persistentClazz );
}
catch ( Exception e ) {
LOG.unableToApplyConstraints(className, e);
}
}
}
}
}
@SuppressWarnings({ "unchecked" })
private void applyBeanValidationConstraintsOnDDL() {
BeanValidationActivator.applyDDL( classes.values(), getProperties() );
}
private void originalSecondPassCompile() throws MappingException {
LOG.debugf("Processing extends queue");
processExtendsQueue();
@ -1789,12 +1713,8 @@ public class Configuration implements Serializable {
secondPassCompile();
if (!metadataSourceQueue.isEmpty()) LOG.incompleteMappingMetadataCacheProcessing();
// todo : processing listeners for validator and search (and envers) requires HHH-5562
enableLegacyHibernateValidator( serviceRegistry );
enableBeanValidation( serviceRegistry );
// enableHibernateSearch();
validate();
Environment.verifyProperties( properties );
Properties copy = new Properties();
copy.putAll( properties );
@ -1840,118 +1760,6 @@ public class Configuration implements Serializable {
return buildSessionFactory( serviceRegistry );
}
private static final String LEGACY_VALIDATOR_EVENT_LISTENER = "org.hibernate.validator.event.ValidateEventListener";
private void enableLegacyHibernateValidator(ServiceRegistry serviceRegistry) {
serviceRegistry.getService( StandardServiceInitiators.EventListenerRegistrationService.class )
.attachEventListenerRegistration( new LegacyHibernateValidatorEventListenerRegistration( properties ) );
}
public static class LegacyHibernateValidatorEventListenerRegistration implements EventListenerRegistration {
private final Properties configurationProperties;
public LegacyHibernateValidatorEventListenerRegistration(Properties configurationProperties) {
this.configurationProperties = configurationProperties;
}
@Override
public void apply(
EventListenerRegistry eventListenerRegistry,
Configuration configuration, Map<?, ?> configValues, ServiceRegistryImplementor serviceRegistry
) {
boolean loadLegacyValidator = ConfigurationHelper.getBoolean( "hibernate.validator.autoregister_listeners", configurationProperties, false );
Class validateEventListenerClass = null;
try {
validateEventListenerClass = serviceRegistry.getService( ClassLoaderService.class ).classForName( LEGACY_VALIDATOR_EVENT_LISTENER );
}
catch ( Exception ignored) {
}
if ( ! loadLegacyValidator || validateEventListenerClass == null) {
LOG.debugf( "Skipping legacy validator loading" );
return;
}
final Object validateEventListener;
try {
validateEventListener = validateEventListenerClass.newInstance();
}
catch ( Exception e ) {
throw new AnnotationException( "Unable to load Validator event listener", e );
}
EventListenerRegistry listenerRegistry = serviceRegistry.getService( EventListenerRegistry.class );
// todo : duplication strategy
listenerRegistry.appendListeners( EventType.PRE_INSERT, (PreInsertEventListener) validateEventListener );
listenerRegistry.appendListeners( EventType.PRE_UPDATE, (PreUpdateEventListener) validateEventListener );
}
}
private void enableBeanValidation(ServiceRegistry serviceRegistry) {
serviceRegistry.getService( StandardServiceInitiators.EventListenerRegistrationService.class ).attachEventListenerRegistration(
new EventListenerRegistration() {
@Override
public void apply(
EventListenerRegistry eventListenerRegistry,
Configuration configuration,
Map<?, ?> configValues,
ServiceRegistryImplementor serviceRegistry) {
BeanValidationActivator.activateBeanValidation( eventListenerRegistry, getProperties() );
}
}
);
}
private static final String SEARCH_EVENT_LISTENER_REGISTERER_CLASS = "org.hibernate.cfg.search.HibernateSearchEventListenerRegister";
/**
* Tries to automatically register Hibernate Search event listeners by locating the
* appropriate bootstrap class and calling the <code>enableHibernateSearch</code> method.
*/
// private void enableHibernateSearch() {
// // load the bootstrap class
// Class searchStartupClass;
// try {
// searchStartupClass = ReflectHelper.classForName( SEARCH_STARTUP_CLASS, getClass() );
// }
// catch ( ClassNotFoundException e ) {
// // TODO remove this together with SearchConfiguration after 3.1.0 release of Search
// // try loading deprecated HibernateSearchEventListenerRegister
// try {
// searchStartupClass = ReflectHelper.classForName( SEARCH_EVENT_LISTENER_REGISTERER_CLASS, getClass() );
// }
// catch ( ClassNotFoundException cnfe ) {
// LOG.debugf("Search not present in classpath, ignoring event listener registration.");
// return;
// }
// }
//
// // call the method for registering the listeners
// try {
// Object searchStartupInstance = searchStartupClass.newInstance();
// Method enableSearchMethod = searchStartupClass.getDeclaredMethod(
// SEARCH_STARTUP_METHOD,
// EventListeners.class,
// Properties.class
// );
// enableSearchMethod.invoke( searchStartupInstance, getEventListeners(), getProperties() );
// }
// catch ( InstantiationException e ) {
// LOG.debugf("Unable to instantiate %s, ignoring event listener registration.", SEARCH_STARTUP_CLASS);
// }
// catch ( IllegalAccessException e ) {
// LOG.debugf("Unable to instantiate %s, ignoring event listener registration.", SEARCH_STARTUP_CLASS);
// }
// catch ( NoSuchMethodException e ) {
// LOG.debugf("Method %s() not found in %s", SEARCH_STARTUP_METHOD, SEARCH_STARTUP_CLASS);
// }
// catch ( InvocationTargetException e ) {
// LOG.debugf("Unable to execute %s, ignoring event listener registration.", SEARCH_STARTUP_METHOD);
// }
// }
/**
* Rterieve the configured {@link Interceptor}.
*

View File

@ -1,174 +0,0 @@
/*
* 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.internal.util.ReflectHelper;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.service.event.spi.EventListenerRegistry;
/**
* 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(EventListenerRegistry listenerRegistry, 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, EventListenerRegistry.class, Properties.class );
activateBeanValidation.invoke( null, listenerRegistry, 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() );
}
}
}
}
}

View File

@ -0,0 +1,234 @@
/*
* 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.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.HibernateLogger;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.impl.Integrator;
import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.service.classloading.spi.ClassLoaderService;
import org.hibernate.service.event.spi.EventListenerRegistry;
import org.hibernate.service.spi.SessionFactoryServiceRegistry;
/**
* @author Steve Ebersole
*/
public class BeanValidationIntegrator implements Integrator {
private static final HibernateLogger LOG = Logger.getMessageLogger(HibernateLogger.class, BeanValidationIntegrator.class.getName());
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";
@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 ) );
// 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,
typeSafeActivatorClass,
configuration
);
applyHibernateListeners(
modes,
typeSafeActivatorClass,
configuration,
sessionFactory,
serviceRegistry
);
}
private Class loadTypeSafeActivatorClass(SessionFactoryServiceRegistry serviceRegistry) {
try {
return serviceRegistry.getService( ClassLoaderService.class ).classForName( ACTIVATOR_CLASS );
}
catch (Exception e) {
// might be ok for the class loading to fail depending on what validation modes were requested...
return null;
}
}
private void applyRelationalConstraints(
Set<ValidationMode> modes,
Class typeSafeActivatorClass,
Configuration configuration) {
if ( ! ConfigurationHelper.getBoolean( LegacyHibernateValidationIntegrator.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 ( typeSafeActivatorClass == null ) {
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 );
try {
applyDDLMethod.invoke(
null,
configuration.createMappings().getClasses().values(),
configuration.getProperties()
);
}
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,
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 ( typeSafeActivatorClass == null ) {
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, Properties.class );
try {
activateMethod.invoke(
null,
serviceRegistry.getService( EventListenerRegistry.class ),
configuration.getProperties()
);
}
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 );
}
}
}
}
}

View File

@ -0,0 +1,155 @@
/*
* 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.Constructor;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.ResourceBundle;
import org.jboss.logging.Logger;
import org.hibernate.AnnotationException;
import org.hibernate.HibernateLogger;
import org.hibernate.annotations.common.reflection.ReflectionManager;
import org.hibernate.cfg.Configuration;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.event.EventType;
import org.hibernate.event.PreInsertEventListener;
import org.hibernate.event.PreUpdateEventListener;
import org.hibernate.impl.Integrator;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.service.classloading.spi.ClassLoaderService;
import org.hibernate.service.event.spi.EventListenerRegistry;
import org.hibernate.service.spi.SessionFactoryServiceRegistry;
/**
* @author Steve Ebersole
*/
public class LegacyHibernateValidationIntegrator implements Integrator {
private static final HibernateLogger LOG = Logger.getMessageLogger( HibernateLogger.class, LegacyHibernateValidationIntegrator.class.getName() );
public static final String APPLY_CONSTRAINTS = "hibernate.validator.apply_to_ddl";
public static final String CLASS_VALIDATOR_CLASS = "org.hibernate.validator.ClassValidator";
public static final String MSG_INTERPOLATOR_CLASS = "org.hibernate.validator.MessageInterpolator";
public static final String AUTO_REGISTER = "hibernate.validator.autoregister_listeners";
public static final String LISTENER_CLASS_NAME = "org.hibernate.validator.event.ValidateEventListener";
// this code mostly all copied and pasted from various spots...
@Override
public void integrate(
Configuration configuration,
SessionFactoryImplementor sessionFactory,
SessionFactoryServiceRegistry serviceRegistry) {
applyRelationalConstraints( configuration, serviceRegistry );
applyListeners( configuration, serviceRegistry );
}
@SuppressWarnings( {"unchecked"})
private void applyRelationalConstraints(Configuration configuration, SessionFactoryServiceRegistry serviceRegistry) {
if ( ! ConfigurationHelper.getBoolean( APPLY_CONSTRAINTS, configuration.getProperties(), true ) ){
LOG.debug( "Skipping application of relational constraints from legacy Hibernate Validator" );
return;
}
Constructor validatorCtr = null;
Method applyMethod = null;
try {
final ClassLoaderService classLoaderService = serviceRegistry.getService( ClassLoaderService.class );
final Class classValidator = classLoaderService.classForName( CLASS_VALIDATOR_CLASS );
final Class messageInterpolator = classLoaderService.classForName( MSG_INTERPOLATOR_CLASS );
validatorCtr = classValidator.getDeclaredConstructor(
Class.class, ResourceBundle.class, messageInterpolator, Map.class, ReflectionManager.class
);
applyMethod = classValidator.getMethod( "apply", PersistentClass.class );
}
catch ( NoSuchMethodException e ) {
throw new AnnotationException( e );
}
catch ( Exception e ) {
LOG.debug( "Legacy Hibernate Validator classes not found, ignoring" );
}
if ( applyMethod != null ) {
Iterable<PersistentClass> persistentClasses = ( (Map<String,PersistentClass>) configuration.createMappings().getClasses() ).values();
for ( PersistentClass persistentClass : persistentClasses ) {
// integrate the validate framework
String className = persistentClass.getClassName();
if ( StringHelper.isNotEmpty( className ) ) {
try {
Object validator = validatorCtr.newInstance(
ReflectHelper.classForName( className ), null, null, null, configuration.getReflectionManager()
);
applyMethod.invoke( validator, persistentClass );
}
catch ( Exception e ) {
LOG.unableToApplyConstraints(className, e);
}
}
}
}
}
private void applyListeners(Configuration configuration, SessionFactoryServiceRegistry serviceRegistry) {
final boolean registerListeners = ConfigurationHelper.getBoolean( AUTO_REGISTER, configuration.getProperties(), false );
if ( !registerListeners ) {
LOG.debug( "Skipping legacy validator auto registration" );
return;
}
final Class listenerClass = loadListenerClass( serviceRegistry );
if ( listenerClass == null ) {
LOG.debug( "Skipping legacy validator auto registration - could not locate listener" );
return;
}
final Object validateEventListener;
try {
validateEventListener = listenerClass.newInstance();
}
catch ( Exception e ) {
throw new AnnotationException( "Unable to instantiate Validator event listener", e );
}
EventListenerRegistry listenerRegistry = serviceRegistry.getService( EventListenerRegistry.class );
// todo : duplication strategy
listenerRegistry.appendListeners( EventType.PRE_INSERT, (PreInsertEventListener) validateEventListener );
listenerRegistry.appendListeners( EventType.PRE_UPDATE, (PreUpdateEventListener) validateEventListener );
}
private Class loadListenerClass(SessionFactoryServiceRegistry serviceRegistry) {
try {
return serviceRegistry.getService( ClassLoaderService.class ).classForName( LISTENER_CLASS_NAME );
}
catch (Exception e) {
return null;
}
}
}

View File

@ -1,245 +0,0 @@
/*
* 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.search;
import java.util.Properties;
import org.hibernate.AnnotationException;
import org.hibernate.HibernateLogger;
import org.hibernate.event.EventListeners;
import org.hibernate.event.PostCollectionRecreateEventListener;
import org.hibernate.event.PostCollectionRemoveEventListener;
import org.hibernate.event.PostCollectionUpdateEventListener;
import org.hibernate.event.PostDeleteEventListener;
import org.hibernate.event.PostInsertEventListener;
import org.hibernate.event.PostUpdateEventListener;
import org.hibernate.internal.util.ReflectHelper;
import org.jboss.logging.Logger;
/**
* Helper methods initializing Hibernate Search event listeners.
*
* @deprecated as of release 3.4.0.CR2, replaced by Hibernate Search's {@link org.hibernate.search.cfg.EventListenerRegister}
* @author Emmanuel Bernard
* @author Hardy Ferentschik
*/
@Deprecated
public class HibernateSearchEventListenerRegister {
private static final HibernateLogger LOG = Logger.getMessageLogger(HibernateLogger.class,
HibernateSearchEventListenerRegister.class.getName());
/**
* Class name of the class needed to enable Search.
*/
private static final String FULL_TEXT_INDEX_EVENT_LISTENER_CLASS = "org.hibernate.search.event.FullTextIndexEventListener";
/**
* @deprecated as of release 3.4.0.CR2, replaced by Hibernate Search's {@link org.hibernate.search.cfg.EventListenerRegister#enableHibernateSearch(EventListeners, Properties)}
*/
@SuppressWarnings("unchecked")
@Deprecated
public static void enableHibernateSearch(EventListeners eventListeners, Properties properties) {
// check whether search is explicitly enabled - if so there is nothing
// to do
String enableSearchListeners = properties.getProperty( "hibernate.search.autoregister_listeners" );
if("false".equalsIgnoreCase(enableSearchListeners )) {
LOG.willNotRegisterListeners();
return;
}
// add search events if the jar is available and class can be loaded
Class searchEventListenerClass = attemptToLoadSearchEventListener();
if ( searchEventListenerClass == null ) {
LOG.unableToFindListenerClass(FULL_TEXT_INDEX_EVENT_LISTENER_CLASS);
return;
}
Object searchEventListener = instantiateEventListener(searchEventListenerClass);
// TODO Generalize this. Pretty much the same code all the time. Reflection?
{
boolean present = false;
PostInsertEventListener[] listeners = eventListeners
.getPostInsertEventListeners();
if (listeners != null) {
for (Object eventListener : listeners) {
// not isAssignableFrom since the user could subclass
present = present
|| searchEventListenerClass == eventListener
.getClass();
}
if (!present) {
int length = listeners.length + 1;
PostInsertEventListener[] newListeners = new PostInsertEventListener[length];
System.arraycopy(listeners, 0, newListeners, 0, length - 1);
newListeners[length - 1] = (PostInsertEventListener) searchEventListener;
eventListeners.setPostInsertEventListeners(newListeners);
}
} else {
eventListeners
.setPostInsertEventListeners(new PostInsertEventListener[] { (PostInsertEventListener) searchEventListener });
}
}
{
boolean present = false;
PostUpdateEventListener[] listeners = eventListeners
.getPostUpdateEventListeners();
if (listeners != null) {
for (Object eventListener : listeners) {
// not isAssignableFrom since the user could subclass
present = present
|| searchEventListenerClass == eventListener
.getClass();
}
if (!present) {
int length = listeners.length + 1;
PostUpdateEventListener[] newListeners = new PostUpdateEventListener[length];
System.arraycopy(listeners, 0, newListeners, 0, length - 1);
newListeners[length - 1] = (PostUpdateEventListener) searchEventListener;
eventListeners.setPostUpdateEventListeners(newListeners);
}
} else {
eventListeners
.setPostUpdateEventListeners(new PostUpdateEventListener[] { (PostUpdateEventListener) searchEventListener });
}
}
{
boolean present = false;
PostDeleteEventListener[] listeners = eventListeners
.getPostDeleteEventListeners();
if (listeners != null) {
for (Object eventListener : listeners) {
// not isAssignableFrom since the user could subclass
present = present
|| searchEventListenerClass == eventListener
.getClass();
}
if (!present) {
int length = listeners.length + 1;
PostDeleteEventListener[] newListeners = new PostDeleteEventListener[length];
System.arraycopy(listeners, 0, newListeners, 0, length - 1);
newListeners[length - 1] = (PostDeleteEventListener) searchEventListener;
eventListeners.setPostDeleteEventListeners(newListeners);
}
} else {
eventListeners
.setPostDeleteEventListeners(new PostDeleteEventListener[] { (PostDeleteEventListener) searchEventListener });
}
}
{
boolean present = false;
PostCollectionRecreateEventListener[] listeners = eventListeners.getPostCollectionRecreateEventListeners();
if ( listeners != null ) {
for (Object eventListener : listeners) {
//not isAssignableFrom since the user could subclass
present = present || searchEventListenerClass == eventListener.getClass();
}
if ( !present ) {
int length = listeners.length + 1;
PostCollectionRecreateEventListener[] newListeners = new PostCollectionRecreateEventListener[length];
System.arraycopy( listeners, 0, newListeners, 0, length - 1 );
newListeners[length - 1] = (PostCollectionRecreateEventListener) searchEventListener;
eventListeners.setPostCollectionRecreateEventListeners( newListeners );
}
}
else {
eventListeners.setPostCollectionRecreateEventListeners(
new PostCollectionRecreateEventListener[] { (PostCollectionRecreateEventListener) searchEventListener }
);
}
}
{
boolean present = false;
PostCollectionRemoveEventListener[] listeners = eventListeners.getPostCollectionRemoveEventListeners();
if ( listeners != null ) {
for (Object eventListener : listeners) {
//not isAssignableFrom since the user could subclass
present = present || searchEventListenerClass == eventListener.getClass();
}
if ( !present ) {
int length = listeners.length + 1;
PostCollectionRemoveEventListener[] newListeners = new PostCollectionRemoveEventListener[length];
System.arraycopy( listeners, 0, newListeners, 0, length - 1 );
newListeners[length - 1] = (PostCollectionRemoveEventListener) searchEventListener;
eventListeners.setPostCollectionRemoveEventListeners( newListeners );
}
}
else {
eventListeners.setPostCollectionRemoveEventListeners(
new PostCollectionRemoveEventListener[] { (PostCollectionRemoveEventListener) searchEventListener }
);
}
}
{
boolean present = false;
PostCollectionUpdateEventListener[] listeners = eventListeners.getPostCollectionUpdateEventListeners();
if ( listeners != null ) {
for (Object eventListener : listeners) {
//not isAssignableFrom since the user could subclass
present = present || searchEventListenerClass == eventListener.getClass();
}
if ( !present ) {
int length = listeners.length + 1;
PostCollectionUpdateEventListener[] newListeners = new PostCollectionUpdateEventListener[length];
System.arraycopy( listeners, 0, newListeners, 0, length - 1 );
newListeners[length - 1] = (PostCollectionUpdateEventListener) searchEventListener;
eventListeners.setPostCollectionUpdateEventListeners( newListeners );
}
}
else {
eventListeners.setPostCollectionUpdateEventListeners(
new PostCollectionUpdateEventListener[] { (PostCollectionUpdateEventListener) searchEventListener }
);
}
}
}
/**
* Tries to load Hibernate Search event listener.
*
* @return An event listener instance in case the jar was available.
*/
private static Class<?> attemptToLoadSearchEventListener() {
Class searchEventListenerClass = null;
try {
searchEventListenerClass = ReflectHelper.classForName(
FULL_TEXT_INDEX_EVENT_LISTENER_CLASS,
HibernateSearchEventListenerRegister.class);
} catch (ClassNotFoundException e) {
LOG.debugf("Search not present in classpath, ignoring event listener registration.");
}
return searchEventListenerClass;
}
private static Object instantiateEventListener(Class<?> clazz) {
Object searchEventListener;
try {
searchEventListener = clazz.newInstance();
} catch (Exception e) {
throw new AnnotationException(
"Unable to load Search event listener", e);
}
return searchEventListener;
}
}

View File

@ -0,0 +1,129 @@
/*
* 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.search;
import org.jboss.logging.Logger;
import org.hibernate.AnnotationException;
import org.hibernate.HibernateLogger;
import org.hibernate.cfg.Configuration;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.event.EventType;
import org.hibernate.event.PostCollectionRecreateEventListener;
import org.hibernate.event.PostCollectionRemoveEventListener;
import org.hibernate.event.PostCollectionUpdateEventListener;
import org.hibernate.event.PostDeleteEventListener;
import org.hibernate.event.PostInsertEventListener;
import org.hibernate.event.PostUpdateEventListener;
import org.hibernate.impl.Integrator;
import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.service.classloading.spi.ClassLoaderService;
import org.hibernate.service.event.spi.DuplicationStrategy;
import org.hibernate.service.event.spi.EventListenerRegistry;
import org.hibernate.service.spi.SessionFactoryServiceRegistry;
/**
* Integrates Hibernate Search into Hibernate Core by registering its needed listeners
* <p/>
* The note on the original (now removed) org.hibernate.cfg.search.HibernateSearchEventListenerRegister class indicated
* that Search now uses a new means for this. However that signature is relying on removed classes...
*
* @author Emmanuel Bernard
* @author Hardy Ferentschik
* @author Steve Ebersole
*/
public class HibernateSearchIntegrator implements Integrator {
private static final HibernateLogger LOG = Logger.getMessageLogger(HibernateLogger.class, HibernateSearchIntegrator.class.getName() );
public static final String AUTO_REGISTER = "hibernate.search.autoregister_listeners";
public static final String LISTENER_CLASS = "org.hibernate.search.event.FullTextIndexEventListener";
@Override
public void integrate(
Configuration configuration,
SessionFactoryImplementor sessionFactory,
SessionFactoryServiceRegistry serviceRegistry) {
final boolean registerListeners = ConfigurationHelper.getBoolean( AUTO_REGISTER, configuration.getProperties(), false );
if ( !registerListeners ) {
LOG.debug( "Skipping search event listener auto registration" );
return;
}
final Class listenerClass = loadSearchEventListener( serviceRegistry );
if ( listenerClass == null ) {
LOG.debug( "Skipping search event listener auto registration - could not fid listener class" );
return;
}
final Object listener = instantiateListener( listenerClass );
EventListenerRegistry listenerRegistry = serviceRegistry.getService( EventListenerRegistry.class );
listenerRegistry.addDuplicationStrategy( new DuplicationStrategyImpl( listenerClass ) );
listenerRegistry.getEventListenerGroup( EventType.POST_INSERT ).appendListener( (PostInsertEventListener) listener );
listenerRegistry.getEventListenerGroup( EventType.POST_UPDATE ).appendListener( (PostUpdateEventListener) listener );
listenerRegistry.getEventListenerGroup( EventType.POST_DELETE ).appendListener( (PostDeleteEventListener) listener );
listenerRegistry.getEventListenerGroup( EventType.POST_COLLECTION_RECREATE ).appendListener( (PostCollectionRecreateEventListener) listener );
listenerRegistry.getEventListenerGroup( EventType.POST_COLLECTION_REMOVE ).appendListener( (PostCollectionRemoveEventListener) listener );
listenerRegistry.getEventListenerGroup( EventType.POST_COLLECTION_UPDATE ).appendListener( (PostCollectionUpdateEventListener) listener );
}
private Class loadSearchEventListener(SessionFactoryServiceRegistry serviceRegistry) {
try {
return serviceRegistry.getService( ClassLoaderService.class ).classForName( LISTENER_CLASS );
}
catch (Exception e) {
return null;
}
}
private Object instantiateListener(Class listenerClass) {
try {
return listenerClass.newInstance();
}
catch (Exception e) {
throw new AnnotationException( "Unable to instantiate Search event listener", e );
}
}
public static class DuplicationStrategyImpl implements DuplicationStrategy {
private final Class checkClass;
public DuplicationStrategyImpl(Class checkClass) {
this.checkClass = checkClass;
}
@Override
public boolean areMatch(Object listener, Object original) {
// not isAssignableFrom since the user could subclass
return checkClass == original.getClass() && checkClass == listener.getClass();
}
@Override
public Action getAction() {
return Action.KEEP_ORIGINAL;
}
}
}

View File

@ -79,6 +79,9 @@ import org.hibernate.cache.impl.CacheDataDescriptionImpl;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;
import org.hibernate.cfg.Settings;
import org.hibernate.cfg.beanvalidation.BeanValidationIntegrator;
import org.hibernate.cfg.beanvalidation.LegacyHibernateValidationIntegrator;
import org.hibernate.cfg.search.HibernateSearchIntegrator;
import org.hibernate.context.CurrentSessionContext;
import org.hibernate.context.JTASessionContext;
import org.hibernate.context.ManagedSessionContext;
@ -488,7 +491,10 @@ public final class SessionFactoryImpl
private Iterable<Integrator> locateIntegrators(ServiceRegistryImplementor serviceRegistry) {
List<Integrator> integrators = new ArrayList<Integrator>();
// todo : add "known" integrators -> BV, hibernate validation, search, envers
// todo : Envers needs to bbe handled by discovery to be because it is in a separate project
integrators.add( new LegacyHibernateValidationIntegrator() );
integrators.add( new BeanValidationIntegrator() );
integrators.add( new HibernateSearchIntegrator() );
final Properties properties = new Properties();

View File

@ -22,6 +22,7 @@
* Boston, MA 02110-1301 USA
*/
package org.hibernate.service.classloading.internal;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
@ -29,6 +30,7 @@ import java.util.Enumeration;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import org.hibernate.service.classloading.spi.ClassLoaderService;
import org.hibernate.service.classloading.spi.ClassLoadingException;
@ -50,7 +52,7 @@ public class ClassLoaderServiceImpl implements ClassLoaderService {
this( determineClassLoaders( configVales ) );
}
private ClassLoaderServiceImpl(ClassLoader[] classLoaders) {
private ClassLoaderServiceImpl(ClassLoader... classLoaders) {
this( classLoaders[0], classLoaders[1], classLoaders[2], classLoaders[3] );
}
@ -128,7 +130,7 @@ public class ClassLoaderServiceImpl implements ClassLoaderService {
try {
return classLoader.loadClass( className );
}
catch ( Exception e ) {
catch ( Exception ignore) {
}
}
throw new ClassLoadingException( "Unable to load class [" + className + "]" );
@ -140,13 +142,13 @@ public class ClassLoaderServiceImpl implements ClassLoaderService {
try {
return new URL( name );
}
catch ( Exception e ) {
catch ( Exception ignore ) {
}
try {
return resourcesClassLoader.getResource( name );
}
catch ( Exception e ) {
catch ( Exception ignore ) {
}
return null;
@ -158,13 +160,13 @@ public class ClassLoaderServiceImpl implements ClassLoaderService {
try {
return new URL( name ).openStream();
}
catch ( Exception e ) {
catch ( Exception ignore ) {
}
try {
return resourcesClassLoader.getResourceAsStream( name );
}
catch ( Exception e ) {
catch ( Exception ignore ) {
}
return null;
@ -172,20 +174,19 @@ public class ClassLoaderServiceImpl implements ClassLoaderService {
@Override
public List<URL> locateResources(String name) {
ArrayList<URL> urls = new ArrayList<URL>();
try {
Enumeration<URL> urlEnumeration = resourcesClassLoader.getResources( name );
if ( urlEnumeration != null && urlEnumeration.hasMoreElements() ) {
ArrayList<URL> urls = new ArrayList<URL>();
while ( urlEnumeration.hasMoreElements() ) {
urls.add( urlEnumeration.nextElement() );
}
return urls;
}
}
catch ( Exception e ) {
catch ( Exception ignore ) {
}
return null;
return urls;
}
}

View File

@ -74,9 +74,9 @@ public class CallbackTest extends BaseCoreFunctionalTestCase {
public void apply(
EventListenerRegistry eventListenerRegistry,
Configuration configuration,
Map<?, ?> configValues, ServiceRegistryImplementor serviceRegistry
) {
serviceRegistry.getService( EventListenerRegistry.class ).setListeners( EventType.DELETE, listener );
Map<?, ?> configValues,
ServiceRegistryImplementor serviceRegistry) {
eventListenerRegistry.setListeners( EventType.DELETE, listener );
}
}
);