/*
 * 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.action.internal;

import java.io.Serializable;

import org.hibernate.AssertionFailure;
import org.hibernate.HibernateException;
import org.hibernate.cache.spi.access.EntityDataAccess;
import org.hibernate.cache.spi.access.SoftLock;
import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.event.service.spi.EventListenerGroup;
import org.hibernate.event.spi.EventType;
import org.hibernate.event.spi.PostCommitDeleteEventListener;
import org.hibernate.event.spi.PostDeleteEvent;
import org.hibernate.event.spi.PostDeleteEventListener;
import org.hibernate.event.spi.PreDeleteEvent;
import org.hibernate.event.spi.PreDeleteEventListener;
import org.hibernate.persister.entity.EntityPersister;

The action for performing an entity deletion.
/** * The action for performing an entity deletion. */
public class EntityDeleteAction extends EntityAction { private final Object version; private final boolean isCascadeDeleteEnabled; private final Object[] state; private SoftLock lock; private Object[] naturalIdValues;
Constructs an EntityDeleteAction.
Params:
  • id – The entity identifier
  • state – The current (extracted) entity state
  • version – The current entity version
  • instance – The entity instance
  • persister – The entity persister
  • isCascadeDeleteEnabled – Whether cascade delete is enabled
  • session – The session
/** * Constructs an EntityDeleteAction. * * @param id The entity identifier * @param state The current (extracted) entity state * @param version The current entity version * @param instance The entity instance * @param persister The entity persister * @param isCascadeDeleteEnabled Whether cascade delete is enabled * @param session The session */
public EntityDeleteAction( final Serializable id, final Object[] state, final Object version, final Object instance, final EntityPersister persister, final boolean isCascadeDeleteEnabled, final SessionImplementor session) { super( session, id, instance, persister ); this.version = version; this.isCascadeDeleteEnabled = isCascadeDeleteEnabled; this.state = state; // before remove we need to remove the local (transactional) natural id cross-reference naturalIdValues = session.getPersistenceContext().getNaturalIdHelper().removeLocalNaturalIdCrossReference( getPersister(), getId(), state ); } @Override public void execute() throws HibernateException { final Serializable id = getId(); final EntityPersister persister = getPersister(); final SharedSessionContractImplementor session = getSession(); final Object instance = getInstance(); final boolean veto = preDelete(); Object version = this.version; if ( persister.isVersionPropertyGenerated() ) { // we need to grab the version value from the entity, otherwise // we have issues with generated-version entities that may have // multiple actions queued during the same flush version = persister.getVersion( instance ); } final Object ck; if ( persister.canWriteToCache() ) { final EntityDataAccess cache = persister.getCacheAccessStrategy(); ck = cache.generateCacheKey( id, persister, session.getFactory(), session.getTenantIdentifier() ); lock = cache.lockItem( session, ck, version ); } else { ck = null; } if ( !isCascadeDeleteEnabled && !veto ) { persister.delete( id, version, instance, session ); } //postDelete: // After actually deleting a row, record the fact that the instance no longer // exists on the database (needed for identity-column key generation), and // remove it from the session cache final PersistenceContext persistenceContext = session.getPersistenceContext(); final EntityEntry entry = persistenceContext.removeEntry( instance ); if ( entry == null ) { throw new AssertionFailure( "possible nonthreadsafe access to session" ); } entry.postDelete(); persistenceContext.removeEntity( entry.getEntityKey() ); persistenceContext.removeProxy( entry.getEntityKey() ); if ( persister.canWriteToCache() ) { persister.getCacheAccessStrategy().remove( session, ck); } persistenceContext.getNaturalIdHelper().removeSharedNaturalIdCrossReference( persister, id, naturalIdValues ); postDelete(); if ( getSession().getFactory().getStatistics().isStatisticsEnabled() && !veto ) { getSession().getFactory().getStatistics().deleteEntity( getPersister().getEntityName() ); } } private boolean preDelete() { boolean veto = false; final EventListenerGroup<PreDeleteEventListener> listenerGroup = listenerGroup( EventType.PRE_DELETE ); if ( listenerGroup.isEmpty() ) { return veto; } final PreDeleteEvent event = new PreDeleteEvent( getInstance(), getId(), state, getPersister(), eventSource() ); for ( PreDeleteEventListener listener : listenerGroup.listeners() ) { veto |= listener.onPreDelete( event ); } return veto; } private void postDelete() { final EventListenerGroup<PostDeleteEventListener> listenerGroup = listenerGroup( EventType.POST_DELETE ); if ( listenerGroup.isEmpty() ) { return; } final PostDeleteEvent event = new PostDeleteEvent( getInstance(), getId(), state, getPersister(), eventSource() ); for ( PostDeleteEventListener listener : listenerGroup.listeners() ) { listener.onPostDelete( event ); } } private void postCommitDelete(boolean success) { final EventListenerGroup<PostDeleteEventListener> listenerGroup = listenerGroup( EventType.POST_COMMIT_DELETE ); if ( listenerGroup.isEmpty() ) { return; } final PostDeleteEvent event = new PostDeleteEvent( getInstance(), getId(), state, getPersister(), eventSource() ); for ( PostDeleteEventListener listener : listenerGroup.listeners() ) { if ( PostCommitDeleteEventListener.class.isInstance( listener ) ) { if ( success ) { listener.onPostDelete( event ); } else { ((PostCommitDeleteEventListener) listener).onPostDeleteCommitFailed( event ); } } else { //default to the legacy implementation that always fires the event listener.onPostDelete( event ); } } } @Override public void doAfterTransactionCompletion(boolean success, SharedSessionContractImplementor session) throws HibernateException { EntityPersister entityPersister = getPersister(); if ( entityPersister.canWriteToCache() ) { EntityDataAccess cache = entityPersister.getCacheAccessStrategy(); final Object ck = cache.generateCacheKey( getId(), entityPersister, session.getFactory(), session.getTenantIdentifier() ); cache.unlockItem( session, ck, lock ); } postCommitDelete( success ); } @Override protected boolean hasPostCommitEventListeners() { final EventListenerGroup<PostDeleteEventListener> group = listenerGroup( EventType.POST_COMMIT_DELETE ); for ( PostDeleteEventListener listener : group.listeners() ) { if ( listener.requiresPostCommitHandling( getPersister() ) ) { return true; } } return false; } }