gt:     if(index < 0) throw new CuriaException();
context: /*************************************************************************************************
   * Java API of Curia, the extended API of QDBM
   *                                                      Copyright (C) 2000-2006 Mikio Hirabayashi
   * This file is part of QDBM, Quick Database Manager.
   * QDBM is free software; you can redistribute it and/or modify it under the terms of the GNU
   * Lesser General Public License as published by the Free Software Foundation; either version
   * 2.1 of the License or any later version.  QDBM is distributed in the hope that it will be
   * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
   * details.
   * You should have received a copy of the GNU Lesser General Public License along with QDBM; if
   * not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   * 02111-1307 USA.
   *************************************************************************************************/
  
  
  package qdbm;
  
  
  
  /**
   * The Java API of Curia, the extended API of QDBM.
   * This class depends on the native library `jqdbm'.
   */
  public class Curia implements ADBM {
    //----------------------------------------------------------------
    // error codes
    //----------------------------------------------------------------
    /** error code: no error */
    public static final int ENOERR = 0;
    /** error code: with fatal error */
    public static final int EFATAL = 1;
    /** error code: invalid mode */
    public static final int EMODE = 2;
    /** error code: broken database file */
    public static final int EBROKEN = 3;
    /** error code: existing record */
    public static final int EKEEP = 4;
    /** error code: no item found */
    public static final int ENOITEM = 5;
    /** error code: memory allocation error */
    public static final int EALLOC = 6;
    /** error code: memory mapping error */
    public static final int EMAP = 7;
    /** error code: open error */
    public static final int EOPEN = 8;
    /** error code: close error */
    public static final int ECLOSE = 9;
    /** error code: trunc error */
    public static final int ETRUNC = 10;
    /** error code: sync error */
    public static final int ESYNC = 11;
    /** error code: stat error */
    public static final int ESTAT = 12;
    /** error code: seek error */
    public static final int ESEEK = 13;
    /** error code: read error */
    public static final int EREAD = 14;
    /** error code: write error */
    public static final int EWRITE = 15;
    /** error code: lock error */
    public static final int ELOCK = 16;
    /** error code: unlink error */
    public static final int EUNLINK = 17;
    /** error code: mkdir error */
    public static final int EMKDIR = 18;
    /** error code: rmdir error */
    public static final int ERMDIR = 19;
    /** error code: miscellaneous error */
    public static final int EMISC = 20;
    //----------------------------------------------------------------
    // open modes
    //----------------------------------------------------------------
    /** open mode: open as a reader */
    public static final int OREADER = 1 << 0;
    /** open mode: open as a writer */
    public static final int OWRITER = 1 << 1;
    /** open mode: writer creating */
    public static final int OCREAT = 1 << 2;
    /** open mode: writer truncating */
    public static final int OTRUNC = 1 << 3;
    /** open mode: open without locking */
    public static final int ONOLCK = 1 << 4;
    /** open mode: lock without blocking */
    public static final int OLCKNB = 1 << 5;
    /** open mode: create as sparse files */
    public static final int OSPARSE = 1 << 6;
    //----------------------------------------------------------------
    // write modes
    //----------------------------------------------------------------
    /** write mode: overwrite the existing value */
    public static final int DOVER = 0;
    /** write mode: keep the existing value */
    public static final int DKEEP = 1;
    /** write mode: concatenate values */
    public static final int DCAT = 2;
    //----------------------------------------------------------------
    // static initializer
    //----------------------------------------------------------------
    static {
      try {
        System.loadLibrary("jqdbm");
      } catch(UnsatisfiedLinkError e){
        e.printStackTrace();
      }
      crinit();
    }
    //----------------------------------------------------------------
    // public static methods
    //----------------------------------------------------------------
    /**
     * Get the version information.
     * @return a string of the version information.
     */
    public static synchronized String version(){
      return crversion();
    }
    /**
     * Get an error message.
     * @param ecode an error code.
     * @return the message string of the error code.
     */
    public static synchronized String errmsg(int ecode){
      return crerrmsg(ecode);
    }
    /**
     * Remove a database directory.
     * @param name the name of a database directory.
     * @throws CuriaException if an error occurs.
     */
    public static void remove(String name) throws CuriaException {
      synchronized(ADBM.class){
        if(crremove(name) == 0) throw new CuriaException(crecode());
      }
    }
    /**
     * Retrieve a record directly from a database directory.
     * @param name the name of a database directory.
     * @param key a byte array of a key.
     * @throws CuriaException if an error occurs or no record corresponds.
     * @note Although this method can be used even while the database directory is locked by
     * another process, it is not assured that recent updated is reflected.
     */
    public static byte[] snaffle(String name, byte[] key) throws CuriaException {
      synchronized(ADBM.class){
        byte[] val = crsnaffle(name, key, key.length);
        if(val == null) throw new CuriaException(crecode());
        return val;
      }
    }
    //----------------------------------------------------------------
    // instance fields
    //----------------------------------------------------------------
    /** Whether to repress frequent exceptions. */
    public boolean silent;
    /** Index of the native table for database handles. */
    private int index;
    //----------------------------------------------------------------
    // public or protected methods
    //----------------------------------------------------------------
    /**
     * Get the database handle.
     * @param name the name of a database directory.
     * @param omode the connection mode: `Curia.OWRITER' as a writer, `Curia.OREADER' as
     * a reader.  If the mode is `Curia.OWRITER', the following may be added by bitwise or:
     * `Curia.OCREAT', which means it creates a new database if not exist, `Curia.OTRUNC',
     * which means it creates a new database regardless if one exists.  Both of `Curia.OREADER'
     * and `Curia.OWRITER' can be added to by bitwise or: `Curia.ONOLCK', which means it opens a
     * database directory without file locking, or `Curia.OLCKNB', which means locking is performed
     * without blocking.  `Curia.OCREAT' can be added to by bitwise or: `Curia.OSPARSE', which
     * means it creates database files as sparse files.
     * @param bnum the number of elements of the each bucket array.  If it is not more than 0,
     * the default value is specified.  The size of each bucket array is determined on creating,
     * and can not be changed except for by optimization of the database.  Suggested size of each
     * bucket array is about from 0.5 to 4 times of the number of all records to store.
     * @param dnum the number of division of the database.  If it is not more than 0, the default
     * value is specified.  The number of division can not be changed from the initial value.  The
     * max number of division is 512.
     * @throws CuriaException if an error occurs.
     * @note While connecting as a writer, an exclusive lock is invoked to the database directory.
     * While connecting as a reader, a shared lock is invoked to the database directory.
     * The thread blocks until the lock is achieved.  If `Curia.ONOLCK' is used, the application
     * is responsible for exclusion control.
     */
    public Curia(String name, int omode, int bnum, int dnum) throws CuriaException {
      synchronized(ADBM.class){
        silent = false;
        if((index = cropen(name, omode, bnum, dnum)) == -1) throw new CuriaException(crecode());
      }
    }
    /**
     * Get the database handle as a reader.
     * The same as `Curia(name, Curia.OREADER, -1)'.
     * @see #Curia(java.lang.String, int, int, int)
     */
    public Curia(String name) throws CuriaException {
      this(name, OREADER, -1, -1);
    }
    /**
     * Release the resources.
     * @note If the database handle is not closed yet, it is closed.  Every database should be
     * closed explicitly.  Do not cast the duty on the gerbage collection.
     */
    protected void finalize() throws Throwable {
      try {
        if(index < 0) return;
        synchronized(ADBM.class){
          crclose(index);
          index = -1;
        }
      } finally {
        super.finalize();
      }
    }
    /**
     * Close the database handle.
     * @throws CuriaException if an error occurs.
     * @note Updating a database is assured to be written when the handle is closed.  If a
     * writer opens a database but does not close it appropriately, the database will be broken.
     */
    public void close() throws CuriaException {
      if(index < 0) throw new CuriaException();
      synchronized(ADBM.class){
        int rv = crclose(index);
        index = -1;
        if(rv == 0) throw new CuriaException(crecode());
      }
    }
    /**
     * Store a record.
     * @param key a byte array of a key.
     * @param val a byte array of a value.
     * @param dmode behavior when the key overlaps, by the following values: `Curia.DOVER',
     * which means the specified value overwrites the existing one, `Curia.DKEEP', which means the
     * existing value is kept, `Curia.DCAT', which means the specified value is concatenated at
     * the end of the existing value.
     * @return always true.  However, if the silent flag is true and replace is cancelled, false is
     * returned instead of exception.
     * @throws CuriaException if an error occurs or replace is cancelled.
     */
    public boolean put(byte[] key, byte[] val, int dmode) throws CuriaException {
      if(index < 0) throw new CuriaException();
      synchronized(ADBM.class){
        if(crput(index, key, key.length, val, val.length, dmode) == 0){
          if(silent && crecode() == EKEEP) return false;
          throw new CuriaException(crecode());
        }
        return true;
      }
    }
    /**
     * Store a record with overwrite.
     * The same as `put(key, val, Curia.DOVER)'.
     * @see #put(byte[], byte[], int)
     */
    public boolean put(byte[] key, byte[] val) throws CuriaException {
      return put(key, val, DOVER);
    }
    /**
     * Delete a record.
     * @param key a byte array of a key.
     * @return always true.  However, if the silent flag is true and no record corresponds, false
     * is returned instead of exception.
     * @throws CuriaException if an error occurs or no record corresponds.
     */
    public boolean out(byte[] key) throws CuriaException {
      if(index < 0) throw new CuriaException();
      synchronized(ADBM.class){
        if(crout(index, key, key.length) == 0){
          if(silent && crecode() == ENOITEM) return false;
          throw new CuriaException(crecode());
        }
        return true;
      }
    }
    /**
     * Retrieve a record.
     * @param key a byte array of a key.
     * @param start the array index of the beginning of the value to be read.
     * @param max the max size to read with.  If it is negative, the size is unlimited.
     * @return a byte array of the value of the corresponding record.  If the silent flag is true
     * and no record corresponds, `null' is returned instead of exception.
     * @throws CuriaException if an error occurs, no record corresponds, or the size of the value
     * of the corresponding record is less than the index specified by the parameter `start'.
     */
    public byte[] get(byte[] key, int start, int max) throws CuriaException {
      if(index < 0) throw new CuriaException();
      synchronized(ADBM.class){
        byte[] val = crget(index, key, key.length, start, max);
        if(val == null){
          if(silent && crecode() == ENOITEM) return null;
          throw new CuriaException(crecode());
        }
        return val;
      }
    }
    /**
     * Retrieve whole value of a record.
     * The same as `get(key, 0, -1)'.
     * @see #get(byte[], int, int)
     */
    public byte[] get(byte[] key) throws CuriaException {
      return get(key, 0, -1);
    }
    /**
     * Get the size of the value of a record.
     * @param key a byte array of a key.
     * @return the size of the value of the corresponding record.  If the silent flag is true and
     * no record corresponds, -1 is returned instead of exception.
     * @throws CuriaException if an error occurs or no record corresponds.
     * @note Because this method does not read the entity of a record, it is faster than `get'.
     */
    public int vsiz(byte[] key) throws CuriaException {
      if(index < 0) throw new CuriaException();
      synchronized(ADBM.class){
        int rv = crvsiz(index, key, key.length);
        if(rv == -1){
          if(silent && crecode() == ENOITEM) return -1;
          throw new CuriaException(crecode());
        }
        return rv;
      }
    }
    /**
     * Initialize the iterator of the database handle.
     * @throws CuriaException if an error occurs.
     * @note The iterator is used in order to access the key of every record stored in a database.
     */
    public void iterinit() throws CuriaException {
      if(index < 0) throw new CuriaException();
      synchronized(ADBM.class){
        if(criterinit(index) == 0) throw new CuriaException(crecode());
      }
    }
    /**
     * Get the next key of the iterator.
     * @return a byte array of the key of the next record.  If the silent flag is true and no
     * record corresponds, `null' is returned instead of exception.
     * @throws CuriaException if an error occurs or no record corresponds.
     * @note It is possible to access every record by iteration of calling this method.
     * However, it is not assured if updating the database is occurred while the iteration.
     * Besides, the order of this traversal access method is arbitrary, so it is not assured
     * that the order of storing matches the one of the traversal access.
     */
    public byte[] iternext() throws CuriaException {
      if(index < 0) throw new CuriaException();
      synchronized(ADBM.class){
        byte[] val = criternext(index);
        if(val == null){
          if(silent && crecode() == ENOITEM) return null;
          throw new CuriaException(crecode());
        }
        return val;
      }
    }
    /**
     * Set alignment of the database handle.
     * @param align the basic size of alignment.
     * @throws CuriaException if an error occurs.
     * @note If alignment is set to a database, the efficiency of overwriting values is improved.
     * The size of alignment is suggested to be average size of the values of the records to be
     * stored.  If alignment is positive, padding whose size is multiple number of the alignment
     * is placed.  If alignment is negative, as `vsiz' is the size of a value, the size of padding
     * is calculated with `(vsiz / pow(2, abs(align) - 1))'.  Because alignment setting is not
     * saved in a database, you should specify alignment every opening a database.
     */
    public void setalign(int align) throws CuriaException {
      if(index < 0) throw new CuriaException();
      synchronized(ADBM.class){
        if(crsetalign(index, align) == 0) throw new CuriaException(crecode());
      }
    }
    /**
     * Set the size of the free block pool.
     * @param size the size of the free block pool of a database.
     * @throws CuriaException if an error occurs.
     * @note The default size of the free block pool is 16.  If the size is greater, the space
     * efficiency of overwriting values is improved with the time efficiency sacrificed.
     */
    public void setfbpsiz(int size) throws CuriaException {
      if(index < 0) throw new CuriaException();
      synchronized(ADBM.class){
        if(crsetfbpsiz(index, size) == 0) throw new CuriaException(crecode());
      }
    }
    /**
     * Synchronize updating contents with the files and the devices.
     * @throws CuriaException if an error occurs.
     * @note This method is useful when another process uses the connected database directory.
     */
    public void sync() throws CuriaException {
      if(index < 0) throw new CuriaException();
      synchronized(ADBM.class){
        if(crsync(index) == 0) throw new CuriaException(crecode());
      }
    }
    /**
     * Optimize the database.
     * @param bnum the number of the elements of each bucket array.  If it is not more than 0, the
     * default value is specified.
     * @throws CuriaException if an error occurs.
     * @note In an alternating succession of deleting and storing with overwrite or concatenate,
     * dispensable regions accumulate.  This method is useful to do away with them.
     */
    public void optimize(int bnum) throws CuriaException {
      if(index < 0) throw new CuriaException();
      synchronized(ADBM.class){
        if(croptimize(index, bnum) == 0) throw new CuriaException(crecode());
      }
    }
    /**
     * Get the name of the database.
     * @return the string of the name of the database.
     * @throws CuriaException if an error occurs.
     */
    public String name() throws CuriaException {
      if(index < 0) throw new CuriaException();
      synchronized(ADBM.class){
        String buf = crname(index);
        if(buf == null) throw new CuriaException(crecode());
        return buf;
      }
    }
    /**
     * Get the total size of the database files.
     * @return the total size of the database files.
     * @throws CuriaException if an error occurs.
     */
    public long fsiz() throws CuriaException {
      if(index < 0) throw new CuriaException();
      synchronized(ADBM.class){
        long rv = (long)crfsizd(index);
        if(rv == -1) throw new CuriaException(crecode());
        return rv;
      }
    }
    /**
     * Get the total number of the elements of each bucket array.
     * @return the total number of the elements of each bucket array.
     * @throws CuriaException if an error occurs.
     */
    public int bnum() throws CuriaException {
      if(index < 0) throw new CuriaException();
      synchronized(ADBM.class){
        int rv = crbnum(index);
        if(rv == -1) throw new CuriaException(crecode());
        return rv;
      }
    }
    /**
     * Get the total number of the used elements of each bucket array.
     * @return the total number of the used elements of each bucket array.
     * @throws CuriaException if an error occurs.
     * @note This method is inefficient because it accesses all elements of each bucket array.
     */
    public int busenum() throws CuriaException {
      if(index < 0) throw new CuriaException();
      synchronized(ADBM.class){
        int rv = crbusenum(index);
        if(rv == -1) throw new CuriaException(crecode());
        return rv;
      }
    }
    /**
     * Get the number of the records stored in the database.
     * @return the number of the records stored in the database.
     * @throws CuriaException if an error occurs.
     */
    public int rnum() throws CuriaException {
      if(index < 0) throw new CuriaException();
      synchronized(ADBM.class){
        int rv = crrnum(index);
        if(rv == -1) throw new CuriaException(crecode());
        return rv;
      }
    }
    /**
     * Check whether the database handle is a writer or not.
     * @return true if the handle is a writer, false if not.
     * @throws CuriaException if an error occurs.
     */
    public boolean writable() throws CuriaException {
      if(index < 0) throw new CuriaException();
      synchronized(ADBM.class){
        return crwritable(index) == 0 ? false : true;
      }
    }
    /**
     * Check whether the database has a fatal error or not.
     * @return true if the database has a fatal error, false if not.
     * @throws CuriaException if an error occurs.
     */
    public boolean fatalerror() throws CuriaException {
  