public Object getNextValue(Sequence sequence, AbstractSession writeSession) {
   String seqName = sequence.getName();
   if (sequence.getPreallocationSize() > 1) {
     Queue sequencesForName = getPreallocationHandler().getPreallocated(seqName);
     // First try to get the next sequence value without locking.
     Object sequenceValue = sequencesForName.poll();
     if (sequenceValue != null) {
       return sequenceValue;
     }
     // Sequences are empty, so must lock and allocate next batch of sequences.
     acquireLock(seqName);
     try {
       sequenceValue = sequencesForName.poll();
       if (sequenceValue != null) {
         return sequenceValue;
       }
       Vector sequences = sequence.getGeneratedVector(null, writeSession);
       // Remove the first value before adding to the global cache to ensure this thread gets
       // one.
       sequenceValue = sequences.remove(0);
       // copy remaining values to global cache.
       getPreallocationHandler().setPreallocated(seqName, sequences);
       logDebugPreallocation(seqName, sequenceValue, sequences);
     } finally {
       releaseLock(seqName);
     }
     return sequenceValue;
   } else {
     // preallocation size is 1 - just return the first (and only) element of the allocated
     // vector.
     return sequence.getGeneratedVector(null, writeSession).firstElement();
   }
 }
 /** Release any locally allocated sequence back to the global sequence pool. */
 void afterCommitInternal(Map localSequences, Accessor accessor) {
   Iterator it = localSequences.entrySet().iterator();
   while (it.hasNext()) {
     Map.Entry entry = (Map.Entry) it.next();
     String seqName = (String) entry.getKey();
     Vector localSequenceForName = (Vector) entry.getValue();
     if (!localSequenceForName.isEmpty()) {
       getPreallocationHandler().setPreallocated(seqName, localSequenceForName);
       // clear all localSequencesForName
       localSequenceForName.clear();
     }
   }
   if (accessor != null) {
     getOwnerSession()
         .log(
             SessionLog.FINEST,
             SessionLog.SEQUENCING,
             "sequencing_afterTransactionCommitted",
             null,
             accessor);
   } else {
     getOwnerSession()
         .log(
             SessionLog.FINEST,
             SessionLog.SEQUENCING,
             "sequencing_afterTransactionCommitted",
             null);
   }
 }
 protected void logDebugPreallocation(
     String seqName, Object firstSequenceValue, Vector sequences) {
   if (getOwnerSession().shouldLog(SessionLog.FINEST, SessionLog.SEQUENCING)) {
     // the first value has been already removed from sequences vector
     Object[] args = {
       seqName, new Integer(sequences.size() + 1), firstSequenceValue, sequences.lastElement()
     };
     getOwnerSession()
         .log(SessionLog.FINEST, SessionLog.SEQUENCING, "sequencing_preallocation", args);
   }
 }
 protected void logDebugLocalPreallocation(
     AbstractSession writeSession, String seqName, Vector sequences, Accessor accessor) {
   if (writeSession.shouldLog(SessionLog.FINEST, SessionLog.SEQUENCING)) {
     Object[] args = {
       seqName, new Integer(sequences.size()), sequences.firstElement(), sequences.lastElement()
     };
     writeSession.log(
         SessionLog.FINEST,
         SessionLog.SEQUENCING,
         "sequencing_localPreallocation",
         args,
         accessor);
   }
 }
  protected void initializeStates() {
    states = new State[NUMBER_OF_STATES];

    Iterator itConnectedSequences = connectedSequences.iterator();
    while (itConnectedSequences.hasNext()) {
      Sequence sequence = (Sequence) itConnectedSequences.next();
      State state = getState(sequence.shouldUsePreallocation(), sequence.shouldUseTransaction());
      if (state == null) {
        createState(sequence.shouldUsePreallocation(), sequence.shouldUseTransaction());
      }
    }
  }
 protected void logDebugSequencingConnected() {
   Vector[] sequenceVectors = new Vector[NUMBER_OF_STATES];
   Iterator itConnectedSequences = connectedSequences.iterator();
   while (itConnectedSequences.hasNext()) {
     Sequence sequence = (Sequence) itConnectedSequences.next();
     int stateId = getStateId(sequence.shouldUsePreallocation(), sequence.shouldUseTransaction());
     Vector v = sequenceVectors[stateId];
     if (v == null) {
       v = new Vector();
       sequenceVectors[stateId] = v;
     }
     v.addElement(sequence);
   }
   for (int i = 0; i < NUMBER_OF_STATES; i++) {
     Vector v = sequenceVectors[i];
     if (v != null) {
       getOwnerSession()
           .log(SessionLog.FINEST, SessionLog.SEQUENCING, "sequencing_connected", states[i]);
       for (int j = 0; j < v.size(); j++) {
         Sequence sequence = (Sequence) v.elementAt(j);
         Object[] args = {
           sequence.getName(),
           Integer.toString(sequence.getPreallocationSize()),
           Integer.toString(sequence.getInitialValue())
         };
         getOwnerSession()
             .log(SessionLog.FINEST, SessionLog.SEQUENCING, "sequence_without_state", args);
       }
     }
   }
 }
  protected void onDisconnectAllSequences() {
    RuntimeException exception = null;

    // defaultSequence has to disconnect the last
    for (int i = connectedSequences.size() - 1; i >= 0; i--) {
      try {
        Sequence sequenceToDisconnect = (Sequence) connectedSequences.elementAt(i);
        sequenceToDisconnect.onDisconnect(getOwnerSession().getDatasourcePlatform());
      } catch (RuntimeException ex) {
        if (exception == null) {
          exception = ex;
        }
      }
    }
    connectedSequences = null;
    whenShouldAcquireValueForAll = UNDEFINED;
    atLeastOneSequenceShouldUseTransaction = false;
    atLeastOneSequenceShouldUsePreallocation = false;
    if (exception != null) {
      throw exception;
    }
  }
  protected void onConnectAllSequences() {
    connectedSequences = new Vector();
    boolean shouldUseTransaction = false;
    boolean shouldUsePreallocation = false;
    boolean shouldAcquireValueAfterInsert = false;
    Iterator descriptors = getOwnerSession().getDescriptors().values().iterator();
    while (descriptors.hasNext()) {
      ClassDescriptor descriptor = (ClassDescriptor) descriptors.next();
      // Find root sequence, because inheritance needs to be resolved here.
      // TODO: The way we initialize sequencing needs to be in line with descriptor init.
      ClassDescriptor parentDescriptor = descriptor;
      while (!parentDescriptor.usesSequenceNumbers() && parentDescriptor.isChildDescriptor()) {
        ClassDescriptor newDescriptor =
            getOwnerSession()
                .getDescriptor(parentDescriptor.getInheritancePolicy().getParentClass());
        // Avoid issue with error cases of self parent, or null parent.
        if ((newDescriptor == null) || (newDescriptor == parentDescriptor)) {
          break;
        }
        parentDescriptor = newDescriptor;
      }
      if (!parentDescriptor.usesSequenceNumbers()) {
        continue;
      }
      String seqName = parentDescriptor.getSequenceNumberName();
      Sequence sequence = getSequence(seqName);
      if (sequence == null) {
        sequence = new DefaultSequence(seqName);
        getOwnerSession().getDatasourcePlatform().addSequence(sequence);
      }
      // PERF: Initialize the sequence, this avoid having to look it up every time.
      descriptor.setSequence(sequence);
      if (connectedSequences.contains(sequence)) {
        continue;
      }
      try {
        if (sequence instanceof DefaultSequence
            && !connectedSequences.contains(getDefaultSequence())) {
          getDefaultSequence().onConnect(getOwnerSession().getDatasourcePlatform());
          connectedSequences.add(0, getDefaultSequence());
          shouldUseTransaction |= getDefaultSequence().shouldUseTransaction();
          shouldUsePreallocation |= getDefaultSequence().shouldUsePreallocation();
          shouldAcquireValueAfterInsert |= getDefaultSequence().shouldAcquireValueAfterInsert();
        }
        sequence.onConnect(getOwnerSession().getDatasourcePlatform());
        connectedSequences.addElement(sequence);
        shouldUseTransaction |= sequence.shouldUseTransaction();
        shouldUsePreallocation |= sequence.shouldUsePreallocation();
        shouldAcquireValueAfterInsert |= sequence.shouldAcquireValueAfterInsert();
      } catch (RuntimeException ex) {
        // defaultSequence has to disconnect the last
        for (int i = connectedSequences.size() - 1; i >= 0; i--) {
          try {
            Sequence sequenceToDisconnect = (Sequence) connectedSequences.elementAt(i);
            sequenceToDisconnect.onDisconnect(getOwnerSession().getDatasourcePlatform());
          } catch (RuntimeException ex2) {
            // ignore
          }
        }
        connectedSequences = null;
        throw ex;
      }
    }

    if (shouldAcquireValueAfterInsert && !shouldUsePreallocation) {
      whenShouldAcquireValueForAll = AFTER_INSERT;
    } else if (!shouldAcquireValueAfterInsert && shouldUsePreallocation) {
      whenShouldAcquireValueForAll = BEFORE_INSERT;
    }
    atLeastOneSequenceShouldUseTransaction = shouldUseTransaction;
    atLeastOneSequenceShouldUsePreallocation = shouldUsePreallocation;
  }
 public Object getNextValue(Sequence sequence, AbstractSession writeSession) {
   String seqName = sequence.getName();
   if (sequence.getPreallocationSize() > 1) {
     Queue sequencesForName = getPreallocationHandler().getPreallocated(seqName);
     // First try to get the next sequence value without locking.
     Object sequenceValue = sequencesForName.poll();
     if (sequenceValue != null) {
       return sequenceValue;
     }
     // Sequences are empty, so must lock and allocate next batch of sequences.
     acquireLock(seqName);
     try {
       sequenceValue = sequencesForName.poll();
       if (sequenceValue != null) {
         return sequenceValue;
       }
       // note that accessor.getLogin().shouldUseExternalTransactionController()
       // should be set to false
       Accessor accessor = getConnectionHandler().acquireAccessor();
       try {
         accessor.beginTransaction(writeSession);
         try {
           Vector sequences = sequence.getGeneratedVector(accessor, writeSession);
           accessor.commitTransaction(writeSession);
           // Remove the first value before adding to the global cache to ensure this thread gets
           // one.
           sequenceValue = sequences.remove(0);
           // copy remaining values to global cache.
           getPreallocationHandler().setPreallocated(seqName, sequences);
           logDebugPreallocation(seqName, sequenceValue, sequences);
         } catch (RuntimeException ex) {
           try {
             // make sure to rollback the transaction we've begun
             accessor.rollbackTransaction(writeSession);
           } catch (Exception rollbackException) {
             // ignore rollback exception
           }
           // don't eat the original exception
           throw ex;
         }
       } finally {
         getConnectionHandler().releaseAccessor(accessor);
       }
     } finally {
       releaseLock(seqName);
     }
     return sequenceValue;
   } else {
     // note that accessor.getLogin().shouldUseExternalTransactionController()
     // should be set to false
     Accessor accessor = getConnectionHandler().acquireAccessor();
     try {
       accessor.beginTransaction(writeSession);
       try {
         // preallocation size is 1 - just return the first (and only) element of the allocated
         // vector.
         Object sequenceValue =
             sequence.getGeneratedVector(accessor, writeSession).firstElement();
         accessor.commitTransaction(writeSession);
         return sequenceValue;
       } catch (RuntimeException ex) {
         try {
           // make sure to rollback the transaction we've begun
           accessor.rollbackTransaction(writeSession);
         } catch (Exception rollbackException) {
           // ignore rollback exception
         }
         // don't eat the original exception
         throw ex;
       }
     } finally {
       getConnectionHandler().releaseAccessor(accessor);
     }
   }
 }
    /**
     * 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;
        }
      }
    }