1 /*
2  * fdbJNI.cpp
3  *
4  * This source file is part of the FoundationDB open source project
5  *
6  * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *     http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20 
21 #include <jni.h>
22 #include <string.h>
23 
24 #define FDB_API_VERSION 610
25 
26 #include <foundationdb/fdb_c.h>
27 
28 #define JNI_NULL nullptr
29 
30 #if defined(__GNUG__)
31 #define thread_local __thread
32 // TODO: figure out why the default definition suppresses visibility
33 #undef JNIEXPORT
34 #define JNIEXPORT __attribute__ ((visibility ("default")))
35 #elif defined(_MSC_VER)
36 #define thread_local __declspec(thread)
37 #else
38 #error Missing thread local storage
39 #endif
40 
41 static JavaVM* g_jvm = nullptr;
42 static thread_local JNIEnv* g_thread_jenv = nullptr;  // Defined for the network thread once it is running, and for any thread that has called registerCallback
43 static thread_local jmethodID g_IFutureCallback_call_methodID = JNI_NULL;
44 static thread_local bool is_external = false;
45 
detachIfExternalThread(void * ignore)46 void detachIfExternalThread(void *ignore) {
47 	if(is_external && g_thread_jenv != nullptr) {
48 		g_thread_jenv = nullptr;
49 		g_IFutureCallback_call_methodID = JNI_NULL;
50 		g_jvm->DetachCurrentThread();
51 	}
52 }
53 
throwOutOfMem(JNIEnv * jenv)54 void throwOutOfMem(JNIEnv *jenv) {
55 	const char *className = "java/lang/OutOfMemoryError";
56 	jclass illegalArgClass = jenv->FindClass( className );
57 
58 	if(jenv->ExceptionOccurred())
59 		return;
60 
61 	if( jenv->ThrowNew( illegalArgClass, nullptr ) != 0 ) {
62 		if( !jenv->ExceptionOccurred() ) {
63 			jenv->FatalError("Could not throw OutOfMemoryError");
64 		} else {
65 			// This means that an exception is pending. We do not know what it is, but are sure
66 			//  that control flow will include throwing that exception into the calling Java code.
67 		}
68 	}
69 }
70 
getThrowable(JNIEnv * jenv,fdb_error_t e,const char * msg=nullptr)71 static jthrowable getThrowable(JNIEnv *jenv, fdb_error_t e, const char* msg = nullptr) {
72 	jclass excepClass = jenv->FindClass("com/apple/foundationdb/FDBException");
73 	if(jenv->ExceptionOccurred())
74 		return JNI_NULL;
75 
76 	jmethodID excepCtor = jenv->GetMethodID(excepClass, "<init>", "(Ljava/lang/String;I)V");
77 	if(jenv->ExceptionOccurred())
78 		return JNI_NULL;
79 
80 	const char *fdb_message = msg ? msg : fdb_get_error(e);
81 	jstring m = jenv->NewStringUTF(fdb_message);
82 	if(jenv->ExceptionOccurred())
83 		return JNI_NULL;
84 
85 	jthrowable t = (jthrowable)jenv->NewObject(excepClass, excepCtor, m, e);
86 	if(jenv->ExceptionOccurred())
87 		return JNI_NULL;
88 
89 	return t;
90 }
91 
throwNamedException(JNIEnv * jenv,const char * class_full_name,const char * message)92 void throwNamedException(JNIEnv *jenv, const char *class_full_name, const char* message ) {
93 	jclass exceptionClass = jenv->FindClass( class_full_name );
94 	if(jenv->ExceptionOccurred())
95 		return;
96 
97 	if( jenv->ThrowNew( exceptionClass, message ) != 0 ) {
98 		if(jenv->ExceptionOccurred())
99 			return;
100 		jenv->FatalError("FDB: Error throwing exception");
101 	}
102 }
103 
throwRuntimeEx(JNIEnv * jenv,const char * message)104 void throwRuntimeEx(JNIEnv *jenv, const char* message) {
105 	throwNamedException( jenv, "java/lang/RuntimeException", message );
106 }
107 
throwParamNotNull(JNIEnv * jenv)108 void throwParamNotNull(JNIEnv *jenv) {
109 	throwNamedException( jenv, "java/lang/IllegalArgumentException", "Argument cannot be null" );
110 }
111 
112 #ifdef __cplusplus
113 extern "C" {
114 #endif
115 
116 // If the methods are not found, exceptions are thrown and this will return false.
117 //  Returns TRUE on success, false otherwise.
findCallbackMethods(JNIEnv * jenv)118 static bool findCallbackMethods(JNIEnv *jenv) {
119 	jclass cls = jenv->FindClass("java/lang/Runnable");
120 	if(jenv->ExceptionOccurred())
121 		return false;
122 
123 	g_IFutureCallback_call_methodID = jenv->GetMethodID(cls, "run", "()V");
124 	if(jenv->ExceptionOccurred())
125 		return false;
126 
127 	return true;
128 }
129 
callCallback(FDBFuture * f,void * data)130 static void callCallback( FDBFuture* f, void* data ) {
131 	if (g_thread_jenv == nullptr) {
132 		// We are on an external thread and must attach to the JVM.
133 		// The shutdown hook will later detach this thread.
134 		is_external = true;
135 		if( g_jvm != nullptr && g_jvm->AttachCurrentThreadAsDaemon((void **) &g_thread_jenv, nullptr) == JNI_OK ) {
136 			if( !findCallbackMethods( g_thread_jenv ) ) {
137 				g_thread_jenv->FatalError("FDB: Could not find callback method.\n");
138 			}
139 		} else {
140 			// Can't call FatalError, because we don't have a pointer to the jenv...
141 			// There will be a segmentation fault from the attempt to call the callback method.
142 			fprintf(stderr, "FDB: Could not attach external client thread to the JVM as daemon.\n");
143 		}
144 	}
145 
146 	jobject callback = (jobject)data;
147 	g_thread_jenv->CallVoidMethod( callback, g_IFutureCallback_call_methodID );
148 	g_thread_jenv->DeleteGlobalRef(callback);
149 }
150 
151 // Attempts to throw 't', attempts to shut down the JVM if this fails.
safeThrow(JNIEnv * jenv,jthrowable t)152 void safeThrow( JNIEnv *jenv, jthrowable t ) {
153 	if( jenv->Throw( t ) != 0 ) {
154 		jenv->FatalError("FDB: Unable to throw exception");
155 	}
156 }
157 
Java_com_apple_foundationdb_NativeFuture_Future_1registerCallback(JNIEnv * jenv,jobject cls,jlong future,jobject callback)158 JNIEXPORT void JNICALL Java_com_apple_foundationdb_NativeFuture_Future_1registerCallback(JNIEnv *jenv, jobject cls, jlong future, jobject callback) {
159 	// SOMEDAY: Do this on module load instead. Can we cache method ids across threads?
160 	if( !g_IFutureCallback_call_methodID ) {
161 		if( !findCallbackMethods( jenv ) ) {
162 			return;
163 		}
164 	}
165 
166 	if( !future || !callback ) {
167 		throwParamNotNull(jenv);
168 		return;
169 	}
170 	FDBFuture *f = (FDBFuture *)future;
171 
172 	// This is documented as not throwing, but simply returning null on OOM.
173 	//  As belt and suspenders, we will check for pending exceptions and then,
174 	//  if there are none and the result is null, we'll throw our own OOM.
175 	callback = jenv->NewGlobalRef( callback );
176 	if( !callback ) {
177 		if( !jenv->ExceptionOccurred() )
178 			throwOutOfMem(jenv);
179 		return;
180 	}
181 
182 	// Here we cache a thread-local reference to jenv
183 	g_thread_jenv = jenv;
184 	fdb_error_t err = fdb_future_set_callback( f, &callCallback, callback );
185 	if( err ) {
186 		jenv->DeleteGlobalRef( callback );
187 		safeThrow( jenv, getThrowable( jenv, err ) );
188 	}
189 }
190 
Java_com_apple_foundationdb_NativeFuture_Future_1blockUntilReady(JNIEnv * jenv,jobject,jlong future)191 JNIEXPORT void JNICALL Java_com_apple_foundationdb_NativeFuture_Future_1blockUntilReady(JNIEnv *jenv, jobject, jlong future) {
192 	if( !future ) {
193 		throwParamNotNull(jenv);
194 		return;
195 	}
196 	FDBFuture *sav = (FDBFuture *)future;
197 
198 	fdb_error_t err = fdb_future_block_until_ready( sav );
199 	if( err )
200 		safeThrow( jenv, getThrowable( jenv, err ) );
201 }
202 
Java_com_apple_foundationdb_NativeFuture_Future_1getError(JNIEnv * jenv,jobject,jlong future)203 JNIEXPORT jthrowable JNICALL Java_com_apple_foundationdb_NativeFuture_Future_1getError(JNIEnv *jenv, jobject, jlong future) {
204 	if( !future ) {
205 		throwParamNotNull(jenv);
206 		return JNI_NULL;
207 	}
208 	FDBFuture *sav = (FDBFuture *)future;
209 	fdb_error_t err = fdb_future_get_error( sav );
210 	if( err )
211 		return getThrowable( jenv, err );
212 	else
213 		return JNI_NULL;
214 }
215 
Java_com_apple_foundationdb_NativeFuture_Future_1isReady(JNIEnv * jenv,jobject,jlong future)216 JNIEXPORT jboolean JNICALL Java_com_apple_foundationdb_NativeFuture_Future_1isReady(JNIEnv *jenv, jobject, jlong future) {
217 	if( !future ) {
218 		throwParamNotNull(jenv);
219 		return JNI_FALSE;
220 	}
221 	FDBFuture *var = (FDBFuture *)future;
222 	return (jboolean)fdb_future_is_ready(var);
223 }
224 
Java_com_apple_foundationdb_NativeFuture_Future_1dispose(JNIEnv * jenv,jobject,jlong future)225 JNIEXPORT void JNICALL Java_com_apple_foundationdb_NativeFuture_Future_1dispose(JNIEnv *jenv, jobject, jlong future) {
226 	if( !future ) {
227 		throwParamNotNull(jenv);
228 		return;
229 	}
230 	FDBFuture *var = (FDBFuture *)future;
231 	fdb_future_destroy(var);
232 }
233 
Java_com_apple_foundationdb_NativeFuture_Future_1cancel(JNIEnv * jenv,jobject,jlong future)234 JNIEXPORT void JNICALL Java_com_apple_foundationdb_NativeFuture_Future_1cancel(JNIEnv *jenv, jobject, jlong future) {
235 	if( !future ) {
236 		throwParamNotNull(jenv);
237 		return;
238 	}
239 	FDBFuture *var = (FDBFuture *)future;
240 	fdb_future_cancel(var);
241 }
242 
Java_com_apple_foundationdb_NativeFuture_Future_1releaseMemory(JNIEnv * jenv,jobject,jlong future)243 JNIEXPORT void JNICALL Java_com_apple_foundationdb_NativeFuture_Future_1releaseMemory(JNIEnv *jenv, jobject, jlong future) {
244 	if( !future ) {
245 		throwParamNotNull(jenv);
246 		return;
247 	}
248 	FDBFuture *var = (FDBFuture *)future;
249 	fdb_future_release_memory(var);
250 }
251 
Java_com_apple_foundationdb_FutureVersion_FutureVersion_1get(JNIEnv * jenv,jobject,jlong future)252 JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FutureVersion_FutureVersion_1get(JNIEnv *jenv, jobject, jlong future) {
253 	if( !future ) {
254 		throwParamNotNull(jenv);
255 		return 0;
256 	}
257 	FDBFuture *f = (FDBFuture *)future;
258 
259 	int64_t version = 0;
260 	fdb_error_t err = fdb_future_get_version(f, &version);
261 	if( err ) {
262 		safeThrow( jenv, getThrowable( jenv, err ) );
263 		return 0;
264 	}
265 
266 	return (jlong)version;
267 }
268 
Java_com_apple_foundationdb_FutureStrings_FutureStrings_1get(JNIEnv * jenv,jobject,jlong future)269 JNIEXPORT jobject JNICALL Java_com_apple_foundationdb_FutureStrings_FutureStrings_1get(JNIEnv *jenv, jobject, jlong future) {
270 	if( !future ) {
271 		throwParamNotNull(jenv);
272 		return JNI_NULL;
273 	}
274 	FDBFuture *f = (FDBFuture *)future;
275 
276 	const char **strings;
277 	int count;
278 	fdb_error_t err = fdb_future_get_string_array( f, &strings, &count );
279 	if( err ) {
280 		safeThrow( jenv, getThrowable( jenv, err ) );
281 		return JNI_NULL;
282 	}
283 
284 	jclass str_clazz = jenv->FindClass("java/lang/String");
285 	if( jenv->ExceptionOccurred() )
286 		return JNI_NULL;
287 	jobjectArray arr = jenv->NewObjectArray(count, str_clazz, JNI_NULL);
288 	if( !arr ) {
289 		if( !jenv->ExceptionOccurred() )
290 			throwOutOfMem(jenv);
291 		return JNI_NULL;
292 	}
293 
294 	for(int i = 0; i < count; i++) {
295 		jstring str = jenv->NewStringUTF( strings[i] );
296 		if( !str ) {
297 			if( !jenv->ExceptionOccurred() )
298 				throwOutOfMem(jenv);
299 			return JNI_NULL;
300 		}
301 
302 		jenv->SetObjectArrayElement( arr, i, str );
303 		if( jenv->ExceptionOccurred() )
304 			return JNI_NULL;
305 	}
306 
307 	return arr;
308 }
309 
Java_com_apple_foundationdb_FutureResults_FutureResults_1getSummary(JNIEnv * jenv,jobject,jlong future)310 JNIEXPORT jobject JNICALL Java_com_apple_foundationdb_FutureResults_FutureResults_1getSummary(JNIEnv *jenv, jobject, jlong future) {
311 	if( !future ) {
312 		throwParamNotNull(jenv);
313 		return JNI_NULL;
314 	}
315 
316 	jclass resultCls = jenv->FindClass("com/apple/foundationdb/RangeResultSummary");
317 	if( jenv->ExceptionOccurred() )
318 		return JNI_NULL;
319 	jmethodID resultCtorId = jenv->GetMethodID(resultCls, "<init>", "([BIZ)V");
320 	if( jenv->ExceptionOccurred() )
321 		return JNI_NULL;
322 
323 	FDBFuture *f = (FDBFuture *)future;
324 
325 	const FDBKeyValue *kvs;
326 	int count;
327 	fdb_bool_t more;
328 	fdb_error_t err = fdb_future_get_keyvalue_array( f, &kvs, &count, &more );
329 	if( err ) {
330 		safeThrow( jenv, getThrowable( jenv, err ) );
331 		return JNI_NULL;
332 	}
333 
334 	jbyteArray lastKey = JNI_NULL;
335 	if(count) {
336 		lastKey = jenv->NewByteArray(kvs[count - 1].key_length);
337 		if( !lastKey ) {
338 			if( !jenv->ExceptionOccurred() )
339 				throwOutOfMem(jenv);
340 			return JNI_NULL;
341 		}
342 
343 		jenv->SetByteArrayRegion(lastKey, 0, kvs[count - 1].key_length, (jbyte *)kvs[count - 1].key);
344 	}
345 
346 	jobject result = jenv->NewObject(resultCls, resultCtorId, lastKey, count, (jboolean)more);
347 	if( jenv->ExceptionOccurred() )
348 		return JNI_NULL;
349 
350 	return result;
351 }
352 
353 // SOMEDAY: explore doing this more efficiently with Direct ByteBuffers
Java_com_apple_foundationdb_FutureResults_FutureResults_1get(JNIEnv * jenv,jobject,jlong future)354 JNIEXPORT jobject JNICALL Java_com_apple_foundationdb_FutureResults_FutureResults_1get(JNIEnv *jenv, jobject, jlong future) {
355 	if( !future ) {
356 		throwParamNotNull(jenv);
357 		return JNI_NULL;
358 	}
359 
360 	jclass resultCls = jenv->FindClass("com/apple/foundationdb/RangeResult");
361 	jmethodID resultCtorId = jenv->GetMethodID(resultCls, "<init>", "([B[IZ)V");
362 
363 	FDBFuture *f = (FDBFuture *)future;
364 
365 	const FDBKeyValue *kvs;
366 	int count;
367 	fdb_bool_t more;
368 	fdb_error_t err = fdb_future_get_keyvalue_array( f, &kvs, &count, &more );
369 	if( err ) {
370 		safeThrow( jenv, getThrowable( jenv, err ) );
371 		return JNI_NULL;
372 	}
373 
374 	int totalKeyValueSize = 0;
375 	for(int i = 0; i < count; i++) {
376 		totalKeyValueSize += kvs[i].key_length + kvs[i].value_length;
377 	}
378 
379 	jbyteArray keyValueArray = jenv->NewByteArray(totalKeyValueSize);
380 	if( !keyValueArray ) {
381 		if( !jenv->ExceptionOccurred() )
382 			throwOutOfMem(jenv);
383 		return JNI_NULL;
384 	}
385 	uint8_t *keyvalues_barr = (uint8_t *)jenv->GetByteArrayElements(keyValueArray, JNI_NULL);
386 	if (!keyvalues_barr) {
387 		throwRuntimeEx( jenv, "Error getting handle to native resources" );
388 		return JNI_NULL;
389 	}
390 
391 	jintArray lengthArray = jenv->NewIntArray(count * 2);
392 	if( !lengthArray ) {
393 		if( !jenv->ExceptionOccurred() )
394 			throwOutOfMem(jenv);
395 
396 		jenv->ReleaseByteArrayElements(keyValueArray, (jbyte *)keyvalues_barr, 0);
397 		return JNI_NULL;
398 	}
399 
400 	jint *length_barr = jenv->GetIntArrayElements(lengthArray, JNI_NULL);
401 	if( !length_barr ) {
402 		if( !jenv->ExceptionOccurred() )
403 			throwOutOfMem(jenv);
404 
405 		jenv->ReleaseByteArrayElements(keyValueArray, (jbyte *)keyvalues_barr, 0);
406 		return JNI_NULL;
407 	}
408 
409 	int offset = 0;
410 	for(int i = 0; i < count; i++) {
411 		memcpy(keyvalues_barr + offset, kvs[i].key, kvs[i].key_length);
412 		length_barr[ i * 2 ] = kvs[i].key_length;
413 		offset += kvs[i].key_length;
414 
415 		memcpy(keyvalues_barr + offset, kvs[i].value, kvs[i].value_length);
416 		length_barr[ (i * 2) + 1 ] = kvs[i].value_length;
417 		offset += kvs[i].value_length;
418 	}
419 
420 	jenv->ReleaseByteArrayElements(keyValueArray, (jbyte *)keyvalues_barr, 0);
421 	jenv->ReleaseIntArrayElements(lengthArray, length_barr, 0);
422 
423 	jobject result = jenv->NewObject(resultCls, resultCtorId, keyValueArray, lengthArray, (jboolean)more);
424 	if( jenv->ExceptionOccurred() )
425 		return JNI_NULL;
426 
427 	return result;
428 }
429 
430 // SOMEDAY: explore doing this more efficiently with Direct ByteBuffers
Java_com_apple_foundationdb_FutureResult_FutureResult_1get(JNIEnv * jenv,jobject,jlong future)431 JNIEXPORT jbyteArray JNICALL Java_com_apple_foundationdb_FutureResult_FutureResult_1get(JNIEnv *jenv, jobject, jlong future) {
432 	if( !future ) {
433 		throwParamNotNull(jenv);
434 		return JNI_NULL;
435 	}
436 	FDBFuture *f = (FDBFuture *)future;
437 
438 	fdb_bool_t present;
439 	const uint8_t *value;
440 	int length;
441 	fdb_error_t err = fdb_future_get_value(f, &present, &value, &length);
442 	if( err ) {
443 		safeThrow( jenv, getThrowable( jenv, err ) );
444 		return JNI_NULL;
445 	}
446 
447 	if( !present )
448 		return JNI_NULL;
449 
450 	jbyteArray result = jenv->NewByteArray(length);
451 	if( !result ) {
452 		if( !jenv->ExceptionOccurred() )
453 			throwOutOfMem(jenv);
454 		return JNI_NULL;
455 	}
456 
457 	jenv->SetByteArrayRegion(result, 0, length, (const jbyte *)value);
458 	return result;
459 }
460 
Java_com_apple_foundationdb_FutureKey_FutureKey_1get(JNIEnv * jenv,jclass,jlong future)461 JNIEXPORT jbyteArray JNICALL Java_com_apple_foundationdb_FutureKey_FutureKey_1get(JNIEnv * jenv, jclass, jlong future) {
462 	if( !future ) {
463 		throwParamNotNull(jenv);
464 		return JNI_NULL;
465 	}
466 	FDBFuture *f = (FDBFuture *)future;
467 
468 	const uint8_t *value;
469 	int length;
470 	fdb_error_t err = fdb_future_get_key(f, &value, &length);
471 	if( err ) {
472 		safeThrow( jenv, getThrowable( jenv, err ) );
473 		return JNI_NULL;
474 	}
475 
476 	jbyteArray result = jenv->NewByteArray(length);
477 	if( !result ) {
478 		if( !jenv->ExceptionOccurred() )
479 			throwOutOfMem(jenv);
480 		return JNI_NULL;
481 	}
482 
483 	jenv->SetByteArrayRegion(result, 0, length, (const jbyte *)value);
484 	return result;
485 }
486 
Java_com_apple_foundationdb_FDBDatabase_Database_1createTransaction(JNIEnv * jenv,jobject,jlong dbPtr)487 JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDBDatabase_Database_1createTransaction(JNIEnv *jenv, jobject, jlong dbPtr) {
488 	if( !dbPtr ) {
489 		throwParamNotNull(jenv);
490 		return 0;
491 	}
492 	FDBDatabase *database = (FDBDatabase *)dbPtr;
493 	FDBTransaction *tr;
494 	fdb_error_t err = fdb_database_create_transaction(database, &tr);
495 	if( err ) {
496 		safeThrow( jenv, getThrowable( jenv, err ) );
497 		return 0;
498 	}
499 	return (jlong)tr;
500 }
501 
Java_com_apple_foundationdb_FDBDatabase_Database_1dispose(JNIEnv * jenv,jobject,jlong dPtr)502 JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDBDatabase_Database_1dispose(JNIEnv *jenv, jobject, jlong dPtr) {
503 	if( !dPtr ) {
504 		throwParamNotNull(jenv);
505 		return;
506 	}
507 	fdb_database_destroy( (FDBDatabase *)dPtr );
508 }
509 
Java_com_apple_foundationdb_FDBDatabase_Database_1setOption(JNIEnv * jenv,jobject,jlong dPtr,jint code,jbyteArray value)510 JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDBDatabase_Database_1setOption(JNIEnv *jenv, jobject, jlong dPtr, jint code, jbyteArray value) {
511 	if( !dPtr ) {
512 		throwParamNotNull(jenv);
513 		return;
514 	}
515 	FDBDatabase *c = (FDBDatabase *)dPtr;
516 	uint8_t *barr = nullptr;
517 	int size = 0;
518 
519 	if(value != JNI_NULL) {
520 		barr = (uint8_t *)jenv->GetByteArrayElements( value, JNI_NULL );
521 		if (!barr) {
522 			throwRuntimeEx( jenv, "Error getting handle to native resources" );
523 			return;
524 		}
525 		size = jenv->GetArrayLength( value );
526 	}
527 	fdb_error_t err = fdb_database_set_option( c, (FDBDatabaseOption)code, barr, size );
528 	if(value != JNI_NULL)
529 		jenv->ReleaseByteArrayElements( value, (jbyte *)barr, JNI_ABORT );
530 	if( err ) {
531 		safeThrow( jenv, getThrowable( jenv, err ) );
532 	}
533 }
534 
Java_com_apple_foundationdb_FDB_Error_1predicate(JNIEnv * jenv,jobject,jint predicate,jint code)535 JNIEXPORT jboolean JNICALL Java_com_apple_foundationdb_FDB_Error_1predicate(JNIEnv *jenv, jobject, jint predicate, jint code) {
536 	return (jboolean)fdb_error_predicate(predicate, code);
537 }
538 
Java_com_apple_foundationdb_FDB_Database_1create(JNIEnv * jenv,jobject,jstring clusterFileName)539 JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDB_Database_1create(JNIEnv *jenv, jobject, jstring clusterFileName) {
540 	const char* fileName = nullptr;
541 	if(clusterFileName != JNI_NULL) {
542 		fileName = jenv->GetStringUTFChars(clusterFileName, JNI_NULL);
543 		if(jenv->ExceptionOccurred()) {
544 			return 0;
545 		}
546 	}
547 
548 	FDBDatabase *db;
549 	fdb_error_t err = fdb_create_database(fileName, &db);
550 
551 	if(clusterFileName != JNI_NULL) {
552 		jenv->ReleaseStringUTFChars(clusterFileName, fileName);
553 	}
554 
555 	if(err) {
556 		safeThrow(jenv, getThrowable(jenv, err));
557 		return 0;
558 	}
559 
560 	return (jlong)db;
561 }
562 
Java_com_apple_foundationdb_FDBTransaction_Transaction_1setVersion(JNIEnv * jenv,jobject,jlong tPtr,jlong version)563 JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1setVersion(JNIEnv *jenv, jobject, jlong tPtr, jlong version) {
564 	if( !tPtr ) {
565 		throwParamNotNull(jenv);
566 		return;
567 	}
568 	FDBTransaction *tr = (FDBTransaction *)tPtr;
569 	fdb_transaction_set_read_version( tr, version );
570 }
571 
Java_com_apple_foundationdb_FDBTransaction_Transaction_1getReadVersion(JNIEnv * jenv,jobject,jlong tPtr)572 JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1getReadVersion(JNIEnv *jenv, jobject, jlong tPtr) {
573 	if( !tPtr ) {
574 		throwParamNotNull(jenv);
575 		return 0;
576 	}
577 	FDBTransaction *tr = (FDBTransaction *)tPtr;
578 	FDBFuture *f = fdb_transaction_get_read_version( tr );
579 	return (jlong)f;
580 }
581 
Java_com_apple_foundationdb_FDBTransaction_Transaction_1get(JNIEnv * jenv,jobject,jlong tPtr,jbyteArray keyBytes,jboolean snapshot)582 JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1get(JNIEnv *jenv, jobject, jlong tPtr, jbyteArray keyBytes, jboolean snapshot) {
583 	if( !tPtr || !keyBytes ) {
584 		throwParamNotNull(jenv);
585 		return 0;
586 	}
587 	FDBTransaction *tr = (FDBTransaction *)tPtr;
588 
589 	uint8_t *barr = (uint8_t *)jenv->GetByteArrayElements( keyBytes, JNI_NULL );
590 	if(!barr) {
591 		if( !jenv->ExceptionOccurred() )
592 			throwRuntimeEx( jenv, "Error getting handle to native resources" );
593 		return 0;
594 	}
595 
596 	FDBFuture *f = fdb_transaction_get( tr, barr, jenv->GetArrayLength( keyBytes ), (fdb_bool_t)snapshot );
597 	jenv->ReleaseByteArrayElements( keyBytes, (jbyte *)barr, JNI_ABORT );
598 	return (jlong)f;
599 }
600 
Java_com_apple_foundationdb_FDBTransaction_Transaction_1getKey(JNIEnv * jenv,jobject,jlong tPtr,jbyteArray keyBytes,jboolean orEqual,jint offset,jboolean snapshot)601 JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1getKey(JNIEnv *jenv, jobject, jlong tPtr,
602 		jbyteArray keyBytes, jboolean orEqual, jint offset, jboolean snapshot) {
603 	if( !tPtr || !keyBytes ) {
604 		throwParamNotNull(jenv);
605 		return 0;
606 	}
607 	FDBTransaction *tr = (FDBTransaction *)tPtr;
608 
609 	uint8_t *barr = (uint8_t *)jenv->GetByteArrayElements( keyBytes, JNI_NULL );
610 	if(!barr) {
611 		if( !jenv->ExceptionOccurred() )
612 			throwRuntimeEx( jenv, "Error getting handle to native resources" );
613 		return 0;
614 	}
615 
616 	FDBFuture *f = fdb_transaction_get_key( tr, barr, jenv->GetArrayLength( keyBytes ), orEqual, offset, (fdb_bool_t)snapshot );
617 	jenv->ReleaseByteArrayElements( keyBytes, (jbyte *)barr, JNI_ABORT );
618 	return (jlong)f;
619 }
620 
Java_com_apple_foundationdb_FDBTransaction_Transaction_1getRange(JNIEnv * jenv,jobject,jlong tPtr,jbyteArray keyBeginBytes,jboolean orEqualBegin,jint offsetBegin,jbyteArray keyEndBytes,jboolean orEqualEnd,jint offsetEnd,jint rowLimit,jint targetBytes,jint streamingMode,jint iteration,jboolean snapshot,jboolean reverse)621 JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1getRange
622   (JNIEnv *jenv, jobject, jlong tPtr, jbyteArray keyBeginBytes, jboolean orEqualBegin, jint offsetBegin,
623 		jbyteArray keyEndBytes, jboolean orEqualEnd, jint offsetEnd, jint rowLimit, jint targetBytes,
624 		jint streamingMode, jint iteration, jboolean snapshot, jboolean reverse) {
625 	if( !tPtr || !keyBeginBytes || !keyEndBytes ) {
626 		throwParamNotNull(jenv);
627 		return 0;
628 	}
629 	FDBTransaction *tr = (FDBTransaction *)tPtr;
630 
631 	uint8_t *barrBegin = (uint8_t *)jenv->GetByteArrayElements( keyBeginBytes, JNI_NULL );
632 	if (!barrBegin) {
633 		if( !jenv->ExceptionOccurred() )
634 			throwRuntimeEx( jenv, "Error getting handle to native resources" );
635 		return 0;
636 	}
637 
638 	uint8_t *barrEnd = (uint8_t *)jenv->GetByteArrayElements( keyEndBytes, JNI_NULL );
639 	if (!barrEnd) {
640 		jenv->ReleaseByteArrayElements( keyBeginBytes, (jbyte *)barrBegin, JNI_ABORT );
641 		if( !jenv->ExceptionOccurred() )
642 			throwRuntimeEx( jenv, "Error getting handle to native resources" );
643 		return 0;
644 	}
645 
646 	FDBFuture *f = fdb_transaction_get_range( tr,
647 			barrBegin, jenv->GetArrayLength( keyBeginBytes ), orEqualBegin, offsetBegin,
648 			barrEnd, jenv->GetArrayLength( keyEndBytes ), orEqualEnd, offsetEnd, rowLimit,
649 			targetBytes, (FDBStreamingMode)streamingMode, iteration, snapshot, reverse);
650 	jenv->ReleaseByteArrayElements( keyBeginBytes, (jbyte *)barrBegin, JNI_ABORT );
651 	jenv->ReleaseByteArrayElements( keyEndBytes, (jbyte *)barrEnd, JNI_ABORT );
652 	return (jlong)f;
653 }
654 
Java_com_apple_foundationdb_FDBTransaction_Transaction_1set(JNIEnv * jenv,jobject,jlong tPtr,jbyteArray keyBytes,jbyteArray valueBytes)655 JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1set(JNIEnv *jenv, jobject, jlong tPtr, jbyteArray keyBytes, jbyteArray valueBytes) {
656 	if( !tPtr || !keyBytes || !valueBytes ) {
657 		throwParamNotNull(jenv);
658 		return;
659 	}
660 	FDBTransaction *tr = (FDBTransaction *)tPtr;
661 
662 	uint8_t *barrKey = (uint8_t *)jenv->GetByteArrayElements( keyBytes, JNI_NULL );
663 	if (!barrKey) {
664 		if( !jenv->ExceptionOccurred() )
665 			throwRuntimeEx( jenv, "Error getting handle to native resources" );
666 		return;
667 	}
668 
669 	uint8_t *barrValue = (uint8_t *)jenv->GetByteArrayElements( valueBytes, JNI_NULL );
670 	if (!barrValue) {
671 		jenv->ReleaseByteArrayElements( keyBytes, (jbyte *)barrKey, JNI_ABORT );
672 		if( !jenv->ExceptionOccurred() )
673 			throwRuntimeEx( jenv, "Error getting handle to native resources" );
674 		return;
675 	}
676 
677 	fdb_transaction_set( tr,
678 			barrKey, jenv->GetArrayLength( keyBytes ),
679 			barrValue, jenv->GetArrayLength( valueBytes ) );
680 	jenv->ReleaseByteArrayElements( keyBytes, (jbyte *)barrKey, JNI_ABORT );
681 	jenv->ReleaseByteArrayElements( valueBytes, (jbyte *)barrValue, JNI_ABORT );
682 }
683 
Java_com_apple_foundationdb_FDBTransaction_Transaction_1clear__J_3B(JNIEnv * jenv,jobject,jlong tPtr,jbyteArray keyBytes)684 JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1clear__J_3B(JNIEnv *jenv, jobject, jlong tPtr, jbyteArray keyBytes) {
685 	if( !tPtr || !keyBytes ) {
686 		throwParamNotNull(jenv);
687 		return;
688 	}
689 	FDBTransaction *tr = (FDBTransaction *)tPtr;
690 
691 	uint8_t *barr = (uint8_t *)jenv->GetByteArrayElements( keyBytes, JNI_NULL );
692 	if (!barr) {
693 		if( !jenv->ExceptionOccurred() )
694 			throwRuntimeEx( jenv, "Error getting handle to native resources" );
695 		return;
696 	}
697 
698 	fdb_transaction_clear( tr, barr, jenv->GetArrayLength( keyBytes ) );
699 	jenv->ReleaseByteArrayElements( keyBytes, (jbyte *)barr, JNI_ABORT );
700 }
701 
Java_com_apple_foundationdb_FDBTransaction_Transaction_1clear__J_3B_3B(JNIEnv * jenv,jobject,jlong tPtr,jbyteArray keyBeginBytes,jbyteArray keyEndBytes)702 JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1clear__J_3B_3B(JNIEnv *jenv, jobject, jlong tPtr, jbyteArray keyBeginBytes, jbyteArray keyEndBytes) {
703 	if( !tPtr || !keyBeginBytes || !keyEndBytes ) {
704 		throwParamNotNull(jenv);
705 		return;
706 	}
707 	FDBTransaction *tr = (FDBTransaction *)tPtr;
708 
709 	uint8_t *barrKeyBegin = (uint8_t *)jenv->GetByteArrayElements( keyBeginBytes, JNI_NULL );
710 	if (!barrKeyBegin) {
711 		if( !jenv->ExceptionOccurred() )
712 			throwRuntimeEx( jenv, "Error getting handle to native resources" );
713 		return;
714 	}
715 
716 	uint8_t *barrKeyEnd = (uint8_t *)jenv->GetByteArrayElements( keyEndBytes, JNI_NULL );
717 	if (!barrKeyEnd) {
718 		jenv->ReleaseByteArrayElements( keyBeginBytes, (jbyte *)barrKeyBegin, JNI_ABORT );
719 		if( !jenv->ExceptionOccurred() )
720 			throwRuntimeEx( jenv, "Error getting handle to native resources" );
721 		return;
722 	}
723 
724 	fdb_transaction_clear_range( tr,
725 			barrKeyBegin, jenv->GetArrayLength( keyBeginBytes ),
726 			barrKeyEnd, jenv->GetArrayLength( keyEndBytes ) );
727 	jenv->ReleaseByteArrayElements( keyBeginBytes, (jbyte *)barrKeyBegin, JNI_ABORT );
728 	jenv->ReleaseByteArrayElements( keyEndBytes, (jbyte *)barrKeyEnd, JNI_ABORT );
729 }
730 
Java_com_apple_foundationdb_FDBTransaction_Transaction_1mutate(JNIEnv * jenv,jobject,jlong tPtr,jint code,jbyteArray key,jbyteArray value)731 JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1mutate(JNIEnv *jenv, jobject, jlong tPtr, jint code,
732 																		jbyteArray key, jbyteArray value ) {
733 	if( !tPtr || !key || !value ) {
734 		throwParamNotNull(jenv);
735 		return;
736 	}
737 	FDBTransaction *tr = (FDBTransaction *)tPtr;
738 
739 	uint8_t *barrKey = (uint8_t *)jenv->GetByteArrayElements( key, JNI_NULL );
740 	if (!barrKey) {
741 		if( !jenv->ExceptionOccurred() )
742 			throwRuntimeEx( jenv, "Error getting handle to native resources" );
743 		return;
744 	}
745 
746 	uint8_t *barrValue = (uint8_t *)jenv->GetByteArrayElements( value, JNI_NULL );
747 	if (!barrValue) {
748 		jenv->ReleaseByteArrayElements( key, (jbyte *)barrKey, JNI_ABORT );
749 		if( !jenv->ExceptionOccurred() )
750 			throwRuntimeEx( jenv, "Error getting handle to native resources" );
751 		return;
752 	}
753 
754 	fdb_transaction_atomic_op( tr,
755 			barrKey, jenv->GetArrayLength( key ),
756 			barrValue, jenv->GetArrayLength( value ),
757 			(FDBMutationType)code);
758 
759 	jenv->ReleaseByteArrayElements( key, (jbyte *)barrKey, JNI_ABORT );
760 	jenv->ReleaseByteArrayElements( value, (jbyte *)barrValue, JNI_ABORT );
761 }
762 
Java_com_apple_foundationdb_FDBTransaction_Transaction_1commit(JNIEnv * jenv,jobject,jlong tPtr)763 JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1commit(JNIEnv *jenv, jobject, jlong tPtr) {
764 	if( !tPtr ) {
765 		throwParamNotNull(jenv);
766 		return 0;
767 	}
768 	FDBTransaction *tr = (FDBTransaction *)tPtr;
769 	FDBFuture *f = fdb_transaction_commit( tr );
770 	return (jlong)f;
771 }
772 
Java_com_apple_foundationdb_FDBTransaction_Transaction_1setOption(JNIEnv * jenv,jobject,jlong tPtr,jint code,jbyteArray value)773 JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1setOption(JNIEnv *jenv, jobject, jlong tPtr, jint code, jbyteArray value) {
774 	if( !tPtr ) {
775 		throwParamNotNull(jenv);
776 		return;
777 	}
778 	FDBTransaction *tr = (FDBTransaction *)tPtr;
779 	uint8_t *barr = nullptr;
780 	int size = 0;
781 
782 	if(value != JNI_NULL) {
783 		barr = (uint8_t *)jenv->GetByteArrayElements( value, JNI_NULL );
784 		if (!barr) {
785 			if( !jenv->ExceptionOccurred() )
786 				throwRuntimeEx( jenv, "Error getting handle to native resources" );
787 			return;
788 		}
789 		size = jenv->GetArrayLength( value );
790 	}
791 	fdb_error_t err = fdb_transaction_set_option( tr, (FDBTransactionOption)code, barr, size );
792 	if(value != JNI_NULL)
793 		jenv->ReleaseByteArrayElements( value, (jbyte *)barr, JNI_ABORT );
794 	if( err ) {
795 		safeThrow( jenv, getThrowable( jenv, err ) );
796 	}
797 }
798 
Java_com_apple_foundationdb_FDBTransaction_Transaction_1getCommittedVersion(JNIEnv * jenv,jobject,jlong tPtr)799 JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1getCommittedVersion(JNIEnv *jenv, jobject, jlong tPtr) {
800 	if( !tPtr ) {
801 		throwParamNotNull(jenv);
802 		return 0;
803 	}
804 	FDBTransaction *tr = (FDBTransaction *)tPtr;
805 	int64_t version;
806 	fdb_error_t err = fdb_transaction_get_committed_version( tr, &version );
807 	if( err ) {
808 		safeThrow( jenv, getThrowable( jenv, err ) );
809 		return 0;
810 	}
811 	return (jlong)version;
812 }
813 
Java_com_apple_foundationdb_FDBTransaction_Transaction_1getVersionstamp(JNIEnv * jenv,jobject,jlong tPtr)814 JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1getVersionstamp(JNIEnv *jenv, jobject, jlong tPtr) {
815 	if (!tPtr) {
816 		throwParamNotNull(jenv);
817 		return 0;
818 	}
819 	FDBTransaction *tr = (FDBTransaction *)tPtr;
820 	FDBFuture *f = fdb_transaction_get_versionstamp(tr);
821 	return (jlong)f;
822 }
823 
Java_com_apple_foundationdb_FDBTransaction_Transaction_1getKeyLocations(JNIEnv * jenv,jobject,jlong tPtr,jbyteArray key)824 JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1getKeyLocations(JNIEnv *jenv, jobject, jlong tPtr, jbyteArray key) {
825 	if( !tPtr || !key ) {
826 		throwParamNotNull(jenv);
827 		return 0;
828 	}
829 	FDBTransaction *tr = (FDBTransaction *)tPtr;
830 
831 	uint8_t *barr = (uint8_t *)jenv->GetByteArrayElements( key, JNI_NULL );
832 	if (!barr) {
833 		if( !jenv->ExceptionOccurred() )
834 			throwRuntimeEx( jenv, "Error getting handle to native resources" );
835 		return 0;
836 	}
837 	int size = jenv->GetArrayLength( key );
838 
839 	FDBFuture *f = fdb_transaction_get_addresses_for_key( tr, barr, size );
840 
841 	jenv->ReleaseByteArrayElements( key, (jbyte *)barr, JNI_ABORT );
842 	return (jlong)f;
843 }
844 
Java_com_apple_foundationdb_FDBTransaction_Transaction_1onError(JNIEnv * jenv,jobject,jlong tPtr,jint errorCode)845 JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1onError(JNIEnv *jenv, jobject, jlong tPtr, jint errorCode) {
846 	if( !tPtr ) {
847 		throwParamNotNull(jenv);
848 		return 0;
849 	}
850 	FDBTransaction *tr = (FDBTransaction *)tPtr;
851 	FDBFuture *f = fdb_transaction_on_error( tr, (fdb_error_t)errorCode );
852 	return (jlong)f;
853 }
854 
Java_com_apple_foundationdb_FDBTransaction_Transaction_1dispose(JNIEnv * jenv,jobject,jlong tPtr)855 JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1dispose(JNIEnv *jenv, jobject, jlong tPtr) {
856 	if( !tPtr ) {
857 		throwParamNotNull(jenv);
858 		return;
859 	}
860 	fdb_transaction_destroy( (FDBTransaction *)tPtr );
861 }
862 
Java_com_apple_foundationdb_FDBTransaction_Transaction_1reset(JNIEnv * jenv,jobject,jlong tPtr)863 JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1reset(JNIEnv *jenv, jobject, jlong tPtr) {
864 	if( !tPtr ) {
865 		throwParamNotNull(jenv);
866 		return;
867 	}
868 	fdb_transaction_reset( (FDBTransaction *)tPtr );
869 }
870 
Java_com_apple_foundationdb_FDBTransaction_Transaction_1watch(JNIEnv * jenv,jobject,jlong tPtr,jbyteArray key)871 JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1watch(JNIEnv *jenv, jobject, jlong tPtr, jbyteArray key) {
872 	if( !tPtr || !key ) {
873 		throwParamNotNull(jenv);
874 		return 0;
875 	}
876 	FDBTransaction *tr = (FDBTransaction *)tPtr;
877 
878 	uint8_t *barr = (uint8_t *)jenv->GetByteArrayElements( key, JNI_NULL );
879 	if (!barr) {
880 		if( !jenv->ExceptionOccurred() )
881 			throwRuntimeEx( jenv, "Error getting handle to native resources" );
882 		return 0;
883 	}
884 	int size = jenv->GetArrayLength( key );
885 	FDBFuture *f = fdb_transaction_watch( tr, barr, size );
886 
887 	jenv->ReleaseByteArrayElements( key, (jbyte *)barr, JNI_ABORT );
888 	return (jlong)f;
889 }
890 
Java_com_apple_foundationdb_FDBTransaction_Transaction_1cancel(JNIEnv * jenv,jobject,jlong tPtr)891 JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1cancel(JNIEnv *jenv, jobject, jlong tPtr) {
892 	if( !tPtr ) {
893 		throwParamNotNull(jenv);
894 		return;
895 	}
896 	fdb_transaction_cancel( (FDBTransaction *)tPtr );
897 }
898 
Java_com_apple_foundationdb_FDBTransaction_Transaction_1addConflictRange(JNIEnv * jenv,jobject,jlong tPtr,jbyteArray keyBegin,jbyteArray keyEnd,jint conflictType)899 JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1addConflictRange(
900 		JNIEnv *jenv, jobject, jlong tPtr, jbyteArray keyBegin, jbyteArray keyEnd, jint conflictType) {
901 	if( !tPtr || !keyBegin || !keyEnd ) {
902 		throwParamNotNull(jenv);
903 		return;
904 	}
905 	FDBTransaction *tr = (FDBTransaction *)tPtr;
906 
907 	uint8_t *begin_barr = (uint8_t *)jenv->GetByteArrayElements( keyBegin, JNI_NULL );
908 	if (!begin_barr) {
909 		if( !jenv->ExceptionOccurred() )
910 			throwRuntimeEx( jenv, "Error getting handle to native resources" );
911 		return;
912 	}
913 	int begin_size = jenv->GetArrayLength( keyBegin );
914 
915 	uint8_t *end_barr = (uint8_t *)jenv->GetByteArrayElements( keyEnd, JNI_NULL );
916 	if (!end_barr) {
917 		jenv->ReleaseByteArrayElements( keyBegin, (jbyte *)begin_barr, JNI_ABORT );
918 		if( !jenv->ExceptionOccurred() )
919 			throwRuntimeEx( jenv, "Error getting handle to native resources" );
920 		return;
921 	}
922 	int end_size = jenv->GetArrayLength( keyEnd );
923 
924 	fdb_error_t err = fdb_transaction_add_conflict_range( tr, begin_barr, begin_size, end_barr, end_size, (FDBConflictRangeType)conflictType );
925 
926 	jenv->ReleaseByteArrayElements( keyBegin, (jbyte *)begin_barr, JNI_ABORT );
927 	jenv->ReleaseByteArrayElements( keyEnd, (jbyte *)end_barr, JNI_ABORT );
928 
929 	if( err ) {
930 		safeThrow( jenv, getThrowable( jenv, err ) );
931 	}
932 }
933 
Java_com_apple_foundationdb_FDB_Select_1API_1version(JNIEnv * jenv,jclass,jint version)934 JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDB_Select_1API_1version(JNIEnv *jenv, jclass, jint version) {
935 	fdb_error_t err = fdb_select_api_version( (int)version );
936 	if( err ) {
937 		if( err == 2203 ) {
938 			int maxSupportedVersion = fdb_get_max_api_version();
939 
940 			char errorStr[1024];
941 			if(FDB_API_VERSION > maxSupportedVersion) {
942 				snprintf(errorStr, sizeof(errorStr), "This version of the FoundationDB Java binding is not supported by the installed "
943 						 							 "FoundationDB C library. The binding requires a library that supports API version "
944 						 							 "%d, but the installed library supports a maximum version of %d.",
945 													 FDB_API_VERSION, maxSupportedVersion);
946 			}
947 			else {
948 				snprintf(errorStr, sizeof(errorStr), "API version %d is not supported by the installed FoundationDB C library.", version);
949 			}
950 
951 			safeThrow( jenv, getThrowable( jenv, err, errorStr ) );
952 		}
953 		else {
954 			safeThrow( jenv, getThrowable( jenv, err ) );
955 		}
956 	}
957 }
958 
Java_com_apple_foundationdb_FDB_Network_1setOption(JNIEnv * jenv,jobject,jint code,jbyteArray value)959 JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDB_Network_1setOption(JNIEnv *jenv, jobject, jint code, jbyteArray value) {
960 	uint8_t *barr = nullptr;
961 	int size = 0;
962 	if(value != JNI_NULL) {
963 		barr = (uint8_t *)jenv->GetByteArrayElements( value, JNI_NULL );
964 		if (!barr) {
965 			if( !jenv->ExceptionOccurred() )
966 				throwRuntimeEx( jenv, "Error getting handle to native resources" );
967 			return;
968 		}
969 		size = jenv->GetArrayLength( value );
970 	}
971 	fdb_error_t err = fdb_network_set_option((FDBNetworkOption)code, barr, size);
972 	if(value != JNI_NULL)
973 		jenv->ReleaseByteArrayElements( value, (jbyte *)barr, JNI_ABORT );
974 	if( err ) {
975 		safeThrow( jenv, getThrowable( jenv, err ) );
976 	}
977 }
978 
Java_com_apple_foundationdb_FDB_Network_1setup(JNIEnv * jenv,jobject)979 JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDB_Network_1setup(JNIEnv *jenv, jobject) {
980 	fdb_error_t err = fdb_setup_network();
981 	if( err ) {
982 		safeThrow( jenv, getThrowable( jenv, err ) );
983 	}
984 }
985 
Java_com_apple_foundationdb_FDB_Network_1run(JNIEnv * jenv,jobject)986 JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDB_Network_1run(JNIEnv *jenv, jobject) {
987 	// initialize things for the callbacks on the network thread
988 	g_thread_jenv = jenv;
989 	if( !g_IFutureCallback_call_methodID ) {
990 		if( !findCallbackMethods( jenv ) )
991 			return;
992 	}
993 
994 	fdb_error_t hookErr = fdb_add_network_thread_completion_hook( &detachIfExternalThread, nullptr );
995 	if( hookErr ) {
996 		safeThrow( jenv, getThrowable( jenv, hookErr ) );
997 	}
998 
999 	fdb_error_t err = fdb_run_network();
1000 	if( err ) {
1001 		safeThrow( jenv, getThrowable( jenv, err ) );
1002 	}
1003 }
1004 
Java_com_apple_foundationdb_FDB_Network_1stop(JNIEnv * jenv,jobject)1005 JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDB_Network_1stop(JNIEnv *jenv, jobject) {
1006 	fdb_error_t err = fdb_stop_network();
1007 	if( err ) {
1008 		safeThrow( jenv, getThrowable( jenv, err ) );
1009 	}
1010 }
1011 
JNI_OnLoad(JavaVM * vm,void * reserved)1012 jint JNI_OnLoad(JavaVM *vm, void *reserved) {
1013 	g_jvm = vm;
1014 	return JNI_VERSION_1_1;
1015 }
1016 
1017 #ifdef __cplusplus
1018 }
1019 #endif
1020 
1021