blob: 38958d0242f9548888ebc8cfd835c462a1d33963 [file] [log] [blame]
/*
* Copyright 2007 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
/*
* Defines the JavaScript classes gwt_nativewrapper_class and
* gwt_functionwrapper_class, which interface via JNI to Java objects.
*/
#include <jni.h>
#include "JsRootedValue.h"
#include "gwt-jni.h"
#include "Tracer.h"
/*
* Helper function to get reference Java attributes from Javascript.
*
* cx - JSContext pointer
* obj - JavaScript object which is a wrapped Java object
* id - property name, as a jsval string
* dispClass - output parameter of DispatchMethod subclass
* dispObj - output parameter of Java object
* jident - output parameter of property name as a Java string
*/
static JSBool getJavaPropertyStats(JSContext *cx, JSObject *obj, jsval id,
jclass& dispClass, jobject& dispObj, jstring& jident)
{
Tracer tracer("getJavaPropertyStats");
if (!JSVAL_IS_STRING(id)) {
tracer.setFail("id is not a string");
return JS_FALSE;
}
jident = savedJNIEnv->NewString(JS_GetStringChars(JSVAL_TO_STRING(id)),
JS_GetStringLength(JSVAL_TO_STRING(id)));
if (!jident || savedJNIEnv->ExceptionCheck()) {
tracer.setFail("unable to create Java string");
return JS_FALSE;
}
dispObj = NS_REINTERPRET_CAST(jobject, JS_GetPrivate(cx, obj));
if (!dispObj) {
tracer.setFail("can't get dispatch object");
return JS_FALSE;
}
dispClass = savedJNIEnv->GetObjectClass(dispObj);
if (savedJNIEnv->ExceptionCheck()) {
tracer.setFail("can't get class of dispatch object");
return JS_FALSE;
}
return JS_TRUE;
}
/*
* Returns the value of a field on a Java object.
*
* context - JavaScript context
* clazz - class of obj
* obj - Java object to retreive field from
* fieldName - name of field on Java object to retrieve
*
* Returns null on failure. Caller is responsible for deleting
* returned JsRootedValue when done with it.
*/
static JsRootedValue* GetFieldAsRootedValue(JSContext* cx, jclass clazz,
jobject obj, jstring fieldName)
{
Tracer tracer("GetFieldAsRootedValue");
JsRootedValue::ContextManager context(cx);
jmethodID getFieldMeth = savedJNIEnv->GetMethodID(clazz, "getField",
"(Ljava/lang/String;I)V");
if (!getFieldMeth || savedJNIEnv->ExceptionCheck()) {
return 0;
}
JsRootedValue* jsRootedValue = new JsRootedValue();
savedJNIEnv->CallVoidMethod(obj, getFieldMeth, fieldName,
reinterpret_cast<jint>(jsRootedValue));
if (savedJNIEnv->ExceptionCheck()) {
delete jsRootedValue;
return 0;
}
return jsRootedValue;
}
/*
* Sets the value of a field on a Java object.
*
* context - JavaScript context
* clazz - class of obj
* obj - Java object to store into field
* fieldName - name of field on Java object to store into
* jsRootedValue - the value to store in the field
*
* returns true on success, false on failure
*/
static bool SetFieldFromRootedValue(JSContext* cx, jclass clazz,
jobject obj, jstring fieldName, JsRootedValue* jsRootedValue)
{
Tracer tracer("SetFieldAsRootedValue");
JsRootedValue::ContextManager context(cx);
jmethodID getFieldMeth = savedJNIEnv->GetMethodID(clazz, "setField",
"(Ljava/lang/String;I)V");
if (!getFieldMeth || savedJNIEnv->ExceptionCheck()) {
return false;
}
savedJNIEnv->CallVoidMethod(obj, getFieldMeth, fieldName,
reinterpret_cast<jint>(jsRootedValue));
if (savedJNIEnv->ExceptionCheck()) {
return false;
}
return true;
}
static JSBool JS_DLL_CALLBACK gwt_nativewrapper_getProperty(JSContext *cx,
JSObject *obj, jsval id, jsval *vp)
{
Tracer tracer("gwt_nativewrapper_getProperty");
tracer.log("context=%08x, obj=%08x", unsigned(cx), unsigned(obj));
JsRootedValue::ContextManager context(cx);
jclass dispClass;
jobject dispObj;
jstring ident;
if (!getJavaPropertyStats(cx, obj, id, dispClass, dispObj, ident)) {
tracer.setFail("getJavaPropertyStats failed");
return JS_FALSE;
}
JsRootedValue* js_rooted_value = GetFieldAsRootedValue(cx, dispClass,
dispObj, ident);
if (!js_rooted_value) {
tracer.setFail("can't get field");
return JS_FALSE;
}
*vp = js_rooted_value->getValue();
return JS_TRUE;
}
static void JS_DLL_CALLBACK gwt_nativewrapper_finalize(JSContext *cx,
JSObject *obj)
{
Tracer tracer("gwt_nativewrapper_finalize");
jobject dispObj = NS_REINTERPRET_CAST(jobject, JS_GetPrivate(cx, obj));
if (dispObj) {
// Remove this pairing from the global map.
jmethodID removeMethod = savedJNIEnv->GetStaticMethodID(lowLevelMozClass, "removeJsvalForObject",
"(Ljava/lang/Object;)V");
if (!removeMethod || savedJNIEnv->ExceptionCheck()) {
tracer.setFail("Cannot GetMethodID for removeJsvalForObject");
return;
}
savedJNIEnv->CallStaticVoidMethod(lowLevelMozClass, removeMethod, dispObj);
if (savedJNIEnv->ExceptionCheck()) {
tracer.setFail("Exception calling removeJsvalForObject");
return;
}
savedJNIEnv->DeleteGlobalRef(dispObj);
}
}
static JSBool JS_DLL_CALLBACK gwt_nativewrapper_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
{
Tracer tracer("gwt_nativewrapper_setProperty");
tracer.log("context=%08x", unsigned(cx));
JsRootedValue::ContextManager context(cx);
jclass dispClass;
jobject dispObj;
jstring ident;
if (!getJavaPropertyStats(cx, obj, id, dispClass, dispObj, ident)) {
tracer.setFail("getJavaPropertyStats failed");
return JS_FALSE;
}
JsRootedValue* js_rooted_value = new JsRootedValue(*vp);
if (!SetFieldFromRootedValue(cx, dispClass, dispObj, ident,
js_rooted_value)) {
tracer.setFail("can't set field");
return JS_FALSE;
}
return JS_TRUE;
}
JSClass gwt_nativewrapper_class = {
"gwt_nativewrapper_class", JSCLASS_HAS_PRIVATE,
JS_PropertyStub, JS_PropertyStub, gwt_nativewrapper_getProperty,
gwt_nativewrapper_setProperty, JS_EnumerateStub, JS_ResolveStub,
JS_ConvertStub, gwt_nativewrapper_finalize,
JSCLASS_NO_OPTIONAL_MEMBERS
};
JSClass gwt_functionwrapper_class = {
"gwt_functionwrapper_class", JSCLASS_HAS_PRIVATE,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, gwt_nativewrapper_finalize,
JSCLASS_NO_OPTIONAL_MEMBERS
};