package org.hibernate.event.service.internal;
import java.lang.reflect.Array;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.hibernate.HibernateException;
import org.hibernate.boot.spi.BootstrapContext;
import org.hibernate.boot.spi.MetadataImplementor;
import org.hibernate.boot.spi.SessionFactoryOptions;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.event.internal.DefaultAutoFlushEventListener;
import org.hibernate.event.internal.DefaultDeleteEventListener;
import org.hibernate.event.internal.DefaultDirtyCheckEventListener;
import org.hibernate.event.internal.DefaultEvictEventListener;
import org.hibernate.event.internal.DefaultFlushEntityEventListener;
import org.hibernate.event.internal.DefaultFlushEventListener;
import org.hibernate.event.internal.DefaultInitializeCollectionEventListener;
import org.hibernate.event.internal.DefaultLoadEventListener;
import org.hibernate.event.internal.DefaultLockEventListener;
import org.hibernate.event.internal.DefaultMergeEventListener;
import org.hibernate.event.internal.DefaultPersistEventListener;
import org.hibernate.event.internal.DefaultPersistOnFlushEventListener;
import org.hibernate.event.internal.DefaultPostLoadEventListener;
import org.hibernate.event.internal.DefaultPreLoadEventListener;
import org.hibernate.event.internal.DefaultRefreshEventListener;
import org.hibernate.event.internal.DefaultReplicateEventListener;
import org.hibernate.event.internal.DefaultResolveNaturalIdEventListener;
import org.hibernate.event.internal.DefaultSaveEventListener;
import org.hibernate.event.internal.DefaultSaveOrUpdateEventListener;
import org.hibernate.event.internal.DefaultUpdateEventListener;
import org.hibernate.event.internal.PostDeleteEventListenerStandardImpl;
import org.hibernate.event.internal.PostInsertEventListenerStandardImpl;
import org.hibernate.event.internal.PostUpdateEventListenerStandardImpl;
import org.hibernate.event.service.spi.DuplicationStrategy;
import org.hibernate.event.service.spi.EventListenerRegistrationException;
import org.hibernate.event.service.spi.EventListenerRegistry;
import org.hibernate.event.spi.EventType;
import org.hibernate.jpa.event.internal.CallbackBuilderLegacyImpl;
import org.hibernate.jpa.event.internal.CallbackRegistryImpl;
import org.hibernate.jpa.event.spi.CallbackBuilder;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property;
import org.hibernate.resource.beans.spi.ManagedBeanRegistry;
import org.hibernate.service.spi.ServiceRegistryImplementor;
import org.hibernate.service.spi.Stoppable;
import static org.hibernate.event.spi.EventType.AUTO_FLUSH;
import static org.hibernate.event.spi.EventType.CLEAR;
import static org.hibernate.event.spi.EventType.DELETE;
import static org.hibernate.event.spi.EventType.DIRTY_CHECK;
import static org.hibernate.event.spi.EventType.EVICT;
import static org.hibernate.event.spi.EventType.FLUSH;
import static org.hibernate.event.spi.EventType.FLUSH_ENTITY;
import static org.hibernate.event.spi.EventType.INIT_COLLECTION;
import static org.hibernate.event.spi.EventType.LOAD;
import static org.hibernate.event.spi.EventType.LOCK;
import static org.hibernate.event.spi.EventType.MERGE;
import static org.hibernate.event.spi.EventType.PERSIST;
import static org.hibernate.event.spi.EventType.PERSIST_ONFLUSH;
import static org.hibernate.event.spi.EventType.POST_COLLECTION_RECREATE;
import static org.hibernate.event.spi.EventType.POST_COLLECTION_REMOVE;
import static org.hibernate.event.spi.EventType.POST_COLLECTION_UPDATE;
import static org.hibernate.event.spi.EventType.POST_COMMIT_DELETE;
import static org.hibernate.event.spi.EventType.POST_COMMIT_INSERT;
import static org.hibernate.event.spi.EventType.POST_COMMIT_UPDATE;
import static org.hibernate.event.spi.EventType.POST_DELETE;
import static org.hibernate.event.spi.EventType.POST_INSERT;
import static org.hibernate.event.spi.EventType.POST_LOAD;
import static org.hibernate.event.spi.EventType.POST_UPDATE;
import static org.hibernate.event.spi.EventType.PRE_COLLECTION_RECREATE;
import static org.hibernate.event.spi.EventType.PRE_COLLECTION_REMOVE;
import static org.hibernate.event.spi.EventType.PRE_COLLECTION_UPDATE;
import static org.hibernate.event.spi.EventType.PRE_DELETE;
import static org.hibernate.event.spi.EventType.PRE_INSERT;
import static org.hibernate.event.spi.EventType.PRE_LOAD;
import static org.hibernate.event.spi.EventType.PRE_UPDATE;
import static org.hibernate.event.spi.EventType.REFRESH;
import static org.hibernate.event.spi.EventType.REPLICATE;
import static org.hibernate.event.spi.EventType.RESOLVE_NATURAL_ID;
import static org.hibernate.event.spi.EventType.SAVE;
import static org.hibernate.event.spi.EventType.SAVE_UPDATE;
import static org.hibernate.event.spi.EventType.UPDATE;
public class EventListenerRegistryImpl implements EventListenerRegistry, Stoppable {
private Map<Class,Object> listenerClassToInstanceMap = new HashMap<>();
private final SessionFactoryImplementor sessionFactory;
private final CallbackRegistryImpl callbackRegistry;
private final EventListenerGroupImpl[] registeredEventListeners;
private CallbackBuilder callbackBuilder;
@Deprecated
EventListenerRegistryImpl(
SessionFactoryImplementor sessionFactory,
SessionFactoryOptions sessionFactoryOptions,
ServiceRegistryImplementor registry) {
this.sessionFactory = sessionFactory;
this.callbackRegistry = new CallbackRegistryImpl();
this.registeredEventListeners = buildListenerGroups();
}
EventListenerRegistryImpl(BootstrapContext bootstrapContext, SessionFactoryImplementor sessionFactory) {
this.sessionFactory = sessionFactory;
this.callbackRegistry = new CallbackRegistryImpl();
this.callbackBuilder = new CallbackBuilderLegacyImpl(
bootstrapContext.getServiceRegistry().getService( ManagedBeanRegistry.class ),
bootstrapContext.getReflectionManager()
);
this.registeredEventListeners = buildListenerGroups();
}
SessionFactoryImplementor getSessionFactory() {
return sessionFactory;
}
CallbackRegistryImpl getCallbackRegistry() {
return callbackRegistry;
}
@Override
public void prepare(MetadataImplementor metadata) {
if ( callbackBuilder == null ) {
this.callbackBuilder = new CallbackBuilderLegacyImpl(
sessionFactory.getServiceRegistry().getService( ManagedBeanRegistry.class ),
metadata.getMetadataBuildingOptions().getReflectionManager()
);
}
for ( PersistentClass persistentClass : metadata.getEntityBindings() ) {
if ( persistentClass.getClassName() == null ) {
continue;
}
callbackBuilder.buildCallbacksForEntity( persistentClass.getClassName(), callbackRegistry );
for ( Iterator propertyIterator = persistentClass.getDeclaredPropertyIterator();
propertyIterator.hasNext(); ) {
Property property = (Property) propertyIterator.next();
if ( property.getType().isComponentType() ) {
callbackBuilder.buildCallbacksForEmbeddable(
property,
persistentClass.getClassName(),
callbackRegistry
);
}
}
}
}
@SuppressWarnings({ "unchecked" })
public <T> EventListenerGroupImpl<T> getEventListenerGroup(EventType<T> eventType) {
EventListenerGroupImpl<T> listeners = registeredEventListeners[ eventType.ordinal() ];
if ( listeners == null ) {
throw new HibernateException( "Unable to find listeners for type [" + eventType.eventName() + "]" );
}
return listeners;
}
@Override
public void addDuplicationStrategy(DuplicationStrategy strategy) {
for ( EventListenerGroupImpl group : registeredEventListeners ) {
if ( group != null ) {
group.addDuplicationStrategy( strategy );
}
}
}
@Override
@SafeVarargs
public final <T> void setListeners(EventType<T> type, Class<? extends T>... listenerClasses) {
setListeners( type, resolveListenerInstances( type, listenerClasses ) );
}
@SuppressWarnings( {"unchecked"})
private <T> T[] resolveListenerInstances(EventType<T> type, Class<? extends T>... listenerClasses) {
T[] listeners = (T[]) Array.newInstance( type.baseListenerInterface(), listenerClasses.length );
for ( int i = 0; i < listenerClasses.length; i++ ) {
listeners[i] = resolveListenerInstance( listenerClasses[i] );
}
return listeners;
}
@SuppressWarnings( {"unchecked"})
private <T> T resolveListenerInstance(Class<T> listenerClass) {
T listenerInstance = (T) listenerClassToInstanceMap.get( listenerClass );
if ( listenerInstance == null ) {
listenerInstance = instantiateListener( listenerClass );
listenerClassToInstanceMap.put( listenerClass, listenerInstance );
}
return listenerInstance;
}
private <T> T instantiateListener(Class<T> listenerClass) {
try {
return listenerClass.newInstance();
}
catch ( Exception e ) {
throw new EventListenerRegistrationException(
"Unable to instantiate specified event listener class: " + listenerClass.getName(),
e
);
}
}
@Override
@SafeVarargs
public final <T> void setListeners(EventType<T> type, T... listeners) {
EventListenerGroupImpl<T> registeredListeners = getEventListenerGroup( type );
registeredListeners.clear();
if ( listeners != null ) {
for ( T listener : listeners ) {
registeredListeners.appendListener( listener );
}
}
}
@Override
@SafeVarargs
public final <T> void appendListeners(EventType<T> type, Class<? extends T>... listenerClasses) {
appendListeners( type, resolveListenerInstances( type, listenerClasses ) );
}
@Override
@SafeVarargs
public final <T> void appendListeners(EventType<T> type, T... listeners) {
getEventListenerGroup( type ).appendListeners( listeners );
}
@Override
@SafeVarargs
public final <T> void prependListeners(EventType<T> type, Class<? extends T>... listenerClasses) {
prependListeners( type, resolveListenerInstances( type, listenerClasses ) );
}
@Override
@SafeVarargs
public final <T> void prependListeners(EventType<T> type, T... listeners) {
getEventListenerGroup( type ).prependListeners( listeners );
}
private EventListenerGroupImpl[] buildListenerGroups() {
EventListenerGroupImpl[] listenerArray = new EventListenerGroupImpl[ EventType.values().size() ];
prepareListeners(
AUTO_FLUSH,
new DefaultAutoFlushEventListener(),
listenerArray
);
prepareListeners(
PERSIST,
new DefaultPersistEventListener(),
listenerArray
);
prepareListeners(
PERSIST_ONFLUSH,
new DefaultPersistOnFlushEventListener(),
listenerArray
);
prepareListeners(
DELETE,
new DefaultDeleteEventListener(),
listenerArray
);
prepareListeners(
DIRTY_CHECK,
new DefaultDirtyCheckEventListener(),
listenerArray
);
prepareListeners(
EVICT,
new DefaultEvictEventListener(),
listenerArray
);
prepareListeners(
CLEAR,
listenerArray
);
prepareListeners(
FLUSH,
new DefaultFlushEventListener(),
listenerArray
);
prepareListeners(
FLUSH_ENTITY,
new DefaultFlushEntityEventListener(),
listenerArray
);
prepareListeners(
LOAD,
new DefaultLoadEventListener(),
listenerArray
);
prepareListeners(
RESOLVE_NATURAL_ID,
new DefaultResolveNaturalIdEventListener(),
listenerArray
);
prepareListeners(
INIT_COLLECTION,
new DefaultInitializeCollectionEventListener(),
listenerArray
);
prepareListeners(
LOCK,
new DefaultLockEventListener(),
listenerArray
);
prepareListeners(
MERGE,
new DefaultMergeEventListener(),
listenerArray
);
prepareListeners(
PRE_COLLECTION_RECREATE,
listenerArray
);
prepareListeners(
PRE_COLLECTION_REMOVE,
listenerArray
);
prepareListeners(
PRE_COLLECTION_UPDATE,
listenerArray
);
prepareListeners(
PRE_DELETE,
listenerArray
);
prepareListeners(
PRE_INSERT,
listenerArray
);
prepareListeners(
PRE_LOAD,
new DefaultPreLoadEventListener(),
listenerArray
);
prepareListeners(
PRE_UPDATE,
listenerArray
);
prepareListeners(
POST_COLLECTION_RECREATE,
listenerArray
);
prepareListeners(
POST_COLLECTION_REMOVE,
listenerArray
);
prepareListeners(
POST_COLLECTION_UPDATE,
listenerArray
);
prepareListeners(
POST_COMMIT_DELETE,
listenerArray
);
prepareListeners(
POST_COMMIT_INSERT,
listenerArray
);
prepareListeners(
POST_COMMIT_UPDATE,
listenerArray
);
prepareListeners(
POST_DELETE,
new PostDeleteEventListenerStandardImpl(),
listenerArray
);
prepareListeners(
POST_INSERT,
new PostInsertEventListenerStandardImpl(),
listenerArray
);
prepareListeners(
POST_LOAD,
new DefaultPostLoadEventListener(),
listenerArray
);
prepareListeners(
POST_UPDATE,
new PostUpdateEventListenerStandardImpl(),
listenerArray
);
prepareListeners(
UPDATE,
new DefaultUpdateEventListener(),
listenerArray
);
prepareListeners(
REFRESH,
new DefaultRefreshEventListener(),
listenerArray
);
prepareListeners(
REPLICATE,
new DefaultReplicateEventListener(),
listenerArray
);
prepareListeners(
SAVE,
new DefaultSaveEventListener(),
listenerArray
);
prepareListeners(
SAVE_UPDATE,
new DefaultSaveOrUpdateEventListener(),
listenerArray
);
return listenerArray;
}
private <T> void prepareListeners(EventType<T> type, EventListenerGroupImpl[] listenerArray) {
prepareListeners( type, null, listenerArray );
}
private <T> void prepareListeners(EventType<T> type, T defaultListener, EventListenerGroupImpl[] listenerArray) {
final EventListenerGroupImpl<T> listenerGroup;
if ( type == EventType.POST_COMMIT_DELETE
|| type == EventType.POST_COMMIT_INSERT
|| type == EventType.POST_COMMIT_UPDATE ) {
listenerGroup = new PostCommitEventListenerGroupImpl<T>( type, this );
}
else {
listenerGroup = new EventListenerGroupImpl<T>( type, this );
}
if ( defaultListener != null ) {
listenerGroup.appendListener( defaultListener );
}
listenerArray[ type.ordinal() ] = listenerGroup;
}
@Override
public void stop() {
if ( callbackRegistry != null ) {
callbackRegistry.release();
}
if ( callbackBuilder != null ) {
callbackBuilder.release();
}
}
}