/*- * See the file LICENSE for redistribution information. * * Copyright (c) 1997, 1998, 1999, 2000 * Sleepycat Software. All rights reserved. */ #include "db_config.h" #ifndef lint static const char revid[] = "$Id: java_info.c,v 11.18 2000/10/28 13:09:39 dda Exp $"; #endif /* not lint */ #include #include #include #include #include "db.h" #include "db_int.h" #include "java_util.h" /**************************************************************** * * Callback functions * */ static void Db_feedback_callback(DB *db, int opcode, int percent) { DB_JAVAINFO *dbinfo; DB_ASSERT(db != NULL); dbinfo = (DB_JAVAINFO *)db->cj_internal; dbji_call_feedback(dbinfo, db, dbinfo->jdbref_, opcode, percent); } static int Db_append_recno_callback(DB *db, DBT *dbt, db_recno_t recno) { DB_JAVAINFO *dbinfo; dbinfo = (DB_JAVAINFO *)db->cj_internal; return (dbji_call_append_recno(dbinfo, db, dbinfo->jdbref_, dbt, recno)); } static int Db_bt_compare_callback(DB *db, const DBT *dbt1, const DBT *dbt2) { DB_JAVAINFO *dbinfo; dbinfo = (DB_JAVAINFO *)db->cj_internal; return (dbji_call_bt_compare(dbinfo, db, dbinfo->jdbref_, dbt1, dbt2)); } static size_t Db_bt_prefix_callback(DB *db, const DBT *dbt1, const DBT *dbt2) { DB_JAVAINFO *dbinfo; dbinfo = (DB_JAVAINFO *)db->cj_internal; return (dbji_call_bt_prefix(dbinfo, db, dbinfo->jdbref_, dbt1, dbt2)); } static int Db_dup_compare_callback(DB *db, const DBT *dbt1, const DBT *dbt2) { DB_JAVAINFO *dbinfo; dbinfo = (DB_JAVAINFO *)db->cj_internal; return (dbji_call_dup_compare(dbinfo, db, dbinfo->jdbref_, dbt1, dbt2)); } static u_int32_t Db_h_hash_callback(DB *db, const void *data, u_int32_t len) { DB_JAVAINFO *dbinfo; dbinfo = (DB_JAVAINFO *)db->cj_internal; return (dbji_call_h_hash(dbinfo, db, dbinfo->jdbref_, data, len)); } static void DbEnv_feedback_callback(DB_ENV *dbenv, int opcode, int percent) { DB_ENV_JAVAINFO *dbinfo; DB_ASSERT(dbenv != NULL); dbinfo = (DB_ENV_JAVAINFO *)dbenv->cj_internal; dbjie_call_feedback(dbinfo, dbenv, dbinfo->jenvref_, opcode, percent); } static int DbEnv_recovery_init_callback(DB_ENV *dbenv) { DB_ENV_JAVAINFO *dbinfo; dbinfo = (DB_ENV_JAVAINFO *)dbenv->cj_internal; return (dbjie_call_recovery_init(dbinfo, dbenv, dbinfo->jenvref_)); } static int DbEnv_tx_recover_callback(DB_ENV *dbenv, DBT *dbt, DB_LSN *lsn, db_recops recops) { DB_ENV_JAVAINFO *dbinfo; DB_ASSERT(dbenv != NULL); dbinfo = (DB_ENV_JAVAINFO *)dbenv->cj_internal; return dbjie_call_tx_recover(dbinfo, dbenv, dbinfo->jenvref_, dbt, lsn, recops); } /**************************************************************** * * Implementation of class DBT_javainfo * */ DBT_JAVAINFO * dbjit_construct() { DBT_JAVAINFO *dbjit; dbjit = (DBT_JAVAINFO *)malloc(sizeof(DBT_JAVAINFO)); memset(dbjit, 0, sizeof(DBT_JAVAINFO)); return (dbjit); } void dbjit_destroy(DBT_JAVAINFO *dbjit) { /* Sanity check: * We cannot delete the global ref because we don't have a JNIEnv. */ if (dbjit->array_ != NULL) { fprintf(stderr, "object is not freed\n"); } /* Extra paranoia */ memset(dbjit, 0, sizeof(DB_JAVAINFO)); free(dbjit); } void dbjit_release(DBT_JAVAINFO *dbjit, JNIEnv *jnienv) { if (dbjit->array_ != NULL) { DELETE_GLOBAL_REF(jnienv, dbjit->array_); dbjit->array_ = NULL; } } /**************************************************************** * * Implementation of class DB_ENV_JAVAINFO * */ /* create/initialize an object */ DB_ENV_JAVAINFO * dbjie_construct(JNIEnv *jnienv, jobject default_errcall, int is_dbopen) { DB_ENV_JAVAINFO *dbjie; dbjie = (DB_ENV_JAVAINFO *)malloc(sizeof(DB_ENV_JAVAINFO)); memset(dbjie, 0, sizeof(DB_ENV_JAVAINFO)); dbjie->is_dbopen_ = is_dbopen; if ((*jnienv)->GetJavaVM(jnienv, &dbjie->javavm_) != 0) { free(dbjie); report_exception(jnienv, "cannot get Java VM", 0, 0); return (NULL); } /* The default error call just prints to the 'System.err' * stream. If the user does set_errcall to null, we'll * want to have a reference to set it back to. * * Why do we have always set db_errcall to our own callback? * Because it makes the interaction between setting the * error prefix, error stream, and user's error callback * that much easier. */ dbjie->default_errcall_ = NEW_GLOBAL_REF(jnienv, default_errcall); dbjie->errcall_ = NEW_GLOBAL_REF(jnienv, default_errcall); return (dbjie); } /* release all objects held by this this one */ void dbjie_dealloc(DB_ENV_JAVAINFO *dbjie, JNIEnv *jnienv) { if (dbjie->recovery_init_ != NULL) { DELETE_GLOBAL_REF(jnienv, dbjie->recovery_init_); dbjie->recovery_init_ = NULL; } if (dbjie->feedback_ != NULL) { DELETE_GLOBAL_REF(jnienv, dbjie->feedback_); dbjie->feedback_ = NULL; } if (dbjie->tx_recover_ != NULL) { DELETE_GLOBAL_REF(jnienv, dbjie->tx_recover_); dbjie->tx_recover_ = NULL; } if (dbjie->errcall_ != NULL) { DELETE_GLOBAL_REF(jnienv, dbjie->errcall_); dbjie->errcall_ = NULL; } if (dbjie->default_errcall_ != NULL) { DELETE_GLOBAL_REF(jnienv, dbjie->default_errcall_); dbjie->default_errcall_ = NULL; } if (dbjie->conflict_ != NULL) { free(dbjie->conflict_); dbjie->conflict_ = NULL; } if (dbjie->errpfx_ != NULL) { free(dbjie->errpfx_); dbjie->errpfx_ = NULL; } } /* free this object, releasing anything allocated on its behalf */ void dbjie_destroy(DB_ENV_JAVAINFO *dbjie, JNIEnv *jnienv) { dbjie_dealloc(dbjie, jnienv); /* Extra paranoia */ memset(dbjie, 0, sizeof(DB_ENV_JAVAINFO)); free(dbjie); } /* Attach to the current thread that is running and * return that. We use the java virtual machine * that we saved in the constructor. */ JNIEnv * dbjie_get_jnienv(DB_ENV_JAVAINFO *dbjie) { /* Note: * Different versions of the JNI disagree on the signature * for AttachCurrentThread. The most recent documentation * seems to say that (JNIEnv **) is correct, but newer * JNIs seem to use (void **), oddly enough. */ #ifdef JNI_VERSION_1_2 void *attachret = 0; #else JNIEnv *attachret = 0; #endif /* This should always succeed, as we are called via * some Java activity. I think therefore I am (a thread). */ if ((*dbjie->javavm_)->AttachCurrentThread(dbjie->javavm_, &attachret, 0) != 0) return (0); return ((JNIEnv *)attachret); } jstring dbjie_get_errpfx(DB_ENV_JAVAINFO *dbjie, JNIEnv *jnienv) { return (get_java_string(jnienv, dbjie->errpfx_)); } void dbjie_set_errcall(DB_ENV_JAVAINFO *dbjie, JNIEnv *jnienv, jobject new_errcall) { /* If the new_errcall is null, we'll set the error call * to the default one. */ if (new_errcall == NULL) new_errcall = dbjie->default_errcall_; DELETE_GLOBAL_REF(jnienv, dbjie->errcall_); dbjie->errcall_ = NEW_GLOBAL_REF(jnienv, new_errcall); } void dbjie_set_errpfx(DB_ENV_JAVAINFO *dbjie, JNIEnv *jnienv, jstring errpfx) { if (dbjie->errpfx_ != NULL) free(dbjie->errpfx_); if (errpfx) dbjie->errpfx_ = get_c_string(jnienv, errpfx); else dbjie->errpfx_ = NULL; } void dbjie_set_conflict(DB_ENV_JAVAINFO *dbjie, unsigned char *newarr) { if (dbjie->conflict_) free(dbjie->conflict_); dbjie->conflict_ = newarr; } void dbjie_set_feedback_object(DB_ENV_JAVAINFO *dbjie, JNIEnv *jnienv, DB_ENV *dbenv, jobject jfeedback) { int err; if (dbjie->feedback_ != NULL) { DELETE_GLOBAL_REF(jnienv, dbjie->feedback_); } if (jfeedback == NULL) { if ((err = dbenv->set_feedback(dbenv, NULL)) != 0) report_exception(jnienv, "set_feedback failed", err, 0); } else { if ((err = dbenv->set_feedback(dbenv, DbEnv_feedback_callback)) != 0) report_exception(jnienv, "set_feedback failed", err, 0); } dbjie->feedback_ = NEW_GLOBAL_REF(jnienv, jfeedback); } void dbjie_call_feedback(DB_ENV_JAVAINFO *dbjie, DB_ENV *dbenv, jobject jenv, int opcode, int percent) { JNIEnv *jnienv; jclass feedback_class; jmethodID id; COMPQUIET(dbenv, NULL); jnienv = dbjie_get_jnienv(dbjie); if (jnienv == NULL) { fprintf(stderr, "Cannot attach to current thread!\n"); return; } feedback_class = get_class(jnienv, name_DbEnvFeedback); id = (*jnienv)->GetMethodID(jnienv, feedback_class, "feedback", "(Lcom/sleepycat/db/DbEnv;II)V"); if (!id) { fprintf(stderr, "Cannot find callback class\n"); return; } (*jnienv)->CallVoidMethod(jnienv, dbjie->feedback_, id, jenv, (jint)opcode, (jint)percent); } void dbjie_set_recovery_init_object(DB_ENV_JAVAINFO *dbjie, JNIEnv *jnienv, DB_ENV *dbenv, jobject jrecovery_init) { int err; if (dbjie->recovery_init_ != NULL) { DELETE_GLOBAL_REF(jnienv, dbjie->recovery_init_); } if (jrecovery_init == NULL) { if ((err = dbenv->set_recovery_init(dbenv, NULL)) != 0) report_exception(jnienv, "set_recovery_init failed", err, 0); } else { if ((err = dbenv->set_recovery_init(dbenv, DbEnv_recovery_init_callback)) != 0) report_exception(jnienv, "set_recovery_init failed", err, 0); } dbjie->recovery_init_ = NEW_GLOBAL_REF(jnienv, jrecovery_init); } int dbjie_call_recovery_init(DB_ENV_JAVAINFO *dbjie, DB_ENV *dbenv, jobject jenv) { JNIEnv *jnienv; jclass recovery_init_class; jmethodID id; COMPQUIET(dbenv, NULL); jnienv = dbjie_get_jnienv(dbjie); if (jnienv == NULL) { fprintf(stderr, "Cannot attach to current thread!\n"); return (EINVAL); } recovery_init_class = get_class(jnienv, name_DbRecoveryInit); id = (*jnienv)->GetMethodID(jnienv, recovery_init_class, "recovery_init", "(Lcom/sleepycat/db/DbEnv;)V"); if (!id) { fprintf(stderr, "Cannot find callback class\n"); return (EINVAL); } return (*jnienv)->CallIntMethod(jnienv, dbjie->recovery_init_, id, jenv); } void dbjie_set_tx_recover_object(DB_ENV_JAVAINFO *dbjie, JNIEnv *jnienv, DB_ENV *dbenv, jobject jtx_recover) { int err; if (dbjie->tx_recover_ != NULL) { DELETE_GLOBAL_REF(jnienv, dbjie->tx_recover_); } if (jtx_recover == NULL) { if ((err = dbenv->set_tx_recover(dbenv, NULL)) != 0) report_exception(jnienv, "set_tx_recover failed", err, 0); } else { if ((err = dbenv->set_tx_recover(dbenv, DbEnv_tx_recover_callback)) != 0) report_exception(jnienv, "set_tx_recover failed", err, 0); } dbjie->tx_recover_ = NEW_GLOBAL_REF(jnienv, jtx_recover); } int dbjie_call_tx_recover(DB_ENV_JAVAINFO *dbjie, DB_ENV *dbenv, jobject jenv, DBT *dbt, DB_LSN *lsn, int recops) { JNIEnv *jnienv; jclass tx_recover_class; jmethodID id; jobject jdbt; jobject jlsn; COMPQUIET(dbenv, NULL); jnienv = dbjie_get_jnienv(dbjie); if (jnienv == NULL) { fprintf(stderr, "Cannot attach to current thread!\n"); return (0); } tx_recover_class = get_class(jnienv, name_DbTxnRecover); id = (*jnienv)->GetMethodID(jnienv, tx_recover_class, "tx_recover", "(Lcom/sleepycat/db/DbEnv;" "Lcom/sleepycat/db/Dbt;" "Lcom/sleepycat/db/DbLsn;" "I)I"); if (!id) { fprintf(stderr, "Cannot find callback class\n"); return (0); } if (dbt == NULL) jdbt = NULL; else jdbt = get_Dbt(jnienv, dbt); if (lsn == NULL) jlsn = NULL; else jlsn = get_DbLsn(jnienv, *lsn); return (*jnienv)->CallIntMethod(jnienv, dbjie->tx_recover_, id, jenv, jdbt, jlsn, recops); } jobject dbjie_get_errcall(DB_ENV_JAVAINFO *dbjie) { return (dbjie->errcall_); } int dbjie_is_dbopen(DB_ENV_JAVAINFO *dbjie) { return (dbjie->is_dbopen_); } /**************************************************************** * * Implementation of class DB_JAVAINFO * */ DB_JAVAINFO *dbji_construct(JNIEnv *jnienv, jint flags) { DB_JAVAINFO *dbji; dbji = (DB_JAVAINFO *)malloc(sizeof(DB_JAVAINFO)); memset(dbji, 0, sizeof(DB_JAVAINFO)); if ((*jnienv)->GetJavaVM(jnienv, &dbji->javavm_) != 0) { report_exception(jnienv, "cannot get Java VM", 0, 0); free(dbji); return (NULL); } dbji->construct_flags_ = flags; return (dbji); } void dbji_dealloc(DB_JAVAINFO *dbji, JNIEnv *jnienv) { if (dbji->append_recno_ != NULL) { DELETE_GLOBAL_REF(jnienv, dbji->append_recno_); dbji->append_recno_ = NULL; } if (dbji->bt_compare_ != NULL) { DELETE_GLOBAL_REF(jnienv, dbji->bt_compare_); dbji->bt_compare_ = NULL; } if (dbji->bt_prefix_ != NULL) { DELETE_GLOBAL_REF(jnienv, dbji->bt_prefix_); dbji->bt_prefix_ = NULL; } if (dbji->dup_compare_ != NULL) { DELETE_GLOBAL_REF(jnienv, dbji->dup_compare_); dbji->dup_compare_ = NULL; } if (dbji->feedback_ != NULL) { DELETE_GLOBAL_REF(jnienv, dbji->feedback_); dbji->feedback_ = NULL; } if (dbji->h_hash_ != NULL) { DELETE_GLOBAL_REF(jnienv, dbji->h_hash_); dbji->h_hash_ = NULL; } } void dbji_destroy(DB_JAVAINFO *dbji, JNIEnv *jnienv) { dbji_dealloc(dbji, jnienv); free(dbji); } JNIEnv *dbji_get_jnienv(DB_JAVAINFO *dbji) { /* Note: * Different versions of the JNI disagree on the signature * for AttachCurrentThread. The most recent documentation * seems to say that (JNIEnv **) is correct, but newer * JNIs seem to use (void **), oddly enough. */ #ifdef JNI_VERSION_1_2 void *attachret = 0; #else JNIEnv *attachret = 0; #endif /* This should always succeed, as we are called via * some Java activity. I think therefore I am (a thread). */ if ((*dbji->javavm_)->AttachCurrentThread(dbji->javavm_, &attachret, 0) != 0) return (0); return ((JNIEnv *)attachret); } jint dbji_get_flags(DB_JAVAINFO *dbji) { return (dbji->construct_flags_); } void dbji_set_feedback_object(DB_JAVAINFO *dbji, JNIEnv *jnienv, DB *db, jobject jfeedback) { jclass feedback_class; if (dbji->feedback_method_id_ == NULL) { feedback_class = get_class(jnienv, name_DbFeedback); dbji->feedback_method_id_ = (*jnienv)->GetMethodID(jnienv, feedback_class, "feedback", "(Lcom/sleepycat/db/Db;II)V"); if (dbji->feedback_method_id_ != NULL) { /* XXX * We should really have a better way * to translate this to a Java exception class. * In theory, it shouldn't happen. */ report_exception(jnienv, "Cannot find callback method", EFAULT, 0); return; } } if (dbji->feedback_ != NULL) { DELETE_GLOBAL_REF(jnienv, dbji->feedback_); } if (jfeedback == NULL) { db->set_feedback(db, NULL); } else { db->set_feedback(db, Db_feedback_callback); } dbji->feedback_ = NEW_GLOBAL_REF(jnienv, jfeedback); } void dbji_call_feedback(DB_JAVAINFO *dbji, DB *db, jobject jdb, int opcode, int percent) { JNIEnv *jnienv; COMPQUIET(db, NULL); jnienv = dbji_get_jnienv(dbji); if (jnienv == NULL) { fprintf(stderr, "Cannot attach to current thread!\n"); return; } DB_ASSERT(dbji->feedback_method_id_ != NULL); (*jnienv)->CallVoidMethod(jnienv, dbji->feedback_, dbji->feedback_method_id_, jdb, (jint)opcode, (jint)percent); } void dbji_set_append_recno_object(DB_JAVAINFO *dbji, JNIEnv *jnienv, DB *db, jobject jcallback) { jclass append_recno_class; if (dbji->append_recno_method_id_ == NULL) { append_recno_class = get_class(jnienv, name_DbAppendRecno); dbji->append_recno_method_id_ = (*jnienv)->GetMethodID(jnienv, append_recno_class, "db_append_recno", "(Lcom/sleepycat/db/Db;" "Lcom/sleepycat/db/Dbt;I)V"); if (dbji->append_recno_method_id_ == NULL) { /* XXX * We should really have a better way * to translate this to a Java exception class. * In theory, it shouldn't happen. */ report_exception(jnienv, "Cannot find callback method", EFAULT, 0); return; } } if (dbji->append_recno_ != NULL) { DELETE_GLOBAL_REF(jnienv, dbji->append_recno_); } if (jcallback == NULL) { db->set_append_recno(db, NULL); } else { db->set_append_recno(db, Db_append_recno_callback); } dbji->append_recno_ = NEW_GLOBAL_REF(jnienv, jcallback); } extern int dbji_call_append_recno(DB_JAVAINFO *dbji, DB *db, jobject jdb, DBT *dbt, jint recno) { JNIEnv *jnienv; jobject jdbt; DBT_JAVAINFO *dbtji; jbyteArray arr; unsigned int arraylen; unsigned char *data; COMPQUIET(db, NULL); jnienv = dbji_get_jnienv(dbji); if (jnienv == NULL) { fprintf(stderr, "Cannot attach to current thread!\n"); return (0); } /* XXX * We should have a pool of Dbt objects used for this purpose * instead of creating new ones each time. Because of * multithreading, we may need an arbitrary number (more than two). * We might also have a byte arrays that grow as needed, * so we don't need to allocate those either. * * Note, we do not set the 'create_array_' flag as on other * callbacks as we are creating the array here. */ jdbt = create_default_object(jnienv, name_DBT); dbtji = get_DBT_JAVAINFO(jnienv, jdbt); memcpy(&dbtji->dbt, dbt, sizeof(DBT)); dbtji->dbt.data = NULL; arr = (*jnienv)->NewByteArray(jnienv, dbt->size); (*jnienv)->SetByteArrayRegion(jnienv, arr, 0, dbt->size, (jbyte *)dbt->data); dbtji->array_ = (jbyteArray)NEW_GLOBAL_REF(jnienv, arr); DB_ASSERT(dbji->append_recno_method_id_ != NULL); (*jnienv)->CallVoidMethod(jnienv, dbji->append_recno_, dbji->append_recno_method_id_, jdb, jdbt, recno); /* The underlying C API requires that an errno be returned * on error. Java users know nothing of errnos, so we * allow them to throw exceptions instead. We leave the * exception in place and return DB_JAVA_CALLBACK to the C API * that called us. Eventually the DB->get will fail and * when java prepares to throw an exception in * report_exception(), this will be spotted as a special case, * and the original exception will be preserved. * * Note: we have sometimes noticed strange behavior with * exceptions under Linux 1.1.7 JVM. (i.e. multiple calls * to ExceptionOccurred() may report different results). * Currently we don't know of any problems related to this * in our code, but if it pops up in the future, users are * encouranged to get a more recent JVM. */ if ((*jnienv)->ExceptionOccurred(jnienv) != NULL) return (DB_JAVA_CALLBACK); if (dbtji->array_ == NULL) { report_exception(jnienv, "Dbt.data is null", 0, 0); return (EFAULT); } arraylen = (*jnienv)->GetArrayLength(jnienv, dbtji->array_); if (dbtji->offset_ < 0 ) { report_exception(jnienv, "Dbt.offset illegal", 0, 0); return (EFAULT); } if (dbt->ulen + dbtji->offset_ > arraylen) { report_exception(jnienv, "Dbt.ulen + Dbt.offset greater than array length", 0, 0); return (EFAULT); } data = (*jnienv)->GetByteArrayElements(jnienv, dbtji->array_, (jboolean *)0); dbt->data = data + dbtji->offset_; return (0); } void dbji_set_bt_compare_object(DB_JAVAINFO *dbji, JNIEnv *jnienv, DB *db, jobject jcompare) { jclass bt_compare_class; if (dbji->bt_compare_method_id_ == NULL) { bt_compare_class = get_class(jnienv, name_DbBtreeCompare); dbji->bt_compare_method_id_ = (*jnienv)->GetMethodID(jnienv, bt_compare_class, "bt_compare", "(Lcom/sleepycat/db/Db;" "Lcom/sleepycat/db/Dbt;" "Lcom/sleepycat/db/Dbt;)I"); if (dbji->bt_compare_method_id_ == NULL) { /* XXX * We should really have a better way * to translate this to a Java exception class. * In theory, it shouldn't happen. */ report_exception(jnienv, "Cannot find callback method", EFAULT, 0); return; } } if (dbji->bt_compare_ != NULL) { DELETE_GLOBAL_REF(jnienv, dbji->bt_compare_); } if (jcompare == NULL) { db->set_bt_compare(db, NULL); } else { db->set_bt_compare(db, Db_bt_compare_callback); } dbji->bt_compare_ = NEW_GLOBAL_REF(jnienv, jcompare); } int dbji_call_bt_compare(DB_JAVAINFO *dbji, DB *db, jobject jdb, const DBT *dbt1, const DBT *dbt2) { JNIEnv *jnienv; jobject jdbt1, jdbt2; DBT_JAVAINFO *dbtji1, *dbtji2; COMPQUIET(db, NULL); jnienv = dbji_get_jnienv(dbji); if (jnienv == NULL) { fprintf(stderr, "Cannot attach to current thread!\n"); return (0); } /* XXX * We should have a pool of Dbt objects used for this purpose * instead of creating new ones each time. Because of * multithreading, we may need an arbitrary number (more than two). * We might also have a byte arrays that grow as needed, * so we don't need to allocate those either. */ jdbt1 = create_default_object(jnienv, name_DBT); jdbt2 = create_default_object(jnienv, name_DBT); dbtji1 = get_DBT_JAVAINFO(jnienv, jdbt1); memcpy(&dbtji1->dbt, dbt1, sizeof(DBT)); dbtji1->create_array_ = 1; dbtji2 = get_DBT_JAVAINFO(jnienv, jdbt2); memcpy(&dbtji2->dbt, dbt2, sizeof(DBT)); dbtji2->create_array_ = 1; DB_ASSERT(dbji->bt_compare_method_id_ != NULL); return (*jnienv)->CallIntMethod(jnienv, dbji->bt_compare_, dbji->bt_compare_method_id_, jdb, jdbt1, jdbt2); } void dbji_set_bt_prefix_object(DB_JAVAINFO *dbji, JNIEnv *jnienv, DB *db, jobject jprefix) { jclass bt_prefix_class; if (dbji->bt_prefix_method_id_ == NULL) { bt_prefix_class = get_class(jnienv, name_DbBtreePrefix); dbji->bt_prefix_method_id_ = (*jnienv)->GetMethodID(jnienv, bt_prefix_class, "bt_prefix", "(Lcom/sleepycat/db/Db;" "Lcom/sleepycat/db/Dbt;" "Lcom/sleepycat/db/Dbt;)I"); if (dbji->bt_prefix_method_id_ == NULL) { /* XXX * We should really have a better way * to translate this to a Java exception class. * In theory, it shouldn't happen. */ report_exception(jnienv, "Cannot find callback method", EFAULT, 0); return; } } if (dbji->bt_prefix_ != NULL) { DELETE_GLOBAL_REF(jnienv, dbji->bt_prefix_); } if (jprefix == NULL) { db->set_bt_prefix(db, NULL); } else { db->set_bt_prefix(db, Db_bt_prefix_callback); } dbji->bt_prefix_ = NEW_GLOBAL_REF(jnienv, jprefix); } size_t dbji_call_bt_prefix(DB_JAVAINFO *dbji, DB *db, jobject jdb, const DBT *dbt1, const DBT *dbt2) { JNIEnv *jnienv; jobject jdbt1, jdbt2; DBT_JAVAINFO *dbtji1, *dbtji2; COMPQUIET(db, NULL); jnienv = dbji_get_jnienv(dbji); if (jnienv == NULL) { fprintf(stderr, "Cannot attach to current thread!\n"); return (0); } /* XXX * We should have a pool of Dbt objects used for this purpose * instead of creating new ones each time. Because of * multithreading, we may need an arbitrary number (more than two). * We might also have a byte arrays that grow as needed, * so we don't need to allocate those either. */ jdbt1 = create_default_object(jnienv, name_DBT); jdbt2 = create_default_object(jnienv, name_DBT); dbtji1 = get_DBT_JAVAINFO(jnienv, jdbt1); memcpy(&dbtji1->dbt, dbt1, sizeof(DBT)); dbtji1->create_array_ = 1; dbtji2 = get_DBT_JAVAINFO(jnienv, jdbt2); memcpy(&dbtji2->dbt, dbt2, sizeof(DBT)); dbtji2->create_array_ = 1; DB_ASSERT(dbji->bt_prefix_method_id_ != NULL); return (size_t)(*jnienv)->CallIntMethod(jnienv, dbji->bt_prefix_, dbji->bt_prefix_method_id_, jdb, jdbt1, jdbt2); } void dbji_set_dup_compare_object(DB_JAVAINFO *dbji, JNIEnv *jnienv, DB *db, jobject jcompare) { jclass dup_compare_class; if (dbji->dup_compare_method_id_ == NULL) { dup_compare_class = get_class(jnienv, name_DbDupCompare); dbji->dup_compare_method_id_ = (*jnienv)->GetMethodID(jnienv, dup_compare_class, "dup_compare", "(Lcom/sleepycat/db/Db;" "Lcom/sleepycat/db/Dbt;" "Lcom/sleepycat/db/Dbt;)I"); if (dbji->dup_compare_method_id_ == NULL) { /* XXX * We should really have a better way * to translate this to a Java exception class. * In theory, it shouldn't happen. */ report_exception(jnienv, "Cannot find callback method", EFAULT, 0); return; } } if (dbji->dup_compare_ != NULL) DELETE_GLOBAL_REF(jnienv, dbji->dup_compare_); if (jcompare == NULL) db->set_dup_compare(db, NULL); else db->set_dup_compare(db, Db_dup_compare_callback); dbji->dup_compare_ = NEW_GLOBAL_REF(jnienv, jcompare); } int dbji_call_dup_compare(DB_JAVAINFO *dbji, DB *db, jobject jdb, const DBT *dbt1, const DBT *dbt2) { JNIEnv *jnienv; jobject jdbt1, jdbt2; DBT_JAVAINFO *dbtji1, *dbtji2; COMPQUIET(db, NULL); jnienv = dbji_get_jnienv(dbji); if (jnienv == NULL) { fprintf(stderr, "Cannot attach to current thread!\n"); return (0); } /* XXX * We should have a pool of Dbt objects used for this purpose * instead of creating new ones each time. Because of * multithreading, we may need an arbitrary number (more than two). * We might also have a byte arrays that grow as needed, * so we don't need to allocate those either. */ jdbt1 = create_default_object(jnienv, name_DBT); jdbt2 = create_default_object(jnienv, name_DBT); dbtji1 = get_DBT_JAVAINFO(jnienv, jdbt1); memcpy(&dbtji1->dbt, dbt1, sizeof(DBT)); dbtji1->create_array_ = 1; dbtji2 = get_DBT_JAVAINFO(jnienv, jdbt2); memcpy(&dbtji2->dbt, dbt2, sizeof(DBT)); dbtji2->create_array_ = 1; DB_ASSERT(dbji->dup_compare_method_id_ != NULL); return (*jnienv)->CallIntMethod(jnienv, dbji->dup_compare_, dbji->dup_compare_method_id_, jdb, jdbt1, jdbt2); } void dbji_set_h_hash_object(DB_JAVAINFO *dbji, JNIEnv *jnienv, DB *db, jobject jhash) { jclass h_hash_class; if (dbji->h_hash_method_id_ == NULL) { h_hash_class = get_class(jnienv, name_DbHash); dbji->h_hash_method_id_ = (*jnienv)->GetMethodID(jnienv, h_hash_class, "hash", "(Lcom/sleepycat/db/Db;" "[BI)I"); if (dbji->h_hash_method_id_ == NULL) { /* XXX * We should really have a better way * to translate this to a Java exception class. * In theory, it shouldn't happen. */ report_exception(jnienv, "Cannot find callback method", EFAULT, 0); return; } } if (dbji->h_hash_ != NULL) DELETE_GLOBAL_REF(jnienv, dbji->h_hash_); if (jhash == NULL) db->set_h_hash(db, NULL); else db->set_h_hash(db, Db_h_hash_callback); dbji->h_hash_ = NEW_GLOBAL_REF(jnienv, jhash); } int dbji_call_h_hash(DB_JAVAINFO *dbji, DB *db, jobject jdb, const void *data, int len) { JNIEnv *jnienv; jbyteArray jarray; COMPQUIET(db, NULL); jnienv = dbji_get_jnienv(dbji); if (jnienv == NULL) { fprintf(stderr, "Cannot attach to current thread!\n"); return (0); } DB_ASSERT(dbji->h_hash_method_id_ != NULL); jarray = (*jnienv)->NewByteArray(jnienv, len); (*jnienv)->SetByteArrayRegion(jnienv, jarray, 0, len, (void *)data); return (*jnienv)->CallIntMethod(jnienv, dbji->h_hash_, dbji->h_hash_method_id_, jdb, jarray, len); }