java: Get the DatabaseOptions.rootDir to work

Note that the rootDir is not exposed in the io.v.syncbase.core. The
purpose of this CL is to get all the high-level API tests from
SyncbaseTest to work. This change also adds the ability to shutdown
syncbase. The high-level API tests are reconfigured to use and empty
list of mounts points speed up the shutdown.

MultiPart: 1/3
Change-Id: Iad82088f94a5dc9c0304155648d87df15b88bc55
diff --git a/services/syncbase/bridge/bridge.go b/services/syncbase/bridge/bridge.go
index 4ecaa1a..3abed4d 100644
--- a/services/syncbase/bridge/bridge.go
+++ b/services/syncbase/bridge/bridge.go
@@ -17,13 +17,15 @@
 
 // Bridge object, representing an in-process Syncbase singleton.
 type Bridge struct {
-	Ctx  *context.T
-	srv  rpc.Server
-	disp rpc.Dispatcher
+	Ctx      *context.T
+	Shutdown context.CancelFunc
+	srv      rpc.Server
+	disp     rpc.Dispatcher
+	Cleanup  func()
 }
 
-func NewBridge(ctx *context.T, srv rpc.Server, disp rpc.Dispatcher) *Bridge {
-	return &Bridge{Ctx: ctx, srv: srv, disp: disp}
+func NewBridge(ctx *context.T, shutdown context.CancelFunc, srv rpc.Server, disp rpc.Dispatcher, cleanup func()) *Bridge {
+	return &Bridge{Ctx: ctx, Shutdown: shutdown, srv: srv, disp: disp, Cleanup: cleanup}
 }
 
 func (b *Bridge) NewCtxCall(suffix string, method rpc.MethodDesc) (*context.T, rpc.ServerCall) {
@@ -31,6 +33,11 @@
 	return ctx, newFakeServerCall(ctx, b.srv, suffix, method)
 }
 
+func (b *Bridge) Destroy() {
+	b.Cleanup()
+	b.Shutdown()
+}
+
 ////////////////////////////////////////
 // Dispatch-related methods
 
diff --git a/services/syncbase/bridge/cgo/impl.go b/services/syncbase/bridge/cgo/impl.go
index ffa8b7b..caccb96 100644
--- a/services/syncbase/bridge/cgo/impl.go
+++ b/services/syncbase/bridge/cgo/impl.go
@@ -79,17 +79,27 @@
 )
 
 //export v23_syncbase_Init
-func v23_syncbase_Init(cClientUnderstandVom C.v23_syncbase_Bool) {
+func v23_syncbase_Init(cClientUnderstandVom C.v23_syncbase_Bool, cRootDir C.v23_syncbase_String) {
+	if b != nil {
+		panic("v23_syncbase_Init called again before a v23_syncbase_Shutdown")
+	}
 	// Strip all flags beyond the binary name; otherwise, v23.Init will fail when it encounters
 	// unknown flags passed by Xcode, e.g. NSTreatUnknownArgumentsAsOpen.
 	os.Args = os.Args[:1]
-	// TODO(sadovsky): Support shutdown?
-	ctx, _ := v23.Init()
-	srv, disp, _ := syncbaselib.Serve(ctx, syncbaselib.Opts{})
-	b = bridge.NewBridge(ctx, srv, disp)
+	ctx, shutdown := v23.Init()
+	srv, disp, cleanup := syncbaselib.Serve(ctx, syncbaselib.Opts{RootDir: cRootDir.extract()})
+	b = bridge.NewBridge(ctx, context.CancelFunc(shutdown), srv, disp, cleanup)
 	clientUnderstandsVOM = cClientUnderstandVom.extract()
 }
 
+//export v23_syncbase_Shutdown
+func v23_syncbase_Shutdown() {
+	if b != nil {
+		b.Destroy()
+		b = nil
+	}
+}
+
 ////////////////////////////////////////
 // OAuth
 
diff --git a/services/syncbase/bridge/cgo/jni.go b/services/syncbase/bridge/cgo/jni.go
index b68037a..003ae2a 100644
--- a/services/syncbase/bridge/cgo/jni.go
+++ b/services/syncbase/bridge/cgo/jni.go
@@ -79,7 +79,6 @@
 	}
 	jVM = vm
 
-	v23_syncbase_Init(C.v23_syncbase_Bool(1))
 	arrayListClass = newJArrayListClass(env)
 	collectionRowPatternClass = newJCollectionRowPattern(env)
 	hashMapClass = newJHashMap(env)
@@ -96,6 +95,17 @@
 	return C.JNI_VERSION_1_6
 }
 
+//export Java_io_v_syncbase_internal_Service_Init
+func Java_io_v_syncbase_internal_Service_Init(env *C.JNIEnv, cls C.jclass, initRoot C.jstring) {
+	cInitRoot := newVStringFromJava(env, initRoot)
+	v23_syncbase_Init(C.v23_syncbase_Bool(1), cInitRoot)
+}
+
+//export Java_io_v_syncbase_internal_Service_Shutdown
+func Java_io_v_syncbase_internal_Service_Shutdown(env *C.JNIEnv, cls C.jclass) {
+	v23_syncbase_Shutdown()
+}
+
 //export Java_io_v_syncbase_internal_Service_Login
 func Java_io_v_syncbase_internal_Service_Login(env *C.JNIEnv, cls C.jclass, provider C.jstring, token C.jstring) {
 	cProvider := newVStringFromJava(env, provider)