TBR implement Java discharge caching support (JNI changes)

Change-Id: If2384c0b1e05b7c5374aaae00571513e8e30da60
diff --git a/util/sign.go b/util/sign.go
index 9020c0c..c20d070 100644
--- a/util/sign.go
+++ b/util/sign.go
@@ -33,6 +33,8 @@
 )
 
 var (
+	// CollectionSign denotes a signature of a Java Collection type.
+	CollectionSign = ClassSign("java.util.Collection")
 	// StringSign denotes a signature of a Java String type.
 	StringSign = ClassSign("java.lang.String")
 	// ObjectSign denotes a signature of a Java Object type.
diff --git a/util/util.go b/util/util.go
index 5c6052d..717116e 100644
--- a/util/util.go
+++ b/util/util.go
@@ -45,6 +45,8 @@
 	jDateTimeClass C.jclass
 	// Global reference for org.joda.time.Duration class.
 	jDurationClass C.jclass
+	// Global reference for java.util.Arrays class
+	jArraysClass C.jclass
 	// Global reference for java.util.ArrayList class.
 	jArrayListClass C.jclass
 	// Global reference for java.lang.Throwable class.
@@ -117,6 +119,11 @@
 		return err
 	}
 	jDurationClass = C.jclass(class)
+	class, err = JFindClass(env, "java/util/Arrays")
+	if err != nil {
+		return err
+	}
+	jArraysClass = C.jclass(class)
 	class, err = JFindClass(env, "java/util/ArrayList")
 	if err != nil {
 		return err
@@ -507,6 +514,26 @@
 	return unsafe.Pointer(ret)
 }
 
+// JObjectArrayList converts the provided slice of C.jobject pointers into a
+// Java ArrayList of the provided element type. The implementation is based on
+// http://stackoverflow.com/questions/157944.
+// 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 JObjectArrayList(jEnv interface{}, arr []interface{}, jElemClass interface{}) (unsafe.Pointer, error) {
+	jArr := JObjectArray(jEnv, arr, jElemClass)
+	env := getEnv(jEnv)
+	jArrAsList, err := CallStaticObjectMethod(env, jArraysClass, "asList", []Sign{ArraySign(ObjectSign)}, ListSign, jArr)
+	if err != nil {
+		return nil, err
+	}
+	jArrayList, err := NewObject(env, jArrayListClass, []Sign{CollectionSign}, C.jobject(jArrAsList))
+	if err != nil {
+		return nil, err
+	}
+	return jArrayList, nil
+}
+
 // GoObjectArray converts a Java Object array to a Go slice of C.jobject
 // pointers.
 // NOTE: Because CGO creates package-local types and because this method may be
diff --git a/v23/security/jni.go b/v23/security/jni.go
index 4bae71e..5dce22b 100644
--- a/v23/security/jni.go
+++ b/v23/security/jni.go
@@ -19,19 +19,21 @@
 import "C"
 
 var (
-	principalSign       = jutil.ClassSign("io.v.v23.security.VPrincipal")
-	blessingsSign       = jutil.ClassSign("io.v.v23.security.Blessings")
-	wireBlessingsSign   = jutil.ClassSign("io.v.v23.security.WireBlessings")
-	wireDischargeSign   = jutil.ClassSign("io.v.v23.security.WireDischarge")
-	blessingStoreSign   = jutil.ClassSign("io.v.v23.security.BlessingStore")
-	blessingRootsSign   = jutil.ClassSign("io.v.v23.security.BlessingRoots")
-	blessingPatternSign = jutil.ClassSign("io.v.v23.security.BlessingPattern")
-	signerSign          = jutil.ClassSign("io.v.v23.security.VSigner")
-	caveatSign          = jutil.ClassSign("io.v.v23.security.Caveat")
-	contextSign         = jutil.ClassSign("io.v.v23.context.VContext")
-	callSign            = jutil.ClassSign("io.v.v23.security.Call")
-	signatureSign       = jutil.ClassSign("io.v.v23.security.VSignature")
-	publicKeySign       = jutil.ClassSign("java.security.interfaces.ECPublicKey")
+	dischargeSign        = jutil.ClassSign("io.v.v23.security.Discharge")
+	dischargeImpetusSign = jutil.ClassSign("io.v.v23.security.DischargeImpetus")
+	principalSign        = jutil.ClassSign("io.v.v23.security.VPrincipal")
+	blessingsSign        = jutil.ClassSign("io.v.v23.security.Blessings")
+	wireBlessingsSign    = jutil.ClassSign("io.v.v23.security.WireBlessings")
+	wireDischargeSign    = jutil.ClassSign("io.v.v23.security.WireDischarge")
+	blessingStoreSign    = jutil.ClassSign("io.v.v23.security.BlessingStore")
+	blessingRootsSign    = jutil.ClassSign("io.v.v23.security.BlessingRoots")
+	blessingPatternSign  = jutil.ClassSign("io.v.v23.security.BlessingPattern")
+	signerSign           = jutil.ClassSign("io.v.v23.security.VSigner")
+	caveatSign           = jutil.ClassSign("io.v.v23.security.Caveat")
+	contextSign          = jutil.ClassSign("io.v.v23.context.VContext")
+	callSign             = jutil.ClassSign("io.v.v23.security.Call")
+	signatureSign        = jutil.ClassSign("io.v.v23.security.VSignature")
+	publicKeySign        = jutil.ClassSign("java.security.interfaces.ECPublicKey")
 
 	// Global reference for io.v.v23.security.Blessings class.
 	jBlessingsClass C.jclass
@@ -59,6 +61,8 @@
 	jVSecurityClass C.jclass
 	// Global reference for io.v.v23.security.Discharge class.
 	jDischargeClass C.jclass
+	// Global reference for io.v.v23.security.DischargeImpetus class.
+	jDischargeImpetusClass C.jclass
 )
 
 // Init initializes the JNI code with the given Java evironment. This method
@@ -137,6 +141,11 @@
 		return err
 	}
 	jDischargeClass = C.jclass(class)
+	class, err = jutil.JFindClass(jEnv, "io/v/v23/security/DischargeImpetus")
+	if err != nil {
+		return err
+	}
+	jDischargeImpetusClass = C.jclass(class)
 	return nil
 }
 
@@ -747,6 +756,66 @@
 	return C.jobject(jBlessingsMap)
 }
 
+//export Java_io_v_v23_security_BlessingStoreImpl_nativeCacheDischarge
+func Java_io_v_v23_security_BlessingStoreImpl_nativeCacheDischarge(env *C.JNIEnv, jBlessingStoreImpl C.jobject, goPtr C.jlong, jDischarge C.jobject, jCaveat C.jobject, jImpetus C.jobject) {
+	blessingStore := *(*security.BlessingStore)(jutil.Ptr(goPtr))
+	discharge, err := GoDischarge(env, jDischarge)
+	if err != nil {
+		jutil.JThrowV(env, err)
+		return
+	}
+	caveat, err := GoCaveat(env, jCaveat)
+	if err != nil {
+		jutil.JThrowV(env, err)
+		return
+	}
+	var impetus security.DischargeImpetus
+	err = jutil.GoVomCopy(env, jImpetus, jDischargeImpetusClass, &impetus)
+	if err != nil {
+		jutil.JThrowV(env, err)
+		return
+	}
+	blessingStore.CacheDischarge(discharge, caveat, impetus)
+}
+
+//export Java_io_v_v23_security_BlessingStoreImpl_nativeClearDischarges
+func Java_io_v_v23_security_BlessingStoreImpl_nativeClearDischarges(env *C.JNIEnv, jBlessingStoreImpl C.jobject, goPtr C.jlong, jDischarges C.jobject) {
+	blessingStore := *(*security.BlessingStore)(jutil.Ptr(goPtr))
+	var discharges []security.Discharge
+	for _, jDischarge := range jutil.GoObjectArray(env, jDischarges) {
+		discharge, err := GoDischarge(env, jDischarge)
+		if err != nil {
+			jutil.JThrowV(env, err)
+			return
+		}
+		discharges = append(discharges, discharge)
+	}
+	blessingStore.ClearDischarges(discharges...)
+}
+
+//export Java_io_v_v23_security_BlessingStoreImpl_nativeDischarge
+func Java_io_v_v23_security_BlessingStoreImpl_nativeDischarge(env *C.JNIEnv, jBlessingStoreImpl C.jobject, goPtr C.jlong, jCaveat C.jobject, jImpetus C.jobject) C.jobject {
+	blessingStore := *(*security.BlessingStore)(jutil.Ptr(goPtr))
+	caveat, err := GoCaveat(env, jCaveat)
+	if err != nil {
+		jutil.JThrowV(env, err)
+		return nil
+	}
+	var impetus security.DischargeImpetus
+	err = jutil.GoVomCopy(env, jImpetus, jDischargeImpetusClass, &impetus)
+	if err != nil {
+		jutil.JThrowV(env, err)
+		return nil
+	}
+	discharge := blessingStore.Discharge(caveat, impetus)
+	jDischarge, err := JavaDischarge(env, discharge)
+	if err != nil {
+		jutil.JThrowV(env, err)
+		return nil
+	}
+	return jDischarge
+}
+
 //export Java_io_v_v23_security_BlessingStoreImpl_nativeDebugString
 func Java_io_v_v23_security_BlessingStoreImpl_nativeDebugString(env *C.JNIEnv, jBlessingStoreImpl C.jobject, goPtr C.jlong) C.jstring {
 	debug := (*(*security.BlessingStore)(jutil.Ptr(goPtr))).DebugString()
diff --git a/v23/security/store.go b/v23/security/store.go
index b93c324..d2c2693 100644
--- a/v23/security/store.go
+++ b/v23/security/store.go
@@ -168,15 +168,76 @@
 }
 
 func (s *blessingStore) CacheDischarge(discharge security.Discharge, caveat security.Caveat, impetus security.DischargeImpetus) {
-	panic("BlessingStore.CacheDischarge() unimplemented in Java")
+	env, freeFunc := jutil.GetEnv()
+	defer freeFunc()
+	jDischarge, err := JavaDischarge(env, discharge)
+	if err != nil {
+		log.Printf("Couldn't get Java discharge: %v", err)
+		return
+	}
+	jCaveat, err := JavaCaveat(env, caveat)
+	if err != nil {
+		log.Printf("Couldn't get Java caveat: %v", err)
+		return
+	}
+	jImpetus, err := jutil.JVomCopy(env, impetus, jDischargeImpetusClass)
+	if err != nil {
+		log.Printf("Couldn't get Java DischargeImpetus: %v", err)
+		return
+	}
+	err = jutil.CallVoidMethod(env, s.jBlessingStore, "cacheDischarge", []jutil.Sign{dischargeSign, caveatSign, dischargeImpetusSign}, jDischarge, jCaveat, jImpetus)
+	if err != nil {
+		log.Printf("Couldn't call cacheDischarge: %v", err)
+	}
 }
 
 func (s *blessingStore) ClearDischarges(discharges ...security.Discharge) {
-	panic("BlessingStore.ClearDischarges() unimplemented in Java")
+	env, freeFunc := jutil.GetEnv()
+	defer freeFunc()
+	jDischarges := make([]interface{}, len(discharges))
+	for i := 0; i < len(discharges); i++ {
+		jDischarge, err := JavaDischarge(env, discharges[i])
+		if err != nil {
+			log.Printf("Couldn't get Java discharge: %v", err)
+			return
+		}
+		jDischarges[i] = jDischarge
+	}
+	jDischargeList, err := jutil.JObjectArrayList(env, jDischarges, jDischargeClass)
+	if err != nil {
+		log.Printf("Couldn't get Java discharge list: %v", err)
+		return
+	}
+	err = jutil.CallVoidMethod(env, s.jBlessingStore, "clearDischarges", []jutil.Sign{jutil.ListSign}, jDischargeList)
+	if err != nil {
+		log.Printf("Couldn't call Java clearDischarges method: %v", err)
+	}
 }
 
 func (s *blessingStore) Discharge(caveat security.Caveat, impetus security.DischargeImpetus) security.Discharge {
-	panic("BlessingStore.Discharge() unimplemented in Java")
+	env, freeFunc := jutil.GetEnv()
+	defer freeFunc()
+	jCaveat, err := JavaCaveat(env, caveat)
+	if err != nil {
+		log.Printf("Couldn't get Java caveat: %v", err)
+		return security.Discharge{}
+	}
+	jImpetus, err := jutil.JVomCopy(env, impetus, jDischargeImpetusClass)
+	if err != nil {
+		log.Printf("Couldn't get Java DischargeImpetus: %v", err)
+		return security.Discharge{}
+	}
+	jDischarge, err := jutil.CallObjectMethod(env, s.jBlessingStore, "discharge", []jutil.Sign{caveatSign, dischargeImpetusSign}, dischargeSign, jCaveat, jImpetus)
+	if err != nil {
+		log.Printf("Couldn't call Java discharge method: %v", err)
+		return security.Discharge{}
+	}
+	discharge, err := GoDischarge(env, jDischarge)
+	if err != nil {
+		log.Printf("Couldn't convert Java discharge to Go: %v", err)
+		return security.Discharge{}
+	}
+	return discharge
 }
 
 func (r *blessingStore) DebugString() string {