java: Implement 6 more JNI syncbase internal functions
The functions added in this CL are:
Database.JoinSyncgroup
Database.LeaveSyncgroup
Database.EjectFromSyncgroup
Database.GetSyncgroupSpec
Database.SetSyncgroupSpec
Database.GetSyncgroupMembers
The only unimplemented JNI functions are now the two that use
callbacks:
Database.WatchPatterns
Collection.Scan
MultiPart: 1/2
Change-Id: Id90f490ebb925e1b6ddf579367865e878cd12f20
diff --git a/services/syncbase/bridge/cgo/jni.go b/services/syncbase/bridge/cgo/jni.go
index 56bd6a8..27b8d5d 100644
--- a/services/syncbase/bridge/cgo/jni.go
+++ b/services/syncbase/bridge/cgo/jni.go
@@ -11,19 +11,31 @@
"unsafe"
)
-// #include <stdlib.h>
-// #include <string.h>
-// #include "jni_wrapper.h"
-// #include "lib.h"
+/*
+#include <stdlib.h>
+#include <string.h>
+#include "jni_wrapper.h"
+#include "lib.h"
+
+static jvalue* allocJValueArray(int elements) {
+ return malloc(sizeof(jvalue) * elements);
+}
+
+static void setJValueArrayElement(jvalue* arr, int index, jvalue val) {
+ arr[index] = val;
+}
+*/
import "C"
var (
- jVM *C.JavaVM
- arrayListClass jArrayListClass
- idClass jIdClass
- syncgroupMemberInfoClass jSyncgroupMemberInfo
- syncgroupSpecClass jSyncgroupSpec
- verrorClass jVErrorClass
+ jVM *C.JavaVM
+ arrayListClass jArrayListClass
+ hashMapClass jHashMap
+ idClass jIdClass
+ syncgroupMemberInfoClass jSyncgroupMemberInfo
+ syncgroupSpecClass jSyncgroupSpec
+ verrorClass jVErrorClass
+ versionedSyncgroupSpecClass jVersionedSyncgroupSpec
)
// JNI_OnLoad is called when System.loadLibrary is called. We need to cache the
@@ -42,10 +54,12 @@
v23_syncbase_Init(C.v23_syncbase_Bool(1))
arrayListClass = newJArrayListClass(env)
+ hashMapClass = newJHashMap(env)
idClass = newJIdClass(env)
syncgroupMemberInfoClass = newJSyncgroupMemberInfo(env)
syncgroupSpecClass = newJSyncgroupSpec(env)
verrorClass = newJVErrorClass(env)
+ versionedSyncgroupSpecClass = newJVersionedSyncgroupSpec(env)
return C.JNI_VERSION_1_6
}
@@ -190,10 +204,27 @@
maybeThrowException(env, &cErr)
}
-func Java_io_v_syncbase_internal_Database_JoinSyncgroup(env *C.JNIEnv, cls C.jclass, name C.jstring, sgId C.jobject, info C.jobject) C.jobject {
- return nil
+//export Java_io_v_syncbase_internal_Database_JoinSyncgroup
+func Java_io_v_syncbase_internal_Database_JoinSyncgroup(env *C.JNIEnv, cls C.jclass, name C.jstring, remoteSyncbaseName C.jstring, expectedSyncbaseBlessings C.jobject, sgId C.jobject, info C.jobject) C.jobject {
+ cName := newVStringFromJava(env, name)
+ cRemoteSyncbaseName := newVStringFromJava(env, remoteSyncbaseName)
+ cExpectedSyncbaseBlessings := newVStringsFromJava(env, expectedSyncbaseBlessings)
+ cSgId := newVIdFromJava(env, sgId)
+ cMyInfo := newVSyncgroupMemberInfoFromJava(env, info)
+ var cSpec C.v23_syncbase_SyncgroupSpec
+ var cErr C.v23_syncbase_VError
+ v23_syncbase_DbJoinSyncgroup(cName, cRemoteSyncbaseName, cExpectedSyncbaseBlessings, cSgId, cMyInfo, &cSpec, &cErr)
+ maybeThrowException(env, &cErr)
+ return cSpec.extractToJava(env)
}
+
+//export Java_io_v_syncbase_internal_Database_LeaveSyncgroup
func Java_io_v_syncbase_internal_Database_LeaveSyncgroup(env *C.JNIEnv, cls C.jclass, name C.jstring, sgId C.jobject) {
+ cName := newVStringFromJava(env, name)
+ cSgId := newVIdFromJava(env, sgId)
+ var cErr C.v23_syncbase_VError
+ v23_syncbase_DbLeaveSyncgroup(cName, cSgId, &cErr)
+ maybeThrowException(env, &cErr)
}
//export Java_io_v_syncbase_internal_Database_DestroySyncgroup
@@ -205,16 +236,56 @@
maybeThrowException(env, &cErr)
}
+//export Java_io_v_syncbase_internal_Database_EjectFromSyncgroup
func Java_io_v_syncbase_internal_Database_EjectFromSyncgroup(env *C.JNIEnv, cls C.jclass, name C.jstring, sgId C.jobject, member C.jstring) {
+ cName := newVStringFromJava(env, name)
+ cSgId := newVIdFromJava(env, sgId)
+ cMember := newVStringFromJava(env, member)
+ var cErr C.v23_syncbase_VError
+ v23_syncbase_DbEjectFromSyncgroup(cName, cSgId, cMember, &cErr)
+ maybeThrowException(env, &cErr)
}
+
+//export Java_io_v_syncbase_internal_Database_GetSyncgroupSpec
func Java_io_v_syncbase_internal_Database_GetSyncgroupSpec(env *C.JNIEnv, cls C.jclass, name C.jstring, sgId C.jobject) C.jobject {
- return nil
+ cName := newVStringFromJava(env, name)
+ cSgId := newVIdFromJava(env, sgId)
+ var cSpec C.v23_syncbase_SyncgroupSpec
+ var cVersion C.v23_syncbase_String
+ var cErr C.v23_syncbase_VError
+ v23_syncbase_DbGetSyncgroupSpec(cName, cSgId, &cSpec, &cVersion, &cErr)
+ if maybeThrowException(env, &cErr) {
+ return nil
+ }
+ obj := C.NewObjectA(env, versionedSyncgroupSpecClass.class, versionedSyncgroupSpecClass.init, nil)
+ C.SetObjectField(env, obj, versionedSyncgroupSpecClass.version, cVersion.extractToJava(env))
+ C.SetObjectField(env, obj, versionedSyncgroupSpecClass.syncgroupSpec, cSpec.extractToJava(env))
+ return obj
}
-func Java_io_v_syncbase_internal_Database_SetSyncgroupSpec(env *C.JNIEnv, cls C.jclass, name C.jstring, sgId C.jobject, spec C.jobject) {
+
+//export Java_io_v_syncbase_internal_Database_SetSyncgroupSpec
+func Java_io_v_syncbase_internal_Database_SetSyncgroupSpec(env *C.JNIEnv, cls C.jclass, name C.jstring, sgId C.jobject, versionedSpec C.jobject) {
+ cName := newVStringFromJava(env, name)
+ cSgId := newVIdFromJava(env, sgId)
+ cSpec, cVersion := newVSyngroupSpecAndVersionFromJava(env, versionedSpec)
+ var cErr C.v23_syncbase_VError
+ v23_syncbase_DbSetSyncgroupSpec(cName, cSgId, cSpec, cVersion, &cErr)
+ maybeThrowException(env, &cErr)
}
+
+//export Java_io_v_syncbase_internal_Database_GetSyncgroupMembers
func Java_io_v_syncbase_internal_Database_GetSyncgroupMembers(env *C.JNIEnv, cls C.jclass, name C.jstring, sgId C.jobject) C.jobject {
- return nil
+ cName := newVStringFromJava(env, name)
+ cSgId := newVIdFromJava(env, sgId)
+ var cMembers C.v23_syncbase_SyncgroupMemberInfoMap
+ var cErr C.v23_syncbase_VError
+ v23_syncbase_DbGetSyncgroupMembers(cName, cSgId, &cMembers, &cErr)
+ if maybeThrowException(env, &cErr) {
+ return nil
+ }
+ return cMembers.extractToJava(env)
}
+
func Java_io_v_syncbase_internal_Database_WatchPatterns(env *C.JNIEnv, cls C.jclass, name C.jstring, resumeMaker C.jbyteArray, patters C.jobject, callbacks C.jobject) {
}
@@ -363,7 +434,9 @@
// "inconsistent definitions" errors for various functions (C.NewObjectA and
// C.SetObjectField for example).
-// extractToJava creates an Id object from a v23_syncbase_Id.
+// All the extractToJava methods return Java types and deallocate all the
+// pointers inside v23_syncbase_* variable.
+
func (x *C.v23_syncbase_Id) extractToJava(env *C.JNIEnv) C.jobject {
obj := C.NewObjectA(env, idClass.class, idClass.init, nil)
C.SetObjectField(env, obj, idClass.blessing, x.blessing.extractToJava(env))
@@ -404,8 +477,6 @@
return r
}
-// extractToJava constructs a jobject from a v23_syncbase_Ids. The pointers
-// inside v23_syncbase_Ids will be freed.
func (x *C.v23_syncbase_Ids) extractToJava(env *C.JNIEnv) C.jobject {
obj := C.NewObjectA(env, arrayListClass.class, arrayListClass.init, nil)
for i := 0; i < int(x.n); i++ {
@@ -449,8 +520,40 @@
return r
}
-// extractToJava constructs a jobject from a v23_syncbase_VError. The pointers
-// from inside v23_syncbase_VError will be freed.
+func (x *C.v23_syncbase_SyncgroupSpec) extractToJava(env *C.JNIEnv) C.jobject {
+ obj := C.NewObjectA(env, syncgroupSpecClass.class, syncgroupSpecClass.init, nil)
+ C.SetObjectField(env, obj, syncgroupSpecClass.description, x.description.extractToJava(env))
+ C.SetObjectField(env, obj, syncgroupSpecClass.publishSyncbaseName, x.publishSyncbaseName.extractToJava(env))
+ // TODO(razvanm): Also extract the permissions.
+ C.SetObjectField(env, obj, syncgroupSpecClass.collections, x.collections.extractToJava(env))
+ C.SetObjectField(env, obj, syncgroupSpecClass.mountTables, x.mountTables.extractToJava(env))
+ C.SetBooleanField(env, obj, syncgroupSpecClass.isPrivate, x.isPrivate.extractToJava())
+ return obj
+}
+
+func (x *C.v23_syncbase_SyncgroupMemberInfo) extractToJava(env *C.JNIEnv) C.jobject {
+ obj := C.NewObjectA(env, syncgroupMemberInfoClass.class, syncgroupMemberInfoClass.init, nil)
+ C.SetByteField(env, obj, syncgroupMemberInfoClass.syncPriority, C.jbyte(x.syncPriority))
+ C.SetByteField(env, obj, syncgroupMemberInfoClass.blobDevType, C.jbyte(x.blobDevType))
+ return obj
+}
+
+func (x *C.v23_syncbase_SyncgroupMemberInfoMap) extractToJava(env *C.JNIEnv) C.jobject {
+ obj := C.NewObjectA(env, hashMapClass.class, hashMapClass.init, nil)
+ for i := 0; i < int(x.n); i++ {
+ k, v := x.at(i)
+ key := k.extractToJava(env)
+ value := v.extractToJava(env)
+ args := C.allocJValueArray(2)
+ C.setJValueArrayElement(args, 0, *(*C.jvalue)(unsafe.Pointer(&key)))
+ C.setJValueArrayElement(args, 1, *(*C.jvalue)(unsafe.Pointer(&value)))
+ C.CallObjectMethodA(env, obj, hashMapClass.put, args)
+ C.free(unsafe.Pointer(args))
+ }
+ x.free()
+ return obj
+}
+
func (x *C.v23_syncbase_VError) extractToJava(env *C.JNIEnv) C.jobject {
if x.id.p == nil {
return nil
@@ -463,3 +566,14 @@
x.free()
return obj
}
+
+func (x *C.v23_syncbase_Strings) extractToJava(env *C.JNIEnv) C.jobject {
+ obj := C.NewObjectA(env, arrayListClass.class, arrayListClass.init, nil)
+ for i := 0; i < int(x.n); i++ {
+ s := x.at(i).extractToJava(env)
+ arg := *(*C.jvalue)(unsafe.Pointer(&s))
+ C.CallBooleanMethodA(env, obj, arrayListClass.add, &arg)
+ }
+ x.free()
+ return obj
+}
diff --git a/services/syncbase/bridge/cgo/jni_lib.go b/services/syncbase/bridge/cgo/jni_lib.go
index f06fc81..a83f4c8 100644
--- a/services/syncbase/bridge/cgo/jni_lib.go
+++ b/services/syncbase/bridge/cgo/jni_lib.go
@@ -27,6 +27,21 @@
}
}
+type jHashMap struct {
+ class C.jclass
+ init C.jmethodID
+ put C.jmethodID
+}
+
+func newJHashMap(env *C.JNIEnv) jHashMap {
+ cls, init := initClass(env, "java/util/HashMap")
+ return jHashMap{
+ class: cls,
+ init: init,
+ put: jGetMethodID(env, cls, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"),
+ }
+}
+
type jIteratorInterface struct {
hasNext C.jmethodID
next C.jmethodID
@@ -133,6 +148,23 @@
}
}
+type jVersionedSyncgroupSpec struct {
+ class C.jclass
+ init C.jmethodID
+ version C.jfieldID
+ syncgroupSpec C.jfieldID
+}
+
+func newJVersionedSyncgroupSpec(env *C.JNIEnv) jVersionedSyncgroupSpec {
+ cls, init := initClass(env, "io/v/syncbase/internal/Database$VersionedSyncgroupSpec")
+ return jVersionedSyncgroupSpec{
+ class: cls,
+ init: init,
+ version: jGetFieldID(env, cls, "version", "Ljava/lang/String;"),
+ syncgroupSpec: jGetFieldID(env, cls, "syncgroupSpec", "Lio/v/syncbase/internal/Database$SyncgroupSpec;"),
+ }
+}
+
// initClass returns the jclass and the jmethodID of the default constructor for
// a class.
func initClass(env *C.JNIEnv, name string) (C.jclass, C.jmethodID) {
diff --git a/services/syncbase/bridge/cgo/jni_types.go b/services/syncbase/bridge/cgo/jni_types.go
index 173d79f..875833c 100644
--- a/services/syncbase/bridge/cgo/jni_types.go
+++ b/services/syncbase/bridge/cgo/jni_types.go
@@ -21,7 +21,17 @@
// #include "lib.h"
import "C"
-// newVBytesFromJava creates a v23_syncbase_Bytes from a jbyteArray.
+// All the extractToJava methods return Java types and deallocate all the
+// pointers inside v23_syncbase_* variable.
+
+// extractToJava constructs a jboolean from a bool.
+func (x *C.bool) extractToJava() C.jboolean {
+ if *x == false {
+ return 0
+ }
+ return 1
+}
+
func newVBytesFromJava(env *C.JNIEnv, array C.jbyteArray) C.v23_syncbase_Bytes {
r := C.v23_syncbase_Bytes{}
n := C.GetArrayLength(env, array)
@@ -34,8 +44,6 @@
return r
}
-// extractToJava constructs a jbyteArray from a v23_syncbase_Bytes. The pointer
-// inside v23_syncbase_Bytes will be freed.
func (x *C.v23_syncbase_Bytes) extractToJava(env *C.JNIEnv) C.jbyteArray {
obj := C.NewByteArray(env, C.jsize(x.n))
if C.ExceptionOccurred(env) != nil {
@@ -49,7 +57,7 @@
return obj
}
-// newVIdFromJava creates a v23_syncbase_Id from a jobject.
+// newVIdFromJava creates a v23_syncbase_Id from an Id object.
func newVIdFromJava(env *C.JNIEnv, obj C.jobject) C.v23_syncbase_Id {
blessing := C.jstring(C.GetObjectField(env, obj, idClass.blessing))
if C.ExceptionOccurred(env) != nil {
@@ -73,6 +81,9 @@
// UTF-8 strings (inner nulls are encoded as 0xC0, 0x80 and the string is
// terminated with a null).
func (x *C.v23_syncbase_String) extractToJava(env *C.JNIEnv) C.jstring {
+ if x.p == nil {
+ return nil
+ }
n := int(x.n)
srcPtr := uintptr(unsafe.Pointer(x.p))
numNulls := 0
@@ -103,7 +114,6 @@
return r
}
-// newVStringFromJava creates a v23_syncbase_String from a jstring.
func newVStringFromJava(env *C.JNIEnv, s C.jstring) C.v23_syncbase_String {
r := C.v23_syncbase_String{}
if s == nil {
@@ -149,7 +159,7 @@
}
// newVSyncgroupMemberInfoFromJava creates a v23_syncbase_SyncgroupMemberInfo
-// from a jobject.
+// from a SyncgroupMemberInfo object.
func newVSyncgroupMemberInfoFromJava(env *C.JNIEnv, obj C.jobject) C.v23_syncbase_SyncgroupMemberInfo {
syncPriority := C.GetIntField(env, obj, syncgroupMemberInfoClass.syncPriority)
if C.ExceptionOccurred(env) != nil {
@@ -165,7 +175,8 @@
}
}
-// newVSyngroupSpecFromJava creates a v23_syncbase_SyncgroupSpec from a jobject.
+// newVSyngroupSpecFromJava creates a v23_syncbase_SyncgroupSpec from a
+// SyncgroupSpec object.
func newVSyngroupSpecFromJava(env *C.JNIEnv, obj C.jobject) C.v23_syncbase_SyncgroupSpec {
description := C.jstring(C.GetObjectField(env, obj, syncgroupSpecClass.description))
if C.ExceptionOccurred(env) != nil {
@@ -199,3 +210,17 @@
mountTables: mountTablesStrings,
}
}
+
+// newVSyngroupSpecAndVersionFromJava creates a v23_syncbase_SyncgroupSpec and
+// v23_syncbase_String version string from a VersionedSyncgroupSpec object.
+func newVSyngroupSpecAndVersionFromJava(env *C.JNIEnv, obj C.jobject) (C.v23_syncbase_SyncgroupSpec, C.v23_syncbase_String) {
+ version := C.jstring(C.GetObjectField(env, obj, versionedSyncgroupSpecClass.version))
+ if C.ExceptionOccurred(env) != nil {
+ panic("newVSyngroupSpecAndVersionFromJava exception while retrieving VersionedSyncgroupSpec.version")
+ }
+ spec := newVSyngroupSpecFromJava(env, C.GetObjectField(env, obj, versionedSyncgroupSpecClass.syncgroupSpec))
+ if C.ExceptionOccurred(env) != nil {
+ panic("newVSyngroupSpecAndVersionFromJava exception while retrieving VersionedSyncgroupSpec.syncgroupSpec")
+ }
+ return spec, newVStringFromJava(env, version)
+}
diff --git a/services/syncbase/bridge/cgo/jni_wrapper.c b/services/syncbase/bridge/cgo/jni_wrapper.c
index be8f139..bb00584 100644
--- a/services/syncbase/bridge/cgo/jni_wrapper.c
+++ b/services/syncbase/bridge/cgo/jni_wrapper.c
@@ -14,6 +14,10 @@
return (*env)->CallObjectMethod(env,obj,methodID);
}
+jobject CallObjectMethodA(JNIEnv *env, jobject obj, jmethodID methodID, jvalue *args) {
+ return (*env)->CallObjectMethodA(env, obj, methodID, args);
+}
+
void ExceptionClear(JNIEnv *env) {
(*env)->ExceptionClear(env);
}
@@ -78,6 +82,10 @@
return (*env)->NewObjectA(env, cls, methodID, args);
}
+void SetBooleanField(JNIEnv *env, jobject obj, jfieldID fieldID, jboolean value) {
+ return (*env)->SetBooleanField(env, obj, fieldID, value);
+}
+
void SetByteArrayRegion(JNIEnv *env, jbyteArray array, jsize start, jsize len, jbyte *buf) {
return (*env)->SetByteArrayRegion(env, array, start, len, buf);
}
@@ -86,6 +94,10 @@
(*env)->SetLongField(env, obj, fieldID, value);
}
+void SetByteField(JNIEnv *env, jobject obj, jfieldID fieldID, jbyte value) {
+ (*env)->SetByteField(env, obj, fieldID, value);
+}
+
jbyteArray NewByteArray(JNIEnv *env, jsize length) {
return (*env)->NewByteArray(env, length);
}
diff --git a/services/syncbase/bridge/cgo/jni_wrapper.h b/services/syncbase/bridge/cgo/jni_wrapper.h
index a4ba834..36be6c8 100644
--- a/services/syncbase/bridge/cgo/jni_wrapper.h
+++ b/services/syncbase/bridge/cgo/jni_wrapper.h
@@ -13,6 +13,7 @@
jboolean CallBooleanMethodA(JNIEnv *env, jobject obj, jmethodID methodID, jvalue *args);
jobject CallIntMethod(JNIEnv *env, jobject obj, jmethodID methodID);
jobject CallObjectMethod(JNIEnv *env, jobject obj, jmethodID methodID);
+jobject CallObjectMethodA(JNIEnv *env, jobject obj, jmethodID methodID, jvalue *args);
void ExceptionClear(JNIEnv *env);
jthrowable ExceptionOccurred(JNIEnv* env);
jclass FindClass(JNIEnv* env, const char* name);
@@ -31,6 +32,8 @@
jobject NewGlobalRef(JNIEnv* env, jobject obj);
jobject NewObjectA(JNIEnv *env, jclass cls, jmethodID methodID, jvalue *args);
jstring NewStringUTF(JNIEnv *env, const char *bytes);
+void SetBooleanField(JNIEnv *env, jobject obj, jfieldID fieldID, jboolean value);
+void SetByteField(JNIEnv *env, jobject obj, jfieldID fieldID, jbyte value);
void SetByteArrayRegion(JNIEnv *env, jbyteArray array, jsize start, jsize len, jbyte *buf);
void SetLongField(JNIEnv *env, jobject obj, jfieldID fieldID, jlong value);
void SetObjectField(JNIEnv *env, jobject obj, jfieldID fieldID, jobject value);
diff --git a/services/syncbase/bridge/cgo/types.go b/services/syncbase/bridge/cgo/types.go
index 73a4ed9..a7b645c 100644
--- a/services/syncbase/bridge/cgo/types.go
+++ b/services/syncbase/bridge/cgo/types.go
@@ -293,6 +293,18 @@
return res
}
+func (x *C.v23_syncbase_Strings) free() {
+ if x.p == nil {
+ return
+ }
+ for i := 0; i < int(x.n); i++ {
+ x.at(i).free()
+ }
+ C.free(unsafe.Pointer(x.p))
+ x.p = nil
+ x.n = 0
+}
+
////////////////////////////////////////////////////////////
// C.v23_syncbase_SyncgroupSpec
@@ -353,6 +365,28 @@
}
}
+func (x *C.v23_syncbase_SyncgroupMemberInfoMap) free() {
+ if x.n == 0 {
+ return
+ }
+ if x.keys == nil {
+ panic("v23_syncbase_SyncgroupMemberInfoMap keys corruption")
+ }
+ if x.values == nil {
+ panic("v23_syncbase_SyncgroupMemberInfoMap values corruption")
+ }
+ for i := 0; i < int(x.n); i++ {
+ // The values don't contain pointers.
+ k, _ := x.at(i)
+ k.free()
+ }
+ C.free(unsafe.Pointer(x.keys))
+ C.free(unsafe.Pointer(x.values))
+ x.keys = nil
+ x.values = nil
+ x.n = 0
+}
+
////////////////////////////////////////////////////////////
// C.v23_syncbase_VError