Example #1
0
  public void add(E value) {

    /*
     * The checkIterAddAllowed method ensures that one of the following two
     * conditions holds and throws UnsupportedOperationException otherwise:
     * 1- This is a list iterator for a recno-renumber database.
     * 2- This is a collection iterator for a duplicates database.
     */
    coll.checkIterAddAllowed();
    OperationStatus status = OperationStatus.SUCCESS;
    DataCursor cursor = null;
    boolean doAutoCommit = coll.beginAutoCommit();
    try {
      if (coll.view.keysRenumbered || !coll.areDuplicatesOrdered()) {

        /*
         * This is a recno-renumber database or a btree/hash database
         * with unordered duplicates.
         */
        boolean hasPrev = hasPrevious();
        if (!hasPrev && !hasNext()) {

          /* The collection is empty. */
          if (coll.view.keysRenumbered) {

            /* Append to an empty recno-renumber database. */
            status = coll.view.append(value, null, null);

          } else if (coll.view.dupsAllowed && coll.view.range.isSingleKey()) {

            /*
             * When inserting a duplicate into a single-key range,
             * the main key is fixed, so we can always insert into
             * an empty collection.
             */
            cursor = new DataCursor(coll.view, writeAllowed);
            cursor.useRangeKey();
            status = cursor.putNoDupData(null, value, null, true);
            coll.closeCursor(cursor);
            cursor = null;
          } else {
            throw new IllegalStateException("Collection is empty, cannot add() duplicate");
          }

          /*
           * Move past the record just inserted (the cursor should be
           * closed above to prevent multiple open cursors in certain
           * DB core modes).
           */
          if (status == OperationStatus.SUCCESS) {
            next();
            dataIndex = nextIndex - 1;
          }
        } else {

          /*
           * The collection is non-empty.  If hasPrev is true then
           * the element at (nextIndex - 1) is available; otherwise
           * the element at nextIndex is available.
           */
          cursor = new DataCursor(coll.view, writeAllowed);
          int insertIndex = hasPrev ? (nextIndex - 1) : nextIndex;

          if (!moveCursor(insertIndex, cursor)) {
            throw new IllegalStateException();
          }

          /*
           * For a recno-renumber database or a database with
           * unsorted duplicates, insert before the iterator 'next'
           * position, or after the 'prev' position.  Then adjust
           * the slots to account for the inserted record.
           */
          status = hasPrev ? cursor.putAfter(value) : cursor.putBefore(value);
          if (status == OperationStatus.SUCCESS) {
            insertSlot(nextIndex, cursor);
          }
        }
      } else {
        /* This is a btree/hash database with ordered duplicates. */
        cursor = new DataCursor(coll.view, writeAllowed);

        if (coll.view.range.isSingleKey()) {

          /*
           * When inserting a duplicate into a single-key range,
           * the main key is fixed.
           */
          cursor.useRangeKey();
        } else {

          /*
           * When inserting into a multi-key range, the main key
           * is the last dataIndex accessed by next(), previous()
           * or add().
           */
          if (dataIndex < 0 || !moveCursor(dataIndex, cursor)) {
            throw new IllegalStateException();
          }
        }

        /*
         * For a hash/btree with duplicates, insert the duplicate,
         * put the new record in slot zero, and set the next index
         * to slot one (past the new record).
         */
        status = cursor.putNoDupData(null, value, null, true);
        if (status == OperationStatus.SUCCESS) {
          clearSlots();
          setSlot(0, cursor);
          dataIndex = 0;
          nextIndex = 1;
        }
      }

      if (status == OperationStatus.KEYEXIST) {
        throw new IllegalArgumentException("Duplicate value");
      } else if (status != OperationStatus.SUCCESS) {
        throw new IllegalArgumentException("Could not insert: " + status);
      }

      /* Prevent subsequent set() or remove() call. */
      dataObject = null;

      coll.closeCursor(cursor);
      coll.commitAutoCommit(doAutoCommit);
    } catch (Exception e) {
      /* Catch RuntimeExceptions too. */
      coll.closeCursor(cursor);
      throw coll.handleException(e, doAutoCommit);
    }
  }