/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.event.spi;
import java.lang.reflect.Field;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import org.hibernate.HibernateException;
/**
* Enumeration of the recognized types of events, including meta-information about each.
*
* @author Steve Ebersole
*/
public final class EventType<T> {
private static AtomicInteger typeCounter = new AtomicInteger( 0 );
public static final EventType<LoadEventListener> LOAD = create( "load", LoadEventListener.class );
public static final EventType<ResolveNaturalIdEventListener> RESOLVE_NATURAL_ID = create( "resolve-natural-id", ResolveNaturalIdEventListener.class );
public static final EventType<InitializeCollectionEventListener> INIT_COLLECTION = create( "load-collection", InitializeCollectionEventListener.class );
public static final EventType<SaveOrUpdateEventListener> SAVE_UPDATE = create( "save-update", SaveOrUpdateEventListener.class );
public static final EventType<SaveOrUpdateEventListener> UPDATE = create( "update", SaveOrUpdateEventListener.class );
public static final EventType<SaveOrUpdateEventListener> SAVE = create( "save", SaveOrUpdateEventListener.class );
public static final EventType<PersistEventListener> PERSIST = create( "create", PersistEventListener.class );
public static final EventType<PersistEventListener> PERSIST_ONFLUSH = create( "create-onflush", PersistEventListener.class );
public static final EventType<MergeEventListener> MERGE = create( "merge", MergeEventListener.class );
public static final EventType<DeleteEventListener> DELETE = create( "delete", DeleteEventListener.class );
public static final EventType<ReplicateEventListener> REPLICATE = create( "replicate", ReplicateEventListener.class );
public static final EventType<FlushEventListener> FLUSH = create( "flush", FlushEventListener.class );
public static final EventType<AutoFlushEventListener> AUTO_FLUSH = create( "auto-flush", AutoFlushEventListener.class );
public static final EventType<DirtyCheckEventListener> DIRTY_CHECK = create( "dirty-check", DirtyCheckEventListener.class );
public static final EventType<FlushEntityEventListener> FLUSH_ENTITY = create( "flush-entity", FlushEntityEventListener.class );
public static final EventType<ClearEventListener> CLEAR = create( "clear", ClearEventListener.class );
public static final EventType<EvictEventListener> EVICT = create( "evict", EvictEventListener.class );
public static final EventType<LockEventListener> LOCK = create( "lock", LockEventListener.class );
public static final EventType<RefreshEventListener> REFRESH = create( "refresh", RefreshEventListener.class );
public static final EventType<PreLoadEventListener> PRE_LOAD = create( "pre-load", PreLoadEventListener.class );
public static final EventType<PreDeleteEventListener> PRE_DELETE = create( "pre-delete", PreDeleteEventListener.class );
public static final EventType<PreUpdateEventListener> PRE_UPDATE = create( "pre-update", PreUpdateEventListener.class );
public static final EventType<PreInsertEventListener> PRE_INSERT = create( "pre-insert", PreInsertEventListener.class );
public static final EventType<PostLoadEventListener> POST_LOAD = create( "post-load", PostLoadEventListener.class );
public static final EventType<PostDeleteEventListener> POST_DELETE = create( "post-delete", PostDeleteEventListener.class );
public static final EventType<PostUpdateEventListener> POST_UPDATE = create( "post-update", PostUpdateEventListener.class );
public static final EventType<PostInsertEventListener> POST_INSERT = create( "post-insert", PostInsertEventListener.class );
public static final EventType<PostDeleteEventListener> POST_COMMIT_DELETE = create( "post-commit-delete", PostDeleteEventListener.class );
public static final EventType<PostUpdateEventListener> POST_COMMIT_UPDATE = create( "post-commit-update", PostUpdateEventListener.class );
public static final EventType<PostInsertEventListener> POST_COMMIT_INSERT = create( "post-commit-insert", PostInsertEventListener.class );
public static final EventType<PreCollectionRecreateEventListener> PRE_COLLECTION_RECREATE = create( "pre-collection-recreate", PreCollectionRecreateEventListener.class );
public static final EventType<PreCollectionRemoveEventListener> PRE_COLLECTION_REMOVE = create( "pre-collection-remove", PreCollectionRemoveEventListener.class );
public static final EventType<PreCollectionUpdateEventListener> PRE_COLLECTION_UPDATE = create( "pre-collection-update", PreCollectionUpdateEventListener.class );
public static final EventType<PostCollectionRecreateEventListener> POST_COLLECTION_RECREATE = create( "post-collection-recreate", PostCollectionRecreateEventListener.class );
public static final EventType<PostCollectionRemoveEventListener> POST_COLLECTION_REMOVE = create( "post-collection-remove", PostCollectionRemoveEventListener.class );
public static final EventType<PostCollectionUpdateEventListener> POST_COLLECTION_UPDATE = create( "post-collection-update", PostCollectionUpdateEventListener.class );
private static <T> EventType<T> create(String name, Class<T> listenerClass) {
return new EventType<T>( name, listenerClass );
}
/**
* Maintain a map of {@link EventType} instances keyed by name for lookup by name as well as {@link #values()}
* resolution.
*/
private static final Map<String,EventType> EVENT_TYPE_BY_NAME_MAP = AccessController.doPrivileged(
new PrivilegedAction<Map<String, EventType>>() {
@Override
public Map<String, EventType> run() {
final Map<String, EventType> typeByNameMap = new HashMap<String, EventType>();
for ( Field field : EventType.class.getDeclaredFields() ) {
if ( EventType.class.isAssignableFrom( field.getType() ) ) {
try {
final EventType typeField = (EventType) field.get( null );
typeByNameMap.put( typeField.eventName(), typeField );
}
catch (Exception t) {
throw new HibernateException( "Unable to initialize EventType map", t );
}
}
}
return typeByNameMap;
}
}
);
/**
* Find an {@link EventType} by its name
*
* @param eventName The name
*
* @return The {@link EventType} instance.
*
* @throws HibernateException If eventName is null, or if eventName does not correlate to any known event type.
*/
public static EventType resolveEventTypeByName(final String eventName) {
if ( eventName == null ) {
throw new HibernateException( "event name to resolve cannot be null" );
}
final EventType eventType = EVENT_TYPE_BY_NAME_MAP.get( eventName );
if ( eventType == null ) {
throw new HibernateException( "Unable to locate proper event type for event name [" + eventName + "]" );
}
return eventType;
}
/**
* Get a collection of all {@link EventType} instances.
*
* @return All {@link EventType} instances
*/
public static Collection<EventType> values() {
return EVENT_TYPE_BY_NAME_MAP.values();
}
private final String eventName;
private final Class<T> baseListenerInterface;
private final int ordinal;
private EventType(String eventName, Class<T> baseListenerInterface) {
this.eventName = eventName;
this.baseListenerInterface = baseListenerInterface;
this.ordinal = typeCounter.getAndIncrement();
}
public String eventName() {
return eventName;
}
public Class baseListenerInterface() {
return baseListenerInterface;
}
@Override
public String toString() {
return eventName();
}
/**
* EventType is effectively an enumeration. Since there is a known, limited number of possible types, we expose an
* ordinal for each in order to be able to efficiently do associations elsewhere in the codebase (array vs. Map)
*
* For the total number of types, see {@link #values()}
*
* @return An unique ordinal for this {@link EventType}, starting at 0 and up to the number of distinct events
*/
public int ordinal() {
return ordinal;
}
}