AbstractSaveEventListenerpublic abstract class AbstractSaveEventListener extends AbstractReassociateEventListener A convenience bas class for listeners responding to save events. |
Fields Summary |
---|
protected static final int | PERSISTENT | protected static final int | TRANSIENT | protected static final int | DETACHED | protected static final int | DELETED | private static final Log | log |
Methods Summary |
---|
protected void | cascadeAfterSave(org.hibernate.event.EventSource source, org.hibernate.persister.entity.EntityPersister persister, java.lang.Object entity, java.lang.Object anything)Handles to calls needed to perform post-save cascades.
// cascade-save to collections AFTER the collection owner was saved
source.getPersistenceContext().incrementCascadeLevel();
try {
new Cascade( getCascadeAction(), Cascade.AFTER_INSERT_BEFORE_DELETE, source )
.cascade( persister, entity, anything );
}
finally {
source.getPersistenceContext().decrementCascadeLevel();
}
| protected void | cascadeBeforeSave(org.hibernate.event.EventSource source, org.hibernate.persister.entity.EntityPersister persister, java.lang.Object entity, java.lang.Object anything)Handles the calls needed to perform pre-save cascades for the given entity.
// cascade-save to many-to-one BEFORE the parent is saved
source.getPersistenceContext().incrementCascadeLevel();
try {
new Cascade( getCascadeAction(), Cascade.BEFORE_INSERT_AFTER_DELETE, source )
.cascade( persister, entity, anything );
}
finally {
source.getPersistenceContext().decrementCascadeLevel();
}
| protected java.lang.Boolean | getAssumedUnsaved()
return null;
| protected abstract org.hibernate.engine.CascadingAction | getCascadeAction()
| protected int | getEntityState(java.lang.Object entity, java.lang.String entityName, org.hibernate.engine.EntityEntry entry, org.hibernate.engine.SessionImplementor source)Determine whether the entity is persistent, detached, or transient
if ( entry != null ) { // the object is persistent
//the entity is associated with the session, so check its status
if ( entry.getStatus() != Status.DELETED ) {
// do nothing for persistent instances
if ( log.isTraceEnabled() ) {
log.trace(
"persistent instance of: " +
getLoggableName( entityName, entity )
);
}
return PERSISTENT;
}
else {
//ie. e.status==DELETED
if ( log.isTraceEnabled() ) {
log.trace(
"deleted instance of: " +
getLoggableName( entityName, entity )
);
}
return DELETED;
}
}
else { // the object is transient or detached
//the entity is not associated with the session, so
//try interceptor and unsaved-value
if ( ForeignKeys.isTransient( entityName, entity, getAssumedUnsaved(), source ) ) {
if ( log.isTraceEnabled() ) {
log.trace(
"transient instance of: " +
getLoggableName( entityName, entity )
);
}
return TRANSIENT;
}
else {
if ( log.isTraceEnabled() ) {
log.trace(
"detached instance of: " +
getLoggableName( entityName, entity )
);
}
return DETACHED;
}
}
| protected java.lang.String | getLoggableName(java.lang.String entityName, java.lang.Object entity)
return entityName == null ? entity.getClass().getName() : entityName;
| protected java.util.Map | getMergeMap(java.lang.Object anything)
return null;
| protected boolean | invokeSaveLifecycle(java.lang.Object entity, org.hibernate.persister.entity.EntityPersister persister, org.hibernate.event.EventSource source)
// Sub-insertions should occur before containing insertion so
// Try to do the callback now
if ( persister.implementsLifecycle( source.getEntityMode() ) ) {
log.debug( "calling onSave()" );
if ( ( ( Lifecycle ) entity ).onSave( source ) ) {
log.debug( "insertion vetoed by onSave()" );
return true;
}
}
return false;
| protected boolean | isVersionIncrementDisabled()After the save, will te version number be incremented
if the instance is modified?
return false;
| private void | markInterceptorDirty(java.lang.Object entity, org.hibernate.persister.entity.EntityPersister persister, org.hibernate.event.EventSource source)
if ( FieldInterceptionHelper.isInstrumented( entity ) ) {
FieldInterceptor interceptor = FieldInterceptionHelper.injectFieldInterceptor(
entity,
persister.getEntityName(),
null,
source
);
interceptor.dirty();
}
| protected java.io.Serializable | performSave(java.lang.Object entity, java.io.Serializable id, org.hibernate.persister.entity.EntityPersister persister, boolean useIdentityColumn, java.lang.Object anything, org.hibernate.event.EventSource source, boolean requiresImmediateIdAccess)Ppepares the save call by checking the session caches for a pre-existing
entity and performing any lifecycle callbacks.
if ( log.isTraceEnabled() ) {
log.trace(
"saving " +
MessageHelper.infoString( persister, id, source.getFactory() )
);
}
EntityKey key;
if ( !useIdentityColumn ) {
key = new EntityKey( id, persister, source.getEntityMode() );
Object old = source.getPersistenceContext().getEntity( key );
if ( old != null ) {
if ( source.getPersistenceContext().getEntry( old ).getStatus() == Status.DELETED ) {
source.forceFlush( source.getPersistenceContext().getEntry( old ) );
}
else {
throw new NonUniqueObjectException( id, persister.getEntityName() );
}
}
persister.setIdentifier( entity, id, source.getEntityMode() );
}
else {
key = null;
}
if ( invokeSaveLifecycle( entity, persister, source ) ) {
return id; //EARLY EXIT
}
return performSaveOrReplicate(
entity,
key,
persister,
useIdentityColumn,
anything,
source,
requiresImmediateIdAccess
);
| protected java.io.Serializable | performSaveOrReplicate(java.lang.Object entity, org.hibernate.engine.EntityKey key, org.hibernate.persister.entity.EntityPersister persister, boolean useIdentityColumn, java.lang.Object anything, org.hibernate.event.EventSource source, boolean requiresImmediateIdAccess)Performs all the actual work needed to save an entity (well to get the save moved to
the execution queue).
validate( entity, persister, source );
Serializable id = key == null ? null : key.getIdentifier();
boolean inTxn = source.getJDBCContext().isTransactionInProgress();
boolean shouldDelayIdentityInserts = !inTxn && !requiresImmediateIdAccess;
if ( useIdentityColumn && !shouldDelayIdentityInserts ) {
log.trace( "executing insertions" );
source.getActionQueue().executeInserts();
}
// Put a placeholder in entries, so we don't recurse back and try to save() the
// same object again. QUESTION: should this be done before onSave() is called?
// likewise, should it be done before onUpdate()?
source.getPersistenceContext().addEntry(
entity,
Status.SAVING,
null,
null,
id,
null,
LockMode.WRITE,
useIdentityColumn,
persister,
false,
false
);
cascadeBeforeSave( source, persister, entity, anything );
Object[] values = persister.getPropertyValuesToInsert( entity, getMergeMap( anything ), source );
Type[] types = persister.getPropertyTypes();
boolean substitute = substituteValuesIfNecessary( entity, id, values, persister, source );
if ( persister.hasCollections() ) {
substitute = substitute || visitCollectionsBeforeSave( entity, id, values, types, source );
}
if ( substitute ) {
persister.setPropertyValues( entity, values, source.getEntityMode() );
}
TypeFactory.deepCopy(
values,
types,
persister.getPropertyUpdateability(),
values,
source
);
new ForeignKeys.Nullifier( entity, false, useIdentityColumn, source )
.nullifyTransientReferences( values, types );
new Nullability( source ).checkNullability( values, persister, false );
if ( useIdentityColumn ) {
EntityIdentityInsertAction insert = new EntityIdentityInsertAction(
values, entity, persister, source, shouldDelayIdentityInserts
);
if ( !shouldDelayIdentityInserts ) {
log.debug( "executing identity-insert immediately" );
source.getActionQueue().execute( insert );
id = insert.getGeneratedId();
//now done in EntityIdentityInsertAction
//persister.setIdentifier( entity, id, source.getEntityMode() );
key = new EntityKey( id, persister, source.getEntityMode() );
source.getPersistenceContext().checkUniqueness( key, entity );
//source.getBatcher().executeBatch(); //found another way to ensure that all batched joined inserts have been executed
}
else {
log.debug( "delaying identity-insert due to no transaction in progress" );
source.getActionQueue().addAction( insert );
key = insert.getDelayedEntityKey();
}
}
Object version = Versioning.getVersion( values, persister );
source.getPersistenceContext().addEntity(
entity,
Status.MANAGED,
values,
key,
version,
LockMode.WRITE,
useIdentityColumn,
persister,
isVersionIncrementDisabled(),
false
);
//source.getPersistenceContext().removeNonExist( new EntityKey( id, persister, source.getEntityMode() ) );
if ( !useIdentityColumn ) {
source.getActionQueue().addAction(
new EntityInsertAction( id, values, entity, version, persister, source )
);
}
cascadeAfterSave( source, persister, entity, anything );
markInterceptorDirty( entity, persister, source );
return id;
| protected java.io.Serializable | saveWithGeneratedId(java.lang.Object entity, java.lang.String entityName, java.lang.Object anything, org.hibernate.event.EventSource source, boolean requiresImmediateIdAccess)Prepares the save call using a newly generated id.
EntityPersister persister = source.getEntityPersister( entityName, entity );
Serializable generatedId = persister.getIdentifierGenerator().generate( source, entity );
if ( generatedId == null ) {
throw new IdentifierGenerationException( "null id generated for:" + entity.getClass() );
}
else if ( generatedId == IdentifierGeneratorFactory.SHORT_CIRCUIT_INDICATOR ) {
return source.getIdentifier( entity );
}
else if ( generatedId == IdentifierGeneratorFactory.POST_INSERT_INDICATOR ) {
return performSave( entity, null, persister, true, anything, source, requiresImmediateIdAccess );
}
else {
if ( log.isDebugEnabled() ) {
log.debug(
"generated identifier: " +
persister.getIdentifierType().toLoggableString( generatedId, source.getFactory() ) +
", using strategy: " +
persister.getIdentifierGenerator().getClass().getName()
//TODO: define toString()s for generators
);
}
return performSave( entity, generatedId, persister, false, anything, source, true );
}
| protected java.io.Serializable | saveWithRequestedId(java.lang.Object entity, java.io.Serializable requestedId, java.lang.String entityName, java.lang.Object anything, org.hibernate.event.EventSource source)Prepares the save call using the given requested id.
return performSave(
entity,
requestedId,
source.getEntityPersister( entityName, entity ),
false,
anything,
source,
true
);
| protected boolean | substituteValuesIfNecessary(java.lang.Object entity, java.io.Serializable id, java.lang.Object[] values, org.hibernate.persister.entity.EntityPersister persister, org.hibernate.engine.SessionImplementor source)Perform any property value substitution that is necessary
(interceptor callback, version initialization...)
boolean substitute = source.getInterceptor().onSave(
entity,
id,
values,
persister.getPropertyNames(),
persister.getPropertyTypes()
);
//keep the existing version number in the case of replicate!
if ( persister.isVersioned() ) {
substitute = Versioning.seedVersion(
values,
persister.getVersionProperty(),
persister.getVersionType(),
source
) || substitute;
}
return substitute;
| protected void | validate(java.lang.Object entity, org.hibernate.persister.entity.EntityPersister persister, org.hibernate.event.EventSource source)
if ( persister.implementsValidatable( source.getEntityMode() ) ) {
( ( Validatable ) entity ).validate();
}
| protected boolean | visitCollectionsBeforeSave(java.lang.Object entity, java.io.Serializable id, java.lang.Object[] values, org.hibernate.type.Type[] types, org.hibernate.event.EventSource source)
WrapVisitor visitor = new WrapVisitor( source );
// substitutes into values by side-effect
visitor.processEntityPropertyValues( values, types );
return visitor.isSubstitutionRequired();
|
|