v.io/x/jni: support change for mounttable server on java

MultiPart: 2/2
Change-Id: If5ae79766300e61e5e5c0c85031844589da4f8fc
diff --git a/impl/google/jni.go b/impl/google/jni.go
index fd14834..466fbcf 100644
--- a/impl/google/jni.go
+++ b/impl/google/jni.go
@@ -11,7 +11,8 @@
 	jns "v.io/x/jni/impl/google/namespace"
 	jrpc "v.io/x/jni/impl/google/rpc"
 	jrt "v.io/x/jni/impl/google/rt"
-	jsyncbased "v.io/x/jni/impl/google/services/syncbase/syncbased"
+	jsyncbase "v.io/x/jni/impl/google/services/syncbase"
+	jmounttable "v.io/x/jni/impl/google/services/mounttable"
 	jutil "v.io/x/jni/util"
 )
 
@@ -21,7 +22,6 @@
 // Init initializes the JNI code with the given Java environment.  This method
 // must be invoked before any other method in this package and must be called
 // from the main Java thread (e.g., On_Load()).
-// interface and then cast into the package-local environment type.
 func Init(env jutil.Env) error {
 	if err := jrpc.Init(env); err != nil {
 		return err
@@ -35,7 +35,10 @@
 	if err := jns.Init(env); err != nil {
 		return err
 	}
-	if err := jsyncbased.Init(env); err != nil {
+	if err := jmounttable.Init(env); err != nil {
+		return err
+	}
+	if err := jsyncbase.Init(env); err != nil {
 		return err
 	}
 	return nil
diff --git a/impl/google/services/mounttable/jni.go b/impl/google/services/mounttable/jni.go
new file mode 100644
index 0000000..50be231
--- /dev/null
+++ b/impl/google/services/mounttable/jni.go
@@ -0,0 +1,160 @@
+// Copyright 2015 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 mounttable
+
+import (
+	"bufio"
+	"encoding/json"
+	"fmt"
+	"os"
+	"path/filepath"
+	"unsafe"
+
+	"v.io/v23"
+	"v.io/v23/security/access"
+	"v.io/x/ref/services/mounttable/mounttablelib"
+
+	jrpc "v.io/x/jni/impl/google/rpc"
+	jutil "v.io/x/jni/util"
+	jcontext "v.io/x/jni/v23/context"
+	jaccess "v.io/x/jni/v23/security/access"
+	"v.io/v23/options"
+)
+
+// #include "jni.h"
+import "C"
+
+var (
+	permissionsSign           = jutil.ClassSign("io.v.v23.security.access.Permissions")
+	listenSpecSign            = jutil.ClassSign("io.v.v23.rpc.ListenSpec")
+	contextSign               = jutil.ClassSign("io.v.v23.context.VContext")
+	serverSign                = jutil.ClassSign("io.v.v23.rpc.Server")
+
+	jSystemClass jutil.Class
+	jVClass      jutil.Class
+	jVRuntimeImplClass jutil.Class
+)
+
+// Init initializes the JNI code with the given Java environment.  This method
+// must be invoked before any other method in this package and must be called
+// from the main Java thread (e.g., On_Load()).
+func Init(env jutil.Env) error {
+	var err error
+	jSystemClass, err = jutil.JFindClass(env, "java/lang/System")
+	if err != nil {
+		return err
+	}
+	jVClass, err = jutil.JFindClass(env, "io/v/v23/V")
+	if err != nil {
+		return err
+	}
+	jVRuntimeImplClass, err = jutil.JFindClass(env, "io/v/impl/google/rt/VRuntimeImpl")
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+//export Java_io_v_impl_google_services_mounttable_MountTableServer_nativeWithNewServer
+func Java_io_v_impl_google_services_mounttable_MountTableServer_nativeWithNewServer(jenv *C.JNIEnv, jMountTableServerClass C.jclass, jContext C.jobject, jMountTableServerParams C.jobject) C.jobject {
+	env := jutil.WrapEnv(jenv)
+	jCtx := jutil.WrapObject(jContext)
+	jParams := jutil.WrapObject(jMountTableServerParams)
+
+	// Read and translate all of the server params.
+	mountName, err := jutil.CallStringMethod(env, jParams, "getName", nil)
+	if err != nil {
+		jutil.JThrowV(env, err)
+		return nil
+	}
+	rootDir, err := jutil.CallStringMethod(env, jParams, "getStorageRootDir", nil)
+	if err != nil {
+		jutil.JThrowV(env, err)
+		return nil
+	}
+	if rootDir == "" {
+		rootDir, err = jutil.CallStaticStringMethod(env, jSystemClass, "getProperty", []jutil.Sign{jutil.StringSign}, "java.io.tmpdir")
+		if err != nil {
+			jutil.JThrowV(env, err)
+			return nil
+		}
+	}
+	permsJMap, err := jutil.CallMapMethod(env, jParams, "getPermissions", nil)
+	if err != nil {
+		jutil.JThrowV(env, err)
+		return nil
+	}
+	permsMap := make(map[string]access.Permissions)
+	for jPath, jPerms := range permsJMap {
+		path := jutil.GoString(env, jPath)
+		perms, err := jaccess.GoPermissions(env, jPerms)
+		if err != nil {
+			jutil.JThrowV(env, err)
+			return nil
+		}
+		permsMap[path] = perms
+	}
+	// Write JSON-encoded permissions to a file.
+	jsonPerms, err := json.Marshal(permsMap)
+	if err != nil {
+		jutil.JThrowV(env, fmt.Errorf("Couldn't JSON-encode path-permissions: %v", err))
+		return nil
+
+	}
+	permsFile, err := os.Create(filepath.Join(rootDir, "jni_permissions"))
+	if err != nil {
+		jutil.JThrowV(env, fmt.Errorf("Couldn't create permissions file: %v", err))
+		return nil
+	}
+	w := bufio.NewWriter(permsFile)
+	if _, err := w.Write(jsonPerms); err != nil {
+		jutil.JThrowV(env, fmt.Errorf("Couldn't write to permissions file: %v", err))
+		return nil
+	}
+	if err := w.Flush(); err != nil {
+		jutil.JThrowV(env, fmt.Errorf("Couldn't flush to permissions file: %v", err))
+	}
+	statsPrefix, err := jutil.CallStringMethod(env, jParams, "getStatsPrefix", nil)
+	if err != nil {
+		jutil.JThrowV(env, err)
+		return nil
+	}
+
+	// Start the mounttable server.
+	ctx, err := jcontext.GoContext(env, jCtx)
+	if err != nil {
+		jutil.JThrowV(env, err)
+		return nil
+	}
+	d, err := mounttablelib.NewMountTableDispatcher(ctx, permsFile.Name(), rootDir, statsPrefix)
+	if err != nil {
+		jutil.JThrowV(env, err)
+		return nil
+	}
+	newCtx, s, err := v23.WithNewDispatchingServer(ctx, mountName, d, options.ServesMountTable(true))
+	if err != nil {
+		jutil.JThrowV(env, err)
+		return nil
+	}
+	jNewCtx, err := jcontext.JavaContext(env, newCtx, nil)
+	if err != nil {
+		jutil.JThrowV(env, err)
+		return nil
+	}
+	jServer, err := jrpc.JavaServer(env, s)
+	if err != nil {
+		jutil.JThrowV(env, err)
+		return nil
+	}
+	// Attach a server to the new context.
+	jServerAttCtx, err := jutil.CallStaticObjectMethod(env, jVRuntimeImplClass, "withServer", []jutil.Sign{contextSign, serverSign}, contextSign, jNewCtx, jServer)
+	if err != nil {
+		jutil.JThrowV(env, err)
+		return nil
+	}
+	return C.jobject(unsafe.Pointer(jServerAttCtx))
+}
diff --git a/impl/google/services/syncbase/syncbased/jni.go b/impl/google/services/syncbase/jni.go
similarity index 83%
rename from impl/google/services/syncbase/syncbased/jni.go
rename to impl/google/services/syncbase/jni.go
index 964c8cd..545bda7 100644
--- a/impl/google/services/syncbase/syncbased/jni.go
+++ b/impl/google/services/syncbase/jni.go
@@ -4,7 +4,7 @@
 
 // +build java android
 
-package syncbased
+package syncbase
 
 import (
 	"unsafe"
@@ -25,7 +25,7 @@
 	permissionsSign           = jutil.ClassSign("io.v.v23.security.access.Permissions")
 	listenSpecSign            = jutil.ClassSign("io.v.v23.rpc.ListenSpec")
 	contextSign               = jutil.ClassSign("io.v.v23.context.VContext")
-	syncbaseStorageEngineSign = jutil.ClassSign("io.v.v23.syncbase.SyncbaseStorageEngine")
+	storageEngineSign         = jutil.ClassSign("io.v.impl.google.services.syncbase.SyncbaseServer$StorageEngine")
 	serverSign                = jutil.ClassSign("io.v.v23.rpc.Server")
 
 	jSystemClass jutil.Class
@@ -33,6 +33,9 @@
 	jVRuntimeImplClass jutil.Class
 )
 
+// Init initializes the JNI code with the given Java environment.  This method
+// must be invoked before any other method in this package and must be called
+// from the main Java thread (e.g., On_Load()).
 func Init(env jutil.Env) error {
 	var err error
 	jSystemClass, err = jutil.JFindClass(env, "java/lang/System")
@@ -50,8 +53,8 @@
 	return nil
 }
 
-//export Java_io_v_impl_google_services_syncbase_syncbased_SyncbaseServer_nativeWithNewServer
-func Java_io_v_impl_google_services_syncbase_syncbased_SyncbaseServer_nativeWithNewServer(jenv *C.JNIEnv, jSyncbaseServerClass C.jclass, jContext C.jobject, jSyncbaseServerParams C.jobject) C.jobject {
+//export Java_io_v_impl_google_services_syncbase_SyncbaseServer_nativeWithNewServer
+func Java_io_v_impl_google_services_syncbase_SyncbaseServer_nativeWithNewServer(jenv *C.JNIEnv, jSyncbaseServerClass C.jclass, jContext C.jobject, jSyncbaseServerParams C.jobject) C.jobject {
 	env := jutil.WrapEnv(jenv)
 	jCtx := jutil.WrapObject(jContext)
 	jParams := jutil.WrapObject(jSyncbaseServerParams)
@@ -84,7 +87,7 @@
 			return nil
 		}
 	}
-	jEngine, err := jutil.CallObjectMethod(env, jParams, "getStorageEngine", nil, syncbaseStorageEngineSign)
+	jEngine, err := jutil.CallObjectMethod(env, jParams, "getStorageEngine", nil, storageEngineSign)
 	if err != nil {
 		jutil.JThrowV(env, err)
 		return nil
diff --git a/impl/google/services/syncbase/syncbased/util.go b/impl/google/services/syncbase/util.go
similarity index 95%
rename from impl/google/services/syncbase/syncbased/util.go
rename to impl/google/services/syncbase/util.go
index 8f8daee..44a21e8 100644
--- a/impl/google/services/syncbase/syncbased/util.go
+++ b/impl/google/services/syncbase/util.go
@@ -4,7 +4,7 @@
 
 // +build java android
 
-package syncbased
+package syncbase
 
 import (
 	jutil "v.io/x/jni/util"