/** Convience method to retreive an entities next version value */
  private Object getNextVersion(FlushEntityEvent event) throws HibernateException {

    EntityEntry entry = event.getEntityEntry();
    EntityPersister persister = entry.getPersister();
    if (persister.isVersioned()) {

      Object[] values = event.getPropertyValues();

      if (entry.isBeingReplicated()) {
        return Versioning.getVersion(values, persister);
      } else {
        int[] dirtyProperties = event.getDirtyProperties();

        final boolean isVersionIncrementRequired =
            isVersionIncrementRequired(event, entry, persister, dirtyProperties);

        final Object nextVersion =
            isVersionIncrementRequired
                ? Versioning.increment(
                    entry.getVersion(), persister.getVersionType(), event.getSession())
                : entry.getVersion(); // use the current version

        Versioning.setVersion(values, nextVersion, persister);

        return nextVersion;
      }
    } else {
      return null;
    }
  }
  @SuppressWarnings("unchecked")
  @Override
  /**
   * Handle the given delete event. This is the cascaded form.
   *
   * @param event The delete event.
   * @param transientEntities The cache of entities already deleted
   * @throws HibernateException
   */
  public void onDelete(DeleteEvent event, Set transientEntities) throws HibernateException {
    final EventSource source = event.getSession();

    final PersistenceContext persistenceContext = source.getPersistenceContext();
    Object entity = persistenceContext.unproxyAndReassociate(event.getObject());
    EntityEntry entityEntry = persistenceContext.getEntry(entity);

    final EntityPersister persister = source.getEntityPersister(event.getEntityName(), entity);
    final Object version;

    if (persister.isVersioned()) {
      version = persister.getVersion(entity, source.getEntityMode());
      // Make sure version has not changed on deleted entities
      if ((entity instanceof TimelineEntity) && !((TimelineEntity) entity).isNew()) {
        if (!persister.getVersionType().isEqual(version, entityEntry.getVersion())) {
          throw new StaleObjectStateException(persister.getEntityName(), entityEntry.getId());
        }
      }
    }
    super.onDelete(event, transientEntities);
  }
  private boolean scheduleUpdate(final FlushEntityEvent event) {

    final EntityEntry entry = event.getEntityEntry();
    final EventSource session = event.getSession();
    final Object entity = event.getEntity();
    final Status status = entry.getStatus();
    final EntityMode entityMode = session.getEntityMode();
    final EntityPersister persister = entry.getPersister();
    final Object[] values = event.getPropertyValues();

    if (LOG.isTraceEnabled()) {
      if (status == Status.DELETED) {
        if (!persister.isMutable())
          LOG.trace(
              "Updating immutable, deleted entity: "
                  + MessageHelper.infoString(persister, entry.getId(), session.getFactory()));
        else if (!entry.isModifiableEntity())
          LOG.trace(
              "Updating non-modifiable, deleted entity: "
                  + MessageHelper.infoString(persister, entry.getId(), session.getFactory()));
        else
          LOG.trace(
              "Updating deleted entity: "
                  + MessageHelper.infoString(persister, entry.getId(), session.getFactory()));
      } else
        LOG.trace(
            "Updating entity: "
                + MessageHelper.infoString(persister, entry.getId(), session.getFactory()));
    }

    final boolean intercepted = !entry.isBeingReplicated() && handleInterception(event);

    // increment the version number (if necessary)
    final Object nextVersion = getNextVersion(event);

    // if it was dirtied by a collection only
    int[] dirtyProperties = event.getDirtyProperties();
    if (event.isDirtyCheckPossible() && dirtyProperties == null) {
      if (!intercepted && !event.hasDirtyCollection()) {
        throw new AssertionFailure("dirty, but no dirty properties");
      }
      dirtyProperties = ArrayHelper.EMPTY_INT_ARRAY;
    }

    // check nullability but do not doAfterTransactionCompletion command execute
    // we'll use scheduled updates for that.
    new Nullability(session).checkNullability(values, persister, true);

    // schedule the update
    // note that we intentionally do _not_ pass in currentPersistentState!
    session
        .getActionQueue()
        .addAction(
            new EntityUpdateAction(
                entry.getId(),
                values,
                dirtyProperties,
                event.hasDirtyCollection(),
                (status == Status.DELETED && !entry.isModifiableEntity()
                    ? persister.getPropertyValues(entity, entityMode)
                    : entry.getLoadedState()),
                entry.getVersion(),
                nextVersion,
                entity,
                entry.getRowId(),
                persister,
                session));

    return intercepted;
  }