diff --git a/hibernate-core/src/main/java/org/hibernate/event/spi/EventEngine.java b/hibernate-core/src/main/java/org/hibernate/event/spi/EventEngine.java index c525377aa9..96ff95c464 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/spi/EventEngine.java +++ b/hibernate-core/src/main/java/org/hibernate/event/spi/EventEngine.java @@ -5,7 +5,6 @@ package org.hibernate.event.spi; import java.util.Collection; -import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.function.Consumer; @@ -13,15 +12,19 @@ import java.util.function.Consumer; import org.hibernate.HibernateException; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.boot.spi.MetadataImplementor; +import org.hibernate.boot.spi.SessionFactoryOptions; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.event.service.internal.EventListenerRegistryImpl; import org.hibernate.event.service.spi.EventListenerGroup; import org.hibernate.event.service.spi.EventListenerRegistry; -import org.hibernate.internal.util.collections.CollectionHelper; -import org.hibernate.jpa.event.internal.CallbacksFactory; import org.hibernate.jpa.event.spi.CallbackRegistry; +import org.hibernate.service.spi.ServiceRegistryImplementor; import org.hibernate.service.spi.Stoppable; +import static java.util.Collections.unmodifiableMap; +import static org.hibernate.internal.util.collections.CollectionHelper.isNotEmpty; +import static org.hibernate.jpa.event.internal.CallbacksFactory.buildCallbackRegistry; + /** * Composite for the things related to Hibernate's event system. * @@ -36,102 +39,39 @@ public class EventEngine { public EventEngine(MetadataImplementor mappings, SessionFactoryImplementor sessionFactory) { + final SessionFactoryOptions sessionFactoryOptions = sessionFactory.getSessionFactoryOptions(); + final ServiceRegistryImplementor serviceRegistry = sessionFactory.getServiceRegistry(); + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // resolve (JPA) callback handlers - callbackRegistry = CallbacksFactory.buildCallbackRegistry( sessionFactory.getSessionFactoryOptions(), - sessionFactory.getServiceRegistry(), mappings.getEntityBindings() ); - + callbackRegistry = buildCallbackRegistry( sessionFactoryOptions, serviceRegistry, mappings.getEntityBindings() ); // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // resolve event types and listeners - final EventListenerRegistryImpl.Builder listenerRegistryBuilder = new EventListenerRegistryImpl.Builder( - callbackRegistry, - sessionFactory.getSessionFactoryOptions().isJpaBootstrap() - ); + final EventListenerRegistryImpl.Builder listenerRegistryBuilder = + new EventListenerRegistryImpl.Builder( callbackRegistry, sessionFactoryOptions.isJpaBootstrap() ); final Map> eventTypes = new HashMap<>(); EventType.registerStandardTypes( eventTypes ); - final EventEngineContributions contributionManager = new EventEngineContributions() { - @Override - public EventType findEventType(String name) { - //noinspection unchecked - return (EventType) eventTypes.get( name ); - } + callContributors( serviceRegistry, new ContributionManager( eventTypes, listenerRegistryBuilder ) ); - @Override - public EventType contributeEventType(String name, Class listenerRole) { - final EventType eventType = registerEventType( name, listenerRole ); - - listenerRegistryBuilder.prepareListeners( eventType ); - - return eventType; - } - - private EventType registerEventType(String name, Class listenerRole) { - if ( name == null ) { - throw new HibernateException( "Custom event-type name must be non-null." ); - } - - if ( listenerRole == null ) { - throw new HibernateException( "Custom event-type listener role must be non-null." ); - } - - // make sure it does not match an existing name... - if ( eventTypes.containsKey( name ) ) { - final EventType existing = eventTypes.get( name ); - throw new HibernateException( - "Custom event-type already registered: " + name + " => " + existing - ); - } - - final EventType eventType = EventType.create( - name, - listenerRole, - eventTypes.size() - ); - - eventTypes.put( name, eventType ); - return eventType; - } - - @Override @SafeVarargs - public final EventType contributeEventType(String name, Class listenerRole, T... defaultListeners) { - final EventType eventType = contributeEventType( name, listenerRole ); - - if ( defaultListeners != null ) { - listenerRegistryBuilder.getListenerGroup( eventType ).appendListeners( defaultListeners ); - } - - return eventType; - } - - @Override - public void configureListeners( - EventType eventType, - Consumer> action) { - if ( ! eventTypes.containsValue( eventType ) ) { - throw new HibernateException( "EventType [" + eventType + "] not registered" ); - } - - action.accept( listenerRegistryBuilder.getListenerGroup( eventType ) ); - } - }; + registeredEventTypes = unmodifiableMap( eventTypes ); + listenerRegistry = listenerRegistryBuilder.buildRegistry( registeredEventTypes ); + } + private static void callContributors( + ServiceRegistryImplementor serviceRegistry, EventEngineContributions contributionManager) { final Collection discoveredContributors = - sessionFactory.getServiceRegistry() - .requireService( ClassLoaderService.class ) + serviceRegistry.requireService( ClassLoaderService.class ) .loadJavaServices( EventEngineContributor.class ); - if ( CollectionHelper.isNotEmpty( discoveredContributors ) ) { + if ( isNotEmpty( discoveredContributors ) ) { for ( EventEngineContributor contributor : discoveredContributors ) { contributor.contribute( contributionManager ); } } - - this.registeredEventTypes = Collections.unmodifiableMap( eventTypes ); - this.listenerRegistry = listenerRegistryBuilder.buildRegistry( registeredEventTypes ); } public Collection> getRegisteredEventTypes() { @@ -152,10 +92,73 @@ public class EventEngine { } public void stop() { - if ( listenerRegistry instanceof Stoppable ) { - ( (Stoppable) listenerRegistry ).stop(); + if ( listenerRegistry instanceof Stoppable stoppable ) { + stoppable.stop(); } - callbackRegistry.release(); } + + private static class ContributionManager implements EventEngineContributions { + private final Map> eventTypes; + private final EventListenerRegistryImpl.Builder listenerRegistryBuilder; + + public ContributionManager( + Map> eventTypes, + EventListenerRegistryImpl.Builder listenerRegistryBuilder) { + this.eventTypes = eventTypes; + this.listenerRegistryBuilder = listenerRegistryBuilder; + } + + @Override + public EventType findEventType(String name) { + //noinspection unchecked + return (EventType) eventTypes.get( name ); + } + + @Override + public EventType contributeEventType(String name, Class listenerRole) { + final EventType eventType = registerEventType( name, listenerRole ); + listenerRegistryBuilder.prepareListeners( eventType ); + return eventType; + } + + private EventType registerEventType(String name, Class listenerRole) { + if ( name == null ) { + throw new HibernateException( "Custom event-type name must be non-null." ); + } + else if ( listenerRole == null ) { + throw new HibernateException( "Custom event-type listener role must be non-null." ); + } + // make sure it does not match an existing name... + else if ( eventTypes.containsKey( name ) ) { + final EventType existing = eventTypes.get( name ); + throw new HibernateException( + "Custom event-type already registered: " + name + " => " + existing + ); + } + else { + final EventType eventType = EventType.create( name, listenerRole, eventTypes.size() ); + eventTypes.put( name, eventType ); + return eventType; + } + } + + @Override + @SafeVarargs + public final EventType contributeEventType(String name, Class listenerRole, T... defaultListeners) { + final EventType eventType = contributeEventType( name, listenerRole ); + if ( defaultListeners != null ) { + listenerRegistryBuilder.getListenerGroup( eventType ).appendListeners( defaultListeners ); + } + return eventType; + } + + @Override + public void configureListeners(EventType eventType, Consumer> action) { + if ( !eventTypes.containsValue( eventType ) ) { + throw new HibernateException( "EventType [" + eventType + "] not registered" ); + } + action.accept( listenerRegistryBuilder.getListenerGroup( eventType ) ); + } + } } diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/CallbacksFactory.java b/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/CallbacksFactory.java index 0a0e8d22d2..1accf10ea8 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/CallbacksFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/CallbacksFactory.java @@ -29,63 +29,67 @@ import org.jboss.logging.Logger; public final class CallbacksFactory { private static final Logger log = Logger.getLogger( CallbacksFactory.class ); - public static CallbackRegistry buildCallbackRegistry(SessionFactoryOptions options, ServiceRegistry serviceRegistry, Collection entityBindings) { - if ( !jpaCallBacksEnabled( options ) ) { + public static CallbackRegistry buildCallbackRegistry( + SessionFactoryOptions options, ServiceRegistry serviceRegistry, Collection entityBindings) { + if ( !options.areJPACallbacksEnabled() ) { return new EmptyCallbackRegistryImpl(); } - ManagedBeanRegistry beanRegistry = serviceRegistry.getService( ManagedBeanRegistry.class ); - CallbackRegistryImpl.Builder registryBuilder = new CallbackRegistryImpl.Builder(); - Set> entityClasses = new HashSet<>(); + final ManagedBeanRegistry beanRegistry = serviceRegistry.getService( ManagedBeanRegistry.class ); + final CallbackRegistryImpl.Builder registryBuilder = new CallbackRegistryImpl.Builder(); + final Set> entityClasses = new HashSet<>(); for ( PersistentClass persistentClass : entityBindings ) { - if ( persistentClass.getClassName() == null ) { - // we can have dynamic (non-java class) mapping - continue; - } - - Class entityClass = persistentClass.getMappedClass(); - - if ( !entityClasses.add( entityClass ) ) { - // this most likely means we have a class mapped multiple times using the hbm.xml - // "entity name" feature - if ( log.isDebugEnabled() ) { - log.debugf( - "Class [%s] already has callbacks registered; " + - "assuming this means the class was mapped twice " + - "(using hbm.xml entity-name support) - skipping subsequent registrations" + - "to avoid duplicates", - entityClass.getName() - ); + if ( persistentClass.getClassName() != null ) { + final Class entityClass = persistentClass.getMappedClass(); + if ( !entityClasses.add( entityClass ) ) { + // this most likely means we have a class mapped multiple + // times using the hbm.xml "entity name" feature + if ( log.isDebugEnabled() ) { + log.debugf( + "Class [%s] already has callbacks registered; " + + "assuming this means the class was mapped twice " + + "(using hbm.xml entity-name support) - skipping subsequent registrations" + + "to avoid duplicates", + entityClass.getName() + ); + } + } + else { + registerAllCallbacks( persistentClass, registryBuilder, entityClass, beanRegistry ); } - continue; - } - - registryBuilder.registerCallbacks( persistentClass.getMappedClass(), - buildCallbacks( persistentClass.getCallbackDefinitions(), beanRegistry ) ); - - for ( Property property : persistentClass.getDeclaredProperties() ) { - registryBuilder.registerCallbacks( persistentClass.getMappedClass(), - buildCallbacks( property.getCallbackDefinitions(), beanRegistry ) ); } + // else we can have dynamic (non-java class) mapping } return registryBuilder.build(); } + private static void registerAllCallbacks( + PersistentClass persistentClass, + CallbackRegistryImpl.Builder registryBuilder, + Class entityClass, + ManagedBeanRegistry beanRegistry) { + registryBuilder.registerCallbacks( entityClass, + buildCallbacks( persistentClass.getCallbackDefinitions(), beanRegistry ) ); + + for ( Property property : persistentClass.getDeclaredProperties() ) { + registryBuilder.registerCallbacks( entityClass, + buildCallbacks( property.getCallbackDefinitions(), beanRegistry ) ); + } + } + private static Callback[] buildCallbacks(List callbackDefinitions, ManagedBeanRegistry beanRegistry) { if ( callbackDefinitions == null || callbackDefinitions.isEmpty() ) { return null; } - List callbacks = new ArrayList<>(); - for ( CallbackDefinition definition : callbackDefinitions ) { - callbacks.add( definition.createCallback( beanRegistry ) ); + else { + final List callbacks = new ArrayList<>(); + for ( CallbackDefinition definition : callbackDefinitions ) { + callbacks.add( definition.createCallback( beanRegistry ) ); + } + return callbacks.toArray( new Callback[0] ); } - return callbacks.toArray( new Callback[0] ); - } - - private static boolean jpaCallBacksEnabled(SessionFactoryOptions options) { - return options.areJPACallbacksEnabled(); } }