blob: 38958d0242f9548888ebc8cfd835c462a1d33963 [file] [log] [blame]
jat@google.com64a55cb2009-10-16 14:16:57 +00001/*
2 * Copyright 2007 Google Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License. You may obtain a copy of
6 * the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations under
14 * the License.
15 */
16
17/*
18 * Defines the JavaScript classes gwt_nativewrapper_class and
19 * gwt_functionwrapper_class, which interface via JNI to Java objects.
20 */
21
22#include <jni.h>
23#include "JsRootedValue.h"
24#include "gwt-jni.h"
25#include "Tracer.h"
26
27/*
28 * Helper function to get reference Java attributes from Javascript.
29 *
30 * cx - JSContext pointer
31 * obj - JavaScript object which is a wrapped Java object
32 * id - property name, as a jsval string
33 * dispClass - output parameter of DispatchMethod subclass
34 * dispObj - output parameter of Java object
35 * jident - output parameter of property name as a Java string
36 */
37static JSBool getJavaPropertyStats(JSContext *cx, JSObject *obj, jsval id,
38 jclass& dispClass, jobject& dispObj, jstring& jident)
39{
40 Tracer tracer("getJavaPropertyStats");
41 if (!JSVAL_IS_STRING(id)) {
42 tracer.setFail("id is not a string");
43 return JS_FALSE;
44 }
45
46 jident = savedJNIEnv->NewString(JS_GetStringChars(JSVAL_TO_STRING(id)),
47 JS_GetStringLength(JSVAL_TO_STRING(id)));
48 if (!jident || savedJNIEnv->ExceptionCheck()) {
49 tracer.setFail("unable to create Java string");
50 return JS_FALSE;
51 }
52
53 dispObj = NS_REINTERPRET_CAST(jobject, JS_GetPrivate(cx, obj));
54 if (!dispObj) {
55 tracer.setFail("can't get dispatch object");
56 return JS_FALSE;
57 }
58
59 dispClass = savedJNIEnv->GetObjectClass(dispObj);
60 if (savedJNIEnv->ExceptionCheck()) {
61 tracer.setFail("can't get class of dispatch object");
62 return JS_FALSE;
63 }
64
65 return JS_TRUE;
66}
67
68/*
69 * Returns the value of a field on a Java object.
70 *
71 * context - JavaScript context
72 * clazz - class of obj
73 * obj - Java object to retreive field from
74 * fieldName - name of field on Java object to retrieve
75 *
76 * Returns null on failure. Caller is responsible for deleting
77 * returned JsRootedValue when done with it.
78 */
79static JsRootedValue* GetFieldAsRootedValue(JSContext* cx, jclass clazz,
80 jobject obj, jstring fieldName)
81{
82 Tracer tracer("GetFieldAsRootedValue");
83 JsRootedValue::ContextManager context(cx);
84 jmethodID getFieldMeth = savedJNIEnv->GetMethodID(clazz, "getField",
85 "(Ljava/lang/String;I)V");
86 if (!getFieldMeth || savedJNIEnv->ExceptionCheck()) {
87 return 0;
88 }
89
90 JsRootedValue* jsRootedValue = new JsRootedValue();
91 savedJNIEnv->CallVoidMethod(obj, getFieldMeth, fieldName,
92 reinterpret_cast<jint>(jsRootedValue));
93 if (savedJNIEnv->ExceptionCheck()) {
94 delete jsRootedValue;
95 return 0;
96 }
97 return jsRootedValue;
98}
99
100/*
101 * Sets the value of a field on a Java object.
102 *
103 * context - JavaScript context
104 * clazz - class of obj
105 * obj - Java object to store into field
106 * fieldName - name of field on Java object to store into
107 * jsRootedValue - the value to store in the field
108 *
109 * returns true on success, false on failure
110 */
111static bool SetFieldFromRootedValue(JSContext* cx, jclass clazz,
112 jobject obj, jstring fieldName, JsRootedValue* jsRootedValue)
113{
114 Tracer tracer("SetFieldAsRootedValue");
115 JsRootedValue::ContextManager context(cx);
116 jmethodID getFieldMeth = savedJNIEnv->GetMethodID(clazz, "setField",
117 "(Ljava/lang/String;I)V");
118 if (!getFieldMeth || savedJNIEnv->ExceptionCheck()) {
119 return false;
120 }
121
122 savedJNIEnv->CallVoidMethod(obj, getFieldMeth, fieldName,
123 reinterpret_cast<jint>(jsRootedValue));
124 if (savedJNIEnv->ExceptionCheck()) {
125 return false;
126 }
127
128 return true;
129}
130
131static JSBool JS_DLL_CALLBACK gwt_nativewrapper_getProperty(JSContext *cx,
132 JSObject *obj, jsval id, jsval *vp)
133{
134 Tracer tracer("gwt_nativewrapper_getProperty");
135 tracer.log("context=%08x, obj=%08x", unsigned(cx), unsigned(obj));
136 JsRootedValue::ContextManager context(cx);
137
138 jclass dispClass;
139 jobject dispObj;
140 jstring ident;
141 if (!getJavaPropertyStats(cx, obj, id, dispClass, dispObj, ident)) {
142 tracer.setFail("getJavaPropertyStats failed");
143 return JS_FALSE;
144 }
145 JsRootedValue* js_rooted_value = GetFieldAsRootedValue(cx, dispClass,
146 dispObj, ident);
147 if (!js_rooted_value) {
148 tracer.setFail("can't get field");
149 return JS_FALSE;
150 }
151 *vp = js_rooted_value->getValue();
152 return JS_TRUE;
153}
154
155static void JS_DLL_CALLBACK gwt_nativewrapper_finalize(JSContext *cx,
156 JSObject *obj)
157{
158 Tracer tracer("gwt_nativewrapper_finalize");
159 jobject dispObj = NS_REINTERPRET_CAST(jobject, JS_GetPrivate(cx, obj));
160 if (dispObj) {
161 // Remove this pairing from the global map.
162 jmethodID removeMethod = savedJNIEnv->GetStaticMethodID(lowLevelMozClass, "removeJsvalForObject",
163 "(Ljava/lang/Object;)V");
164 if (!removeMethod || savedJNIEnv->ExceptionCheck()) {
165 tracer.setFail("Cannot GetMethodID for removeJsvalForObject");
166 return;
167 }
168 savedJNIEnv->CallStaticVoidMethod(lowLevelMozClass, removeMethod, dispObj);
169 if (savedJNIEnv->ExceptionCheck()) {
170 tracer.setFail("Exception calling removeJsvalForObject");
171 return;
172 }
173 savedJNIEnv->DeleteGlobalRef(dispObj);
174 }
175}
176
177static JSBool JS_DLL_CALLBACK gwt_nativewrapper_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
178{
179 Tracer tracer("gwt_nativewrapper_setProperty");
180 tracer.log("context=%08x", unsigned(cx));
181 JsRootedValue::ContextManager context(cx);
182 jclass dispClass;
183 jobject dispObj;
184 jstring ident;
185 if (!getJavaPropertyStats(cx, obj, id, dispClass, dispObj, ident)) {
186 tracer.setFail("getJavaPropertyStats failed");
187 return JS_FALSE;
188 }
189 JsRootedValue* js_rooted_value = new JsRootedValue(*vp);
190 if (!SetFieldFromRootedValue(cx, dispClass, dispObj, ident,
191 js_rooted_value)) {
192 tracer.setFail("can't set field");
193 return JS_FALSE;
194 }
195 return JS_TRUE;
196}
197
198JSClass gwt_nativewrapper_class = {
199 "gwt_nativewrapper_class", JSCLASS_HAS_PRIVATE,
200 JS_PropertyStub, JS_PropertyStub, gwt_nativewrapper_getProperty,
201 gwt_nativewrapper_setProperty, JS_EnumerateStub, JS_ResolveStub,
202 JS_ConvertStub, gwt_nativewrapper_finalize,
203 JSCLASS_NO_OPTIONAL_MEMBERS
204};
205
206JSClass gwt_functionwrapper_class = {
207 "gwt_functionwrapper_class", JSCLASS_HAS_PRIVATE,
208 JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
209 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, gwt_nativewrapper_finalize,
210 JSCLASS_NO_OPTIONAL_MEMBERS
211};