Package org.hibernate.event.def

Source Code of org.hibernate.event.def.DefaultSaveOrUpdateEventListener

// $Id: DefaultSaveOrUpdateEventListener.java 9673 2006-03-22 14:57:59Z steve.ebersole@jboss.com $
package org.hibernate.event.def;

import java.io.Serializable;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.AssertionFailure;
import org.hibernate.EntityMode;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.PersistentObjectException;
import org.hibernate.TransientObjectException;
import org.hibernate.classic.Lifecycle;
import org.hibernate.engine.Cascade;
import org.hibernate.engine.CascadingAction;
import org.hibernate.engine.EntityEntry;
import org.hibernate.engine.EntityKey;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.engine.Status;
import org.hibernate.event.EventSource;
import org.hibernate.event.SaveOrUpdateEvent;
import org.hibernate.event.SaveOrUpdateEventListener;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.pretty.MessageHelper;
import org.hibernate.proxy.HibernateProxy;

/**
* Defines the default update event listener used by hibernate for updating
* transient entities in response to generated update events.
*
* @author Steve Ebersole, Gavin King
*/
public class DefaultSaveOrUpdateEventListener extends AbstractSaveEventListener implements SaveOrUpdateEventListener {

  private static final Log log = LogFactory.getLog(DefaultSaveOrUpdateEventListener.class);

  /**
   * Handle the given update event.
   *
   * @param event The update event to be handled.
   * @throws HibernateException
   */
  public void onSaveOrUpdate(SaveOrUpdateEvent event) throws HibernateException {
   
    final SessionImplementor source = event.getSession();
    final Object object = event.getObject();

    final Serializable requestedId = event.getRequestedId();
    if ( requestedId!=null ) {
      //assign the requested id to the proxy, *before*
      //reassociating the proxy
      if ( object instanceof HibernateProxy ) {
        ( (HibernateProxy) object ).getHibernateLazyInitializer().setIdentifier(requestedId);
      }
    }
   
    if ( reassociateIfUninitializedProxy(object, source) ) {
      log.trace("reassociated uninitialized proxy");
      // an uninitialized proxy, noop, don't even need to
      // return an id, since it is never a save()
    }
    else {
      //initialize properties of the event:
      final Object entity = source.getPersistenceContext().unproxyAndReassociate(object);
      event.setEntity(entity);
      event.setEntry( source.getPersistenceContext().getEntry(entity) );
      //return the id in the event object
      event.setResultId( performSaveOrUpdate(event) );
    }
   
  }
 
  protected boolean reassociateIfUninitializedProxy(Object object, SessionImplementor source) {
    return source.getPersistenceContext().reassociateIfUninitializedProxy(object);
  }
 
  protected Serializable performSaveOrUpdate(SaveOrUpdateEvent event) {
   
    // use various roles to determine if the instance is
    // transient, persistent or detached:
   
    int entityState = getEntityState(
        event.getEntity(),
        event.getEntityName(),
        event.getEntry(),
        event.getSession()
      );
   
    switch (entityState) {
      case DETACHED:
        entityIsDetached(event);
        return null;
      case PERSISTENT:
        return entityIsPersistent(event);
      default: //TRANSIENT or DELETED
        return entityIsTransient(event)
    }
   
  }
 
  protected Serializable entityIsPersistent(SaveOrUpdateEvent event) throws HibernateException {
   
    log.trace("ignoring persistent instance");
   
    EntityEntry entityEntry = event.getEntry();
    if ( entityEntry==null ) {
      throw new AssertionFailure("entity was transient or detached");
    }
    else {
     
      if ( entityEntry.getStatus() == Status.DELETED ) {
        throw new AssertionFailure("entity was deleted");
      }
     
      final SessionFactoryImplementor factory = event.getSession().getFactory();

      Serializable requestedId = event.getRequestedId();
     
      Serializable savedId;
      if ( requestedId == null ) {
        savedId = entityEntry.getId();
      }
      else {
       
        final boolean isEqual = !entityEntry.getPersister().getIdentifierType()
            .isEqual( requestedId, entityEntry.getId(), event.getSession().getEntityMode(), factory );
       
        if ( isEqual ) {
          throw new PersistentObjectException(
              "object passed to save() was already persistent: " +
              MessageHelper.infoString( entityEntry.getPersister(), requestedId, factory )
            );
        }
       
        savedId = requestedId;
       
      }
     
      if ( log.isTraceEnabled() ) {
        log.trace(
            "object already associated with session: " +
            MessageHelper.infoString( entityEntry.getPersister(), savedId, factory )
          );
      }
     
      return savedId;
     
    }
  }
   
  /**
   * Handle the given save event.
   *
   * @param event The save event to be handled.
   * @throws HibernateException
   */
  protected Serializable entityIsTransient(SaveOrUpdateEvent event) throws HibernateException {
   
    log.trace("saving transient instance");

    final EventSource source = event.getSession();   

    EntityEntry entityEntry = event.getEntry();
    if ( entityEntry != null ) {
      if ( entityEntry.getStatus() == Status.DELETED ) {
        source.forceFlush(entityEntry);
      }
      else {
        throw new AssertionFailure("entity was persistent");
      }
    }
   
    Serializable id = saveWithGeneratedOrRequestedId(event);

    source.getPersistenceContext().reassociateProxy( event.getObject(), id );
   
    return id;
  }
 
  /**
   * Save the transient instance, assigning the right identifier
   */
  protected Serializable saveWithGeneratedOrRequestedId(SaveOrUpdateEvent event) {
    return saveWithGeneratedId(
        event.getEntity(),
        event.getEntityName(),
        null,
        event.getSession(),
            true
    );
  }
 
  /**
   * Handle the given update event.
   *
   * @param event The update event to be handled.
   * @throws HibernateException
   */
  protected void entityIsDetached(SaveOrUpdateEvent event) throws HibernateException {
   
    log.trace("updating detached instance");
       
   
    if ( event.getSession().getPersistenceContext().isEntryFor( event.getEntity() ) ) {
      //TODO: assertion only, could be optimized away
      throw new AssertionFailure("entity was persistent");
    }
   
    Object entity = event.getEntity();

    EntityPersister persister = event.getSession().getEntityPersister( event.getEntityName(), entity );

    event.setRequestedId( getUpdateId( entity, persister, event.getRequestedId(), event.getSession().getEntityMode() ) );
   
    performUpdate(event, entity, persister);

  }
 
  protected Serializable getUpdateId(Object entity, EntityPersister persister, Serializable requestedId, EntityMode entityMode)
  throws HibernateException {
    // use the id assigned to the instance
    Serializable id = persister.getIdentifier(entity, entityMode);
    if ( id==null ) {
      // assume this is a newly instantiated transient object
      // which should be saved rather than updated
      throw new TransientObjectException(
          "The given object has a null identifier: " +
          persister.getEntityName()
        );
    }
    else {
      return id;
    }
     
  }

  protected void performUpdate(SaveOrUpdateEvent event, Object entity, EntityPersister persister)
  throws HibernateException {
 
    if ( !persister.isMutable() ) {
      log.trace( "immutable instance passed to doUpdate(), locking" );
      reassociate( event, entity, event.getRequestedId(), persister );
    }
    else {

      if ( log.isTraceEnabled() ) {
        log.trace(
            "updating " +
            MessageHelper.infoString( persister, event.getRequestedId(), event.getSession().getFactory() )
          );
      }
 
      final EventSource source = event.getSession();
     
      EntityKey key = new EntityKey( event.getRequestedId(), persister, source.getEntityMode() );
     
      source.getPersistenceContext().checkUniqueness( key, entity );
 
      if ( invokeUpdateLifecycle( entity, persister, source ) ) {
        reassociate( event, event.getObject(), event.getRequestedId(), persister );
        return;
      }
 
      // this is a transient object with existing persistent state not loaded by the session
 
      new OnUpdateVisitor( source, event.getRequestedId() ).process( entity, persister );
     
      //TODO: put this stuff back in to read snapshot from
      //      the second-level cache (needs some extra work)
      /*Object[] cachedState = null;

      if ( persister.hasCache() ) {
        CacheEntry entry = (CacheEntry) persister.getCache()
            .get( event.getRequestedId(), source.getTimestamp() );
          cachedState = entry==null ?
              null :
              entry.getState(); //TODO: half-assemble this stuff
      }*/

      source.getPersistenceContext().addEntity(
          entity,
          Status.MANAGED,
          null, //cachedState,
          key,
          persister.getVersion( entity, source.getEntityMode() ),
          LockMode.NONE,
          true,
          persister,
          false,
          true //assume true, since we don't really know, and it doesn't matter
        );
     
      persister.afterReassociate(entity, source);
 
      if ( log.isTraceEnabled() ) {
        log.trace(
            "updating " +
            MessageHelper.infoString( persister, event.getRequestedId(), source.getFactory() )
          );
      }
 
      cascadeOnUpdate(event, persister, entity);
     
    }
  }

  protected boolean invokeUpdateLifecycle(Object entity, EntityPersister persister, EventSource source) {
    if ( persister.implementsLifecycle( source.getEntityMode() ) ) {
      log.debug( "calling onUpdate()" );
      if ( ( ( Lifecycle ) entity ).onUpdate(source) ) {
        log.debug( "update vetoed by onUpdate()" );
        return true;
      }
    }
    return false;
  }

  /**
   * Handles the calls needed to perform cascades as part of an update request
   * for the given entity.
   *
   * @param event The event currently being processed.
   * @param persister The defined persister for the entity being updated.
   * @param entity The entity being updated.
   */
  private void cascadeOnUpdate(SaveOrUpdateEvent event, EntityPersister persister, Object entity) {
    EventSource source = event.getSession();
    source.getPersistenceContext().incrementCascadeLevel();
    try {
      new Cascade(CascadingAction.SAVE_UPDATE, Cascade.AFTER_UPDATE, source)
          .cascade(persister, entity);
    }
    finally {
      source.getPersistenceContext().decrementCascadeLevel();
    }
  }

  protected CascadingAction getCascadeAction() {
    return CascadingAction.SAVE_UPDATE;
  }
}
TOP

Related Classes of org.hibernate.event.def.DefaultSaveOrUpdateEventListener

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.