veyron/runtimes/google/security/jni: added Java PublicIDStore interface.

Change-Id: I7a9916ed4fea8b54ce5744848dab3f9587a20aed
diff --git a/runtimes/google/ipc/jni/jni.go b/runtimes/google/ipc/jni/jni.go
index d9115f1..625f73c 100644
--- a/runtimes/google/ipc/jni/jni.go
+++ b/runtimes/google/ipc/jni/jni.go
@@ -79,6 +79,13 @@
 		id := jnisecurity.NewPrivateID(env, jPrivateID)
 		ret = append(ret, veyron2.RuntimeID(id))
 	}
+	// Process RuntimePublicIDStoreOpt
+	runtimePublicIDStoreKey := util.JStaticStringField(env, jOptionDefsClass, "RUNTIME_PUBLIC_ID_STORE")
+	if util.CallBooleanMethodOrCatch(env, jOptions, "has", []util.Sign{util.StringSign}, runtimePublicIDStoreKey) {
+		jStore := C.jobject(util.CallObjectMethodOrCatch(env, jOptions, "get", []util.Sign{util.StringSign}, util.ObjectSign, runtimePublicIDStoreKey))
+		store := jnisecurity.NewPublicIDStore(env, jStore)
+		ret = append(ret, veyron2.RuntimePublicIDStore(store))
+	}
 	return
 }
 
diff --git a/runtimes/google/jni/util/util.go b/runtimes/google/jni/util/util.go
index 13ad34b..284f620 100644
--- a/runtimes/google/jni/util/util.go
+++ b/runtimes/google/jni/util/util.go
@@ -198,6 +198,17 @@
 	return errors.New(GoString(env, jMsg))
 }
 
+// JObjectFieldPtr returns the value of the provided Java object's Object field.
+// NOTE: Because CGO creates package-local types and because this method may be
+// invoked from a different package, Java types are passed in an empty interface
+// and then cast into their package local types.
+func JObjectFieldPtr(jEnv, jObj interface{}, field string) unsafe.Pointer {
+	env := getEnv(jEnv)
+	obj := getObject(jObj)
+	fid := C.jfieldID(JFieldIDPtrOrDie(env, C.GetObjectClass(env, obj), field, ObjectSign))
+	return unsafe.Pointer(C.GetObjectField(env, obj, fid))
+}
+
 // JBoolField returns the value of the provided Java object's boolean field.
 // NOTE: Because CGO creates package-local types and because this method may be
 // invoked from a different package, Java types are passed in an empty interface
diff --git a/runtimes/google/security/jni/jni.go b/runtimes/google/security/jni/jni.go
index a89744a..499f2dd 100644
--- a/runtimes/google/security/jni/jni.go
+++ b/runtimes/google/security/jni/jni.go
@@ -31,6 +31,11 @@
 	jPrincipalPatternClass C.jclass
 	// Global reference for org.joda.time.Duration class.
 	jDurationClass C.jclass
+
+	// Signature of the PublicID interface.
+	publicIDSign = util.ClassSign("com.veyron2.security.PublicID")
+	// Signature of the PrincipalPattern class.
+	principalPatternSign = util.ClassSign("com.veyron2.security.PrincipalPattern")
 )
 
 // Init initializes the JNI code with the given Java evironment. This method
@@ -52,6 +57,76 @@
 	jDurationClass = C.jclass(util.JFindClassPtrOrDie(env, "org/joda/time/Duration"))
 }
 
+//export Java_com_veyron_runtimes_google_security_PublicIDStore_nativeCreate
+func Java_com_veyron_runtimes_google_security_PublicIDStore_nativeCreate(env *C.JNIEnv, jPublicIDStoreClass C.jclass, jParams C.jobject) C.jlong {
+	var params *isecurity.PublicIDStoreParams
+	if jParams != nil {
+		dir := util.JStringField(env, jParams, "dir")
+		jSigner := C.jobject(util.JObjectFieldPtr(env, jParams, "signer"))
+		signer := newSigner(env, jSigner)
+		params = &isecurity.PublicIDStoreParams{
+			Dir:    dir,
+			Signer: signer,
+		}
+	}
+	store, err := isecurity.NewPublicIDStore(params)
+	if err != nil {
+		util.JThrowV(env, err)
+		return C.jlong(0)
+	}
+	util.GoRef(&store) // Un-refed when the Java PublicIDStore is finalized.
+	return C.jlong(util.PtrValue(&store))
+}
+
+//export Java_com_veyron_runtimes_google_security_PublicIDStore_nativeAdd
+func Java_com_veyron_runtimes_google_security_PublicIDStore_nativeAdd(env *C.JNIEnv, jPublicIDStore C.jobject, goPublicIDStorePtr C.jlong, jID C.jobject, jPeerPattern C.jstring) {
+	idPtr := util.CallLongMethodOrCatch(env, jID, "getNativePtr", nil)
+	id := (*(*security.PublicID)(util.Ptr(idPtr)))
+	peerPattern := security.PrincipalPattern(util.GoString(env, jPeerPattern))
+	if err := (*(*security.PublicIDStore)(util.Ptr(goPublicIDStorePtr))).Add(id, peerPattern); err != nil {
+		util.JThrowV(env, err)
+		return
+	}
+}
+
+//export Java_com_veyron_runtimes_google_security_PublicIDStore_nativeGetPeerID
+func Java_com_veyron_runtimes_google_security_PublicIDStore_nativeGetPeerID(env *C.JNIEnv, jPublicIDStore C.jobject, goPublicIDStorePtr C.jlong, jPeerID C.jobject) C.jlong {
+	peerIDPtr := util.CallLongMethodOrCatch(env, jPeerID, "getNativePtr", nil)
+	peerID := (*(*security.PublicID)(util.Ptr(peerIDPtr)))
+	id, err := (*(*security.PublicIDStore)(util.Ptr(goPublicIDStorePtr))).ForPeer(peerID)
+	if err != nil {
+		util.JThrowV(env, err)
+		return C.jlong(0)
+	}
+	util.GoRef(&id) // Un-refed when the Java PublicID is finalized.
+	return C.jlong(util.PtrValue(&id))
+}
+
+//export Java_com_veyron_runtimes_google_security_PublicIDStore_nativeDefaultPublicID
+func Java_com_veyron_runtimes_google_security_PublicIDStore_nativeDefaultPublicID(env *C.JNIEnv, jPublicIDStore C.jobject, goPublicIDStorePtr C.jlong) C.jlong {
+	id, err := (*(*security.PublicIDStore)(util.Ptr(goPublicIDStorePtr))).DefaultPublicID()
+	if err != nil {
+		util.JThrowV(env, err)
+		return C.jlong(0)
+	}
+	util.GoRef(&id) // Un-refed when the Java PublicID is finalized.
+	return C.jlong(util.PtrValue(&id))
+}
+
+//export Java_com_veyron_runtimes_google_security_PublicIDStore_nativeSetDefaultPrincipalPattern
+func Java_com_veyron_runtimes_google_security_PublicIDStore_nativeSetDefaultPrincipalPattern(env *C.JNIEnv, jPublicIDStore C.jobject, goPublicIDStorePtr C.jlong, jPattern C.jstring) {
+	pattern := security.PrincipalPattern(util.GoString(env, jPattern))
+	if err := (*(*security.PublicIDStore)(util.Ptr(goPublicIDStorePtr))).SetDefaultPrincipalPattern(pattern); err != nil {
+		util.JThrowV(env, err)
+		return
+	}
+}
+
+//export Java_com_veyron_runtimes_google_security_PublicIDStore_nativeFinalize
+func Java_com_veyron_runtimes_google_security_PublicIDStore_nativeFinalize(env *C.JNIEnv, jPublicIDStore C.jobject, goPublicIDStorePtr C.jlong) {
+	util.GoUnref((*security.PublicIDStore)(util.Ptr(goPublicIDStorePtr)))
+}
+
 //export Java_com_veyron_runtimes_google_security_PublicID_nativeNames
 func Java_com_veyron_runtimes_google_security_PublicID_nativeNames(env *C.JNIEnv, jPublicID C.jobject, goPublicIDPtr C.jlong) C.jobjectArray {
 	names := (*(*security.PublicID)(util.Ptr(goPublicIDPtr))).Names()
diff --git a/runtimes/google/security/jni/privateid.go b/runtimes/google/security/jni/privateid.go
index 71fb68b..b223a34 100644
--- a/runtimes/google/security/jni/privateid.go
+++ b/runtimes/google/security/jni/privateid.go
@@ -16,10 +16,6 @@
 // #include "jni_wrapper.h"
 import "C"
 
-var (
-	publicIDSign = util.ClassSign("com.veyron2.security.PublicID")
-)
-
 // NewPrivateID creates an instance of security.PrivateID that uses the provided
 // Java PrivateID as its underlying implementation.
 // NOTE: Because CGO creates package-local types and because this method may be
diff --git a/runtimes/google/security/jni/publicid_store.go b/runtimes/google/security/jni/publicid_store.go
new file mode 100644
index 0000000..eeb0e3a
--- /dev/null
+++ b/runtimes/google/security/jni/publicid_store.go
@@ -0,0 +1,99 @@
+// +build android
+
+package jni
+
+import (
+	"runtime"
+	"unsafe"
+
+	"veyron/runtimes/google/jni/util"
+	"veyron2/security"
+)
+
+// #cgo LDFLAGS: -ljniwrapper
+// #include "jni_wrapper.h"
+import "C"
+
+// NewPublicIDStore creates an instance of security.PublicIDStore that uses the
+// provided Java PublicIDStore as its underlying implementation.
+// NOTE: Because CGO creates package-local types and because this method may be
+// invoked from a different package, Java types are passed in an empty interface
+// and then cast into their package local types.
+func NewPublicIDStore(jEnv, jStore interface{}) security.PublicIDStore {
+	env := (*C.JNIEnv)(unsafe.Pointer(util.PtrValue(jEnv)))
+	jPublicIDStore := C.jobject(unsafe.Pointer(util.PtrValue(jStore)))
+
+	// We cannot cache Java environments as they are only valid in the current
+	// thread.  We can, however, cache the Java VM and obtain an environment
+	// from it in whatever thread happens to be running at the time.
+	var jVM *C.JavaVM
+	if status := C.GetJavaVM(env, &jVM); status != 0 {
+		panic("couldn't get Java VM from the (Java) environment")
+	}
+
+	// Reference Java PublicIDStore; it will be de-referenced when the Go
+	// PublicIDStore created below is garbage-collected (through the finalizer
+	// callback we setup just below).
+	jPublicIDStore = C.NewGlobalRef(env, jPublicIDStore)
+	// Create Go PublicIDStore.
+	s := &publicIDStore{
+		jVM:            jVM,
+		jPublicIDStore: jPublicIDStore,
+	}
+	runtime.SetFinalizer(s, func(s *publicIDStore) {
+		envPtr, freeFunc := util.GetEnv(s.jVM)
+		env := (*C.JNIEnv)(envPtr)
+		defer freeFunc()
+		C.DeleteGlobalRef(env, s.jPublicIDStore)
+	})
+	return s
+}
+
+type publicIDStore struct {
+	jVM            *C.JavaVM
+	jPublicIDStore C.jobject
+}
+
+func (s *publicIDStore) Add(id security.PublicID, peerPattern security.PrincipalPattern) error {
+	envPtr, freeFunc := util.GetEnv(s.jVM)
+	env := (*C.JNIEnv)(envPtr)
+	defer freeFunc()
+	util.GoRef(&id) // Un-refed when the Java PublicID object created below is finalized.
+	jPublicID := C.jobject(util.NewObjectOrCatch(env, jPublicIDImplClass, []util.Sign{util.LongSign}, &id))
+	jPrincipalPattern := C.jobject(util.NewObjectOrCatch(env, jPrincipalPatternClass, []util.Sign{util.StringSign}, string(peerPattern)))
+	return util.CallVoidMethod(env, s.jPublicIDStore, "add", []util.Sign{publicIDSign, principalPatternSign}, jPublicID, jPrincipalPattern)
+}
+
+func (s *publicIDStore) ForPeer(peer security.PublicID) (security.PublicID, error) {
+	envPtr, freeFunc := util.GetEnv(s.jVM)
+	env := (*C.JNIEnv)(envPtr)
+	defer freeFunc()
+	util.GoRef(&peer) // Un-refed when the Java peer object created below is finalized.
+	jPeer := C.jobject(util.NewObjectOrCatch(env, jPublicIDImplClass, []util.Sign{util.LongSign}, &peer))
+	jPublicID, err := util.CallObjectMethod(env, s.jPublicIDStore, "forPeer", []util.Sign{publicIDSign}, publicIDSign, jPeer)
+	if err != nil {
+		return nil, err
+	}
+	publicIDPtr := util.CallLongMethodOrCatch(env, jPublicID, "getNativePtr", nil)
+	return (*(*security.PublicID)(util.Ptr(publicIDPtr))), nil
+}
+
+func (s *publicIDStore) DefaultPublicID() (security.PublicID, error) {
+	envPtr, freeFunc := util.GetEnv(s.jVM)
+	env := (*C.JNIEnv)(envPtr)
+	defer freeFunc()
+	jPublicID, err := util.CallObjectMethod(env, s.jPublicIDStore, "defaultPublicID", []util.Sign{}, publicIDSign)
+	if err != nil {
+		return nil, err
+	}
+	publicIDPtr := util.CallLongMethodOrCatch(env, jPublicID, "getNativePtr", nil)
+	return (*(*security.PublicID)(util.Ptr(publicIDPtr))), nil
+}
+
+func (s *publicIDStore) SetDefaultPrincipalPattern(pattern security.PrincipalPattern) error {
+	envPtr, freeFunc := util.GetEnv(s.jVM)
+	env := (*C.JNIEnv)(envPtr)
+	defer freeFunc()
+	jPattern := C.jobject(util.NewObjectOrCatch(env, jPrincipalPatternClass, []util.Sign{util.StringSign}, string(pattern)))
+	return util.CallVoidMethod(env, s.jPublicIDStore, "setDefaultPrincipalPattern", []util.Sign{principalPatternSign}, jPattern)
+}