org.hibernate.event.internal.DefaultLockEventListener Maven / Gradle / Ivy
/*
* 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 .
*/
package org.hibernate.event.internal;
import java.io.Serializable;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.TransientObjectException;
import org.hibernate.engine.internal.Cascade;
import org.hibernate.engine.internal.CascadePoint;
import org.hibernate.engine.internal.ForeignKeys;
import org.hibernate.engine.spi.CascadingActions;
import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.event.spi.EventSource;
import org.hibernate.event.spi.LockEvent;
import org.hibernate.event.spi.LockEventListener;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.persister.entity.EntityPersister;
import org.jboss.logging.Logger;
/**
* Defines the default lock event listeners used by hibernate to lock entities
* in response to generated lock events.
*
* @author Steve Ebersole
*/
public class DefaultLockEventListener extends AbstractLockUpgradeEventListener implements LockEventListener {
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
CoreMessageLogger.class,
DefaultLockEventListener.class.getName()
);
/**
* Handle the given lock event.
*
* @param event The lock event to be handled.
* @throws HibernateException
*/
public void onLock(LockEvent event) throws HibernateException {
if ( event.getObject() == null ) {
throw new NullPointerException( "attempted to lock null" );
}
if ( event.getLockMode() == LockMode.WRITE ) {
throw new HibernateException( "Invalid lock mode for lock()" );
}
if ( event.getLockMode() == LockMode.UPGRADE_SKIPLOCKED ) {
LOG.explicitSkipLockedLockCombo();
}
SessionImplementor source = event.getSession();
Object entity = source.getPersistenceContext().unproxyAndReassociate( event.getObject() );
//TODO: if object was an uninitialized proxy, this is inefficient,
// resulting in two SQL selects
EntityEntry entry = source.getPersistenceContext().getEntry(entity);
if (entry==null) {
final EntityPersister persister = source.getEntityPersister( event.getEntityName(), entity );
final Serializable id = persister.getIdentifier( entity, source );
if ( !ForeignKeys.isNotTransient( event.getEntityName(), entity, Boolean.FALSE, source ) ) {
throw new TransientObjectException(
"cannot lock an unsaved transient instance: " +
persister.getEntityName()
);
}
entry = reassociate(event, entity, id, persister);
cascadeOnLock(event, persister, entity);
}
upgradeLock( entity, entry, event.getLockOptions(), event.getSession() );
}
private void cascadeOnLock(LockEvent event, EntityPersister persister, Object entity) {
EventSource source = event.getSession();
source.getPersistenceContext().incrementCascadeLevel();
try {
Cascade.cascade(
CascadingActions.LOCK,
CascadePoint.AFTER_LOCK,
source,
persister,
entity,
event.getLockOptions()
);
}
finally {
source.getPersistenceContext().decrementCascadeLevel();
}
}
}