Plumbing additional RPC options
MultiPart: 2/3
Change-Id: I7becc9b76f8b0b0c3ccc9990468794ec4dd6491c
diff --git a/impl/google/namespace/jni.go b/impl/google/namespace/jni.go
index d315f27..35b542e 100644
--- a/impl/google/namespace/jni.go
+++ b/impl/google/namespace/jni.go
@@ -30,7 +30,7 @@
// Global reference for io.v.v23.naming.GlobReply class.
jGlobReplyClass jutil.Class
// Global reference for io.v.v23.naming.MountEntry class.
- jMountEntryClass jutil.Class
+ JMountEntryClass jutil.Class
// Global reference for io.v.v23.security.access.Permissions
jPermissionsClass jutil.Class
)
@@ -47,7 +47,7 @@
if err != nil {
return err
}
- jMountEntryClass, err = jutil.JFindClass(env, "io/v/v23/naming/MountEntry")
+ JMountEntryClass, err = jutil.JFindClass(env, "io/v/v23/naming/MountEntry")
if err != nil {
return err
}
@@ -219,7 +219,7 @@
}
env, freeFunc := jutil.GetEnv()
defer freeFunc()
- jEntry, err := jutil.JVomCopy(env, entry, jMountEntryClass)
+ jEntry, err := jutil.JVomCopy(env, entry, JMountEntryClass)
if err != nil {
return jutil.NullObject, err
}
@@ -263,7 +263,7 @@
}
env, freeFunc := jutil.GetEnv()
defer freeFunc()
- jEntry, err := jutil.JVomCopy(env, entry, jMountEntryClass)
+ jEntry, err := jutil.JVomCopy(env, entry, JMountEntryClass)
if err != nil {
return jutil.NullObject, err
}
diff --git a/impl/google/rpc/jni.go b/impl/google/rpc/jni.go
index 549b4de..05b43a6 100644
--- a/impl/google/rpc/jni.go
+++ b/impl/google/rpc/jni.go
@@ -11,7 +11,6 @@
"unsafe"
"v.io/v23/context"
- "v.io/v23/options"
"v.io/v23/rpc"
"v.io/v23/vdl"
"v.io/v23/verror"
@@ -23,6 +22,7 @@
jutil "v.io/x/jni/util"
jcontext "v.io/x/jni/v23/context"
jnaming "v.io/x/jni/v23/naming"
+ jopts "v.io/x/jni/v23/options"
jsecurity "v.io/x/jni/v23/security"
)
@@ -295,11 +295,11 @@
//export Java_io_v_impl_google_rpc_ClientImpl_nativeStartCall
func Java_io_v_impl_google_rpc_ClientImpl_nativeStartCall(jenv *C.JNIEnv, jClientObj C.jobject, goRef C.jlong,
- jContext C.jobject, jName C.jstring, jMethod C.jstring, jVomArgs C.jobjectArray, jNameResolutionAuthorizerObj,
- jServerAuthorizerObj C.jobject, jCallbackObj C.jobject) {
+ jContext C.jobject, jName C.jstring, jMethod C.jstring, jVomArgs C.jobjectArray, jOptionsObj C.jobject, jCallbackObj C.jobject) {
env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
name := jutil.GoString(env, jutil.Object(uintptr(unsafe.Pointer(jName))))
method := jutil.GoString(env, jutil.Object(uintptr(unsafe.Pointer(jMethod))))
+ jOptions := jutil.Object(uintptr(unsafe.Pointer(jOptionsObj)))
jCallback := jutil.Object(uintptr(unsafe.Pointer(jCallbackObj)))
ctx, cancel, err := jcontext.GoContext(env, jutil.Object(uintptr(unsafe.Pointer(jContext))))
if err != nil {
@@ -311,25 +311,13 @@
jutil.CallbackOnFailure(env, jCallback, err)
return
}
- var opts []rpc.CallOpt
- jNameResolutionAuthorizer := jutil.Object(uintptr(unsafe.Pointer(jNameResolutionAuthorizerObj)))
- if !jNameResolutionAuthorizer.IsNull() {
- auth, err := jsecurity.GoAuthorizer(env, jNameResolutionAuthorizer)
- if err != nil {
- jutil.CallbackOnFailure(env, jCallback, err)
- return
- }
- opts = append(opts, options.NameResolutionAuthorizer{auth})
+
+ opts, err := jopts.GoRpcOpts(env, jOptions)
+ if err != nil {
+ jutil.CallbackOnFailure(env, jCallback, err)
+ return
}
- jServerAuthorizer := jutil.Object(uintptr(unsafe.Pointer(jServerAuthorizerObj)))
- if !jServerAuthorizer.IsNull() {
- auth, err := jsecurity.GoAuthorizer(env, jServerAuthorizer)
- if err != nil {
- jutil.CallbackOnFailure(env, jCallback, err)
- return
- }
- opts = append(opts, options.ServerAuthorizer{auth})
- }
+
// Create a global reference to the client object for the duration of the call
// so that the java object doesn't get garbage collected while the async call
// is happening. This is an issue because if the java object is garbage collected,
diff --git a/impl/google/rt/jni.go b/impl/google/rt/jni.go
index d6732f4..0429ed0 100644
--- a/impl/google/rt/jni.go
+++ b/impl/google/rt/jni.go
@@ -11,13 +11,13 @@
"v.io/v23"
"v.io/v23/context"
- "v.io/v23/options"
jdiscovery "v.io/x/jni/impl/google/discovery"
jns "v.io/x/jni/impl/google/namespace"
jrpc "v.io/x/jni/impl/google/rpc"
jutil "v.io/x/jni/util"
jcontext "v.io/x/jni/v23/context"
+ jopts "v.io/x/jni/v23/options"
jsecurity "v.io/x/jni/v23/security"
)
@@ -119,7 +119,7 @@
}
//export Java_io_v_impl_google_rt_VRuntimeImpl_nativeWithNewServer
-func Java_io_v_impl_google_rt_VRuntimeImpl_nativeWithNewServer(jenv *C.JNIEnv, jRuntime C.jclass, jContext C.jobject, jName C.jstring, jDispatcher C.jobject, jLameDuck C.jobject) C.jobject {
+func Java_io_v_impl_google_rt_VRuntimeImpl_nativeWithNewServer(jenv *C.JNIEnv, jRuntime C.jclass, jContext C.jobject, jName C.jstring, jDispatcher C.jobject, jOptions C.jobject) C.jobject {
env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
ctx, cancel, err := jcontext.GoContext(env, jutil.Object(uintptr(unsafe.Pointer(jContext))))
if err != nil {
@@ -132,12 +132,12 @@
jutil.JThrowV(env, err)
return nil
}
- timeout, err := jutil.GoDuration(env, jutil.Object(uintptr(unsafe.Pointer(jLameDuck))))
+ opts, err := jopts.GoRpcServerOpts(env, jutil.Object(uintptr(unsafe.Pointer(jOptions))))
if err != nil {
jutil.JThrowV(env, err)
return nil
}
- newCtx, server, err := v23.WithNewDispatchingServer(ctx, name, d, options.LameDuckTimeout(timeout))
+ newCtx, server, err := v23.WithNewDispatchingServer(ctx, name, d, opts...)
if err != nil {
jutil.JThrowV(env, err)
return nil
diff --git a/util/util.go b/util/util.go
index 264c7eb..649625e 100644
--- a/util/util.go
+++ b/util/util.go
@@ -732,6 +732,9 @@
// jFieldID returns the Java field ID for the given object (i.e., non-static)
// field, or an error if the field couldn't be found.
+// TODO(rosswang): Make these exported/cacheable (likely warrants refactor of corresponding
+// GetXField methods)
+// https://rkennke.wordpress.com/2007/07/24/efficient-jni-programming-ii-field-and-method-access/
func jFieldID(env Env, class Class, name string, sign Sign) (C.jfieldID, error) {
cName := C.CString(name)
defer C.free(unsafe.Pointer(cName))
diff --git a/v23/options/rpc_options.go b/v23/options/rpc_options.go
new file mode 100644
index 0000000..aa7b9b9
--- /dev/null
+++ b/v23/options/rpc_options.go
@@ -0,0 +1,148 @@
+// Copyright 2016 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build java android
+
+package options
+
+import (
+ "time"
+
+ "v.io/v23/naming"
+ "v.io/v23/options"
+ "v.io/v23/rpc"
+ "v.io/v23/security"
+
+ jnamespace "v.io/x/jni/impl/google/namespace"
+ jutil "v.io/x/jni/util"
+ jsecurity "v.io/x/jni/v23/security"
+)
+
+// #include "jni.h"
+import "C"
+
+var (
+ authorizerSign = jutil.ClassSign("io.v.v23.security.Authorizer")
+ mountEntrySign = jutil.ClassSign("io.v.v23.naming.MountEntry")
+)
+
+func getAuthorizer(env jutil.Env, obj jutil.Object, field string) (security.Authorizer, error) {
+ jAuthorizer, err := jutil.JObjectField(env, obj, field, authorizerSign)
+ if err != nil {
+ return nil, err
+ }
+
+ if !jAuthorizer.IsNull() {
+ auth, err := jsecurity.GoAuthorizer(env, jAuthorizer)
+ if err != nil {
+ return nil, err
+ }
+ return auth, nil
+ }
+ return nil, nil
+}
+
+func getPreresolved(env jutil.Env, obj jutil.Object) (*naming.MountEntry, error) {
+ jMountEntry, err := jutil.JObjectField(env, obj, "preresolved", mountEntrySign)
+ if err != nil {
+ return nil, err
+ }
+
+ if !jMountEntry.IsNull() {
+ var mountEntry naming.MountEntry
+ if err := jutil.GoVomCopy(env, obj, jnamespace.JMountEntryClass, &mountEntry); err != nil {
+ return nil, err
+ }
+ return &mountEntry, nil
+ }
+ return nil, nil
+}
+
+func getDuration(env jutil.Env, obj jutil.Object, field string) (*time.Duration, error) {
+ jDuration, err := jutil.JObjectField(env, obj, field, jutil.DurationSign)
+ if err != nil {
+ return nil, err
+ }
+
+ if !jDuration.IsNull() {
+ duration, err := jutil.GoDuration(env, jDuration)
+ if err != nil {
+ return nil, err
+ }
+ return &duration, nil
+ }
+ return nil, nil
+}
+
+func GoRpcOpts(env jutil.Env, obj jutil.Object) ([]rpc.CallOpt, error) {
+ var opts []rpc.CallOpt
+
+ if opt, err := getAuthorizer(env, obj, "nameResolutionAuthorizer"); err != nil {
+ return nil, err
+ } else if opt != nil {
+ opts = append(opts, options.NameResolutionAuthorizer{opt})
+ }
+
+ if opt, err := getAuthorizer(env, obj, "serverAuthorizer"); err != nil {
+ return nil, err
+ } else if opt != nil {
+ opts = append(opts, options.ServerAuthorizer{opt})
+ }
+
+ if opt, err := getPreresolved(env, obj); err != nil {
+ return nil, err
+ } else if opt != nil {
+ opts = append(opts, options.Preresolved{opt})
+ }
+
+ if opt, err := jutil.JBoolField(env, obj, "noRetry"); err != nil {
+ return nil, err
+ } else if opt {
+ opts = append(opts, options.NoRetry{})
+ }
+
+ if opt, err := getDuration(env, obj, "connectionTimeout"); err != nil {
+ return nil, err
+ } else if opt != nil {
+ opts = append(opts, options.ConnectionTimeout(*opt))
+ }
+
+ if opt, err := getDuration(env, obj, "channelTimeout"); err != nil {
+ return nil, err
+ } else if opt != nil {
+ opts = append(opts, options.ChannelTimeout(*opt))
+ }
+
+ return opts, nil
+}
+
+func GoRpcServerOpts(env jutil.Env, obj jutil.Object) ([]rpc.ServerOpt, error) {
+ var opts []rpc.ServerOpt
+
+ if opt, err := jutil.JBoolField(env, obj, "servesMountTable"); err != nil {
+ return nil, err
+ } else {
+ opts = append(opts, options.ServesMountTable(opt))
+ }
+
+ if opt, err := getDuration(env, obj, "lameDuckTimeout"); err != nil {
+ return nil, err
+ } else if opt != nil {
+ opts = append(opts, options.LameDuckTimeout(*opt))
+ }
+
+ if opt, err := jutil.JBoolField(env, obj, "isLeaf"); err != nil {
+ return nil, err
+ } else {
+ opts = append(opts, options.IsLeaf(opt))
+ }
+
+ if opt, err := getDuration(env, obj, "channelTimeout"); err != nil {
+ return nil, err
+ } else if opt != nil {
+ opts = append(opts, options.ChannelTimeout(*opt))
+ }
+
+ return opts, nil
+}