Ejemplo n.º 1
0
 /** INTERNAL: Begin the transaction on all child sessions. */
 protected void basicBeginTransaction() throws DatabaseException {
   for (Iterator sessionEnum = getSessionsByName().values().iterator(); sessionEnum.hasNext(); ) {
     AbstractSession session = (AbstractSession) sessionEnum.next();
     session.beginTransaction();
   }
 }
    /**
     * Return the next sequence value. First check the global pool, if empty then allocate new
     * sequences locally.
     */
    public Object getNextValue(Sequence sequence, AbstractSession writeSession) {
      String seqName = sequence.getName();
      if (sequence.getPreallocationSize() > 1) {
        Queue sequencesForName = getPreallocationHandler().getPreallocated(seqName);
        // First grab the first sequence value without locking, a lock is only required if empty.
        Object sequenceValue = sequencesForName.poll();
        if (sequenceValue != null) {
          return sequenceValue;
        }
        // KeepLocked indicates whether the sequence lock should be kept for the whole duration of
        // this method.
        // Of course the lock should be released in any case when the method returns or throws an
        // exception.
        // This is only used if a sequence transaction was begun by the unit of work,
        // and will be committed before the unit of work commit.
        boolean keepLocked = false;
        if (!getOwnerSession().getDatasourceLogin().shouldUseExternalTransactionController()
            && !writeSession.isInTransaction()) {
          // To prevent several threads from simultaneously allocating a separate bunch of
          // sequencing numbers each. With keepLocked==true the first thread locks out others
          // until it copies the obtained sequence numbers to the global storage.
          // Note that this optimization possible only in non-jts case when there is no transaction.
          acquireLock(seqName);
          try {
            sequenceValue = sequencesForName.poll();
            if (sequenceValue != null) {
              return sequenceValue;
            }
            writeSession.beginTransaction(); // write accessor is set in begin
            keepLocked = true;
          } finally {
            if (!keepLocked) {
              releaseLock(seqName);
            }
          }
        }

        Accessor accessor;
        Vector localSequencesForName;
        if (!keepLocked) {
          writeSession.beginTransaction(); // write accessor is set in begin
        }
        try {
          accessor = writeSession.getAccessor();
          SequencingCallbackImpl seqCallbackImpl = getCallbackImpl(writeSession, accessor);
          Map localSequences = seqCallbackImpl.getPreallocatedSequenceValues();
          localSequencesForName = (Vector) localSequences.get(seqName);
          if ((localSequencesForName == null) || localSequencesForName.isEmpty()) {
            localSequencesForName = sequence.getGeneratedVector(null, writeSession);
            localSequences.put(seqName, localSequencesForName);
            logDebugLocalPreallocation(writeSession, seqName, localSequencesForName, accessor);
          }
        } catch (RuntimeException ex) {
          if (keepLocked) {
            releaseLock(seqName);
          }
          try {
            // make sure to rollback the transaction we've begun
            writeSession.rollbackTransaction();
          } catch (Exception rollbackException) {
            // ignore rollback exception
          }

          // don't eat the original exception
          throw ex;
        }

        try {
          try {
            // commitTransaction may copy preallocated sequence numbers
            // from localSequences to preallocationHandler: that happens
            // if it isn't a nested transaction, and sequencingCallback.afterCommit
            // method has been called.
            // In this case:
            // 1. localSequences corresponding to the accessor
            //    has been removed from accessorToPreallocated;
            // 2. All its members are empty (therefore localSequenceForName is empty).
            writeSession.commitTransaction();
          } catch (DatabaseException ex) {
            try {
              // make sure to rollback the transaction we've begun
              writeSession.rollbackTransaction();
            } catch (Exception rollbackException) {
              // ignore rollback exception
            }
            // don't eat the original exception
            throw ex;
          }

          if (!localSequencesForName.isEmpty()) {
            // localSeqencesForName is not empty, that means
            // sequencingCallback has not been called.
            sequenceValue = localSequencesForName.remove(0);
            return sequenceValue;
          } else {
            // localSeqencesForName is empty, that means
            // sequencingCallback has been called.
            sequenceValue = sequencesForName.poll();
            if (sequenceValue != null) {
              return sequenceValue;
            }
            return getNextValue(sequence, writeSession);
          }
        } finally {
          if (keepLocked) {
            releaseLock(seqName);
          }
        }
      } else {
        writeSession.beginTransaction();
        try {
          // preallocation size is 1 - just return the first (and only) element of the allocated
          // vector.
          Object sequenceValue = sequence.getGeneratedVector(null, writeSession).firstElement();
          writeSession.commitTransaction();
          return sequenceValue;
        } catch (RuntimeException ex) {
          try {
            // make sure to rollback the transaction we've begun
            writeSession.rollbackTransaction();
          } catch (Exception rollbackException) {
            // ignore rollback exception
          }

          // don't eat the original exception
          throw ex;
        }
      }
    }
  /**
   * INTERNAL: Perform the work to delete an object.
   *
   * @return object - the object being deleted.
   */
  public Object executeDatabaseQuery() throws DatabaseException, OptimisticLockException {
    AbstractSession session = getSession();
    CommitManager commitManager = session.getCommitManager();
    Object object = getObject();
    boolean isUnitOfWork = session.isUnitOfWork();
    try {
      // Check if the object has already been committed, then no work is required
      if (commitManager.isProcessedCommit(object)) {
        return object;
      }
      commitManager.markPreModifyCommitInProgress(getObject());
      if (!isUnitOfWork) {
        session.beginTransaction();
      }
      ClassDescriptor descriptor = this.descriptor;
      DescriptorEventManager eventManager = descriptor.getEventManager();
      // PERF: Avoid events if no listeners.
      if (eventManager.hasAnyEventListeners()) {
        // Need to run pre-delete selector if available
        eventManager.executeEvent(new DescriptorEvent(DescriptorEventManager.PreDeleteEvent, this));
      }

      // Verify if deep shallow modify is turned on
      if (shouldCascadeParts()) {
        descriptor.getQueryManager().preDelete(this);
      }

      // CR#2660080 missing aboutToDelete event.
      // PERF: Avoid events if no listeners.
      if (eventManager.hasAnyEventListeners()) {
        DescriptorEvent event =
            new DescriptorEvent(DescriptorEventManager.AboutToDeleteEvent, this);
        event.setRecord(getModifyRow());
        eventManager.executeEvent(event);
      }

      if (QueryMonitor.shouldMonitor()) {
        QueryMonitor.incrementDelete(this);
      }
      int rowCount = 0;
      // If the object was/will be deleted from a cascade delete constraint, ignore it.
      if (isUnitOfWork
          && ((UnitOfWorkImpl) session).hasCascadeDeleteObjects()
          && ((UnitOfWorkImpl) session).getCascadeDeleteObjects().contains(object)) {
        // Cascade delete does not check optimistic lock, assume ok.
        rowCount = 1;
      } else {
        rowCount = getQueryMechanism().deleteObject().intValue();
      }

      if (rowCount < 1) {
        if (session.hasEventManager()) {
          session.getEventManager().noRowsModified(this, object);
        }
      }

      if (descriptor.usesOptimisticLocking()) {
        descriptor.getOptimisticLockingPolicy().validateDelete(rowCount, object, this);
      }

      commitManager.markPostModifyCommitInProgress(getObject());
      // Verify if deep shallow modify is turned on
      if (shouldCascadeParts()) {
        descriptor.getQueryManager().postDelete(this);
      }

      if ((descriptor.getHistoryPolicy() != null)
          && descriptor.getHistoryPolicy().shouldHandleWrites()) {
        descriptor.getHistoryPolicy().postDelete(this);
      }

      // PERF: Avoid events if no listeners.
      if (eventManager.hasAnyEventListeners()) {
        // Need to run post-delete selector if available
        eventManager.executeEvent(
            new DescriptorEvent(DescriptorEventManager.PostDeleteEvent, this));
      }

      if (!isUnitOfWork) {
        session.commitTransaction();
      }
      commitManager.markCommitCompleted(object);

      // CR3510313, avoid removing aggregate collections from cache (maintain cache is false).
      if (shouldMaintainCache()) {
        if (isUnitOfWork) {
          ((UnitOfWorkImpl) session).addObjectDeletedDuringCommit(object, descriptor);
        } else {
          session
              .getIdentityMapAccessorInstance()
              .removeFromIdentityMap(
                  getPrimaryKey(), descriptor.getJavaClass(), descriptor, object);
        }
      }
      return object;

    } catch (RuntimeException exception) {
      if (!isUnitOfWork) {
        session.rollbackTransaction();
      }
      commitManager.markCommitCompleted(object);
      throw exception;
    }
  }
  /**
   * INTERNAL: Perform the work to delete an object.
   *
   * @return object - the object being deleted.
   */
  public Object executeDatabaseQuery() throws DatabaseException, OptimisticLockException {
    AbstractSession session = getSession();
    CommitManager commitManager = session.getCommitManager();
    Object object = getObject();
    boolean isUnitOfWork = session.isUnitOfWork();
    try {
      // Check if the object has already been deleted, then no work is required.
      if (commitManager.isCommitCompletedInPostOrIgnore(object)) {
        return object;
      }
      ClassDescriptor descriptor = this.descriptor;
      // Check whether the object is already being deleted,
      // if it is, then there is a cycle, and the foreign keys must be nulled.
      if (commitManager.isCommitInPreModify(object)) {
        if (!commitManager.isShallowCommitted(object)) {
          getQueryMechanism().updateForeignKeyFieldBeforeDelete();
          if ((descriptor.getHistoryPolicy() != null)
              && descriptor.getHistoryPolicy().shouldHandleWrites()) {
            descriptor.getHistoryPolicy().postUpdate(this);
          }
          commitManager.markShallowCommit(object);
        }
        return object;
      }
      commitManager.markPreModifyCommitInProgress(getObject());
      if (!isUnitOfWork) {
        session.beginTransaction();
      }
      DescriptorEventManager eventManager = descriptor.getEventManager();
      // PERF: Avoid events if no listeners.
      if (eventManager.hasAnyEventListeners()) {
        // Need to run pre-delete selector if available
        eventManager.executeEvent(new DescriptorEvent(DescriptorEventManager.PreDeleteEvent, this));
      }

      // Verify if deep shallow modify is turned on
      if (shouldCascadeParts()) {
        descriptor.getQueryManager().preDelete(this);
      }

      // Check for deletion dependencies.
      if (isUnitOfWork) {
        Set dependencies = ((UnitOfWorkImpl) session).getDeletionDependencies(object);
        if (dependencies != null) {
          for (Object dependency : dependencies) {
            if (!commitManager.isCommitCompletedInPostOrIgnore(dependency)) {
              ClassDescriptor dependencyDescriptor = session.getDescriptor(dependency);
              // PERF: Get the descriptor query, to avoid extra query creation.
              DeleteObjectQuery deleteQuery =
                  dependencyDescriptor.getQueryManager().getDeleteQuery();
              if (deleteQuery == null) {
                deleteQuery = new DeleteObjectQuery();
                deleteQuery.setDescriptor(dependencyDescriptor);
              } else {
                // Ensure original query has been prepared.
                deleteQuery.checkPrepare(session, deleteQuery.getTranslationRow());
                deleteQuery = (DeleteObjectQuery) deleteQuery.clone();
              }
              deleteQuery.setIsExecutionClone(true);
              deleteQuery.setObject(dependency);
              session.executeQuery(deleteQuery);
            }
          }
        }
      }

      // CR#2660080 missing aboutToDelete event.
      // PERF: Avoid events if no listeners.
      if (eventManager.hasAnyEventListeners()) {
        DescriptorEvent event =
            new DescriptorEvent(DescriptorEventManager.AboutToDeleteEvent, this);
        event.setRecord(getModifyRow());
        eventManager.executeEvent(event);
      }

      if (QueryMonitor.shouldMonitor()) {
        QueryMonitor.incrementDelete(this);
      }
      int rowCount = 0;
      // If the object was/will be deleted from a cascade delete constraint, ignore it.
      if (isUnitOfWork
          && ((UnitOfWorkImpl) session).hasCascadeDeleteObjects()
          && ((UnitOfWorkImpl) session).getCascadeDeleteObjects().contains(object)) {
        // Cascade delete does not check optimistic lock, assume ok.
        rowCount = 1;
      } else {
        rowCount = getQueryMechanism().deleteObject().intValue();
      }

      if (rowCount < 1) {
        if (session.hasEventManager()) {
          session.getEventManager().noRowsModified(this, object);
        }
      }

      if (this.usesOptimisticLocking) {
        descriptor.getOptimisticLockingPolicy().validateDelete(rowCount, object, this);
      }

      commitManager.markPostModifyCommitInProgress(getObject());
      // Verify if deep shallow modify is turned on
      if (shouldCascadeParts()) {
        descriptor.getQueryManager().postDelete(this);
      }

      if ((descriptor.getHistoryPolicy() != null)
          && descriptor.getHistoryPolicy().shouldHandleWrites()) {
        descriptor.getHistoryPolicy().postDelete(this);
      }

      // PERF: Avoid events if no listeners.
      if (eventManager.hasAnyEventListeners()) {
        // Need to run post-delete selector if available
        eventManager.executeEvent(
            new DescriptorEvent(DescriptorEventManager.PostDeleteEvent, this));
      }

      if (!isUnitOfWork) {
        session.commitTransaction();
      }
      commitManager.markCommitCompleted(object);

      // CR3510313, avoid removing aggregate collections from cache (maintain cache is false).
      if (shouldMaintainCache()) {
        if (isUnitOfWork) {
          ((UnitOfWorkImpl) session).addObjectDeletedDuringCommit(object, descriptor);
        } else {
          session
              .getIdentityMapAccessorInstance()
              .removeFromIdentityMap(
                  getPrimaryKey(), descriptor.getJavaClass(), descriptor, object);
        }
      }
      return object;

    } catch (RuntimeException exception) {
      if (!isUnitOfWork) {
        session.rollbackTransaction();
      }
      commitManager.markCommitCompleted(object);
      throw exception;
    }
  }