blob: 4bbb922a3b241fc3ba73a17bbf2aa1eb33fc703d [file] [log] [blame]
// 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 security
import (
"log"
"runtime"
"time"
jutil "v.io/x/jni/util"
jcontext "v.io/x/jni/v23/context"
"v.io/v23"
"v.io/v23/context"
"v.io/v23/naming"
"v.io/v23/security"
"v.io/v23/vdl"
)
// #include "jni.h"
import "C"
// JavaCall converts the provided Go (security) Call into a Java Call object.
func JavaCall(env jutil.Env, call security.Call) (jutil.Object, error) {
ref := jutil.GoNewRef(&call) // Un-refed when the Java CallImpl object is finalized.
jCall, err := jutil.NewObject(env, jCallImplClass, []jutil.Sign{jutil.LongSign}, int64(ref))
if err != nil {
jutil.GoDecRef(ref)
return jutil.NullObject, err
}
return jCall, nil
}
// GoCall creates instance of security.Call that uses the provided Java
// Call as its underlying implementation.
func GoCall(env jutil.Env, jCall jutil.Object) (security.Call, error) {
if jCall.IsNull() {
return nil, nil
}
if jutil.IsInstanceOf(env, jCall, jCallImplClass) {
// Called with our implementation of Call, which maintains a Go reference - use it.
ref, err := jutil.CallLongMethod(env, jCall, "nativeRef", nil)
if err != nil {
return nil, err
}
return (*(*security.Call)(jutil.GoRefValue(jutil.Ref(ref)))), nil
}
// Reference Java call; it will be de-referenced when the go call
// created below is garbage-collected (through the finalizer callback we
// setup just below).
jCall = jutil.NewGlobalRef(env, jCall)
call := &callImpl{
jCall: jCall,
}
runtime.SetFinalizer(call, func(c *callImpl) {
env, freeFunc := jutil.GetEnv()
defer freeFunc()
jutil.DeleteGlobalRef(env, c.jCall)
})
return call, nil
}
// callImpl is the go interface to the java implementation of security.Call
type callImpl struct {
jCall jutil.Object
}
func (c *callImpl) Timestamp() time.Time {
env, freeFunc := jutil.GetEnv()
defer freeFunc()
jTime, err := jutil.CallObjectMethod(env, c.jCall, "timestamp", nil, jutil.DateTimeSign)
if err != nil {
log.Println("Couldn't call Java timestamp method: ", err)
return time.Time{}
}
t, err := jutil.GoTime(env, jTime)
if err != nil {
log.Println("Couldn't convert Java time to Go: ", err)
return time.Time{}
}
return t
}
func (c *callImpl) Method() string {
return jutil.UpperCamelCase(c.callStringMethod("method"))
}
func (c *callImpl) MethodTags() []*vdl.Value {
env, freeFunc := jutil.GetEnv()
defer freeFunc()
jTags, err := jutil.CallObjectMethod(env, c.jCall, "methodTags", nil, jutil.ArraySign(jutil.VdlValueSign))
if err != nil {
log.Println("Couldn't call Java methodTags method: ", err)
return nil
}
tags, err := jutil.GoVDLValueArray(env, jTags)
if err != nil {
log.Println("Couldn't convert Java tags to Go: ", err)
return nil
}
return tags
}
func (c *callImpl) Suffix() string {
return c.callStringMethod("suffix")
}
func (c *callImpl) LocalDischarges() map[string]security.Discharge {
return c.callDischargeMapMethod("localDischarges")
}
func (c *callImpl) RemoteDischarges() map[string]security.Discharge {
return c.callDischargeMapMethod("remoteDischarges")
}
func (c *callImpl) LocalEndpoint() naming.Endpoint {
epStr := c.callStringMethod("localEndpoint")
ep, err := v23.NewEndpoint(epStr)
if err != nil {
log.Printf("Couldn't parse endpoint string %q: %v", epStr, err)
return nil
}
return ep
}
func (c *callImpl) LocalPrincipal() security.Principal {
env, freeFunc := jutil.GetEnv()
defer freeFunc()
jPrincipal, err := jutil.CallObjectMethod(env, c.jCall, "localPrincipal", nil, principalSign)
if err != nil {
log.Printf("Couldn't call Java localPrincipal method: %v", err)
return nil
}
principal, err := GoPrincipal(env, jPrincipal)
if err != nil {
log.Printf("Couldn't convert Java principal to Go: %v", err)
return nil
}
return principal
}
func (c *callImpl) LocalBlessings() security.Blessings {
env, freeFunc := jutil.GetEnv()
defer freeFunc()
jBlessings, err := jutil.CallObjectMethod(env, c.jCall, "localBlessings", nil, blessingsSign)
if err != nil {
log.Printf("Couldn't call Java localBlessings method: %v", err)
return security.Blessings{}
}
blessings, err := GoBlessings(env, jBlessings)
if err != nil {
log.Printf("Couldn't convert Java Blessings into Go: %v", err)
return security.Blessings{}
}
return blessings
}
func (c *callImpl) RemoteBlessings() security.Blessings {
env, freeFunc := jutil.GetEnv()
defer freeFunc()
jBlessings, err := jutil.CallObjectMethod(env, c.jCall, "remoteBlessings", nil, blessingsSign)
if err != nil {
log.Printf("Couldn't call Java remoteBlessings method: %v", err)
return security.Blessings{}
}
blessings, err := GoBlessings(env, jBlessings)
if err != nil {
log.Printf("Couldn't convert Java Blessings into Go: %v", err)
return security.Blessings{}
}
return blessings
}
func (c *callImpl) RemoteEndpoint() naming.Endpoint {
epStr := c.callStringMethod("remoteEndpoint")
ep, err := v23.NewEndpoint(epStr)
if err != nil {
log.Printf("Couldn't parse endpoint string %q: %v", epStr, err)
return nil
}
return ep
}
func (c *callImpl) Context() *context.T {
env, freeFunc := jutil.GetEnv()
defer freeFunc()
contextSign := jutil.ClassSign("io.v.v23.context.VContext")
jCtx, err := jutil.CallObjectMethod(env, c.jCall, "context", nil, contextSign)
if err != nil {
log.Printf("Couldn't get Java Vanadium context: %v", err)
}
ctx, _, err := jcontext.GoContext(env, jCtx)
if err != nil {
log.Printf("Couldn't convert Java Vanadium context to Go: %v", err)
}
return ctx
}
func (c *callImpl) callStringMethod(methodName string) string {
env, freeFunc := jutil.GetEnv()
defer freeFunc()
ret, err := jutil.CallStringMethod(env, c.jCall, methodName, nil)
if err != nil {
log.Printf("Couldn't call Java %q method: %v", methodName, err)
return ""
}
return ret
}
func (c *callImpl) callDischargeMapMethod(methodName string) map[string]security.Discharge {
env, freeFunc := jutil.GetEnv()
defer freeFunc()
javaObjectMap, err := jutil.CallMapMethod(env, c.jCall, methodName, nil)
if err != nil {
log.Printf("Couldn't call Java %q method: %v", methodName, err)
return nil
}
discharges := make(map[string]security.Discharge)
for jKey, jValue := range javaObjectMap {
key := jutil.GoString(env, jKey)
discharge, err := GoDischarge(env, jValue)
if err != nil {
log.Printf("Couldn't convert Java Discharge to Go Discharge: %v", err)
return nil
}
discharges[key] = discharge
}
return discharges
}