java_info.c
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:26k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /*-
  2.  * See the file LICENSE for redistribution information.
  3.  *
  4.  * Copyright (c) 1997, 1998, 1999, 2000
  5.  * Sleepycat Software.  All rights reserved.
  6.  */
  7. #include "db_config.h"
  8. #ifndef lint
  9. static const char revid[] = "$Id: java_info.c,v 11.18 2000/10/28 13:09:39 dda Exp $";
  10. #endif /* not lint */
  11. #include <jni.h>
  12. #include <errno.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include "db.h"
  16. #include "db_int.h"
  17. #include "java_util.h"
  18. /****************************************************************
  19.  *
  20.  * Callback functions
  21.  *
  22.  */
  23. static void Db_feedback_callback(DB *db, int opcode, int percent)
  24. {
  25. DB_JAVAINFO *dbinfo;
  26. DB_ASSERT(db != NULL);
  27. dbinfo = (DB_JAVAINFO *)db->cj_internal;
  28. dbji_call_feedback(dbinfo, db, dbinfo->jdbref_, opcode, percent);
  29. }
  30. static int Db_append_recno_callback(DB *db, DBT *dbt, db_recno_t recno)
  31. {
  32. DB_JAVAINFO *dbinfo;
  33. dbinfo = (DB_JAVAINFO *)db->cj_internal;
  34. return (dbji_call_append_recno(dbinfo, db, dbinfo->jdbref_, dbt, recno));
  35. }
  36. static int Db_bt_compare_callback(DB *db, const DBT *dbt1, const DBT *dbt2)
  37. {
  38. DB_JAVAINFO *dbinfo;
  39. dbinfo = (DB_JAVAINFO *)db->cj_internal;
  40. return (dbji_call_bt_compare(dbinfo, db, dbinfo->jdbref_, dbt1, dbt2));
  41. }
  42. static size_t Db_bt_prefix_callback(DB *db, const DBT *dbt1, const DBT *dbt2)
  43. {
  44. DB_JAVAINFO *dbinfo;
  45. dbinfo = (DB_JAVAINFO *)db->cj_internal;
  46. return (dbji_call_bt_prefix(dbinfo, db, dbinfo->jdbref_, dbt1, dbt2));
  47. }
  48. static int Db_dup_compare_callback(DB *db, const DBT *dbt1, const DBT *dbt2)
  49. {
  50. DB_JAVAINFO *dbinfo;
  51. dbinfo = (DB_JAVAINFO *)db->cj_internal;
  52. return (dbji_call_dup_compare(dbinfo, db, dbinfo->jdbref_, dbt1, dbt2));
  53. }
  54. static u_int32_t Db_h_hash_callback(DB *db, const void *data, u_int32_t len)
  55. {
  56. DB_JAVAINFO *dbinfo;
  57. dbinfo = (DB_JAVAINFO *)db->cj_internal;
  58. return (dbji_call_h_hash(dbinfo, db, dbinfo->jdbref_, data, len));
  59. }
  60. static void DbEnv_feedback_callback(DB_ENV *dbenv, int opcode, int percent)
  61. {
  62. DB_ENV_JAVAINFO *dbinfo;
  63. DB_ASSERT(dbenv != NULL);
  64. dbinfo = (DB_ENV_JAVAINFO *)dbenv->cj_internal;
  65. dbjie_call_feedback(dbinfo, dbenv, dbinfo->jenvref_, opcode, percent);
  66. }
  67. static int DbEnv_recovery_init_callback(DB_ENV *dbenv)
  68. {
  69. DB_ENV_JAVAINFO *dbinfo;
  70. dbinfo = (DB_ENV_JAVAINFO *)dbenv->cj_internal;
  71. return (dbjie_call_recovery_init(dbinfo, dbenv, dbinfo->jenvref_));
  72. }
  73. static int DbEnv_tx_recover_callback(DB_ENV *dbenv, DBT *dbt,
  74.      DB_LSN *lsn, db_recops recops)
  75. {
  76. DB_ENV_JAVAINFO *dbinfo;
  77. DB_ASSERT(dbenv != NULL);
  78. dbinfo = (DB_ENV_JAVAINFO *)dbenv->cj_internal;
  79. return dbjie_call_tx_recover(dbinfo, dbenv, dbinfo->jenvref_, dbt,
  80.      lsn, recops);
  81. }
  82. /****************************************************************
  83.  *
  84.  * Implementation of class DBT_javainfo
  85.  *
  86.  */
  87. DBT_JAVAINFO *
  88. dbjit_construct()
  89. {
  90. DBT_JAVAINFO *dbjit;
  91. dbjit = (DBT_JAVAINFO *)malloc(sizeof(DBT_JAVAINFO));
  92. memset(dbjit, 0, sizeof(DBT_JAVAINFO));
  93. return (dbjit);
  94. }
  95. void dbjit_destroy(DBT_JAVAINFO *dbjit)
  96. {
  97. /* Sanity check:
  98.  * We cannot delete the global ref because we don't have a JNIEnv.
  99.  */
  100. if (dbjit->array_ != NULL) {
  101. fprintf(stderr, "object is not freedn");
  102. }
  103. /* Extra paranoia */
  104. memset(dbjit, 0, sizeof(DB_JAVAINFO));
  105. free(dbjit);
  106. }
  107. void dbjit_release(DBT_JAVAINFO *dbjit, JNIEnv *jnienv)
  108. {
  109. if (dbjit->array_ != NULL) {
  110. DELETE_GLOBAL_REF(jnienv, dbjit->array_);
  111. dbjit->array_ = NULL;
  112. }
  113. }
  114. /****************************************************************
  115.  *
  116.  * Implementation of class DB_ENV_JAVAINFO
  117.  *
  118.  */
  119. /* create/initialize an object */
  120. DB_ENV_JAVAINFO *
  121. dbjie_construct(JNIEnv *jnienv,
  122. jobject default_errcall,
  123. int is_dbopen)
  124. {
  125. DB_ENV_JAVAINFO *dbjie;
  126. dbjie = (DB_ENV_JAVAINFO *)malloc(sizeof(DB_ENV_JAVAINFO));
  127. memset(dbjie, 0, sizeof(DB_ENV_JAVAINFO));
  128. dbjie->is_dbopen_ = is_dbopen;
  129. if ((*jnienv)->GetJavaVM(jnienv, &dbjie->javavm_) != 0) {
  130. free(dbjie);
  131. report_exception(jnienv, "cannot get Java VM", 0, 0);
  132. return (NULL);
  133. }
  134. /* The default error call just prints to the 'System.err'
  135.  * stream.  If the user does set_errcall to null, we'll
  136.  * want to have a reference to set it back to.
  137.  *
  138.  * Why do we have always set db_errcall to our own callback?
  139.  * Because it makes the interaction between setting the
  140.  * error prefix, error stream, and user's error callback
  141.  * that much easier.
  142.  */
  143. dbjie->default_errcall_ = NEW_GLOBAL_REF(jnienv, default_errcall);
  144. dbjie->errcall_ = NEW_GLOBAL_REF(jnienv, default_errcall);
  145. return (dbjie);
  146. }
  147. /* release all objects held by this this one */
  148. void dbjie_dealloc(DB_ENV_JAVAINFO *dbjie, JNIEnv *jnienv)
  149. {
  150. if (dbjie->recovery_init_ != NULL) {
  151. DELETE_GLOBAL_REF(jnienv, dbjie->recovery_init_);
  152. dbjie->recovery_init_ = NULL;
  153. }
  154. if (dbjie->feedback_ != NULL) {
  155. DELETE_GLOBAL_REF(jnienv, dbjie->feedback_);
  156. dbjie->feedback_ = NULL;
  157. }
  158. if (dbjie->tx_recover_ != NULL) {
  159. DELETE_GLOBAL_REF(jnienv, dbjie->tx_recover_);
  160. dbjie->tx_recover_ = NULL;
  161. }
  162. if (dbjie->errcall_ != NULL) {
  163. DELETE_GLOBAL_REF(jnienv, dbjie->errcall_);
  164. dbjie->errcall_ = NULL;
  165. }
  166. if (dbjie->default_errcall_ != NULL) {
  167. DELETE_GLOBAL_REF(jnienv, dbjie->default_errcall_);
  168. dbjie->default_errcall_ = NULL;
  169. }
  170. if (dbjie->conflict_ != NULL) {
  171. free(dbjie->conflict_);
  172. dbjie->conflict_ = NULL;
  173. }
  174. if (dbjie->errpfx_ != NULL) {
  175. free(dbjie->errpfx_);
  176. dbjie->errpfx_ = NULL;
  177. }
  178. }
  179. /* free this object, releasing anything allocated on its behalf */
  180. void dbjie_destroy(DB_ENV_JAVAINFO *dbjie, JNIEnv *jnienv)
  181. {
  182. dbjie_dealloc(dbjie, jnienv);
  183. /* Extra paranoia */
  184. memset(dbjie, 0, sizeof(DB_ENV_JAVAINFO));
  185. free(dbjie);
  186. }
  187. /* Attach to the current thread that is running and
  188.  * return that.  We use the java virtual machine
  189.  * that we saved in the constructor.
  190.  */
  191. JNIEnv *
  192. dbjie_get_jnienv(DB_ENV_JAVAINFO *dbjie)
  193. {
  194. /* Note:
  195.  * Different versions of the JNI disagree on the signature
  196.  * for AttachCurrentThread.  The most recent documentation
  197.  * seems to say that (JNIEnv **) is correct, but newer
  198.  * JNIs seem to use (void **), oddly enough.
  199.  */
  200. #ifdef JNI_VERSION_1_2
  201. void *attachret = 0;
  202. #else
  203. JNIEnv *attachret = 0;
  204. #endif
  205. /* This should always succeed, as we are called via
  206.  * some Java activity.  I think therefore I am (a thread).
  207.  */
  208. if ((*dbjie->javavm_)->AttachCurrentThread(dbjie->javavm_, &attachret, 0) != 0)
  209. return (0);
  210. return ((JNIEnv *)attachret);
  211. }
  212. jstring
  213. dbjie_get_errpfx(DB_ENV_JAVAINFO *dbjie, JNIEnv *jnienv)
  214. {
  215. return (get_java_string(jnienv, dbjie->errpfx_));
  216. }
  217. void
  218. dbjie_set_errcall(DB_ENV_JAVAINFO *dbjie, JNIEnv *jnienv, jobject new_errcall)
  219. {
  220. /* If the new_errcall is null, we'll set the error call
  221.  * to the default one.
  222.  */
  223. if (new_errcall == NULL)
  224. new_errcall = dbjie->default_errcall_;
  225. DELETE_GLOBAL_REF(jnienv, dbjie->errcall_);
  226. dbjie->errcall_ = NEW_GLOBAL_REF(jnienv, new_errcall);
  227. }
  228. void
  229. dbjie_set_errpfx(DB_ENV_JAVAINFO *dbjie, JNIEnv *jnienv, jstring errpfx)
  230. {
  231. if (dbjie->errpfx_ != NULL)
  232. free(dbjie->errpfx_);
  233. if (errpfx)
  234. dbjie->errpfx_ = get_c_string(jnienv, errpfx);
  235. else
  236. dbjie->errpfx_ = NULL;
  237. }
  238. void
  239. dbjie_set_conflict(DB_ENV_JAVAINFO *dbjie, unsigned char *newarr)
  240. {
  241. if (dbjie->conflict_)
  242. free(dbjie->conflict_);
  243. dbjie->conflict_ = newarr;
  244. }
  245. void dbjie_set_feedback_object(DB_ENV_JAVAINFO *dbjie, JNIEnv *jnienv,
  246.        DB_ENV *dbenv, jobject jfeedback)
  247. {
  248. int err;
  249. if (dbjie->feedback_ != NULL) {
  250. DELETE_GLOBAL_REF(jnienv, dbjie->feedback_);
  251. }
  252. if (jfeedback == NULL) {
  253. if ((err = dbenv->set_feedback(dbenv, NULL)) != 0)
  254. report_exception(jnienv, "set_feedback failed",
  255.  err, 0);
  256. }
  257. else {
  258. if ((err = dbenv->set_feedback(dbenv,
  259.        DbEnv_feedback_callback)) != 0)
  260. report_exception(jnienv, "set_feedback failed",
  261.  err, 0);
  262. }
  263. dbjie->feedback_ = NEW_GLOBAL_REF(jnienv, jfeedback);
  264. }
  265. void dbjie_call_feedback(DB_ENV_JAVAINFO *dbjie, DB_ENV *dbenv, jobject jenv,
  266.  int opcode, int percent)
  267. {
  268. JNIEnv *jnienv;
  269. jclass feedback_class;
  270. jmethodID id;
  271. COMPQUIET(dbenv, NULL);
  272. jnienv = dbjie_get_jnienv(dbjie);
  273. if (jnienv == NULL) {
  274. fprintf(stderr, "Cannot attach to current thread!n");
  275. return;
  276. }
  277. feedback_class = get_class(jnienv, name_DbEnvFeedback);
  278. id = (*jnienv)->GetMethodID(jnienv, feedback_class,
  279.     "feedback",
  280.     "(Lcom/sleepycat/db/DbEnv;II)V");
  281. if (!id) {
  282. fprintf(stderr, "Cannot find callback classn");
  283. return;
  284. }
  285. (*jnienv)->CallVoidMethod(jnienv, dbjie->feedback_, id,
  286.   jenv, (jint)opcode, (jint)percent);
  287. }
  288. void dbjie_set_recovery_init_object(DB_ENV_JAVAINFO *dbjie,
  289.     JNIEnv *jnienv, DB_ENV *dbenv,
  290.     jobject jrecovery_init)
  291. {
  292. int err;
  293. if (dbjie->recovery_init_ != NULL) {
  294. DELETE_GLOBAL_REF(jnienv, dbjie->recovery_init_);
  295. }
  296. if (jrecovery_init == NULL) {
  297. if ((err = dbenv->set_recovery_init(dbenv, NULL)) != 0)
  298. report_exception(jnienv, "set_recovery_init failed",
  299.  err, 0);
  300. }
  301. else {
  302. if ((err = dbenv->set_recovery_init(dbenv,
  303. DbEnv_recovery_init_callback)) != 0)
  304. report_exception(jnienv, "set_recovery_init failed",
  305.  err, 0);
  306. }
  307. dbjie->recovery_init_ = NEW_GLOBAL_REF(jnienv, jrecovery_init);
  308. }
  309. int dbjie_call_recovery_init(DB_ENV_JAVAINFO *dbjie, DB_ENV *dbenv,
  310.      jobject jenv)
  311. {
  312. JNIEnv *jnienv;
  313. jclass recovery_init_class;
  314. jmethodID id;
  315. COMPQUIET(dbenv, NULL);
  316. jnienv = dbjie_get_jnienv(dbjie);
  317. if (jnienv == NULL) {
  318. fprintf(stderr, "Cannot attach to current thread!n");
  319. return (EINVAL);
  320. }
  321. recovery_init_class = get_class(jnienv, name_DbRecoveryInit);
  322. id = (*jnienv)->GetMethodID(jnienv, recovery_init_class,
  323.     "recovery_init",
  324.     "(Lcom/sleepycat/db/DbEnv;)V");
  325. if (!id) {
  326. fprintf(stderr, "Cannot find callback classn");
  327. return (EINVAL);
  328. }
  329. return (*jnienv)->CallIntMethod(jnienv, dbjie->recovery_init_,
  330. id, jenv);
  331. }
  332. void dbjie_set_tx_recover_object(DB_ENV_JAVAINFO *dbjie, JNIEnv *jnienv,
  333.  DB_ENV *dbenv, jobject jtx_recover)
  334. {
  335. int err;
  336. if (dbjie->tx_recover_ != NULL) {
  337. DELETE_GLOBAL_REF(jnienv, dbjie->tx_recover_);
  338. }
  339. if (jtx_recover == NULL) {
  340. if ((err = dbenv->set_tx_recover(dbenv, NULL)) != 0)
  341. report_exception(jnienv, "set_tx_recover failed",
  342.  err, 0);
  343. }
  344. else {
  345. if ((err = dbenv->set_tx_recover(dbenv,
  346.  DbEnv_tx_recover_callback)) != 0)
  347. report_exception(jnienv, "set_tx_recover failed",
  348.  err, 0);
  349. }
  350. dbjie->tx_recover_ = NEW_GLOBAL_REF(jnienv, jtx_recover);
  351. }
  352. int dbjie_call_tx_recover(DB_ENV_JAVAINFO *dbjie, DB_ENV *dbenv, jobject jenv,
  353.   DBT *dbt, DB_LSN *lsn, int recops)
  354. {
  355. JNIEnv *jnienv;
  356. jclass tx_recover_class;
  357. jmethodID id;
  358. jobject jdbt;
  359. jobject jlsn;
  360. COMPQUIET(dbenv, NULL);
  361. jnienv = dbjie_get_jnienv(dbjie);
  362. if (jnienv == NULL) {
  363. fprintf(stderr, "Cannot attach to current thread!n");
  364. return (0);
  365. }
  366. tx_recover_class = get_class(jnienv, name_DbTxnRecover);
  367. id = (*jnienv)->GetMethodID(jnienv, tx_recover_class,
  368.     "tx_recover",
  369.     "(Lcom/sleepycat/db/DbEnv;"
  370.     "Lcom/sleepycat/db/Dbt;"
  371.     "Lcom/sleepycat/db/DbLsn;"
  372.     "I)I");
  373. if (!id) {
  374. fprintf(stderr, "Cannot find callback classn");
  375. return (0);
  376. }
  377. if (dbt == NULL)
  378. jdbt = NULL;
  379. else
  380. jdbt = get_Dbt(jnienv, dbt);
  381. if (lsn == NULL)
  382. jlsn = NULL;
  383. else
  384. jlsn = get_DbLsn(jnienv, *lsn);
  385. return (*jnienv)->CallIntMethod(jnienv, dbjie->tx_recover_, id, jenv,
  386. jdbt, jlsn, recops);
  387. }
  388. jobject dbjie_get_errcall(DB_ENV_JAVAINFO *dbjie)
  389. {
  390. return (dbjie->errcall_);
  391. }
  392. int dbjie_is_dbopen(DB_ENV_JAVAINFO *dbjie)
  393. {
  394. return (dbjie->is_dbopen_);
  395. }
  396. /****************************************************************
  397.  *
  398.  * Implementation of class DB_JAVAINFO
  399.  *
  400.  */
  401. DB_JAVAINFO *dbji_construct(JNIEnv *jnienv, jint flags)
  402. {
  403. DB_JAVAINFO *dbji;
  404. dbji = (DB_JAVAINFO *)malloc(sizeof(DB_JAVAINFO));
  405. memset(dbji, 0, sizeof(DB_JAVAINFO));
  406. if ((*jnienv)->GetJavaVM(jnienv, &dbji->javavm_) != 0) {
  407. report_exception(jnienv, "cannot get Java VM", 0, 0);
  408. free(dbji);
  409. return (NULL);
  410. }
  411. dbji->construct_flags_ = flags;
  412. return (dbji);
  413. }
  414. void
  415. dbji_dealloc(DB_JAVAINFO *dbji, JNIEnv *jnienv)
  416. {
  417. if (dbji->append_recno_ != NULL) {
  418. DELETE_GLOBAL_REF(jnienv, dbji->append_recno_);
  419. dbji->append_recno_ = NULL;
  420. }
  421. if (dbji->bt_compare_ != NULL) {
  422. DELETE_GLOBAL_REF(jnienv, dbji->bt_compare_);
  423. dbji->bt_compare_ = NULL;
  424. }
  425. if (dbji->bt_prefix_ != NULL) {
  426. DELETE_GLOBAL_REF(jnienv, dbji->bt_prefix_);
  427. dbji->bt_prefix_ = NULL;
  428. }
  429. if (dbji->dup_compare_ != NULL) {
  430. DELETE_GLOBAL_REF(jnienv, dbji->dup_compare_);
  431. dbji->dup_compare_ = NULL;
  432. }
  433. if (dbji->feedback_ != NULL) {
  434. DELETE_GLOBAL_REF(jnienv, dbji->feedback_);
  435. dbji->feedback_ = NULL;
  436. }
  437. if (dbji->h_hash_ != NULL) {
  438. DELETE_GLOBAL_REF(jnienv, dbji->h_hash_);
  439. dbji->h_hash_ = NULL;
  440. }
  441. }
  442. void
  443. dbji_destroy(DB_JAVAINFO *dbji, JNIEnv *jnienv)
  444. {
  445. dbji_dealloc(dbji, jnienv);
  446. free(dbji);
  447. }
  448. JNIEnv *dbji_get_jnienv(DB_JAVAINFO *dbji)
  449. {
  450. /* Note:
  451.  * Different versions of the JNI disagree on the signature
  452.  * for AttachCurrentThread.  The most recent documentation
  453.  * seems to say that (JNIEnv **) is correct, but newer
  454.  * JNIs seem to use (void **), oddly enough.
  455.  */
  456. #ifdef JNI_VERSION_1_2
  457. void *attachret = 0;
  458. #else
  459. JNIEnv *attachret = 0;
  460. #endif
  461. /* This should always succeed, as we are called via
  462.  * some Java activity.  I think therefore I am (a thread).
  463.  */
  464. if ((*dbji->javavm_)->AttachCurrentThread(dbji->javavm_, &attachret, 0) != 0)
  465. return (0);
  466. return ((JNIEnv *)attachret);
  467. }
  468. jint dbji_get_flags(DB_JAVAINFO *dbji)
  469. {
  470. return (dbji->construct_flags_);
  471. }
  472. void dbji_set_feedback_object(DB_JAVAINFO *dbji, JNIEnv *jnienv,
  473.       DB *db, jobject jfeedback)
  474. {
  475. jclass feedback_class;
  476. if (dbji->feedback_method_id_ == NULL) {
  477. feedback_class = get_class(jnienv, name_DbFeedback);
  478. dbji->feedback_method_id_ =
  479. (*jnienv)->GetMethodID(jnienv, feedback_class,
  480.        "feedback",
  481.        "(Lcom/sleepycat/db/Db;II)V");
  482. if (dbji->feedback_method_id_ != NULL) {
  483. /* XXX
  484.  * We should really have a better way
  485.  * to translate this to a Java exception class.
  486.  * In theory, it shouldn't happen.
  487.  */
  488. report_exception(jnienv, "Cannot find callback method",
  489.  EFAULT, 0);
  490. return;
  491. }
  492. }
  493. if (dbji->feedback_ != NULL) {
  494. DELETE_GLOBAL_REF(jnienv, dbji->feedback_);
  495. }
  496. if (jfeedback == NULL) {
  497. db->set_feedback(db, NULL);
  498. }
  499. else {
  500. db->set_feedback(db, Db_feedback_callback);
  501. }
  502. dbji->feedback_ = NEW_GLOBAL_REF(jnienv, jfeedback);
  503. }
  504. void dbji_call_feedback(DB_JAVAINFO *dbji, DB *db, jobject jdb,
  505. int opcode, int percent)
  506. {
  507. JNIEnv *jnienv;
  508. COMPQUIET(db, NULL);
  509. jnienv = dbji_get_jnienv(dbji);
  510. if (jnienv == NULL) {
  511. fprintf(stderr, "Cannot attach to current thread!n");
  512. return;
  513. }
  514. DB_ASSERT(dbji->feedback_method_id_ != NULL);
  515. (*jnienv)->CallVoidMethod(jnienv, dbji->feedback_,
  516.   dbji->feedback_method_id_,
  517.   jdb, (jint)opcode, (jint)percent);
  518. }
  519. void dbji_set_append_recno_object(DB_JAVAINFO *dbji, JNIEnv *jnienv,
  520.   DB *db, jobject jcallback)
  521. {
  522. jclass append_recno_class;
  523. if (dbji->append_recno_method_id_ == NULL) {
  524. append_recno_class = get_class(jnienv, name_DbAppendRecno);
  525. dbji->append_recno_method_id_ =
  526. (*jnienv)->GetMethodID(jnienv, append_recno_class,
  527.        "db_append_recno",
  528.        "(Lcom/sleepycat/db/Db;"
  529.        "Lcom/sleepycat/db/Dbt;I)V");
  530. if (dbji->append_recno_method_id_ == NULL) {
  531. /* XXX
  532.  * We should really have a better way
  533.  * to translate this to a Java exception class.
  534.  * In theory, it shouldn't happen.
  535.  */
  536. report_exception(jnienv, "Cannot find callback method",
  537.  EFAULT, 0);
  538. return;
  539. }
  540. }
  541. if (dbji->append_recno_ != NULL) {
  542. DELETE_GLOBAL_REF(jnienv, dbji->append_recno_);
  543. }
  544. if (jcallback == NULL) {
  545. db->set_append_recno(db, NULL);
  546. }
  547. else {
  548. db->set_append_recno(db, Db_append_recno_callback);
  549. }
  550. dbji->append_recno_ = NEW_GLOBAL_REF(jnienv, jcallback);
  551. }
  552. extern int dbji_call_append_recno(DB_JAVAINFO *dbji, DB *db, jobject jdb,
  553.   DBT *dbt, jint recno)
  554. {
  555. JNIEnv *jnienv;
  556. jobject jdbt;
  557. DBT_JAVAINFO *dbtji;
  558. jbyteArray arr;
  559. unsigned int arraylen;
  560. unsigned char *data;
  561. COMPQUIET(db, NULL);
  562. jnienv = dbji_get_jnienv(dbji);
  563. if (jnienv == NULL) {
  564. fprintf(stderr, "Cannot attach to current thread!n");
  565. return (0);
  566. }
  567. /* XXX
  568.  * We should have a pool of Dbt objects used for this purpose
  569.  * instead of creating new ones each time.  Because of
  570.  * multithreading, we may need an arbitrary number (more than two).
  571.  * We might also have a byte arrays that grow as needed,
  572.  * so we don't need to allocate those either.
  573.  *
  574.  * Note, we do not set the 'create_array_' flag as on other
  575.  * callbacks as we are creating the array here.
  576.  */
  577. jdbt = create_default_object(jnienv, name_DBT);
  578. dbtji = get_DBT_JAVAINFO(jnienv, jdbt);
  579. memcpy(&dbtji->dbt, dbt, sizeof(DBT));
  580. dbtji->dbt.data = NULL;
  581. arr = (*jnienv)->NewByteArray(jnienv, dbt->size);
  582. (*jnienv)->SetByteArrayRegion(jnienv, arr, 0, dbt->size,
  583.       (jbyte *)dbt->data);
  584. dbtji->array_ = (jbyteArray)NEW_GLOBAL_REF(jnienv, arr);
  585. DB_ASSERT(dbji->append_recno_method_id_ != NULL);
  586. (*jnienv)->CallVoidMethod(jnienv, dbji->append_recno_,
  587.   dbji->append_recno_method_id_,
  588.   jdb, jdbt, recno);
  589. /* The underlying C API requires that an errno be returned
  590.  * on error.  Java users know nothing of errnos, so we
  591.  * allow them to throw exceptions instead.  We leave the
  592.  * exception in place and return DB_JAVA_CALLBACK to the C API
  593.  * that called us.  Eventually the DB->get will fail and
  594.  * when java prepares to throw an exception in
  595.  * report_exception(), this will be spotted as a special case,
  596.  * and the original exception will be preserved.
  597.  *
  598.  * Note: we have sometimes noticed strange behavior with
  599.  * exceptions under Linux 1.1.7 JVM.  (i.e. multiple calls
  600.  * to ExceptionOccurred() may report different results).
  601.  * Currently we don't know of any problems related to this
  602.  * in our code, but if it pops up in the future, users are
  603.  * encouranged to get a more recent JVM.
  604.  */
  605. if ((*jnienv)->ExceptionOccurred(jnienv) != NULL)
  606. return (DB_JAVA_CALLBACK);
  607. if (dbtji->array_ == NULL) {
  608. report_exception(jnienv, "Dbt.data is null", 0, 0);
  609. return (EFAULT);
  610. }
  611. arraylen = (*jnienv)->GetArrayLength(jnienv, dbtji->array_);
  612. if (dbtji->offset_ < 0 ) {
  613. report_exception(jnienv, "Dbt.offset illegal", 0, 0);
  614. return (EFAULT);
  615. }
  616. if (dbt->ulen + dbtji->offset_ > arraylen) {
  617. report_exception(jnienv,
  618.    "Dbt.ulen + Dbt.offset greater than array length", 0, 0);
  619. return (EFAULT);
  620. }
  621. data = (*jnienv)->GetByteArrayElements(jnienv, dbtji->array_,
  622.        (jboolean *)0);
  623. dbt->data = data + dbtji->offset_;
  624. return (0);
  625. }
  626. void dbji_set_bt_compare_object(DB_JAVAINFO *dbji, JNIEnv *jnienv,
  627. DB *db, jobject jcompare)
  628. {
  629. jclass bt_compare_class;
  630. if (dbji->bt_compare_method_id_ == NULL) {
  631. bt_compare_class = get_class(jnienv, name_DbBtreeCompare);
  632. dbji->bt_compare_method_id_ =
  633. (*jnienv)->GetMethodID(jnienv, bt_compare_class,
  634.        "bt_compare",
  635.        "(Lcom/sleepycat/db/Db;"
  636.        "Lcom/sleepycat/db/Dbt;"
  637.        "Lcom/sleepycat/db/Dbt;)I");
  638. if (dbji->bt_compare_method_id_ == NULL) {
  639. /* XXX
  640.  * We should really have a better way
  641.  * to translate this to a Java exception class.
  642.  * In theory, it shouldn't happen.
  643.  */
  644. report_exception(jnienv, "Cannot find callback method",
  645.  EFAULT, 0);
  646. return;
  647. }
  648. }
  649. if (dbji->bt_compare_ != NULL) {
  650. DELETE_GLOBAL_REF(jnienv, dbji->bt_compare_);
  651. }
  652. if (jcompare == NULL) {
  653. db->set_bt_compare(db, NULL);
  654. }
  655. else {
  656. db->set_bt_compare(db, Db_bt_compare_callback);
  657. }
  658. dbji->bt_compare_ = NEW_GLOBAL_REF(jnienv, jcompare);
  659. }
  660. int dbji_call_bt_compare(DB_JAVAINFO *dbji, DB *db, jobject jdb,
  661.  const DBT *dbt1, const DBT *dbt2)
  662. {
  663. JNIEnv *jnienv;
  664. jobject jdbt1, jdbt2;
  665. DBT_JAVAINFO *dbtji1, *dbtji2;
  666. COMPQUIET(db, NULL);
  667. jnienv = dbji_get_jnienv(dbji);
  668. if (jnienv == NULL) {
  669. fprintf(stderr, "Cannot attach to current thread!n");
  670. return (0);
  671. }
  672. /* XXX
  673.  * We should have a pool of Dbt objects used for this purpose
  674.  * instead of creating new ones each time.  Because of
  675.  * multithreading, we may need an arbitrary number (more than two).
  676.  * We might also have a byte arrays that grow as needed,
  677.  * so we don't need to allocate those either.
  678.  */
  679. jdbt1 = create_default_object(jnienv, name_DBT);
  680. jdbt2 = create_default_object(jnienv, name_DBT);
  681. dbtji1 = get_DBT_JAVAINFO(jnienv, jdbt1);
  682. memcpy(&dbtji1->dbt, dbt1, sizeof(DBT));
  683. dbtji1->create_array_ = 1;
  684. dbtji2 = get_DBT_JAVAINFO(jnienv, jdbt2);
  685. memcpy(&dbtji2->dbt, dbt2, sizeof(DBT));
  686. dbtji2->create_array_ = 1;
  687. DB_ASSERT(dbji->bt_compare_method_id_ != NULL);
  688. return (*jnienv)->CallIntMethod(jnienv, dbji->bt_compare_,
  689. dbji->bt_compare_method_id_,
  690. jdb, jdbt1, jdbt2);
  691. }
  692. void dbji_set_bt_prefix_object(DB_JAVAINFO *dbji, JNIEnv *jnienv,
  693. DB *db, jobject jprefix)
  694. {
  695. jclass bt_prefix_class;
  696. if (dbji->bt_prefix_method_id_ == NULL) {
  697. bt_prefix_class = get_class(jnienv, name_DbBtreePrefix);
  698. dbji->bt_prefix_method_id_ =
  699. (*jnienv)->GetMethodID(jnienv, bt_prefix_class,
  700.        "bt_prefix",
  701.        "(Lcom/sleepycat/db/Db;"
  702.        "Lcom/sleepycat/db/Dbt;"
  703.        "Lcom/sleepycat/db/Dbt;)I");
  704. if (dbji->bt_prefix_method_id_ == NULL) {
  705. /* XXX
  706.  * We should really have a better way
  707.  * to translate this to a Java exception class.
  708.  * In theory, it shouldn't happen.
  709.  */
  710. report_exception(jnienv, "Cannot find callback method",
  711.  EFAULT, 0);
  712. return;
  713. }
  714. }
  715. if (dbji->bt_prefix_ != NULL) {
  716. DELETE_GLOBAL_REF(jnienv, dbji->bt_prefix_);
  717. }
  718. if (jprefix == NULL) {
  719. db->set_bt_prefix(db, NULL);
  720. }
  721. else {
  722. db->set_bt_prefix(db, Db_bt_prefix_callback);
  723. }
  724. dbji->bt_prefix_ = NEW_GLOBAL_REF(jnienv, jprefix);
  725. }
  726. size_t dbji_call_bt_prefix(DB_JAVAINFO *dbji, DB *db, jobject jdb,
  727.    const DBT *dbt1, const DBT *dbt2)
  728. {
  729. JNIEnv *jnienv;
  730. jobject jdbt1, jdbt2;
  731. DBT_JAVAINFO *dbtji1, *dbtji2;
  732. COMPQUIET(db, NULL);
  733. jnienv = dbji_get_jnienv(dbji);
  734. if (jnienv == NULL) {
  735. fprintf(stderr, "Cannot attach to current thread!n");
  736. return (0);
  737. }
  738. /* XXX
  739.  * We should have a pool of Dbt objects used for this purpose
  740.  * instead of creating new ones each time.  Because of
  741.  * multithreading, we may need an arbitrary number (more than two).
  742.  * We might also have a byte arrays that grow as needed,
  743.  * so we don't need to allocate those either.
  744.  */
  745. jdbt1 = create_default_object(jnienv, name_DBT);
  746. jdbt2 = create_default_object(jnienv, name_DBT);
  747. dbtji1 = get_DBT_JAVAINFO(jnienv, jdbt1);
  748. memcpy(&dbtji1->dbt, dbt1, sizeof(DBT));
  749. dbtji1->create_array_ = 1;
  750. dbtji2 = get_DBT_JAVAINFO(jnienv, jdbt2);
  751. memcpy(&dbtji2->dbt, dbt2, sizeof(DBT));
  752. dbtji2->create_array_ = 1;
  753. DB_ASSERT(dbji->bt_prefix_method_id_ != NULL);
  754. return (size_t)(*jnienv)->CallIntMethod(jnienv, dbji->bt_prefix_,
  755. dbji->bt_prefix_method_id_,
  756. jdb, jdbt1, jdbt2);
  757. }
  758. void dbji_set_dup_compare_object(DB_JAVAINFO *dbji, JNIEnv *jnienv,
  759. DB *db, jobject jcompare)
  760. {
  761. jclass dup_compare_class;
  762. if (dbji->dup_compare_method_id_ == NULL) {
  763. dup_compare_class = get_class(jnienv, name_DbDupCompare);
  764. dbji->dup_compare_method_id_ =
  765. (*jnienv)->GetMethodID(jnienv, dup_compare_class,
  766.        "dup_compare",
  767.        "(Lcom/sleepycat/db/Db;"
  768.        "Lcom/sleepycat/db/Dbt;"
  769.        "Lcom/sleepycat/db/Dbt;)I");
  770. if (dbji->dup_compare_method_id_ == NULL) {
  771. /* XXX
  772.  * We should really have a better way
  773.  * to translate this to a Java exception class.
  774.  * In theory, it shouldn't happen.
  775.  */
  776. report_exception(jnienv, "Cannot find callback method",
  777.  EFAULT, 0);
  778. return;
  779. }
  780. }
  781. if (dbji->dup_compare_ != NULL)
  782. DELETE_GLOBAL_REF(jnienv, dbji->dup_compare_);
  783. if (jcompare == NULL)
  784. db->set_dup_compare(db, NULL);
  785. else
  786. db->set_dup_compare(db, Db_dup_compare_callback);
  787. dbji->dup_compare_ = NEW_GLOBAL_REF(jnienv, jcompare);
  788. }
  789. int dbji_call_dup_compare(DB_JAVAINFO *dbji, DB *db, jobject jdb,
  790.  const DBT *dbt1, const DBT *dbt2)
  791. {
  792. JNIEnv *jnienv;
  793. jobject jdbt1, jdbt2;
  794. DBT_JAVAINFO *dbtji1, *dbtji2;
  795. COMPQUIET(db, NULL);
  796. jnienv = dbji_get_jnienv(dbji);
  797. if (jnienv == NULL) {
  798. fprintf(stderr, "Cannot attach to current thread!n");
  799. return (0);
  800. }
  801. /* XXX
  802.  * We should have a pool of Dbt objects used for this purpose
  803.  * instead of creating new ones each time.  Because of
  804.  * multithreading, we may need an arbitrary number (more than two).
  805.  * We might also have a byte arrays that grow as needed,
  806.  * so we don't need to allocate those either.
  807.  */
  808. jdbt1 = create_default_object(jnienv, name_DBT);
  809. jdbt2 = create_default_object(jnienv, name_DBT);
  810. dbtji1 = get_DBT_JAVAINFO(jnienv, jdbt1);
  811. memcpy(&dbtji1->dbt, dbt1, sizeof(DBT));
  812. dbtji1->create_array_ = 1;
  813. dbtji2 = get_DBT_JAVAINFO(jnienv, jdbt2);
  814. memcpy(&dbtji2->dbt, dbt2, sizeof(DBT));
  815. dbtji2->create_array_ = 1;
  816. DB_ASSERT(dbji->dup_compare_method_id_ != NULL);
  817. return (*jnienv)->CallIntMethod(jnienv, dbji->dup_compare_,
  818. dbji->dup_compare_method_id_,
  819. jdb, jdbt1, jdbt2);
  820. }
  821. void dbji_set_h_hash_object(DB_JAVAINFO *dbji, JNIEnv *jnienv,
  822. DB *db, jobject jhash)
  823. {
  824. jclass h_hash_class;
  825. if (dbji->h_hash_method_id_ == NULL) {
  826. h_hash_class = get_class(jnienv, name_DbHash);
  827. dbji->h_hash_method_id_ =
  828. (*jnienv)->GetMethodID(jnienv, h_hash_class,
  829.        "hash",
  830.        "(Lcom/sleepycat/db/Db;"
  831.        "[BI)I");
  832. if (dbji->h_hash_method_id_ == NULL) {
  833. /* XXX
  834.  * We should really have a better way
  835.  * to translate this to a Java exception class.
  836.  * In theory, it shouldn't happen.
  837.  */
  838. report_exception(jnienv, "Cannot find callback method",
  839.  EFAULT, 0);
  840. return;
  841. }
  842. }
  843. if (dbji->h_hash_ != NULL)
  844. DELETE_GLOBAL_REF(jnienv, dbji->h_hash_);
  845. if (jhash == NULL)
  846. db->set_h_hash(db, NULL);
  847. else
  848. db->set_h_hash(db, Db_h_hash_callback);
  849. dbji->h_hash_ = NEW_GLOBAL_REF(jnienv, jhash);
  850. }
  851. int dbji_call_h_hash(DB_JAVAINFO *dbji, DB *db, jobject jdb,
  852.      const void *data, int len)
  853. {
  854. JNIEnv *jnienv;
  855. jbyteArray jarray;
  856. COMPQUIET(db, NULL);
  857. jnienv = dbji_get_jnienv(dbji);
  858. if (jnienv == NULL) {
  859. fprintf(stderr, "Cannot attach to current thread!n");
  860. return (0);
  861. }
  862. DB_ASSERT(dbji->h_hash_method_id_ != NULL);
  863. jarray = (*jnienv)->NewByteArray(jnienv, len);
  864. (*jnienv)->SetByteArrayRegion(jnienv, jarray, 0, len, (void *)data);
  865. return (*jnienv)->CallIntMethod(jnienv, dbji->h_hash_,
  866. dbji->h_hash_method_id_,
  867. jdb, jarray, len);
  868. }