• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <ejdb2.h>
2 #include <jni.h>
3 #include <string.h>
4 #include <errno.h>
5 #include <stdlib.h>
6 
7 #include "com_softmotions_ejdb2_EJDB2.h"
8 #include "com_softmotions_ejdb2_JQL.h"
9 
10 
11 #define JBN_JSON_FLUSH_BUFFER_SZ 4096
12 
13 typedef struct JBN_STR {
14   const char *utf;
15   jstring     str;
16 } JBN_STR;
17 
18 typedef enum {
19   _JBN_ERROR_START = (IW_ERROR_START + 15000UL + 5000),
20   JBN_ERROR_INVALID_FIELD,          /**< Failed to get class field (JBN_ERROR_INVALID_FIELD) */
21   JBN_ERROR_INVALID_METHOD,         /**< Failed to get class method (JBN_ERROR_INVALID_METHOD) */
22   JBN_ERROR_INVALID_OPTIONS,
23   /**< Invalid com.softmotions.ejdb2.EJDB2Builder configuration provided
24      (JBN_ERROR_INVALID_OPTIONS) */
25   JBN_ERROR_INVALID_STATE,          /**< Invalid com.softmotions.ejdb2.EJDB2 JNI state (JBN_ERROR_INVALID_STATE) */
26   JBN_ERROR_CREATION_OBJ,           /**< Failed to create/allocate JNI object (JBN_ERROR_CREATION_OBJ) */
27   _JBN_ERROR_END,
28 } jbn_ecode_t;
29 
30 static jclass k_EJDB2Exception_clazz;
31 static jmethodID k_EJDB2Exception_constructor; // EJDB2Exception(int code, String message)
32 
33 static jclass k_EJDB2_clazz;
34 static jfieldID k_EJDB2_handle_fid;
35 
36 static jclass k_JQL_clazz;
37 static jfieldID k_JQL_handle_fid;
38 static jfieldID k_JQL_db_fid;
39 static jfieldID k_JQL_query_fid;
40 static jfieldID k_JQL_collection_fid;
41 static jfieldID k_JQL_skip_fid;
42 static jfieldID k_JQL_limit_fid;
43 
44 #define JBNFIELD(fid_, env_, clazz_, name_, type_)           \
45   fid_ = (*(env_))->GetFieldID(env_, clazz_, name_, type_);
46 
47 #define JBNFIELD2(fid_, env_, clazz_, name_, type_, label_)  \
48   fid_ = (*(env_))->GetFieldID(env_, clazz_, name_, type_);  \
49   if (!fid_) goto label_;
50 
51 typedef struct JBN_JSPRINT_CTX {
52   int     flush_buffer_sz;
53   IWXSTR *xstr;
54   iwrc (*flushFn)(struct JBN_JSPRINT_CTX *pctx);
55   JNIEnv   *env;
56   jclass    osClazz;
57   jobject   osObj;
58   jmethodID write_mid;
59 } JBN_JSPRINT_CTX;
60 
jbn_json_printer(const char * data,int size,char ch,int count,void * op)61 static iwrc jbn_json_printer(const char *data, int size, char ch, int count, void *op) {
62   JBN_JSPRINT_CTX *pctx = op;
63   IWXSTR *xstr = pctx->xstr;
64   if (!data) {
65     if (count) {
66       for (int i = 0; i < count; ++i) {
67         iwrc rc = iwxstr_cat(xstr, &ch, 1);
68         RCRET(rc);
69       }
70     }
71   } else {
72     if (size < 0) {
73       size = (int) strlen(data);
74     }
75     if (!count) {
76       count = 1;
77     }
78     for (int i = 0; i < count; ++i) {
79       iwrc rc = iwxstr_cat(xstr, data, size);
80       RCRET(rc);
81     }
82   }
83   if (iwxstr_size(xstr) >= pctx->flush_buffer_sz) {
84     iwrc rc = pctx->flushFn(pctx);
85     RCRET(rc);
86   }
87   return 0;
88 }
89 
jbn_db(JNIEnv * env,jobject thisObj,EJDB * db)90 IW_INLINE iwrc jbn_db(JNIEnv *env, jobject thisObj, EJDB *db) {
91   *db = 0;
92   jlong ptr = (*env)->GetLongField(env, thisObj, k_EJDB2_handle_fid);
93   if (!ptr) {
94     return JBN_ERROR_INVALID_STATE;
95   }
96   *db = (void*) ptr;
97   return 0;
98 }
99 
jbn_jql_q(JNIEnv * env,jobject thisObj,JQL * q)100 IW_INLINE iwrc jbn_jql_q(JNIEnv *env, jobject thisObj, JQL *q) {
101   *q = 0;
102   jlong ptr = (*env)->GetLongField(env, thisObj, k_JQL_handle_fid);
103   if (!ptr) {
104     return JBN_ERROR_INVALID_STATE;
105   }
106   *q = (void*) ptr;
107   return 0;
108 }
109 
jbn_flush_to_stream(JBN_JSPRINT_CTX * pctx)110 static iwrc jbn_flush_to_stream(JBN_JSPRINT_CTX *pctx) {
111   JNIEnv *env = pctx->env;
112   IWXSTR *xstr = pctx->xstr;
113   size_t xsz = iwxstr_size(xstr);
114   if (xsz == 0) {
115     return 0;
116   }
117   jbyteArray arr = (*env)->NewByteArray(env, xsz);
118   if (!arr) {
119     return JBN_ERROR_CREATION_OBJ;
120   }
121   (*env)->SetByteArrayRegion(env, arr, 0, xsz, (void*) iwxstr_ptr(xstr));
122   iwxstr_clear(xstr);
123   (*env)->CallVoidMethod(env, pctx->osObj, pctx->write_mid, arr);
124   return 0;
125 }
126 
jbn_init_pctx(JNIEnv * env,JBN_JSPRINT_CTX * pctx,jobject thisObj,jobject osObj)127 static iwrc jbn_init_pctx(JNIEnv *env, JBN_JSPRINT_CTX *pctx, jobject thisObj, jobject osObj) {
128   memset(pctx, 0, sizeof(*pctx));
129   iwrc rc = 0;
130   jclass osClazz = (*env)->GetObjectClass(env, osObj);
131   jmethodID writeMid = (*env)->GetMethodID(env, osClazz, "write", "([B)V");
132   IWXSTR *xstr = iwxstr_new();
133   if (!xstr) {
134     return iwrc_set_errno(rc, IW_ERROR_ALLOC);
135   }
136   pctx->xstr = xstr;
137   pctx->flush_buffer_sz = JBN_JSON_FLUSH_BUFFER_SZ;
138   pctx->env = env;
139   pctx->osClazz = osClazz;
140   pctx->osObj = osObj;
141   pctx->write_mid = writeMid;
142   pctx->flushFn = jbn_flush_to_stream;
143   return rc;
144 }
145 
jbn_destroy_pctx(JBN_JSPRINT_CTX * pctx)146 static void jbn_destroy_pctx(JBN_JSPRINT_CTX *pctx) {
147   if (pctx->xstr) {
148     iwxstr_destroy(pctx->xstr);
149     pctx->xstr = 0;
150   }
151 }
152 
jbn_throw_rc_exception(JNIEnv * env,iwrc rc,const char * msg_)153 static void jbn_throw_rc_exception(JNIEnv *env, iwrc rc, const char *msg_) {
154   const char *msg;
155   if (msg_) {
156     msg = msg_;
157   } else {
158     msg = iwlog_ecode_explained(rc);
159     if (!msg) {
160       msg = "Unknown iwrc error";
161     }
162   }
163   uint32_t eno = iwrc_strip_errno(&rc);
164   jstring msgStr = (*env)->NewStringUTF(env, msg);
165   jobject exObj = (*env)->NewObject(env, k_EJDB2Exception_clazz,
166                                     k_EJDB2Exception_constructor, (jlong) rc, (jlong) eno, msgStr);
167   if ((*env)->Throw(env, exObj) < 0) {
168     iwlog_error("Failed to throw exception for EJDB2Exception: %s", msg);
169   }
170 }
171 
Java_com_softmotions_ejdb2_EJDB2__1open(JNIEnv * env,jobject thisObj,jobject optsObj)172 JNIEXPORT void JNICALL Java_com_softmotions_ejdb2_EJDB2__1open(
173   JNIEnv *env,
174   jobject thisObj,
175   jobject optsObj) {
176   iwrc rc = 0;
177   EJDB_OPTS opts = { 0 };
178   JNIEnv e = *env;
179   jfieldID fid;
180   jobject iwkv, http, wal;
181   jclass iwkvClazz, httpClazz, walClazz;
182   jclass optsClazz = e->GetObjectClass(env, optsObj);
183 
184   int sc = 0;
185   EJDB db = 0;
186   JBN_STR strings[3] = { 0 };
187 
188   // opts
189   JBNFIELD(fid, env, optsClazz, "no_wal", "Z");
190   opts.no_wal = e->GetBooleanField(env, optsObj, fid);
191 
192   JBNFIELD(fid, env, optsClazz, "sort_buffer_sz", "I");
193   opts.sort_buffer_sz = (uint32_t) e->GetIntField(env, optsObj, fid);
194 
195   JBNFIELD(fid, env, optsClazz, "document_buffer_sz", "I");
196   opts.document_buffer_sz = (uint32_t) e->GetIntField(env, optsObj, fid);
197 
198   // iwkv
199   JBNFIELD(fid, env, optsClazz, "iwkv", "Lcom/softmotions/ejdb2/IWKVOptions;");
200   iwkv = e->GetObjectField(env, optsObj, fid);
201   if (!iwkv) {
202     jbn_throw_rc_exception(env, JBN_ERROR_INVALID_OPTIONS, 0);
203     return;
204   }
205   iwkvClazz = e->GetObjectClass(env, iwkv);
206 
207   JBNFIELD(fid, env, iwkvClazz, "random_seed", "J");
208   opts.kv.random_seed = (uint32_t) e->GetLongField(env, iwkv, fid);
209 
210   JBNFIELD(fid, env, iwkvClazz, "oflags", "J");
211   opts.kv.oflags = (iwkv_openflags) e->GetLongField(env, iwkv, fid);
212 
213   JBNFIELD(fid, env, iwkvClazz, "file_lock_fail_fast", "Z");
214   opts.kv.file_lock_fail_fast = e->GetBooleanField(env, iwkv, fid);
215 
216   JBNFIELD(fid, env, iwkvClazz, "path", "Ljava/lang/String;");
217   strings[sc].str = e->GetObjectField(env, iwkv, fid);
218   strings[sc].utf = strings[sc].str ? e->GetStringUTFChars(env, strings[sc].str, 0) : 0;
219   opts.kv.path = strings[sc++].utf;
220   if (!opts.kv.path) {
221     rc = JBN_ERROR_INVALID_OPTIONS;
222     goto finish;
223   }
224 
225   // wal
226   JBNFIELD2(fid, env, iwkvClazz, "wal", "Lcom/softmotions/ejdb2/IWKVOptions$WALOptions;", finish);
227   wal = e->GetObjectField(env, iwkv, fid);
228   if (!wal) {
229     jbn_throw_rc_exception(env, JBN_ERROR_INVALID_OPTIONS, 0);
230     goto finish;
231   }
232   walClazz = e->GetObjectClass(env, wal);
233 
234   JBNFIELD2(fid, env, walClazz, "check_crc_on_checkpoint", "Z", finish);
235   opts.kv.wal.check_crc_on_checkpoint = e->GetBooleanField(env, wal, fid);
236 
237   JBNFIELD2(fid, env, walClazz, "savepoint_timeout_sec", "I", finish);
238   opts.kv.wal.savepoint_timeout_sec = (uint32_t) e->GetIntField(env, wal, fid);
239 
240   JBNFIELD2(fid, env, walClazz, "checkpoint_timeout_sec", "I", finish);
241   opts.kv.wal.checkpoint_timeout_sec = (uint32_t) e->GetIntField(env, wal, fid);
242 
243   JBNFIELD2(fid, env, walClazz, "buffer_sz", "J", finish);
244   opts.kv.wal.wal_buffer_sz = (uint64_t) e->GetLongField(env, wal, fid);
245 
246   JBNFIELD2(fid, env, walClazz, "checkpoint_buffer_sz", "J", finish);
247   opts.kv.wal.checkpoint_buffer_sz = (uint64_t) e->GetLongField(env, wal, fid);
248 
249 
250   // http
251   JBNFIELD2(fid, env, optsClazz, "http", "Lcom/softmotions/ejdb2/EJDB2Builder$EJDB2HttpOptions;", finish);
252   http = e->GetObjectField(env, optsObj, fid);
253   httpClazz = e->GetObjectClass(env, http);
254 
255   JBNFIELD2(fid, env, httpClazz, "enabled", "Z", finish);
256   opts.http.enabled = e->GetBooleanField(env, http, fid);
257 
258   JBNFIELD2(fid, env, httpClazz, "port", "I", finish);
259   opts.http.port = e->GetIntField(env, http, fid);
260 
261   JBNFIELD2(fid, env, httpClazz, "bind", "Ljava/lang/String;", finish);
262   strings[sc].str = e->GetObjectField(env, http, fid);
263   strings[sc].utf = strings[sc].str ? e->GetStringUTFChars(env, strings[sc].str, 0) : 0;
264   opts.http.bind = strings[sc++].utf;
265 
266   JBNFIELD2(fid, env, httpClazz, "access_token", "Ljava/lang/String;", finish);
267   strings[sc].str = e->GetObjectField(env, http, fid);
268   strings[sc].utf = strings[sc].str ? e->GetStringUTFChars(env, strings[sc].str, 0) : 0;
269   opts.http.access_token = strings[sc++].utf;
270   opts.http.access_token_len = opts.http.access_token ? strlen(opts.http.access_token) : 0;
271 
272   JBNFIELD2(fid, env, httpClazz, "read_anon", "Z", finish);
273   opts.http.read_anon = e->GetBooleanField(env, http, fid);
274 
275   JBNFIELD2(fid, env, httpClazz, "max_body_size", "I", finish);
276   opts.http.max_body_size = (size_t) e->GetIntField(env, http, fid);
277 
278   rc = ejdb_open(&opts, &db);
279   RCGO(rc, finish);
280 
281   e->SetLongField(env, thisObj, k_EJDB2_handle_fid, (jlong) db);
282 
283 finish:
284   for (int i = 0; i < (sizeof(strings) / sizeof(strings[0])); ++i) {
285     if (strings[i].str) {
286       e->ReleaseStringUTFChars(env, strings[i].str, strings[i].utf);
287     }
288   }
289   if (rc) {
290     jbn_throw_rc_exception(env, rc, 0);
291   }
292 }
293 
294 // DISPOSE
Java_com_softmotions_ejdb2_EJDB2__1dispose(JNIEnv * env,jobject thisObj)295 JNIEXPORT void JNICALL Java_com_softmotions_ejdb2_EJDB2__1dispose(JNIEnv *env, jobject thisObj) {
296   jlong ptr = (*env)->GetLongField(env, thisObj, k_EJDB2_handle_fid);
297   if (ptr) {
298     (*env)->SetLongField(env, thisObj, k_EJDB2_handle_fid, 0);
299     EJDB db = (void*) ptr;
300     iwrc rc = ejdb_close(&db);
301     if (rc) {
302       jbn_throw_rc_exception(env, rc, 0);
303     }
304   }
305 }
306 
307 // PUT
Java_com_softmotions_ejdb2_EJDB2__1put(JNIEnv * env,jobject thisObj,jstring coll_,jstring json_,jlong id)308 JNIEXPORT jlong JNICALL Java_com_softmotions_ejdb2_EJDB2__1put(
309   JNIEnv *env,
310   jobject thisObj,
311   jstring coll_,
312   jstring json_,
313   jlong   id) {
314   iwrc rc;
315   EJDB db;
316   JBL jbl = 0;
317   jlong ret = id;
318 
319   const char *coll = (*env)->GetStringUTFChars(env, coll_, 0);
320   const char *json = (*env)->GetStringUTFChars(env, json_, 0);
321   if (!coll || !json) {
322     rc = IW_ERROR_INVALID_ARGS;
323     goto finish;
324   }
325 
326   rc = jbn_db(env, thisObj, &db);
327   RCGO(rc, finish);
328 
329   rc = jbl_from_json(&jbl, json);
330   RCGO(rc, finish);
331 
332   if (id > 0) {
333     rc = ejdb_put(db, coll, jbl, id);
334   } else {
335     rc = ejdb_put_new(db, coll, jbl, &ret);
336   }
337 
338 finish:
339   if (jbl) {
340     jbl_destroy(&jbl);
341   }
342   if (coll) {
343     (*env)->ReleaseStringUTFChars(env, coll_, coll);
344   }
345   if (json) {
346     (*env)->ReleaseStringUTFChars(env, json_, json);
347   }
348   if (rc) {
349     jbn_throw_rc_exception(env, rc, 0);
350   }
351   return ret;
352 }
353 
Java_com_softmotions_ejdb2_EJDB2__1online_1backup(JNIEnv * env,jobject thisObj,jstring target_)354 JNIEXPORT jlong JNICALL Java_com_softmotions_ejdb2_EJDB2__1online_1backup(
355   JNIEnv *env, jobject thisObj,
356   jstring target_) {
357   EJDB db;
358   uint64_t ts = 0;
359   const char *target = (*env)->GetStringUTFChars(env, target_, 0);
360 
361   iwrc rc = jbn_db(env, thisObj, &db);
362   RCGO(rc, finish);
363 
364   rc = ejdb_online_backup(db, &ts, target);
365 
366 finish:
367   if (target) {
368     (*env)->ReleaseStringUTFChars(env, target_, target);
369   }
370   if (rc) {
371     jbn_throw_rc_exception(env, rc, 0);
372   }
373   return ts;
374 }
375 
376 // GET
Java_com_softmotions_ejdb2_EJDB2__1get(JNIEnv * env,jobject thisObj,jstring coll_,jlong id,jobject osObj,jboolean pretty)377 JNIEXPORT void JNICALL Java_com_softmotions_ejdb2_EJDB2__1get(
378   JNIEnv  *env,
379   jobject  thisObj,
380   jstring  coll_,
381   jlong    id,
382   jobject  osObj,
383   jboolean pretty) {
384   iwrc rc;
385   EJDB db;
386   JBL jbl = 0;
387   JBN_JSPRINT_CTX pctx;
388 
389   const char *coll = (*env)->GetStringUTFChars(env, coll_, 0);
390   if (!coll) {
391     rc = IW_ERROR_INVALID_ARGS;
392     goto finish;
393   }
394 
395   rc = jbn_db(env, thisObj, &db);
396   RCGO(rc, finish);
397 
398   rc = jbn_init_pctx(env, &pctx, thisObj, osObj);
399   RCGO(rc, finish);
400 
401   rc = ejdb_get(db, coll, (int64_t) id, &jbl);
402   RCGO(rc, finish);
403 
404   rc = jbl_as_json(jbl, jbn_json_printer, &pctx, 0);
405   RCGO(rc, finish);
406 
407   rc = pctx.flushFn(&pctx);
408 
409 finish:
410   if (coll) {
411     (*env)->ReleaseStringUTFChars(env, coll_, coll);
412   }
413   if (jbl) {
414     jbl_destroy(&jbl);
415   }
416   jbn_destroy_pctx(&pctx);
417   if (rc) {
418     jbn_throw_rc_exception(env, rc, 0);
419   }
420 }
421 
422 // INFO
Java_com_softmotions_ejdb2_EJDB2__1info(JNIEnv * env,jobject thisObj,jobject osObj)423 JNIEXPORT void JNICALL Java_com_softmotions_ejdb2_EJDB2__1info(
424   JNIEnv *env,
425   jobject thisObj,
426   jobject osObj) {
427   iwrc rc;
428   EJDB db;
429   JBL jbl = 0;
430   JBN_JSPRINT_CTX pctx;
431 
432   rc = jbn_db(env, thisObj, &db);
433   RCGO(rc, finish);
434 
435   rc = jbn_init_pctx(env, &pctx, thisObj, osObj);
436   RCGO(rc, finish);
437 
438   rc = ejdb_get_meta(db, &jbl);
439   RCGO(rc, finish);
440 
441   rc = jbl_as_json(jbl, jbn_json_printer, &pctx, 0);
442   RCGO(rc, finish);
443 
444   rc = pctx.flushFn(&pctx);
445 
446 finish:
447   if (jbl) {
448     jbl_destroy(&jbl);
449   }
450   jbn_destroy_pctx(&pctx);
451   if (rc) {
452     jbn_throw_rc_exception(env, rc, 0);
453   }
454 }
455 
456 // DEL
Java_com_softmotions_ejdb2_EJDB2__1del(JNIEnv * env,jobject thisObj,jstring coll_,jlong id)457 JNIEXPORT void JNICALL Java_com_softmotions_ejdb2_EJDB2__1del(
458   JNIEnv *env,
459   jobject thisObj,
460   jstring coll_,
461   jlong   id) {
462   iwrc rc;
463   EJDB db;
464   const char *coll = (*env)->GetStringUTFChars(env, coll_, 0);
465   if (!coll) {
466     rc = IW_ERROR_INVALID_ARGS;
467     goto finish;
468   }
469   rc = jbn_db(env, thisObj, &db);
470   RCGO(rc, finish);
471 
472   rc = ejdb_del(db, coll, (int64_t) id);
473 
474 finish:
475   if (coll) {
476     (*env)->ReleaseStringUTFChars(env, coll_, coll);
477   }
478   if (rc) {
479     jbn_throw_rc_exception(env, rc, 0);
480   }
481 }
482 
483 // RENAME COLLECTION
Java_com_softmotions_ejdb2_EJDB2__1rename_1collection(JNIEnv * env,jobject thisObj,jstring oldColl_,jstring newColl_)484 JNIEXPORT void JNICALL Java_com_softmotions_ejdb2_EJDB2__1rename_1collection(
485   JNIEnv *env, jobject thisObj,
486   jstring oldColl_, jstring newColl_) {
487   iwrc rc;
488   EJDB db;
489   const char *newColl = 0;
490   const char *oldColl = (*env)->GetStringUTFChars(env, oldColl_, 0);
491   if (!oldColl) {
492     rc = IW_ERROR_INVALID_ARGS;
493     goto finish;
494   }
495   newColl = (*env)->GetStringUTFChars(env, newColl_, 0);
496   if (!newColl) {
497     rc = IW_ERROR_INVALID_ARGS;
498     goto finish;
499   }
500   rc = jbn_db(env, thisObj, &db);
501   RCGO(rc, finish);
502 
503   rc = ejdb_rename_collection(db, oldColl, newColl);
504 
505 finish:
506   if (oldColl) {
507     (*env)->ReleaseStringUTFChars(env, oldColl_, oldColl);
508   }
509   if (newColl) {
510     (*env)->ReleaseStringUTFChars(env, newColl_, newColl);
511   }
512   if (rc) {
513     jbn_throw_rc_exception(env, rc, 0);
514   }
515 }
516 
517 // PATCH
Java_com_softmotions_ejdb2_EJDB2__1patch(JNIEnv * env,jobject thisObj,jstring coll_,jstring patch_,jlong id,jboolean upsert)518 JNIEXPORT void JNICALL Java_com_softmotions_ejdb2_EJDB2__1patch(
519   JNIEnv  *env,
520   jobject  thisObj,
521   jstring  coll_,
522   jstring  patch_,
523   jlong    id,
524   jboolean upsert) {
525   iwrc rc;
526   EJDB db;
527   const char *coll = (*env)->GetStringUTFChars(env, coll_, 0);
528   const char *patch = (*env)->GetStringUTFChars(env, patch_, 0);
529   if (!coll || !patch) {
530     rc = IW_ERROR_INVALID_ARGS;
531     goto finish;
532   }
533   rc = jbn_db(env, thisObj, &db);
534   RCGO(rc, finish);
535 
536   if (upsert) {
537     rc = ejdb_merge_or_put(db, coll, patch, (int64_t) id);
538   } else {
539     rc = ejdb_patch(db, coll, patch, (int64_t) id);
540   }
541 
542 finish:
543   if (coll) {
544     (*env)->ReleaseStringUTFChars(env, coll_, coll);
545   }
546   if (patch_) {
547     (*env)->ReleaseStringUTFChars(env, patch_, patch);
548   }
549   if (rc) {
550     jbn_throw_rc_exception(env, rc, 0);
551   }
552 }
553 
Java_com_softmotions_ejdb2_EJDB2__1remove_1collection(JNIEnv * env,jobject thisObj,jstring coll_)554 JNIEXPORT void JNICALL Java_com_softmotions_ejdb2_EJDB2__1remove_1collection(
555   JNIEnv *env,
556   jobject thisObj,
557   jstring coll_) {
558   iwrc rc;
559   EJDB db;
560   const char *coll = (*env)->GetStringUTFChars(env, coll_, 0);
561   if (!coll) {
562     rc = IW_ERROR_INVALID_ARGS;
563     goto finish;
564   }
565   rc = jbn_db(env, thisObj, &db);
566   RCGO(rc, finish);
567 
568   rc = ejdb_remove_collection(db, coll);
569 
570 finish:
571   if (coll) {
572     (*env)->ReleaseStringUTFChars(env, coll_, coll);
573   }
574   if (rc) {
575     jbn_throw_rc_exception(env, rc, 0);
576   }
577 }
578 
Java_com_softmotions_ejdb2_EJDB2__1ensure_1index(JNIEnv * env,jobject thisObj,jstring coll_,jstring path_,jint mode)579 JNIEXPORT void JNICALL Java_com_softmotions_ejdb2_EJDB2__1ensure_1index(
580   JNIEnv *env,
581   jobject thisObj,
582   jstring coll_,
583   jstring path_,
584   jint    mode) {
585 
586   iwrc rc;
587   EJDB db;
588   const char *coll = (*env)->GetStringUTFChars(env, coll_, 0);
589   const char *path = (*env)->GetStringUTFChars(env, path_, 0);
590   if (!coll || !path) {
591     rc = IW_ERROR_INVALID_ARGS;
592     goto finish;
593   }
594   rc = jbn_db(env, thisObj, &db);
595   RCGO(rc, finish);
596 
597   rc = ejdb_ensure_index(db, coll, path, (ejdb_idx_mode_t) mode);
598 
599 finish:
600   if (coll) {
601     (*env)->ReleaseStringUTFChars(env, coll_, coll);
602   }
603   if (path) {
604     (*env)->ReleaseStringUTFChars(env, path_, path);
605   }
606   if (rc) {
607     jbn_throw_rc_exception(env, rc, 0);
608   }
609 }
610 
Java_com_softmotions_ejdb2_EJDB2__1remove_1index(JNIEnv * env,jobject thisObj,jstring coll_,jstring path_,jint mode)611 JNIEXPORT void JNICALL Java_com_softmotions_ejdb2_EJDB2__1remove_1index(
612   JNIEnv *env,
613   jobject thisObj,
614   jstring coll_,
615   jstring path_,
616   jint    mode) {
617   iwrc rc;
618   EJDB db;
619   const char *coll = (*env)->GetStringUTFChars(env, coll_, 0);
620   const char *path = (*env)->GetStringUTFChars(env, path_, 0);
621   if (!coll || !path) {
622     rc = IW_ERROR_INVALID_ARGS;
623     goto finish;
624   }
625   rc = jbn_db(env, thisObj, &db);
626   RCGO(rc, finish);
627 
628   rc = ejdb_remove_index(db, coll, path, (ejdb_idx_mode_t) mode);
629 
630 finish:
631   if (coll) {
632     (*env)->ReleaseStringUTFChars(env, coll_, coll);
633   }
634   if (path) {
635     (*env)->ReleaseStringUTFChars(env, path_, path);
636   }
637   if (rc) {
638     jbn_throw_rc_exception(env, rc, 0);
639   }
640 }
641 
642 // JQL INIT
Java_com_softmotions_ejdb2_JQL__1init(JNIEnv * env,jobject thisObj,jobject dbObj,jstring queryStr,jstring collStr)643 JNIEXPORT void JNICALL Java_com_softmotions_ejdb2_JQL__1init(
644   JNIEnv *env,
645   jobject thisObj,
646   jobject dbObj,
647   jstring queryStr,
648   jstring collStr) {
649   EJDB db;
650   iwrc rc;
651   JQL q = 0;
652   const char *query = 0, *coll = 0;
653 
654   if (!dbObj || !queryStr) {
655     rc = IW_ERROR_INVALID_ARGS;
656     goto finish;
657   }
658 
659   rc = jbn_db(env, dbObj, &db);
660   RCGO(rc, finish);
661 
662   query = (*env)->GetStringUTFChars(env, queryStr, 0);
663   if (!query) {
664     rc = IW_ERROR_INVALID_ARGS;
665     goto finish;
666   }
667 
668   if (collStr) {
669     coll = (*env)->GetStringUTFChars(env, collStr, 0);
670   }
671   rc = jql_create2(&q, coll, query, JQL_KEEP_QUERY_ON_PARSE_ERROR | JQL_SILENT_ON_PARSE_ERROR);
672   RCGO(rc, finish);
673 
674   (*env)->SetLongField(env, thisObj, k_JQL_handle_fid, (jlong) q);
675   if (!coll) {
676     collStr = (*env)->NewStringUTF(env, jql_collection(q));
677     (*env)->SetObjectField(env, thisObj, k_JQL_collection_fid, collStr);
678   }
679 
680 finish:
681   if (query) {
682     (*env)->ReleaseStringUTFChars(env, queryStr, query);
683   }
684   if (coll) {
685     (*env)->ReleaseStringUTFChars(env, collStr, coll);
686   }
687   if (rc) {
688     if (q && (rc == JQL_ERROR_QUERY_PARSE)) {
689       jbn_throw_rc_exception(env, rc, jql_error(q));
690     } else {
691       jbn_throw_rc_exception(env, rc, 0);
692     }
693     if (q) {
694       jql_destroy(&q);
695     }
696   }
697 }
698 
699 // JQL RESET
Java_com_softmotions_ejdb2_JQL__1reset(JNIEnv * env,jobject thisObj)700 JNIEXPORT void JNICALL Java_com_softmotions_ejdb2_JQL__1reset(JNIEnv *env, jobject thisObj) {
701   jlong ptr = (*env)->GetLongField(env, thisObj, k_JQL_handle_fid);
702   if (ptr) {
703     JQL q = (void*) ptr;
704     jql_reset(q, true, true);
705   }
706 }
707 
708 // JQL DESTROY
Java_com_softmotions_ejdb2_JQL__1destroy(JNIEnv * env,jclass clazz,jlong handle)709 JNIEXPORT void JNICALL Java_com_softmotions_ejdb2_JQL__1destroy(JNIEnv *env, jclass clazz, jlong handle) {
710   if (handle) {
711     JQL q = (void*) handle;
712     jql_destroy(&q);
713   }
714 }
715 
716 typedef struct JBN_EXEC_CTX {
717   JNIEnv   *env;
718   jobject   cbObj;
719   jclass    cbClazz;
720   jmethodID cbMid;
721 } JBN_EXEC_CTX;
722 
jbn_exec_visitor(struct _EJDB_EXEC * ux,EJDB_DOC doc,int64_t * step)723 static iwrc jbn_exec_visitor(struct _EJDB_EXEC *ux, EJDB_DOC doc, int64_t *step) {
724   iwrc rc = 0;
725   jstring json = 0;
726   JBN_EXEC_CTX *ectx = ux->opaque;
727   JNIEnv *env = ectx->env;
728   IWXSTR *xstr = iwxstr_new2(jbl_size(doc->raw) * 2);
729   if (!xstr) {
730     return iwrc_set_errno(IW_ERROR_ALLOC, errno);
731   }
732   if (doc->node) {
733     rc = jbn_as_json(doc->node, jbl_xstr_json_printer, xstr, 0);
734   } else {
735     rc = jbl_as_json(doc->raw, jbl_xstr_json_printer, xstr, 0);
736   }
737   RCGO(rc, finish);
738 
739   json = (*env)->NewStringUTF(env, iwxstr_ptr(xstr));
740   if (!json) {
741     if (!(*env)->ExceptionOccurred(env)) {
742       rc = JBN_ERROR_CREATION_OBJ;
743     }
744     goto finish;
745   }
746   int64_t llv = (*env)->CallLongMethod(env, ectx->cbObj, ectx->cbMid, (jlong) doc->id, json);
747   if (llv < -2) {
748     *step = 0;
749   } else {
750     *step = llv;
751   }
752 
753 finish:
754   if (json) {
755     (*env)->DeleteLocalRef(env, json);
756   }
757   iwxstr_destroy(xstr);
758   return rc;
759 }
760 
761 // JQL EXECUTE
Java_com_softmotions_ejdb2_JQL__1execute(JNIEnv * env,jobject thisObj,jobject dbObj,jobject cbObj,jobject logStreamObj)762 JNIEXPORT void JNICALL Java_com_softmotions_ejdb2_JQL__1execute(
763   JNIEnv *env,
764   jobject thisObj,
765   jobject dbObj,
766   jobject cbObj,
767   jobject logStreamObj) {
768   iwrc rc;
769   EJDB db;
770   JQL q;
771   IWXSTR *log = 0;
772 
773   if (!dbObj) {
774     jbn_throw_rc_exception(env, IW_ERROR_INVALID_ARGS, 0);
775     return;
776   }
777 
778   rc = jbn_jql_q(env, thisObj, &q);
779   RCGO(rc, finish);
780 
781   rc = jbn_db(env, dbObj, &db);
782   RCGO(rc, finish);
783 
784   JBN_EXEC_CTX ectx = {
785     .env   = env,
786     .cbObj = cbObj
787   };
788 
789   if (cbObj) {
790     ectx.cbClazz = (*env)->GetObjectClass(env, cbObj);
791     ectx.cbMid = (*env)->GetMethodID(env, ectx.cbClazz, "onRecord", "(JLjava/lang/String;)J");
792     if (!ectx.cbMid) {
793       goto finish;
794     }
795   }
796 
797   jlong skip = (*env)->GetLongField(env, thisObj, k_JQL_skip_fid);
798   jlong limit = (*env)->GetLongField(env, thisObj, k_JQL_limit_fid);
799   if (logStreamObj) {
800     log = iwxstr_new();
801     if (!log) {
802       rc = iwrc_set_errno(IW_ERROR_ALLOC, errno);
803       goto finish;
804     }
805   }
806 
807   EJDB_EXEC ux = {
808     .db      = db,
809     .q       = q,
810     .skip    = skip > 0 ? skip : 0,
811     .limit   = limit > 0 ? limit : 0,
812     .opaque  = &ectx,
813     .visitor = cbObj ? jbn_exec_visitor : 0,
814     .log     = log
815   };
816 
817   rc = ejdb_exec(&ux);
818   RCGO(rc, finish);
819 
820   if (log) { // Send query execution log
821     size_t xsz = iwxstr_size(log);
822     jclass logStreamClazz = (*env)->GetObjectClass(env, logStreamObj);
823     jmethodID writeMid = (*env)->GetMethodID(env, logStreamClazz, "write", "([B)V");
824     if (!writeMid) {
825       goto finish;
826     }
827     jbyteArray arr = (*env)->NewByteArray(env, xsz);
828     if (!arr) {
829       goto finish;
830     }
831     (*env)->SetByteArrayRegion(env, arr, 0, xsz, (void*) iwxstr_ptr(log));
832     (*env)->CallVoidMethod(env, logStreamObj, writeMid, arr);
833   }
834 
835 finish:
836   if (log) {
837     iwxstr_destroy(log);
838   }
839   if (rc) {
840     jbn_throw_rc_exception(env, rc, 0);
841   }
842 }
843 
844 // JQL EXECUTE SCALAR LONG
Java_com_softmotions_ejdb2_JQL__1execute_1scalar_1long(JNIEnv * env,jobject thisObj,jobject dbObj,jobject logStreamObj)845 JNIEXPORT jlong JNICALL Java_com_softmotions_ejdb2_JQL__1execute_1scalar_1long(
846   JNIEnv *env,
847   jobject thisObj,
848   jobject dbObj,
849   jobject logStreamObj) {
850   iwrc rc;
851   EJDB db;
852   JQL q;
853   IWXSTR *log = 0;
854   jlong ret = 0;
855 
856   if (!dbObj) {
857     jbn_throw_rc_exception(env, IW_ERROR_INVALID_ARGS, 0);
858     return 0;
859   }
860 
861   rc = jbn_jql_q(env, thisObj, &q);
862   RCGO(rc, finish);
863 
864   rc = jbn_db(env, dbObj, &db);
865   RCGO(rc, finish);
866 
867   jlong skip = (*env)->GetLongField(env, thisObj, k_JQL_skip_fid);
868   jlong limit = (*env)->GetLongField(env, thisObj, k_JQL_limit_fid);
869   if (logStreamObj) {
870     log = iwxstr_new();
871     if (!log) {
872       rc = iwrc_set_errno(IW_ERROR_ALLOC, errno);
873       goto finish;
874     }
875   }
876 
877   EJDB_EXEC ux = {
878     .db    = db,
879     .q     = q,
880     .skip  = skip > 0 ? skip : 0,
881     .limit = limit > 0 ? limit : 0,
882     .log   = log
883   };
884 
885   rc = ejdb_exec(&ux);
886   RCGO(rc, finish);
887 
888   if (log) { // Send query execution log
889     size_t xsz = iwxstr_size(log);
890     jclass logStreamClazz = (*env)->GetObjectClass(env, logStreamObj);
891     jmethodID writeMid = (*env)->GetMethodID(env, logStreamClazz, "write", "([B)V");
892     if (!writeMid) {
893       goto finish;
894     }
895     jbyteArray arr = (*env)->NewByteArray(env, xsz);
896     if (!arr) {
897       goto finish;
898     }
899     (*env)->SetByteArrayRegion(env, arr, 0, xsz, (void*) iwxstr_ptr(log));
900     (*env)->CallVoidMethod(env, logStreamObj, writeMid, arr);
901   }
902 
903   ret = ux.cnt;
904 
905 finish:
906   if (log) {
907     iwxstr_destroy(log);
908   }
909   if (rc) {
910     jbn_throw_rc_exception(env, rc, 0);
911   }
912   return ret;
913 }
914 
jbn_free_json_node(void * ptr,void * op)915 static void jbn_free_json_node(void *ptr, void *op) {
916   IWPOOL *pool = op;
917   if (pool) {
918     iwpool_destroy(pool);
919   }
920 }
921 
jbn_free_str(void * ptr,void * op)922 static void jbn_free_str(void *ptr, void *op) {
923   free(ptr);
924 }
925 
Java_com_softmotions_ejdb2_JQL__1set_1string(JNIEnv * env,jobject thisObj,jint pos,jstring placeholder_,jstring val_,jint type)926 JNIEXPORT void JNICALL Java_com_softmotions_ejdb2_JQL__1set_1string(
927   JNIEnv *env,
928   jobject thisObj,
929   jint    pos,
930   jstring placeholder_,
931   jstring val_,
932   jint    type) {
933   JQL q;
934   iwrc rc;
935   const char *placeholder = 0, *val;
936 
937   if (!val_) {
938     jbn_throw_rc_exception(env, IW_ERROR_INVALID_ARGS, 0);
939     return;
940   }
941   val = (*env)->GetStringUTFChars(env, val_, 0);
942 
943   rc = jbn_jql_q(env, thisObj, &q);
944   RCGO(rc, finish);
945 
946   if (placeholder_) {
947     placeholder = (*env)->GetStringUTFChars(env, placeholder_, 0);
948   }
949   if (type == 1) {  // JSON
950     JBL_NODE node;
951     IWPOOL *pool = iwpool_create(1024);
952     if (!pool) {
953       rc = iwrc_set_errno(IW_ERROR_ALLOC, errno);
954       goto finish;
955     }
956     rc = jbn_from_json(val, &node, pool);
957     if (rc) {
958       iwpool_destroy(pool);
959       goto finish;
960     }
961     rc = jql_set_json2(q, placeholder, pos, node, jbn_free_json_node, pool);
962     if (rc) {
963       iwpool_destroy(pool);
964       goto finish;
965     }
966   } else if (type == 2) { // Regexp
967     char *str = strdup(val);
968     if (!str) {
969       rc = iwrc_set_errno(IW_ERROR_ALLOC, errno);
970       goto finish;
971     }
972     rc = jql_set_regexp2(q, placeholder, pos, str, jbn_free_str, 0);
973     if (rc) {
974       free(str);
975       goto finish;
976     }
977   } else { // All other cases
978     char *str = strdup(val);
979     if (!str) {
980       rc = iwrc_set_errno(IW_ERROR_ALLOC, errno);
981       goto finish;
982     }
983     rc = jql_set_str2(q, placeholder, pos, str, jbn_free_str, 0);
984     if (rc) {
985       free(str);
986       goto finish;
987     }
988   }
989 
990 finish:
991   if (val) {
992     (*env)->ReleaseStringUTFChars(env, val_, val);
993   }
994   if (placeholder) {
995     (*env)->ReleaseStringUTFChars(env, placeholder_, placeholder);
996   }
997   if (rc) {
998     jbn_throw_rc_exception(env, rc, 0);
999   }
1000 }
1001 
Java_com_softmotions_ejdb2_JQL__1set_1long(JNIEnv * env,jobject thisObj,jint pos,jstring placeholder_,jlong val)1002 JNIEXPORT void JNICALL Java_com_softmotions_ejdb2_JQL__1set_1long(
1003   JNIEnv *env,
1004   jobject thisObj,
1005   jint    pos,
1006   jstring placeholder_,
1007   jlong   val) {
1008 
1009   JQL q;
1010   iwrc rc;
1011   const char *placeholder = 0;
1012 
1013   rc = jbn_jql_q(env, thisObj, &q);
1014   RCGO(rc, finish);
1015 
1016   if (placeholder_) {
1017     placeholder = (*env)->GetStringUTFChars(env, placeholder_, 0);
1018   }
1019 
1020   rc = jql_set_i64(q, placeholder, pos, val);
1021 
1022 finish:
1023   if (placeholder) {
1024     (*env)->ReleaseStringUTFChars(env, placeholder_, placeholder);
1025   }
1026   if (rc) {
1027     jbn_throw_rc_exception(env, rc, 0);
1028   }
1029 }
1030 
Java_com_softmotions_ejdb2_JQL__1set_1double(JNIEnv * env,jobject thisObj,jint pos,jstring placeholder_,jdouble val)1031 JNIEXPORT void JNICALL Java_com_softmotions_ejdb2_JQL__1set_1double(
1032   JNIEnv *env,
1033   jobject thisObj,
1034   jint    pos,
1035   jstring placeholder_,
1036   jdouble val) {
1037   JQL q;
1038   iwrc rc;
1039   const char *placeholder = 0;
1040 
1041   rc = jbn_jql_q(env, thisObj, &q);
1042   RCGO(rc, finish);
1043 
1044   if (placeholder_) {
1045     placeholder = (*env)->GetStringUTFChars(env, placeholder_, 0);
1046   }
1047 
1048   rc = jql_set_f64(q, placeholder, pos, val);
1049 
1050 finish:
1051   if (placeholder) {
1052     (*env)->ReleaseStringUTFChars(env, placeholder_, placeholder);
1053   }
1054   if (rc) {
1055     jbn_throw_rc_exception(env, rc, 0);
1056   }
1057 }
1058 
Java_com_softmotions_ejdb2_JQL__1set_1boolean(JNIEnv * env,jobject thisObj,jint pos,jstring placeholder_,jboolean val)1059 JNIEXPORT void JNICALL Java_com_softmotions_ejdb2_JQL__1set_1boolean(
1060   JNIEnv  *env,
1061   jobject  thisObj,
1062   jint     pos,
1063   jstring  placeholder_,
1064   jboolean val) {
1065   JQL q;
1066   iwrc rc;
1067   const char *placeholder = 0;
1068 
1069   rc = jbn_jql_q(env, thisObj, &q);
1070   RCGO(rc, finish);
1071 
1072   if (placeholder_) {
1073     placeholder = (*env)->GetStringUTFChars(env, placeholder_, 0);
1074   }
1075 
1076   rc = jql_set_bool(q, placeholder, pos, val);
1077 
1078 finish:
1079   if (placeholder) {
1080     (*env)->ReleaseStringUTFChars(env, placeholder_, placeholder);
1081   }
1082   if (rc) {
1083     jbn_throw_rc_exception(env, rc, 0);
1084   }
1085 }
1086 
Java_com_softmotions_ejdb2_JQL__1set_1null(JNIEnv * env,jobject thisObj,jint pos,jstring placeholder_)1087 JNIEXPORT void JNICALL Java_com_softmotions_ejdb2_JQL__1set_1null(
1088   JNIEnv *env,
1089   jobject thisObj,
1090   jint    pos,
1091   jstring placeholder_) {
1092   JQL q;
1093   iwrc rc;
1094   const char *placeholder = 0;
1095 
1096   rc = jbn_jql_q(env, thisObj, &q);
1097   RCGO(rc, finish);
1098 
1099   if (placeholder_) {
1100     placeholder = (*env)->GetStringUTFChars(env, placeholder_, 0);
1101   }
1102 
1103   rc = jql_set_null(q, placeholder, pos);
1104 
1105 finish:
1106   if (placeholder) {
1107     (*env)->ReleaseStringUTFChars(env, placeholder_, placeholder);
1108   }
1109   if (rc) {
1110     jbn_throw_rc_exception(env, rc, 0);
1111   }
1112 }
1113 
Java_com_softmotions_ejdb2_JQL__1get_1limit(JNIEnv * env,jobject thisObj)1114 JNIEXPORT jlong JNICALL Java_com_softmotions_ejdb2_JQL__1get_1limit(JNIEnv *env, jobject thisObj) {
1115   JQL q;
1116   int64_t limit = 0;
1117   iwrc rc = jbn_jql_q(env, thisObj, &q);
1118   RCGO(rc, finish);
1119   rc = jql_get_limit(q, &limit);
1120 
1121 finish:
1122   if (rc) {
1123     jbn_throw_rc_exception(env, rc, 0);
1124   }
1125   return (jlong) limit;
1126 }
1127 
Java_com_softmotions_ejdb2_JQL__1get_1skip(JNIEnv * env,jobject thisObj)1128 JNIEXPORT jlong JNICALL Java_com_softmotions_ejdb2_JQL__1get_1skip(JNIEnv *env, jobject thisObj) {
1129   JQL q;
1130   int64_t skip = 0;
1131   iwrc rc = jbn_jql_q(env, thisObj, &q);
1132   RCGO(rc, finish);
1133   rc = jql_get_skip(q, &skip);
1134 
1135 finish:
1136   if (rc) {
1137     jbn_throw_rc_exception(env, rc, 0);
1138   }
1139   return (jlong) skip;
1140 }
1141 
jbn_ecodefn(locale_t locale,uint32_t ecode)1142 static const char *jbn_ecodefn(locale_t locale, uint32_t ecode) {
1143   if (!((ecode > _JBN_ERROR_START) && (ecode < _JBN_ERROR_END))) {
1144     return 0;
1145   }
1146   switch (ecode) {
1147     case JBN_ERROR_INVALID_FIELD:
1148       return "Failed to get class field (JBN_ERROR_INVALID_FIELD)";
1149     case JBN_ERROR_INVALID_METHOD:
1150       return "Failed to get class method (JBN_ERROR_INVALID_METHOD)";
1151     case JBN_ERROR_INVALID_OPTIONS:
1152       return "Invalid com.softmotions.ejdb2.EJDB2Builder configuration provided (JBN_ERROR_INVALID_OPTIONS)";
1153     case JBN_ERROR_INVALID_STATE:
1154       return "Invalid com.softmotions.ejdb2.EJDB2 JNI state. Database closed? (JBN_ERROR_INVALID_STATE)";
1155     case JBN_ERROR_CREATION_OBJ:
1156       return "Failed to create/allocate JNI object (JBN_ERROR_CREATION_OBJ)";
1157   }
1158   return 0;
1159 }
1160 
JNI_OnLoad(JavaVM * vm,void * reserved)1161 JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
1162   JNIEnv *env;
1163   if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_6) != JNI_OK) {
1164     return -1;
1165   }
1166   static volatile int jbn_ecodefn_initialized = 0;
1167   if (__sync_bool_compare_and_swap(&jbn_ecodefn_initialized, 0, 1)) {
1168     iwrc rc = ejdb_init();
1169     if (rc) {
1170       iwlog_ecode_error3(rc);
1171       return JNI_ERR;
1172     }
1173     iwlog_register_ecodefn(jbn_ecodefn);
1174   }
1175 
1176   jclass clazz = (*env)->FindClass(env, "com/softmotions/ejdb2/EJDB2");
1177   if (!clazz) {
1178     iwlog_error2("Cannot find com.softmotions.ejdb2.EJDB2 class");
1179     return -1;
1180   }
1181   k_EJDB2_clazz = (*env)->NewGlobalRef(env, clazz);
1182   k_EJDB2_handle_fid = (*env)->GetFieldID(env, k_EJDB2_clazz, "_handle", "J");
1183 
1184 
1185   clazz = (*env)->FindClass(env, "com/softmotions/ejdb2/EJDB2Exception");
1186   if (!clazz) {
1187     iwlog_error2("Cannot find com.softmotions.ejdb2.EJDB2Exception class");
1188     return -1;
1189   }
1190   k_EJDB2Exception_clazz = (*env)->NewGlobalRef(env, clazz);
1191   k_EJDB2Exception_constructor = (*env)->GetMethodID(env, k_EJDB2Exception_clazz,
1192                                                      "<init>", "(JJLjava/lang/String;)V");
1193   if (!k_EJDB2Exception_constructor) {
1194     iwlog_error2("Cannot find com.softmotions.ejdb2.EJDB2Exception#<init>(long,String)");
1195     return -1;
1196   }
1197 
1198   clazz = (*env)->FindClass(env, "com/softmotions/ejdb2/JQL");
1199   if (!clazz) {
1200     iwlog_error2("Cannot find com.softmotions.ejdb2.JQL class");
1201     return -1;
1202   }
1203   k_JQL_clazz = (*env)->NewGlobalRef(env, clazz);
1204   k_JQL_handle_fid = (*env)->GetFieldID(env, k_JQL_clazz, "_handle", "J");
1205   k_JQL_db_fid = (*env)->GetFieldID(env, k_JQL_clazz, "db", "Lcom/softmotions/ejdb2/EJDB2;");
1206   k_JQL_query_fid = (*env)->GetFieldID(env, k_JQL_clazz, "query", "Ljava/lang/String;");
1207   k_JQL_collection_fid = (*env)->GetFieldID(env, k_JQL_clazz, "collection", "Ljava/lang/String;");
1208   k_JQL_skip_fid = (*env)->GetFieldID(env, k_JQL_clazz, "skip", "J");
1209   k_JQL_limit_fid = (*env)->GetFieldID(env, k_JQL_clazz, "limit", "J");
1210 
1211   return JNI_VERSION_1_6;
1212 }
1213 
JNI_OnUnload(JavaVM * vm,void * reserved)1214 JNIEXPORT void JNI_OnUnload(JavaVM *vm, void *reserved) { // Not really useless
1215   JNIEnv *env;
1216   if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_6) != JNI_OK) {
1217     return;
1218   }
1219   if (k_EJDB2_clazz) {
1220     (*env)->DeleteGlobalRef(env, k_EJDB2_clazz);
1221   }
1222   if (k_JQL_clazz) {
1223     (*env)->DeleteGlobalRef(env, k_JQL_clazz);
1224   }
1225   if (k_EJDB2Exception_clazz) {
1226     (*env)->DeleteGlobalRef(env, k_EJDB2Exception_clazz);
1227   }
1228 }
1229