Merge "Fix bug trying to access wrong method over JNI & support multiple services in arg getter"
diff --git a/runtimes/google/ipc/jni/arg_getter.go b/runtimes/google/ipc/jni/arg_getter.go
index 7540bd3..fc6bf3b 100644
--- a/runtimes/google/ipc/jni/arg_getter.go
+++ b/runtimes/google/ipc/jni/arg_getter.go
@@ -24,8 +24,8 @@
registerInterface((*proximity.ProximityAnnouncerService)(nil))
}
-// A list of all registered argGetter-s.
-var register map[string]*argGetter = make(map[string]*argGetter)
+// A list of all registered serviceArgGetter-s.
+var register map[string]*serviceArgGetter = make(map[string]*serviceArgGetter)
// registerInterface registers the provided VDL client or server interface
// so that its methods' arguments can be created on-the-fly.
@@ -81,7 +81,7 @@
methods[m.Name] = append(methods[m.Name], &mArgs)
}
path := path.Join(t.PkgPath(), t.Name())
- register[path] = &argGetter{
+ register[path] = &serviceArgGetter{
methods: methods,
vdlPath: path,
}
@@ -115,19 +115,47 @@
return nil
}
-// newArgGetter returns the argument getter for the provided VDL interface.
-func newArgGetter(vdlIfacePath string) *argGetter {
- return register[vdlIfacePath]
-}
-
-// argGetter serves method arguments for a specific interface.
-type argGetter struct {
+// serviceArgGetter serves method arguments for a specific service.
+type serviceArgGetter struct {
methods map[string][]*methodArgs
vdlPath string
}
+func (sag *serviceArgGetter) String() (ret string) {
+ ret = "VDLPath: " + sag.vdlPath
+ for k, v := range sag.methods {
+ for _, m := range v {
+ ret += "; "
+ ret += fmt.Sprintf("Method: %s, Args: %v", k, m)
+ }
+ }
+ return
+}
+
+// argGetter serves method arguments for a service object.
+// (which may implement multiple services)
+type argGetter struct {
+ methods map[string][]*methodArgs
+}
+
+// newArgGetter returns the argument getter for the provided service object.
+func newArgGetter(paths []string) (*argGetter, error) {
+ ag := &argGetter{
+ methods: make(map[string][]*methodArgs),
+ }
+ for _, path := range paths {
+ sag := register[path]
+ if sag == nil {
+ return nil, fmt.Errorf("unknown service %s", path)
+ }
+ for method, args := range sag.methods {
+ ag.methods[method] = args
+ }
+ }
+ return ag, nil
+}
+
func (ag *argGetter) String() (ret string) {
- ret = "VDLPath: " + ag.vdlPath
for k, v := range ag.methods {
for _, m := range v {
ret += "; "
@@ -154,9 +182,6 @@
return m
}
-// argGetters is a cache of created argument getters, keyed by VDL interface path.
-var argGetters map[string]*argGetter = make(map[string]*argGetter)
-
// method contains argument type information for a method belonging to an interface.
type methodArgs struct {
inTypes []reflect.Type
diff --git a/runtimes/google/ipc/jni/client.go b/runtimes/google/ipc/jni/client.go
index 58b446c..c55adff 100644
--- a/runtimes/google/ipc/jni/client.go
+++ b/runtimes/google/ipc/jni/client.go
@@ -38,13 +38,13 @@
}
// Get argument instances that correspond to the provided method.
vdlPackagePath := strings.Join(strings.Split(goString(env, jPath), ".")[1:], "/")
- getter := newArgGetter(vdlPackagePath)
- if getter == nil {
- return nil, fmt.Errorf("couldn't find VDL interface corresponding to path %q", vdlPackagePath)
+ getter, err := newArgGetter([]string{vdlPackagePath})
+ if err != nil {
+ return nil, err
}
mArgs := getter.FindMethod(method, len(argStrs))
if mArgs == nil {
- return nil, fmt.Errorf("couldn't find method %s with %d args in VDL interface at path %q, getter: %v", method, len(argStrs), goString(env, jPath), getter)
+ return nil, fmt.Errorf("couldn't find method %s with %d args in VDL interface at path %q", method, len(argStrs), goString(env, jPath))
}
argptrs := mArgs.InPtrs()
if len(argptrs) != len(argStrs) {
diff --git a/runtimes/google/ipc/jni/invoker.go b/runtimes/google/ipc/jni/invoker.go
index 12d8c57..5835d86 100644
--- a/runtimes/google/ipc/jni/invoker.go
+++ b/runtimes/google/ipc/jni/invoker.go
@@ -6,7 +6,6 @@
"encoding/json"
"fmt"
"runtime"
- "strings"
"veyron2/ipc"
"veyron2/security"
@@ -42,12 +41,12 @@
return nil, fmt.Errorf("error creating Java VDLInvoker object: %v", err)
}
// Fetch the argGetter for the object.
- pid := jMethodID(env, jVDLInvokerClass, "getInterfacePath", fmt.Sprintf("()%s", stringSign))
- jPath := C.jstring(C.CallGetInterfacePath(env, jInvoker, pid))
- vdlPackagePath := strings.Join(strings.Split(goString(env, jPath), ".")[1:], "/")
- getter := newArgGetter(vdlPackagePath)
- if getter == nil {
- return nil, fmt.Errorf("couldn't find VDL interface corresponding to path %q", vdlPackagePath)
+ pid := jMethodID(env, jVDLInvokerClass, "getImplementedServices", fmt.Sprintf("()%s", arraySign(stringSign)))
+ jPathArray := C.jobjectArray(C.CallGetInterfacePath(env, jInvoker, pid))
+ paths := goStringArray(env, jPathArray)
+ getter, err := newArgGetter(paths)
+ if err != nil {
+ return nil, err
}
// Reference Java invoker; it will be de-referenced when the go invoker
// created below is garbage-collected (through the finalizer callback we
diff --git a/runtimes/google/ipc/jni/util.go b/runtimes/google/ipc/jni/util.go
index b122926..d87f3bd 100644
--- a/runtimes/google/ipc/jni/util.go
+++ b/runtimes/google/ipc/jni/util.go
@@ -35,6 +35,10 @@
objectSign = "Ljava/lang/Object;"
)
+func arraySign(sign string) string {
+ return "[" + sign
+}
+
// refs stores references to instances of various Go types, namely instances
// that are referenced only by the Java code. The only purpose of this store
// is to prevent Go runtime from garbage collecting those instances.
@@ -96,6 +100,19 @@
return C.NewStringUTF(env, cString)
}
+// goStringArray converts a Java string array to a go string array.
+func goStringArray(env *C.JNIEnv, jStrArray C.jobjectArray) []string {
+ if jStrArray == nil {
+ return nil
+ }
+ length := C.GetArrayLength(env, C.jarray(jStrArray))
+ ret := make([]string, int(length))
+ for i := 0; i < int(length); i++ {
+ ret[i] = goString(env, C.jstring(C.GetObjectArrayElement(env, jStrArray, C.jsize(i))))
+ }
+ return ret
+}
+
// jThrow throws a new Java exception of the provided type with the given message.
func jThrow(env *C.JNIEnv, class C.jclass, msg string) {
s := C.CString(msg)
@@ -165,15 +182,7 @@
defer C.free(unsafe.Pointer(cSig))
fid := C.GetFieldID(env, C.GetObjectClass(env, obj), cField, cSig)
jStrArray := C.jobjectArray(C.GetObjectField(env, obj, fid))
- if jStrArray == nil {
- return nil
- }
- length := C.GetArrayLength(env, C.jarray(jStrArray))
- ret := make([]string, int(length))
- for i := 0; i < int(length); i++ {
- ret[i] = goString(env, C.jstring(C.GetObjectArrayElement(env, jStrArray, C.jsize(i))))
- }
- return ret
+ return goStringArray(env, jStrArray)
}
// jMethodID returns the Java method ID for the given method.