/* * Copyright (c) 1998 The Regenstrief Institute. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Written by Gunther Schadow. * * $Id: jdbm_Database.c,v 1.3 1999/07/30 18:13:44 schadow Exp $ */ #include #include #include #include #include #include #ifdef __GCC__ # define NORETURN __attribute__ ((__noreturn__)); #else # define NORETURN /* NORETURN */ #endif /* Throw exception */ void throw_exception(JNIEnv *env, const char *eclass, const char *esig, ...) NORETURN { jclass excpC; jobject excp; jmethodID excpInit; int throwRes; va_list args; va_start(args, esig); excpC = (*env)->FindClass(env, eclass); if(excpC == NULL) (*env)->FatalError(env, eclass); excpInit = (*env)->GetMethodID(env, excpC, "", esig); if(excpInit == NULL) (*env)->FatalError(env, esig); excp = (*env)->NewObjectV(env, excpC, excpInit, args); if(excp == NULL) (*env)->FatalError(env, "error in creation of exception"); throwRes = (*env)->Throw(env, excp); if(throwRes != 0) (*env)->FatalError(env, "throw IOException failed"); } void throw_simple_exception(JNIEnv *env, const char *eclass, const char *emsg) NORETURN { jstring excp_msg; excp_msg = (*env)->NewStringUTF(env, emsg); throw_exception(env, eclass, "(Ljava/lang/String;)V", excp_msg); } /* Get the GDBM handle from a Database object. */ GDBM_FILE get_handle(JNIEnv *env, jobject obj) { jclass dbClass; jfieldID id; GDBM_FILE handle; if (!obj) return 0; dbClass = (*env)->FindClass(env, "jdbm/Database"); if(dbClass == NULL) (*env)->FatalError(env, "no class jdbm/Database"); id = (*env)->GetFieldID(env, dbClass, "handle", "I"); if(dbClass == NULL) (*env)->FatalError(env, "no field int handle"); handle = (GDBM_FILE)(*env)->GetIntField(env, obj, id); if(handle == NULL) { throw_simple_exception(env, "java/io/IOException", "attempt to access database after close"); return NULL; } return handle; } /* Set the GDBM handle of a new Database object. */ void set_handle(JNIEnv *env, jobject this, GDBM_FILE handle) { jclass dbClass; jfieldID id; dbClass = (*env)->FindClass(env, "jdbm/Database"); if(dbClass == NULL) (*env)->FatalError(env, "no class jdbm/Database"); id = (*env)->GetFieldID(env, dbClass, "handle", "I"); if(dbClass == NULL) (*env)->FatalError(env, "no field int handle"); (*env)->SetIntField(env, this, id, (jint)handle); } /* * Class: jdbm_Database * Method: init * Signature: (Ljava/lang/String;I)V */ JNIEXPORT void JNICALL Java_jdbm_Database_init (JNIEnv *env, jobject this, jstring filename, jint mode) { const char *fnstr; GDBM_FILE db; /* Obtain a C-copy of the Java string */ fnstr = (*env)->GetStringUTFChars(env, filename, 0); db = gdbm_open((char *)fnstr, 0, mode, 0644, NULL); if(db == NULL) { const char *gdbm_msg; char *msg; gdbm_msg = gdbm_strerror(gdbm_errno); if(msg == NULL) gdbm_msg = "Error with"; msg = (char *)alloca(strlen(gdbm_msg) + strlen(fnstr) + 4); strcpy(msg, gdbm_msg); strcat(msg, ": "); strcat(msg, fnstr); switch(gdbm_errno) { case GDBM_CANT_BE_READER: case GDBM_CANT_BE_WRITER: throw_simple_exception(env, "jdbm/FileUnavailableException", msg); return; case GDBM_FILE_OPEN_ERROR: throw_simple_exception(env, "jdbm/io/FileNotFoundException", msg); return; default: throw_simple_exception(env, "java/io/IOException", msg); return; } /* Now we are done with str */ (*env)->ReleaseStringUTFChars(env, filename, fnstr); return; } /* set the handle */ set_handle(env, this, db); /* Now we are done with str */ (*env)->ReleaseStringUTFChars(env, filename, fnstr); /* and be done with it */ return; } /* * Class: jdbm_Database * Method: close * Signature: ()V */ JNIEXPORT void JNICALL Java_jdbm_Database_close (JNIEnv *env, jobject this) { GDBM_FILE db = get_handle(env, this); if(db == NULL) throw_simple_exception(env, "jdbm/IllegalStateException", "no valid GDBM_FILE handle avaliable"); gdbm_close(db); set_handle(env, this, NULL); return; } /* * Class: jdbm_Database * Method: exists * Signature: ([B)Z */ JNIEXPORT jboolean JNICALL Java_jdbm_Database_exists (JNIEnv *env, jobject this, jbyteArray jkey) { datum key; int res; GDBM_FILE db = get_handle(env, this); if(db == NULL) throw_simple_exception(env, "jdbm/IllegalStateException", "no valid GDBM_FILE handle avaliable"); key.dsize = (*env)->GetArrayLength(env, jkey); key.dptr = (char *)alloca(key.dsize); (*env)->GetByteArrayRegion(env, jkey, 0, key.dsize, key.dptr); res = gdbm_exists(db, key); if(res == 1) return JNI_TRUE; else return JNI_FALSE; } /* * Class: jdbm_Database * Method: fetch * Signature: ([B)[B */ JNIEXPORT jbyteArray JNICALL Java_jdbm_Database_fetch (JNIEnv *env, jobject this, jbyteArray jkey) { datum key; datum data; jbyteArray jdata; GDBM_FILE db = get_handle(env, this); if(db == NULL) throw_simple_exception(env, "jdbm/IllegalStateException", "no valid GDBM_FILE handle avaliable"); key.dsize = (*env)->GetArrayLength(env, jkey); key.dptr = (char *)alloca(key.dsize); (*env)->GetByteArrayRegion(env, jkey, 0, key.dsize, key.dptr); data = gdbm_fetch(db, key); if(data.dptr == NULL) { throw_exception(env, "jdbm/NoSuchKeyException", "(Ljdbm/Database;[B)V", this, jkey); return NULL; } jdata = (*env)->NewByteArray(env, (jsize)data.dsize); (*env)->SetByteArrayRegion(env, jdata, 0, (jsize)data.dsize, data.dptr); free(data.dptr); return jdata; } /* * Class: jdbm_Database * Method: store * Signature: ([B[BI)V */ JNIEXPORT void JNICALL Java_jdbm_Database_store (JNIEnv *env, jobject this, jbyteArray jkey, jbyteArray jdata, jint jmode) { datum key; datum data; int res; GDBM_FILE db = get_handle(env, this); if(db == NULL) throw_simple_exception(env, "jdbm/IllegalStateException", "no valid GDBM_FILE handle avaliable"); key.dsize = (*env)->GetArrayLength(env, jkey); key.dptr = (char *)alloca(key.dsize); (*env)->GetByteArrayRegion(env, jkey, 0, key.dsize, key.dptr); data.dsize = (*env)->GetArrayLength(env, jdata); data.dptr = (char *)alloca(data.dsize); (*env)->GetByteArrayRegion(env, jdata, 0, data.dsize, data.dptr); res = gdbm_store(db, key, data, jmode); if(res == 1) throw_exception(env, "jdbm/KeyExistsException", "(Ljdbm/Database;[B)V", this, jkey); else if(res == -1) switch(gdbm_errno) { case GDBM_READER_CANT_STORE: throw_simple_exception(env, "jdbm/IllegalOperationError", gdbm_strerror(gdbm_errno)); return; default: throw_simple_exception(env, "java/lang/Error", gdbm_strerror(gdbm_errno)); return; } } /* * Class: jdbm_Database * Method: delete * Signature: ([B)V */ JNIEXPORT void JNICALL Java_jdbm_Database_delete (JNIEnv *env, jobject this, jbyteArray jkey) { datum key; int res; GDBM_FILE db = get_handle(env, this); if(db == NULL) throw_simple_exception(env, "jdbm/IllegalStateException", "no valid GDBM_FILE handle avaliable"); key.dsize = (*env)->GetArrayLength(env, jkey); key.dptr = (char *)alloca(key.dsize); (*env)->GetByteArrayRegion(env, jkey, 0, key.dsize, key.dptr); res = gdbm_delete(db, key); if(res == -1) switch(gdbm_errno) { case GDBM_ITEM_NOT_FOUND: break; case GDBM_READER_CANT_DELETE: throw_simple_exception(env, "jdbm/IllegalOperationError", gdbm_strerror(gdbm_errno)); return; default: throw_simple_exception(env, "java/lang/Error", gdbm_strerror(gdbm_errno)); return; } } /* * Class: jdbm_Database * Method: firstkey * Signature: ()[B */ JNIEXPORT jbyteArray JNICALL Java_jdbm_Database_firstkey (JNIEnv *env, jobject this) { datum key; jbyteArray jkey; GDBM_FILE db = get_handle(env, this); if(db == NULL) throw_simple_exception(env, "jdbm/IllegalStateException", "no valid GDBM_FILE handle avaliable"); key = gdbm_firstkey(db); if(key.dptr == NULL) return NULL; jkey = (*env)->NewByteArray(env, (jsize)key.dsize); (*env)->SetByteArrayRegion(env, jkey, 0, (jsize)key.dsize, key.dptr); free(key.dptr); return jkey; } /* * Class: jdbm_Database * Method: nextkey * Signature: ([B)[B */ JNIEXPORT jbyteArray JNICALL Java_jdbm_Database_nextkey (JNIEnv *env, jobject this, jbyteArray jkey) { datum key; jbyteArray jnextkey; GDBM_FILE db = get_handle(env, this); if(db == NULL) throw_simple_exception(env, "jdbm/IllegalStateException", "no valid GDBM_FILE handle avaliable"); key.dsize = (*env)->GetArrayLength(env, jkey); key.dptr = (char *)alloca(key.dsize); (*env)->GetByteArrayRegion(env, jkey, 0, key.dsize, key.dptr); key = gdbm_nextkey(db, key); if(key.dptr == NULL) return NULL; jnextkey = (*env)->NewByteArray(env, (jsize)key.dsize); (*env)->SetByteArrayRegion(env, jnextkey, 0, (jsize)key.dsize, key.dptr); free(key.dptr); return jnextkey; } /* * Class: jdbm_Database * Method: reorganize * Signature: ()V */ JNIEXPORT void JNICALL Java_jdbm_Database_reorganize (JNIEnv *env, jobject this) { int res; GDBM_FILE db = get_handle(env, this); if(db == NULL) throw_simple_exception(env, "jdbm/IllegalStateException", "no valid GDBM_FILE handle avaliable"); res = gdbm_reorganize(db); if(res == -1) switch(gdbm_errno) { case GDBM_READER_CANT_REORGANIZE: throw_simple_exception(env, "jdbm/IllegalOperationError", gdbm_strerror(gdbm_errno)); return; default: throw_simple_exception(env, "java/lang/Error", gdbm_strerror(gdbm_errno)); return; } } /* * Class: jdbm_Database * Method: sync * Signature: ()V */ JNIEXPORT void JNICALL Java_jdbm_Database_sync (JNIEnv *env, jobject this) { GDBM_FILE db = get_handle(env, this); if(db == NULL) throw_simple_exception(env, "jdbm/IllegalStateException", "no valid GDBM_FILE handle avaliable"); gdbm_sync(db); } /* * Class: jdbm_Database * Method: enableFastUpdateMode * Signature: ()V */ JNIEXPORT void JNICALL Java_jdbm_Database_enableFastUpdateMode (JNIEnv *env, jobject this) { int res; int value = 1; GDBM_FILE db = get_handle(env, this); if(db == NULL) throw_simple_exception(env, "jdbm/IllegalStateException", "no valid GDBM_FILE handle avaliable"); res = gdbm_setopt(db, GDBM_FASTMODE, &value, sizeof(int)); if(res == -1) switch(gdbm_errno) { default: throw_simple_exception(env, "java/lang/Error", gdbm_strerror(gdbm_errno)); return; } } /* * Class: jdbm_Database * Method: disableFastUpdateMode * Signature: ()V */ JNIEXPORT void JNICALL Java_jdbm_Database_disableFastUpdateMode (JNIEnv *env, jobject this) { int res; int value = 0; GDBM_FILE db = get_handle(env, this); if(db == NULL) throw_simple_exception(env, "jdbm/IllegalStateException", "no valid GDBM_FILE handle avaliable"); res = gdbm_setopt(db, GDBM_FASTMODE, &value, sizeof(int)); if(res == -1) switch(gdbm_errno) { default: throw_simple_exception(env, "java/lang/Error", gdbm_strerror(gdbm_errno)); return; } } /* * Class: jdbm_Database * Method: setCacheSize * Signature: ()V */ JNIEXPORT void JNICALL Java_jdbm_Database_setCacheSize (JNIEnv *env, jobject this, jint cachesize) { int res; int value = cachesize; GDBM_FILE db = get_handle(env, this); if(db == NULL) throw_simple_exception(env, "jdbm/IllegalStateException", "no valid GDBM_FILE handle avaliable"); res = gdbm_setopt(db, GDBM_CACHESIZE, &value, sizeof(int)); if(res == -1) switch(gdbm_errno) { case GDBM_OPT_ALREADY_SET: throw_simple_exception(env, "jdbm/IllegalOperationError", "cache size may be set only once"); return; default: throw_simple_exception(env, "java/lang/Error", gdbm_strerror(gdbm_errno)); return; } } /* { char *buf = (char*)alloca(key.dsize + data.dsize + 5); memcpy(buf, key.dptr, key.dsize); memcpy(buf + key.dsize, " -> ", 4); memcpy(buf + key.dsize + 4, data.dptr, data.dsize); memcpy(buf + key.dsize + 4 + data.dsize, "\0", 1); fprintf(stderr, "fetch: %s\n", buf); fflush(stderr); } */