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