blob: 05af4f93be3ab789bbb5e2a252fb670ad84bd0f3 [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 context
import (
"fmt"
"runtime"
"v.io/v23/context"
jutil "v.io/x/jni/util"
)
// #include "jni.h"
import "C"
type goContextKey string
type goContextValue struct {
jObj jutil.Object
}
// JavaContext converts the provided Go Context into a Java VContext.
// If the provided cancel function is nil, Java VContext won't be
// cancelable.
func JavaContext(env jutil.Env, ctx *context.T, cancel context.CancelFunc) (jutil.Object, error) {
ctxRef := jutil.GoNewRef(ctx) // Un-refed when the Java context object is finalized.
cancelRef := jutil.NullRef
if cancel != nil {
cancelRef = jutil.GoNewRef(&cancel) // Un-refed when the Java context object is finalized.
}
jCtx, err := jutil.NewObject(env, jVContextClass, []jutil.Sign{jutil.LongSign, jutil.LongSign}, int64(ctxRef), int64(cancelRef))
if err != nil {
jutil.GoDecRef(ctxRef)
if cancel != nil {
jutil.GoDecRef(cancelRef)
}
return jutil.NullObject, err
}
return jCtx, err
}
// GoContext converts the provided Java VContext into a Go context and
// a cancel function (if any) that can be used to cancel the context.
func GoContext(env jutil.Env, jContext jutil.Object) (*context.T, context.CancelFunc, error) {
if jContext.IsNull() {
return nil, nil, nil
}
goCtxRefVal, err := jutil.CallLongMethod(env, jContext, "nativeRef", nil)
if err != nil {
return nil, nil, err
}
goCtxRef := jutil.Ref(goCtxRefVal)
goCancelRefVal, err := jutil.CallLongMethod(env, jContext, "nativeCancelRef", nil)
if err != nil {
return nil, nil, err
}
goCancelRef := jutil.Ref(goCancelRefVal)
var cancel context.CancelFunc
if goCancelRef != jutil.NullRef {
cancel = *(*context.CancelFunc)(jutil.GoRefValue(goCancelRef))
}
return (*context.T)(jutil.GoRefValue(goCtxRef)), cancel, nil
}
// GoContextValue returns the Go Context value given the Java Context value.
func GoContextValue(env jutil.Env, jValue jutil.Object) (interface{}, error) {
// Reference Java object; it will be de-referenced when the Go wrapper
// object created below is garbage-collected (via the finalizer we setup
// just below.)
jValue = jutil.NewGlobalRef(env, jValue)
value := &goContextValue{
jObj: jValue,
}
runtime.SetFinalizer(value, func(value *goContextValue) {
env, freeFunc := jutil.GetEnv()
defer freeFunc()
jutil.DeleteGlobalRef(env, value.jObj)
})
return value, nil
}
// JavaContextValue returns the Java Context value given the Go Context value.
func JavaContextValue(env jutil.Env, value interface{}) (jutil.Object, error) {
if value == nil {
return jutil.NullObject, nil
}
val, ok := value.(*goContextValue)
if !ok {
return jutil.NullObject, fmt.Errorf("Invalid type %T for value %v, wanted goContextValue", value, value)
}
return val.jObj, nil
}
// JavaContextDoneReason return the Java DoneReason given the Go error returned
// by ctx.Error().
func JavaContextDoneReason(env jutil.Env, err error) (jutil.Object, error) {
var name string
switch err {
case context.Canceled:
name = "CANCELED"
case context.DeadlineExceeded:
name = "DEADLINE_EXCEEDED"
default:
return jutil.NullObject, fmt.Errorf("Unrecognized context done reason: %v", err)
}
return jutil.CallStaticObjectMethod(env, jDoneReasonClass, "valueOf", []jutil.Sign{jutil.StringSign}, doneReasonSign, name)
}