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.entry.CacheEntry;
import org.hibernate.engine.internal.Versioning;
import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.PersistenceContext;
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;
import org.hibernate.event.spi.PreInsertEvent;
import org.hibernate.event.spi.PreInsertEventListener;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.stat.internal.StatsHelper;
public final class EntityInsertAction extends AbstractEntityInsertAction {
private Object version;
private Object cacheEntry;
public EntityInsertAction(
Serializable id,
Object[] state,
Object instance,
Object version,
EntityPersister persister,
boolean isVersionIncrementDisabled,
SharedSessionContractImplementor session) {
super( id, state, instance, isVersionIncrementDisabled, persister, session );
this.version = version;
}
@Override
public boolean isEarlyInsert() {
return false;
}
@Override
protected EntityKey getEntityKey() {
return getSession().generateEntityKey( getId(), getPersister() );
}
@Override
public void execute() throws HibernateException {
nullifyTransientReferencesIfNotAlready();
final EntityPersister persister = getPersister();
final SharedSessionContractImplementor session = getSession();
final Object instance = getInstance();
final Serializable id = getId();
final boolean veto = preInsert();
if ( !veto ) {
persister.insert( id, getState(), instance, session );
PersistenceContext persistenceContext = session.getPersistenceContext();
final EntityEntry entry = persistenceContext.getEntry( instance );
if ( entry == null ) {
throw new AssertionFailure( "possible non-threadsafe access to session" );
}
entry.postInsert( getState() );
if ( persister.hasInsertGeneratedProperties() ) {
persister.processInsertGeneratedProperties( id, instance, getState(), session );
if ( persister.isVersionPropertyGenerated() ) {
version = Versioning.getVersion( getState(), persister );
}
entry.postUpdate( instance, getState(), version );
}
persistenceContext.registerInsertedKey( persister, getId() );
}
final SessionFactoryImplementor factory = session.getFactory();
if ( isCachePutEnabled( persister, session ) ) {
final CacheEntry ce = persister.buildCacheEntry(
instance,
getState(),
version,
session
);
cacheEntry = persister.getCacheEntryStructure().structure( ce );
final EntityDataAccess cache = persister.getCacheAccessStrategy();
final Object ck = cache.generateCacheKey( id, persister, factory, session.getTenantIdentifier() );
final boolean put = cacheInsert( persister, ck );
if ( put && factory.getStatistics().isStatisticsEnabled() ) {
factory.getStatistics().entityCachePut(
StatsHelper.INSTANCE.getRootEntityRole( persister ),
cache.getRegion().getName()
);
}
}
handleNaturalIdPostSaveNotifications( id );
postInsert();
if ( factory.getStatistics().isStatisticsEnabled() && !veto ) {
factory.getStatistics().insertEntity( getPersister().getEntityName() );
}
markExecuted();
}
private boolean cacheInsert(EntityPersister persister, Object ck) {
SharedSessionContractImplementor session = getSession();
try {
session.getEventListenerManager().cachePutStart();
return persister.getCacheAccessStrategy().insert( session, ck, cacheEntry, version);
}
finally {
session.getEventListenerManager().cachePutEnd();
}
}
private void postInsert() {
final EventListenerGroup<PostInsertEventListener> listenerGroup = listenerGroup( EventType.POST_INSERT );
if ( listenerGroup.isEmpty() ) {
return;
}
final PostInsertEvent event = new PostInsertEvent(
getInstance(),
getId(),
getState(),
getPersister(),
eventSource()
);
for ( PostInsertEventListener listener : listenerGroup.listeners() ) {
listener.onPostInsert( event );
}
}
private void postCommitInsert(boolean success) {
final EventListenerGroup<PostInsertEventListener> listenerGroup = listenerGroup( EventType.POST_COMMIT_INSERT );
if ( listenerGroup.isEmpty() ) {
return;
}
final PostInsertEvent event = new PostInsertEvent(
getInstance(),
getId(),
getState(),
getPersister(),
eventSource()
);
for ( PostInsertEventListener listener : listenerGroup.listeners() ) {
if ( PostCommitInsertEventListener.class.isInstance( listener ) ) {
if ( success ) {
listener.onPostInsert( event );
}
else {
((PostCommitInsertEventListener) listener).onPostInsertCommitFailed( event );
}
}
else {
listener.onPostInsert( event );
}
}
}
private boolean preInsert() {
boolean veto = false;
final EventListenerGroup<PreInsertEventListener> listenerGroup = listenerGroup( EventType.PRE_INSERT );
if ( listenerGroup.isEmpty() ) {
return veto;
}
final PreInsertEvent event = new PreInsertEvent( getInstance(), getId(), getState(), getPersister(), eventSource() );
for ( PreInsertEventListener listener : listenerGroup.listeners() ) {
veto |= listener.onPreInsert( event );
}
return veto;
}
@Override
public void doAfterTransactionCompletion(boolean success, SharedSessionContractImplementor session) throws HibernateException {
final EntityPersister persister = getPersister();
if ( success && isCachePutEnabled( persister, getSession() ) ) {
final EntityDataAccess cache = persister.getCacheAccessStrategy();
SessionFactoryImplementor factory = session.getFactory();
final Object ck = cache.generateCacheKey( getId(), persister, factory, session.getTenantIdentifier() );
final boolean put = cacheAfterInsert( cache, ck );
if ( put && factory.getStatistics().isStatisticsEnabled() ) {
factory.getStatistics().entityCachePut(
StatsHelper.INSTANCE.getRootEntityRole( persister ),
cache.getRegion().getName()
);
}
}
postCommitInsert( success );
}
private boolean cacheAfterInsert(EntityDataAccess cache, Object ck) {
SharedSessionContractImplementor session = getSession();
final SessionEventListenerManager eventListenerManager = session.getEventListenerManager();
try {
eventListenerManager.cachePutStart();
return cache.afterInsert( session, ck, cacheEntry, version );
}
finally {
eventListenerManager.cachePutEnd();
}
}
@Override
protected boolean hasPostCommitEventListeners() {
final EventListenerGroup<PostInsertEventListener> group = listenerGroup( EventType.POST_COMMIT_INSERT );
for ( PostInsertEventListener listener : group.listeners() ) {
if ( listener.requiresPostCommitHandling( getPersister() ) ) {
return true;
}
}
return false;
}
private boolean isCachePutEnabled(EntityPersister persister, SharedSessionContractImplementor session) {
return persister.canWriteToCache()
&& !persister.isCacheInvalidationRequired()
&& session.getCacheMode().isPutEnabled();
}
}