| /* | |
| * 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 | |
| }; |