minor cleanups to Actions

This commit is contained in:
Gavin King 2022-01-26 00:12:33 +01:00
parent 8f8ae50e0b
commit ee1d27719c
16 changed files with 132 additions and 109 deletions

View File

@ -34,13 +34,13 @@ import org.hibernate.query.sqm.tree.cte.SqmCteStatement;
import org.hibernate.sql.ast.tree.insert.InsertStatement;
/**
* An {@link org.hibernate.engine.spi.ActionQueue} {@link Executable} for ensuring
* shared cache cleanup in relation to performed bulk HQL queries.
* An {@link org.hibernate.engine.spi.ActionQueue} {@link Executable} for
* ensuring shared cache cleanup in relation to performed bulk HQL queries.
* <p/>
* NOTE: currently this executes for {@code INSERT} queries as well as
* {@code UPDATE} and {@code DELETE} queries. For {@code INSERT} it is
* really not needed as we'd have no invalid entity/collection data to
* cleanup (we'd still nee to invalidate the appropriate update-timestamps
* clean up (we'd still need to invalidate the appropriate update-timestamps
* regions) as a result of this query.
*
* @author Steve Ebersole
@ -112,8 +112,7 @@ public class BulkOperationCleanupAction implements Executable, Serializable {
* @param session The session to which this request is tied.
* @param tableSpaces The table spaces.
*/
@SuppressWarnings( { "unchecked", "rawtypes" } )
public BulkOperationCleanupAction(SharedSessionContractImplementor session, Set tableSpaces) {
public BulkOperationCleanupAction(SharedSessionContractImplementor session, Set<String> tableSpaces) {
final LinkedHashSet<String> spacesList = new LinkedHashSet<>( tableSpaces );
final SessionFactoryImplementor factory = session.getFactory();

View File

@ -113,10 +113,10 @@ public abstract class CollectionAction implements Executable, Serializable, Comp
if ( key instanceof DelayedPostInsertIdentifier ) {
// need to look it up from the persistence-context
finalKey = session.getPersistenceContextInternal().getEntry( collection.getOwner() ).getId();
if ( finalKey == key ) {
// if ( finalKey == key ) {
// we may be screwed here since the collection action is about to execute
// and we do not know the final owner key value
}
// }
}
return finalKey;
}

View File

@ -22,7 +22,7 @@ import org.hibernate.stat.spi.StatisticsImplementor;
*/
public final class CollectionRemoveAction extends CollectionAction {
private final Object affectedOwner;
private boolean emptySnapshot;
private final boolean emptySnapshot;
/**
* Removes a persistent collection from its loaded owner.

View File

@ -10,8 +10,6 @@ import org.hibernate.AssertionFailure;
import org.hibernate.HibernateException;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.event.service.spi.EventListenerGroup;
import org.hibernate.event.spi.EventType;
import org.hibernate.event.spi.PostCollectionUpdateEvent;
import org.hibernate.event.spi.PostCollectionUpdateEventListener;
import org.hibernate.event.spi.PreCollectionUpdateEvent;

View File

@ -12,23 +12,25 @@ import java.util.concurrent.atomic.AtomicLong;
/**
* Acts as a stand-in for an entity identifier which is supposed to be
* generated on insert (like an IDENTITY column) where the insert needed to
* be delayed because we were outside a transaction when the persist
* occurred (save currently still performs the insert).
* be delayed because we were outside a transaction when the persist operation
* was called (save currently still performs the insert).
* <p/>
* The stand-in is only used within the {@link org.hibernate.engine.spi.PersistenceContext}
* in order to distinguish one instance from another; it is never injected into
* the entity instance or returned to the client...
* the entity instance or returned to the client.
*
* @author Steve Ebersole
* @author Sanne Grinovero
*/
public class DelayedPostInsertIdentifier implements Serializable, Comparable<DelayedPostInsertIdentifier> {
public class DelayedPostInsertIdentifier
implements Serializable, Comparable<DelayedPostInsertIdentifier> {
private static final AtomicLong SEQUENCE = new AtomicLong();
private final long identifier;
/**
* Constructs a DelayedPostInsertIdentifier
* Constructs a {@link DelayedPostInsertIdentifier}
*/
public DelayedPostInsertIdentifier() {
long value = SEQUENCE.incrementAndGet();

View File

@ -14,10 +14,7 @@ import org.hibernate.action.spi.BeforeTransactionCompletionProcess;
import org.hibernate.action.spi.Executable;
import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.event.service.spi.EventListenerGroup;
import org.hibernate.event.service.spi.EventListenerRegistry;
import org.hibernate.event.spi.EventSource;
import org.hibernate.event.spi.EventType;
import org.hibernate.internal.FastSessionServices;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.persister.entity.EntityPersister;
@ -30,7 +27,7 @@ import org.hibernate.pretty.MessageHelper;
* @author Gavin King
*/
public abstract class EntityAction
implements Executable, Serializable, Comparable, AfterTransactionCompletionProcess {
implements Executable, Serializable, Comparable<EntityAction>, AfterTransactionCompletionProcess {
private final String entityName;
private final Object id;
@ -49,7 +46,11 @@ public abstract class EntityAction
* @param instance The entity instance
* @param persister The entity persister
*/
protected EntityAction(SharedSessionContractImplementor session, Object id, Object instance, EntityPersister persister) {
protected EntityAction(
SharedSessionContractImplementor session,
Object id,
Object instance,
EntityPersister persister) {
this.entityName = persister.getEntityName();
this.id = id;
this.instance = instance;
@ -107,8 +108,8 @@ public abstract class EntityAction
}
public final DelayedPostInsertIdentifier getDelayedId() {
return DelayedPostInsertIdentifier.class.isInstance( id )
? DelayedPostInsertIdentifier.class.cast( id )
return id instanceof DelayedPostInsertIdentifier
? (DelayedPostInsertIdentifier) id
: null;
}
@ -155,8 +156,7 @@ public abstract class EntityAction
}
@Override
public int compareTo(Object other) {
final EntityAction action = (EntityAction) other;
public int compareTo(EntityAction action) {
//sort first by entity name
final int roleComparison = entityName.compareTo( action.entityName );
if ( roleComparison != 0 ) {

View File

@ -34,7 +34,6 @@ public class EntityDeleteAction extends EntityAction {
private SoftLock lock;
private final NaturalIdMapping naturalIdMapping;
private Object naturalIdValues;
/**
@ -60,14 +59,15 @@ public class EntityDeleteAction extends EntityAction {
this.isCascadeDeleteEnabled = isCascadeDeleteEnabled;
this.state = state;
this.naturalIdMapping = persister.getNaturalIdMapping();
NaturalIdMapping naturalIdMapping = persister.getNaturalIdMapping();
if ( naturalIdMapping != null ) {
naturalIdValues = session.getPersistenceContextInternal().getNaturalIdResolutions().removeLocalResolution(
getId(),
naturalIdMapping.extractNaturalIdFromEntityState( state, session ),
getPersister()
);
naturalIdValues = session.getPersistenceContextInternal().getNaturalIdResolutions()
.removeLocalResolution(
getId(),
naturalIdMapping.extractNaturalIdFromEntityState( state, session ),
getPersister()
);
}
}

View File

@ -12,8 +12,6 @@ import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.event.service.spi.EventListenerGroup;
import org.hibernate.event.spi.EventSource;
import org.hibernate.event.spi.EventType;
import org.hibernate.event.spi.PostCommitInsertEventListener;
import org.hibernate.event.spi.PostInsertEvent;
import org.hibernate.event.spi.PostInsertEventListener;

View File

@ -12,8 +12,9 @@ import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.persister.entity.EntityPersister;
/**
* A BeforeTransactionCompletionProcess impl to verify and increment an entity version as party
* of before-transaction-completion processing
* A {@link BeforeTransactionCompletionProcess} implementation to verify and
* increment an entity version as party of before-transaction-completion
* processing.
*
* @author Scott Marlow
*/

View File

@ -18,7 +18,6 @@ import org.hibernate.engine.spi.SessionEventListenerManager;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.event.service.spi.EventListenerGroup;
import org.hibernate.event.spi.EventType;
import org.hibernate.event.spi.PostCommitInsertEventListener;
import org.hibernate.event.spi.PostInsertEvent;
import org.hibernate.event.spi.PostInsertEventListener;

View File

@ -14,8 +14,8 @@ import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.pretty.MessageHelper;
/**
* A BeforeTransactionCompletionProcess impl to verify an entity version as part of
* before-transaction-completion processing
* A {@link BeforeTransactionCompletionProcess} impl to verify an entity
* version as part of before-transaction-completion processing.
*
* @author Scott Marlow
*/

View File

@ -15,8 +15,10 @@ import org.hibernate.persister.collection.CollectionPersister;
/**
* If a collection is extra lazy and has queued ops, we still need to
* process them. Ex: OneToManyPersister needs to insert indexes for List
* collections. See HHH-8083.
* process them.
* <p>
* For example, {@link org.hibernate.persister.collection.OneToManyPersister}
* needs to insert indexes for lists. See HHH-8083.
*
* @author Brett Meyer
*/

View File

@ -45,6 +45,7 @@ import org.hibernate.cache.CacheException;
import org.hibernate.engine.internal.NonNullableTransientDependencies;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.LazyInitializer;
@ -52,7 +53,6 @@ import org.hibernate.type.CollectionType;
import org.hibernate.type.CompositeType;
import org.hibernate.type.EntityType;
import org.hibernate.type.ForeignKeyDirection;
import org.hibernate.type.OneToOneType;
import org.hibernate.type.Type;
/**
@ -68,7 +68,7 @@ import org.hibernate.type.Type;
public class ActionQueue {
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( ActionQueue.class );
private SessionImplementor session;
private final SessionImplementor session;
private UnresolvedEntityInsertActions unresolvedInsertions;
@ -103,7 +103,7 @@ public class ActionQueue {
/**
* A LinkedHashMap containing providers for all the ExecutableLists, inserted in execution order
*/
private static final LinkedHashMap<Class<? extends Executable>,ListProvider> EXECUTABLE_LISTS_MAP;
private static final LinkedHashMap<Class<? extends Executable>,ListProvider<?>> EXECUTABLE_LISTS_MAP;
static {
EXECUTABLE_LISTS_MAP = CollectionHelper.linkedMapOfSize( 8 );
@ -302,9 +302,13 @@ public class ActionQueue {
}
}
private <T extends Executable & Comparable<? super T> & Serializable> void addAction(Class<T> executableClass, T action) {
listProvider( executableClass ).getOrInit( this ).add( action );
}
@SuppressWarnings("unchecked")
private <T extends Executable & Comparable & Serializable> void addAction(Class<T> executableClass, T action) {
EXECUTABLE_LISTS_MAP.get( executableClass ).getOrInit( this ).add( action );
private <T extends Executable & Comparable<? super T> & Serializable> ListProvider<T> listProvider(Class<T> actionClass) {
return (ListProvider<T>) EXECUTABLE_LISTS_MAP.get(actionClass);
}
/**
@ -533,7 +537,10 @@ public class ActionQueue {
* @return {@code true} if insertions or deletions are currently queued; {@code false} otherwise.
*/
public boolean areInsertionsOrDeletionsQueued() {
return ( insertions != null && !insertions.isEmpty() ) || hasUnresolvedEntityInsertActions() || (deletions != null && !deletions.isEmpty()) || (orphanRemovals != null && !orphanRemovals.isEmpty());
return insertions != null && !insertions.isEmpty()
|| hasUnresolvedEntityInsertActions()
|| deletions != null && !deletions.isEmpty()
|| orphanRemovals != null && !orphanRemovals.isEmpty();
}
/**
@ -543,11 +550,11 @@ public class ActionQueue {
*
* @return {@code true} if we contain pending actions against any of the given tables; {@code false} otherwise.
*/
public boolean areTablesToBeUpdated(@SuppressWarnings("rawtypes") Set tables) {
public boolean areTablesToBeUpdated(Set<Serializable> tables) {
if ( tables.isEmpty() ) {
return false;
}
for ( ListProvider listProvider : EXECUTABLE_LISTS_MAP.values() ) {
for ( ListProvider<?> listProvider : EXECUTABLE_LISTS_MAP.values() ) {
ExecutableList<?> l = listProvider.get( this );
if ( areTablesToBeUpdated( l, tables ) ) {
return true;
@ -559,7 +566,7 @@ public class ActionQueue {
return areTablesToBeUpdated( unresolvedInsertions, tables );
}
private static boolean areTablesToBeUpdated(ExecutableList<?> actions, @SuppressWarnings("rawtypes") Set tableSpaces) {
private static boolean areTablesToBeUpdated(ExecutableList<?> actions, Set<Serializable> tableSpaces) {
if ( actions == null || actions.isEmpty() ) {
return false;
}
@ -574,7 +581,7 @@ public class ActionQueue {
return false;
}
private static boolean areTablesToBeUpdated(UnresolvedEntityInsertActions actions, @SuppressWarnings("rawtypes") Set tableSpaces) {
private static boolean areTablesToBeUpdated(UnresolvedEntityInsertActions actions, Set<Serializable> tableSpaces) {
for ( Executable action : actions.getDependentEntityInsertActions() ) {
final Serializable[] spaces = action.getPropertySpaces();
for ( Serializable space : spaces ) {
@ -593,7 +600,8 @@ public class ActionQueue {
* @param list The list of Executable elements to be performed
*
*/
private <E extends Executable & Comparable<?> & Serializable> void executeActions(ExecutableList<E> list) throws HibernateException {
private <E extends Executable & Comparable<? super E> & Serializable> void executeActions(ExecutableList<E> list)
throws HibernateException {
// todo : consider ways to improve the double iteration of Executables here:
// 1) we explicitly iterate list here to perform Executable#execute()
// 2) ExecutableList#getQuerySpaces also iterates the Executables to collect query spaces.
@ -632,8 +640,8 @@ public class ActionQueue {
session.getJdbcCoordinator().executeBatch();
}
private static String[] convertTimestampSpaces(Set spaces) {
return (String[]) spaces.toArray( new String[ spaces.size() ] );
private static String[] convertTimestampSpaces(Set<String> spaces) {
return spaces.toArray(StringHelper.EMPTY_STRINGS);
}
/**
@ -655,11 +663,11 @@ public class ActionQueue {
*/
private void invalidateSpaces(String... spaces) {
if ( spaces != null && spaces.length > 0 ) {
for ( Serializable s : spaces ) {
for ( String space : spaces ) {
if ( afterTransactionProcesses == null ) {
afterTransactionProcesses = new AfterTransactionCompletionProcessQueue( session );
}
afterTransactionProcesses.addSpaceToInvalidate( (String) s );
afterTransactionProcesses.addSpaceToInvalidate( space );
}
// Performance win: If we are processing an ExecutableList, this will only be called once
session.getFactory().getCache().getTimestampsCache().preInvalidate( spaces, session );
@ -685,7 +693,7 @@ public class ActionQueue {
+ "]";
}
private static String toString(ExecutableList q) {
private static String toString(ExecutableList<?> q) {
return q == null ? "ExecutableList{size=0}" : q.toString();
}
@ -748,7 +756,9 @@ public class ActionQueue {
* @param processes Transaction completion processes.
* @param isTransactionCoordinatorShared Flag indicating shared transaction context.
*/
public void setTransactionCompletionProcesses(TransactionCompletionProcesses processes, boolean isTransactionCoordinatorShared) {
public void setTransactionCompletionProcesses(
TransactionCompletionProcesses processes,
boolean isTransactionCoordinatorShared) {
this.isTransactionCoordinatorShared = isTransactionCoordinatorShared;
this.beforeTransactionProcesses = processes.beforeTransactionCompletionProcesses;
this.afterTransactionProcesses = processes.afterTransactionCompletionProcesses;
@ -812,12 +822,14 @@ public class ActionQueue {
@SuppressWarnings("SimplifiableConditionalExpression")
public boolean hasAfterTransactionActions() {
return isTransactionCoordinatorShared ? false : afterTransactionProcesses != null && afterTransactionProcesses.hasActions();
return isTransactionCoordinatorShared ? false
: afterTransactionProcesses != null && afterTransactionProcesses.hasActions();
}
@SuppressWarnings("SimplifiableConditionalExpression")
public boolean hasBeforeTransactionActions() {
return isTransactionCoordinatorShared ? false : beforeTransactionProcesses != null && beforeTransactionProcesses.hasActions();
return isTransactionCoordinatorShared ? false
: beforeTransactionProcesses != null && beforeTransactionProcesses.hasActions();
}
public boolean hasAnyQueuedActions() {
@ -868,7 +880,7 @@ public class ActionQueue {
}
unresolvedInsertions.serialize( oos );
for ( ListProvider p : EXECUTABLE_LISTS_MAP.values() ) {
for ( ListProvider<?> p : EXECUTABLE_LISTS_MAP.values() ) {
ExecutableList<?> l = p.get( this );
if ( l == null ) {
oos.writeBoolean( false );
@ -889,7 +901,8 @@ public class ActionQueue {
* @throws IOException indicates a problem reading from the stream
* @throws ClassNotFoundException Generally means we were unable to locate user classes.
*/
public static ActionQueue deserialize(ObjectInputStream ois, SessionImplementor session) throws IOException, ClassNotFoundException {
public static ActionQueue deserialize(ObjectInputStream ois, SessionImplementor session)
throws IOException, ClassNotFoundException {
final boolean traceEnabled = LOG.isTraceEnabled();
if ( traceEnabled ) {
LOG.trace( "Deserializing action-queue" );
@ -898,7 +911,7 @@ public class ActionQueue {
rtn.unresolvedInsertions = UnresolvedEntityInsertActions.deserialize( ois, session );
for ( ListProvider provider : EXECUTABLE_LISTS_MAP.values() ) {
for ( ListProvider<?> provider : EXECUTABLE_LISTS_MAP.values() ) {
ExecutableList<?> l = provider.get( rtn );
boolean notNull = ois.readBoolean();
if ( notNull ) {
@ -921,7 +934,7 @@ public class ActionQueue {
protected SessionImplementor session;
// Concurrency handling required when transaction completion process is dynamically registered
// inside event listener (HHH-7478).
protected Queue<T> processes = new ConcurrentLinkedQueue<T>();
protected Queue<T> processes = new ConcurrentLinkedQueue<>();
private AbstractTransactionCompletionProcessQueue(SessionImplementor session) {
this.session = session;
@ -965,8 +978,9 @@ public class ActionQueue {
/**
* Encapsulates behavior needed for after transaction processing
*/
private static class AfterTransactionCompletionProcessQueue extends AbstractTransactionCompletionProcessQueue<AfterTransactionCompletionProcess> {
private Set<String> querySpacesToInvalidate = new HashSet<>();
private static class AfterTransactionCompletionProcessQueue
extends AbstractTransactionCompletionProcessQueue<AfterTransactionCompletionProcess> {
private final Set<String> querySpacesToInvalidate = new HashSet<>();
private AfterTransactionCompletionProcessQueue(SessionImplementor session) {
super( session );
@ -992,7 +1006,7 @@ public class ActionQueue {
if ( session.getFactory().getSessionFactoryOptions().isQueryCacheEnabled() ) {
session.getFactory().getCache().getTimestampsCache().invalidate(
querySpacesToInvalidate.toArray( new String[querySpacesToInvalidate.size()] ),
querySpacesToInvalidate.toArray(StringHelper.EMPTY_STRINGS),
session
);
}
@ -1038,9 +1052,9 @@ public class ActionQueue {
private final String entityName;
private final String rootEntityName;
private Set<String> parentEntityNames = new HashSet<>( );
private final Set<String> parentEntityNames = new HashSet<>( );
private Set<String> childEntityNames = new HashSet<>( );
private final Set<String> childEntityNames = new HashSet<>( );
private BatchIdentifier parent;
@ -1111,7 +1125,8 @@ public class ActionQueue {
return (
parent == batchIdentifier
|| parentEntityNames.contains( batchIdentifier.getEntityName() )
|| ( parentEntityNames.contains( batchIdentifier.getRootEntityName() ) && !this.getEntityName().equals( batchIdentifier.getRootEntityName() ) )
|| ( parentEntityNames.contains( batchIdentifier.getRootEntityName() )
&& !this.getEntityName().equals( batchIdentifier.getRootEntityName() ) )
|| parent != null && parent.hasParent( batchIdentifier, new ArrayList<>() )
);
}
@ -1233,8 +1248,12 @@ public class ActionQueue {
while ( !sorted && iterations <= maxIterations );
if ( iterations > maxIterations ) {
LOG.warn( "The batch containing " + latestBatches.size() + " statements could not be sorted after " + maxIterations + " iterations. " +
"This might indicate a circular entity relationship." );
LOG.warn( "The batch containing "
+ latestBatches.size()
+ " statements could not be sorted after "
+ maxIterations
+ " iterations. "
+ "This might indicate a circular entity relationship." );
}
// Now, rebuild the insertions list. There is a batch for each entry in the name list.
@ -1277,13 +1296,18 @@ public class ActionQueue {
}
}
private void addParentChildEntityNameByPropertyAndValue(AbstractEntityInsertAction action, BatchIdentifier batchIdentifier, Type type, Object value) {
private void addParentChildEntityNameByPropertyAndValue(
AbstractEntityInsertAction action,
BatchIdentifier batchIdentifier,
Type type,
Object value) {
if ( type.isEntityType() ) {
final EntityType entityType = (EntityType) type;
final String entityName = entityType.getName();
final String rootEntityName = action.getSession().getFactory().getMetamodel().entityPersister( entityName ).getRootEntityName();
final String rootEntityName = action.getSession().getFactory().getMetamodel().
entityPersister( entityName ).getRootEntityName();
if ( entityType.isOneToOne() && OneToOneType.class.cast( entityType ).getForeignKeyDirection() == ForeignKeyDirection.TO_PARENT ) {
if ( entityType.isOneToOne() && entityType.getForeignKeyDirection() == ForeignKeyDirection.TO_PARENT ) {
if ( !entityType.isReferenceToPrimaryKey() ) {
batchIdentifier.getChildEntityNames().add( entityName );
}
@ -1308,12 +1332,12 @@ public class ActionQueue {
}
else if ( type.isCollectionType() ) {
CollectionType collectionType = (CollectionType) type;
final SessionFactoryImplementor sessionFactory = ( (SessionImplementor) action.getSession() )
.getSessionFactory();
final SessionFactoryImplementor sessionFactory = action.getSession().getSessionFactory();
if ( collectionType.getElementType( sessionFactory ).isEntityType() &&
!sessionFactory.getMetamodel().collectionPersister( collectionType.getRole() ).isManyToMany() ) {
String entityName = collectionType.getAssociatedEntityName( sessionFactory );
String rootEntityName = action.getSession().getFactory().getMetamodel().entityPersister( entityName ).getRootEntityName();
String rootEntityName = action.getSession().getFactory().getMetamodel()
.entityPersister( entityName ).getRootEntityName();
batchIdentifier.getChildEntityNames().add( entityName );
if ( !rootEntityName.equals( entityName ) ) {
batchIdentifier.getChildEntityNames().add( rootEntityName );
@ -1345,7 +1369,7 @@ public class ActionQueue {
}
private abstract static class ListProvider<T extends Executable & Comparable & Serializable> {
private abstract static class ListProvider<T extends Executable & Comparable<? super T> & Serializable> {
abstract ExecutableList<T> get(ActionQueue instance);
abstract ExecutableList<T> init(ActionQueue instance);
ExecutableList<T> getOrInit( ActionQueue instance ) {

View File

@ -16,8 +16,8 @@ import java.io.Serializable;
* @author Gavin King
*/
public final class AssociationKey implements Serializable {
private EntityKey ownerKey;
private String propertyName;
private final EntityKey ownerKey;
private final String propertyName;
/**
* Constructs an AssociationKey

View File

@ -22,29 +22,26 @@ import org.hibernate.action.spi.Executable;
import org.hibernate.internal.util.collections.CollectionHelper;
/**
* Specialized encapsulating of the state pertaining to each Executable list.
* <p/>
* Manages sorting the executables (lazily)
* <p/>
* Manages the querySpaces affected by the executables in the list, and caches this too.
* A list of {@link Executable executeble actions}. Responsible for
* {@linkplain #sort() sorting} the executables, and calculating the
* affected {@linkplain #getQuerySpaces() query spaces}.
*
* @author Steve Ebersole
* @author Anton Marsden
*
* @param <E> Intersection type describing Executable implementations
* @param <E> Intersection type describing {@link Executable} implementations
*/
@SuppressWarnings("rawtypes")
public class ExecutableList<E extends Executable & Comparable & Serializable> implements Serializable, Iterable<E>, Externalizable {
public class ExecutableList<E extends Executable & Comparable<? super E> & Serializable>
implements Serializable, Iterable<E>, Externalizable {
public static final int INIT_QUEUE_LIST_SIZE = 5;
/**
* Provides a sorting interface for ExecutableList.
* Provides a sorting interface for {@link ExecutableList}.
*
* @param <E>
*/
public interface Sorter<E extends Executable> {
/**
* Sorts the list.
*/
@ -58,22 +55,22 @@ public class ExecutableList<E extends Executable & Comparable & Serializable> im
private boolean sorted;
/**
* Used to hold the query spaces (table names, roughly) that all the Executable instances contained
* in this list define. This information is ultimately used to invalidate cache regions as it is
* exposed from {@link #getQuerySpaces}. This value being {@code null} indicates that the
* query spaces should be calculated.
* Used to hold the query spaces (table names, roughly) that all the {@link Executable}
* instances contained in this list define. This information is ultimately used to
* invalidate cache regions as it is exposed from {@link #getQuerySpaces}. This value
* being {@code null} indicates that the query spaces should be calculated.
*/
private transient Set<Serializable> querySpaces;
/**
* Creates a new ExecutableList with the default settings.
* Creates a new instance with the default settings.
*/
public ExecutableList() {
this( INIT_QUEUE_LIST_SIZE );
}
/**
* Creates a new ExecutableList with the specified initialCapacity.
* Creates a new instance with the given initial capacity.
*
* @param initialCapacity The initial capacity for instantiating the internal List
*/
@ -95,7 +92,7 @@ public class ExecutableList<E extends Executable & Comparable & Serializable> im
}
/**
* Creates a new ExecutableList using the specified Sorter.
* Creates a new instance using the given {@link Sorter}.
*
* @param sorter The Sorter to use; may be {@code null}
*/
@ -104,7 +101,7 @@ public class ExecutableList<E extends Executable & Comparable & Serializable> im
}
/**
* Creates a new ExecutableList with the specified initialCapacity and Sorter.
* Creates a new instance with the given initial capacity and {@link Sorter}.
*
* @param initialCapacity The initial capacity for instantiating the internal List
* @param sorter The Sorter to use; may be {@code null}
@ -156,7 +153,7 @@ public class ExecutableList<E extends Executable & Comparable & Serializable> im
* @return the entry that was removed
*/
public E remove(int index) {
// removals are generally safe in regards to sorting...
// removals are generally safe with regard to sorting...
final E e = executables.remove( index );
@ -201,7 +198,7 @@ public class ExecutableList<E extends Executable & Comparable & Serializable> im
}
/**
* Add an Executable to this list.
* Add an {@link Executable} to this list.
*
* @param executable the executable to add to the list
*
@ -235,13 +232,13 @@ public class ExecutableList<E extends Executable & Comparable & Serializable> im
Collections.addAll( this.querySpaces, querySpaces );
}
return added;
return true;
}
/**
* Sorts the list using the natural ordering or using the Sorter if it's not null.
* Sorts the list using the natural ordering or using the {@link Sorter}
* if it's not null.
*/
@SuppressWarnings("unchecked")
public void sort() {
if ( sorted || !requiresSorting ) {
// nothing to do
@ -311,12 +308,12 @@ public class ExecutableList<E extends Executable & Comparable & Serializable> im
}
/**
* Read this object state back in from the given stream as part of de-serialization
* Read this object state back in from the given stream as part of
* the deserialization process.
*
* @param in The stream from which to read our serial state
*/
@Override
@SuppressWarnings("unchecked")
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
sorted = in.readBoolean();
@ -324,6 +321,7 @@ public class ExecutableList<E extends Executable & Comparable & Serializable> im
executables.ensureCapacity( numberOfExecutables );
if ( numberOfExecutables > 0 ) {
for ( int i = 0; i < numberOfExecutables; i++ ) {
@SuppressWarnings("unchecked")
E e = (E) in.readObject();
executables.add( e );
}
@ -342,9 +340,10 @@ public class ExecutableList<E extends Executable & Comparable & Serializable> im
}
/**
* Allow the Executables to re-associate themselves with the Session after deserialization.
* Allow the {@link Executable}s to reassociate themselves with the
* session after deserialization.
*
* @param session The session to which to associate the Executables
* @param session The session with which to associate the {@code Executable}s
*/
public void afterDeserialize(SessionImplementor session) {
for ( E e : executables ) {

View File

@ -67,7 +67,7 @@ public class DefaultDeleteEventListener implements DeleteEventListener, Callback
*
*/
public void onDelete(DeleteEvent event) throws HibernateException {
onDelete( event, new IdentitySet() );
onDelete( event, new IdentitySet<>() );
}
/**
@ -281,7 +281,8 @@ public class DefaultDeleteEventListener implements DeleteEventListener, Callback
persistenceContext.registerNullifiableEntityKey( key );
if ( isOrphanRemovalBeforeUpdates ) {
// TODO: The removeOrphan concept is a temporary "hack" for HHH-6484. This should be removed once action/task
// TODO: The removeOrphan concept is a temporary "hack" for HHH-6484.
// This should be removed once action/task
// ordering is improved.
session.getActionQueue().addAction(
new OrphanRemovalAction(