java: Add an initial implementation for testWatch and testRunInBatch
To get the tests to work this change also finish properly exposing the
v23_syncbase_WatchChange.
MultiPart: 1/2
Change-Id: I3ce4f4b11791a993f3ba0af1ba1a1ce541d887e8
diff --git a/services/syncbase/bridge/cgo/jni.go b/services/syncbase/bridge/cgo/jni.go
index eda5486..3b9dec8 100644
--- a/services/syncbase/bridge/cgo/jni.go
+++ b/services/syncbase/bridge/cgo/jni.go
@@ -49,6 +49,7 @@
var (
jVM *C.JavaVM
arrayListClass jArrayListClass
+ changeTypeClass jChangeType
collectionRowPatternClass jCollectionRowPattern
hashMapClass jHashMap
idClass jIdClass
@@ -77,6 +78,7 @@
jVM = vm
arrayListClass = newJArrayListClass(env)
+ changeTypeClass = newJChangeType(env)
collectionRowPatternClass = newJCollectionRowPattern(env)
hashMapClass = newJHashMap(env)
idClass = newJIdClass(env)
@@ -380,20 +382,17 @@
//export v23_syncbase_internal_onChange
func v23_syncbase_internal_onChange(handle C.v23_syncbase_Handle, change C.v23_syncbase_WatchChange) {
- // TODO(razvanm): Remove the panic and uncomment the code from below
- // after the onChange starts working.
- panic("v23_syncbase_internal_onChange not implemented")
- //id := uint64(uintptr(handle))
- //h := globalRrefMap.Get(id).(*watchPatternsCallbacksHandle)
- //env, free := getEnv()
- //obj := change.extractToJava(env)
- //arg := *(*C.jvalue)(unsafe.Pointer(&obj))
- //C.CallVoidMethodA(env, C.jobject(unsafe.Pointer(h.obj)), h.callbacks.onChange, &arg)
- //if C.ExceptionOccurred(env) != nil {
- // C.ExceptionDescribe(env)
- // panic("java exception")
- //}
- //free()
+ id := uint64(uintptr(handle))
+ h := globalRefMap.Get(id).(*watchPatternsCallbacksHandle)
+ env, free := getEnv()
+ obj := change.extractToJava(env)
+ arg := *(*C.jvalue)(unsafe.Pointer(&obj))
+ C.CallVoidMethodA(env, C.jobject(unsafe.Pointer(h.obj)), h.callbacks.onChange, &arg)
+ if C.ExceptionOccurred(env) != nil {
+ C.ExceptionDescribe(env)
+ panic("java exception")
+ }
+ free()
}
//export v23_syncbase_internal_onError
@@ -646,6 +645,17 @@
// All the extractToJava methods return Java types and deallocate all the
// pointers inside v23_syncbase_* variable.
+func (x *C.v23_syncbase_ChangeType) extractToJava(env *C.JNIEnv) C.jobject {
+ var obj C.jobject
+ switch *x {
+ case C.v23_syncbase_ChangeTypePut:
+ obj = C.GetStaticObjectField(env, changeTypeClass.class, changeTypeClass.put)
+ case C.v23_syncbase_ChangeTypeDelete:
+ obj = C.GetStaticObjectField(env, changeTypeClass.class, changeTypeClass.delete)
+ }
+ return obj
+}
+
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))
@@ -809,6 +819,18 @@
return obj
}
+func (x *C.v23_syncbase_WatchChange) extractToJava(env *C.JNIEnv) C.jobject {
+ obj := C.NewObjectA(env, watchChangeClass.class, watchChangeClass.init, nil)
+ C.SetObjectField(env, obj, watchChangeClass.collection, x.collection.extractToJava(env))
+ C.SetObjectField(env, obj, watchChangeClass.row, x.row.extractToJava(env))
+ C.SetObjectField(env, obj, watchChangeClass.changeType, x.changeType.extractToJava(env))
+ C.SetObjectField(env, obj, watchChangeClass.value, x.value.extractToJava(env))
+ C.SetObjectField(env, obj, watchChangeClass.resumeMarker, x.resumeMarker.extractToJava(env))
+ C.SetBooleanField(env, obj, watchChangeClass.fromSync, x.fromSync.extractToJava())
+ C.SetBooleanField(env, obj, watchChangeClass.continued, x.continued.extractToJava())
+ return obj
+}
+
// newVCollectionRowPatternsFromJava creates a
// v23_syncbase_CollectionRowPatterns from a List<CollectionRowPattern>.
func newVCollectionRowPatternsFromJava(env *C.JNIEnv, obj C.jobject) C.v23_syncbase_CollectionRowPatterns {
diff --git a/services/syncbase/bridge/cgo/jni_lib.go b/services/syncbase/bridge/cgo/jni_lib.go
index 7a720c7..1169ef6 100644
--- a/services/syncbase/bridge/cgo/jni_lib.go
+++ b/services/syncbase/bridge/cgo/jni_lib.go
@@ -287,15 +287,34 @@
}
}
+type jChangeType struct {
+ class C.jclass
+ put C.jfieldID
+ delete C.jfieldID
+}
+
+func newJChangeType(env *C.JNIEnv) jChangeType {
+ cls := findClass(env, "io/v/syncbase/core/WatchChange$ChangeType")
+ return jChangeType{
+ class: cls,
+ put: jGetStaticFieldID(env, cls, "PUT", "Lio/v/syncbase/core/WatchChange$ChangeType;"),
+ delete: jGetStaticFieldID(env, cls, "DELETE", "Lio/v/syncbase/core/WatchChange$ChangeType;"),
+ }
+}
+
// 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) {
+ cls := findClass(env, name)
+ return cls, jGetMethodID(env, cls, "<init>", "()V")
+}
+
+func findClass(env *C.JNIEnv, name string) C.jclass {
cls, err := jFindClass(env, name)
if err != nil {
// The invariant is that we only deal with classes that must be
// known to the JVM. A panic indicates a bug in our code.
panic(err)
}
- init := jGetMethodID(env, cls, "<init>", "()V")
- return cls, init
+ return cls
}
diff --git a/services/syncbase/bridge/cgo/jni_util.go b/services/syncbase/bridge/cgo/jni_util.go
index 1baf81d..e2fdc34 100644
--- a/services/syncbase/bridge/cgo/jni_util.go
+++ b/services/syncbase/bridge/cgo/jni_util.go
@@ -52,6 +52,23 @@
return field
}
+func jGetStaticFieldID(env *C.JNIEnv, cls C.jclass, name, sig string) C.jfieldID {
+ cName := C.CString(name)
+ defer C.free(unsafe.Pointer(cName))
+
+ cSig := C.CString(sig)
+ defer C.free(unsafe.Pointer(cSig))
+
+ field := C.GetStaticFieldID(env, cls, cName, cSig)
+ if field == nil {
+ panic(fmt.Sprintf("couldn't get field %q with signature %s", name, sig))
+ }
+
+ // Note: the validity of the field is bounded by the lifetime of the
+ // ClassLoader that did the loading of the class.
+ return field
+}
+
// The function from below was hoisted from jni/util/util.go and adapted to not
// use custom types.
diff --git a/services/syncbase/bridge/cgo/jni_wrapper.c b/services/syncbase/bridge/cgo/jni_wrapper.c
index 4e36f47..9fafc41 100644
--- a/services/syncbase/bridge/cgo/jni_wrapper.c
+++ b/services/syncbase/bridge/cgo/jni_wrapper.c
@@ -74,6 +74,15 @@
return (*env)->GetObjectField(env, obj, fieldID);
}
+jfieldID GetStaticFieldID(JNIEnv *env, jclass cls, const char *name, const char *sig) {
+ return (*env)->GetStaticFieldID(env, cls, name, sig);
+}
+
+jobject GetStaticObjectField(JNIEnv *env, jclass cls, jfieldID fieldID)
+{
+ return (*env)->GetStaticObjectField(env, cls, fieldID);
+}
+
jsize GetStringLength(JNIEnv *env, jstring string) {
return (*env)->GetStringLength(env, string);
}
diff --git a/services/syncbase/bridge/cgo/jni_wrapper.h b/services/syncbase/bridge/cgo/jni_wrapper.h
index a322045..8955790 100644
--- a/services/syncbase/bridge/cgo/jni_wrapper.h
+++ b/services/syncbase/bridge/cgo/jni_wrapper.h
@@ -30,6 +30,8 @@
jmethodID GetMethodID(JNIEnv* env, jclass cls, const char* name, const char* sig);
jclass GetObjectClass(JNIEnv *env, jobject obj);
jobject GetObjectField(JNIEnv *env, jobject obj, jfieldID fieldID);
+jfieldID GetStaticFieldID(JNIEnv *env, jclass cls, const char *name, const char *sig);
+jobject GetStaticObjectField(JNIEnv *env, jclass cls, jfieldID fieldID);
jsize GetStringLength(JNIEnv *env, jstring string);
jsize GetStringUTFLength(JNIEnv *env, jstring string);
void GetStringUTFRegion(JNIEnv *env, jstring str, jsize start, jsize len, char *buf);