/* * Convert a Java object to a JSObject. */ static JSBool convert_javaobject_to_jsobject(JSContext *cx, JNIEnv *jEnv, JavaClassDescriptor *class_descriptor, jobject java_obj, jsval *vp) { JSObject *js_obj; /* * If it's an instance of netscape.javascript.JSObject, i.e. a wrapper * around a JS object that has been passed into the Java world, unwrap * it to obtain the original JS object. */ if (njJSObject && (*jEnv)->IsInstanceOf(jEnv, java_obj, njJSObject)) { #ifdef PRESERVE_JSOBJECT_IDENTITY #if JS_BYTES_PER_LONG == 8 js_obj = (JSObject *)((*jEnv)->GetLongField(jEnv, java_obj, njJSObject_long_internal)); #else js_obj = (JSObject *)((*jEnv)->GetIntField(jEnv, java_obj, njJSObject_internal)); #endif #else js_obj = jsj_UnwrapJSObjectWrapper(jEnv, java_obj); #endif } else { /* otherwise, wrap it inside a JavaObject */ js_obj = jsj_WrapJavaObject(cx, jEnv, java_obj, class_descriptor->java_class); if (!js_obj) return JS_FALSE; } *vp = OBJECT_TO_JSVAL(js_obj); return JS_TRUE; }
/* * Reflect a Java object into a JS value. The source object, java_obj, must * be of type java.lang.Object or a subclass and may, therefore, be an array. */ JSBool jsj_ConvertJavaObjectToJSValue(JSContext *cx, JNIEnv *jEnv, jobject java_obj, jsval *vp) { jclass java_class; JSObject *js_obj; /* A null in Java-land is also null in JS */ if (!java_obj) { *vp = JSVAL_NULL; return JS_TRUE; } java_class = (*jEnv)->GetObjectClass(jEnv, java_obj); /* * If it's an instance of netscape.javascript.JSObject, i.e. a wrapper * around a JS object that has been passed into the Java world, unwrap * it to obtain the original JS object. */ if (njJSObject && (*jEnv)->IsInstanceOf(jEnv, java_obj, njJSObject)) { #ifdef PRESERVE_JSOBJECT_IDENTITY #if JS_BYTES_PER_LONG == 8 js_obj = (JSObject *)((*jEnv)->GetLongField(jEnv, java_obj, njJSObject_long_internal)); #else js_obj = (JSObject *)((*jEnv)->GetIntField(jEnv, java_obj, njJSObject_internal)); #endif #else js_obj = jsj_UnwrapJSObjectWrapper(jEnv, java_obj); #endif /* NULL is actually a valid value. It means 'null'. JS_ASSERT(js_obj); if (!js_obj) goto error; */ *vp = OBJECT_TO_JSVAL(js_obj); goto done; } /* otherwise, wrap it inside a JavaObject */ js_obj = jsj_WrapJavaObject(cx, jEnv, java_obj, java_class); if (!js_obj) goto error; *vp = OBJECT_TO_JSVAL(js_obj); done: (*jEnv)->DeleteLocalRef(jEnv, java_class); return JS_TRUE; error: (*jEnv)->DeleteLocalRef(jEnv, java_class); return JS_FALSE; }
JNIEXPORT jboolean JNICALL Java_netscape_javascript_JSObject_equals(JNIEnv *jEnv, jobject java_wrapper_obj, jobject comparison_obj) { #ifdef PRESERVE_JSOBJECT_IDENTITY # error "Missing code should be added here" #else JSObject *js_obj1, *js_obj2; /* Check that we're comparing with another netscape.javascript.JSObject */ if (!comparison_obj) return 0; if (!(*jEnv)->IsInstanceOf(jEnv, comparison_obj, njJSObject)) return 0; js_obj1 = jsj_UnwrapJSObjectWrapper(jEnv, java_wrapper_obj); js_obj2 = jsj_UnwrapJSObjectWrapper(jEnv, comparison_obj); return (js_obj1 == js_obj2); #endif /* PRESERVE_JSOBJECT_IDENTITY */ }
JSJavaThreadState * jsj_enter_js(JNIEnv *jEnv, void* applet_obj, jobject java_wrapper_obj, JSContext **cxp, JSObject **js_objp, JSErrorReporter *old_error_reporterp, void **pNSIPrincipaArray, int numPrincipals, void *pNSISecurityContext) { JSContext *cx; char *err_msg; JSObject *js_obj; JSJavaThreadState *jsj_env; cx = NULL; err_msg = NULL; /* Invoke callback, presumably used to implement concurrency constraints */ if (JSJ_callbacks && JSJ_callbacks->enter_js_from_java) { #ifdef OJI if (!JSJ_callbacks->enter_js_from_java(jEnv, &err_msg, pNSIPrincipaArray, numPrincipals, pNSISecurityContext,applet_obj)) #else if (!JSJ_callbacks->enter_js_from_java(jEnv, &err_msg)) #endif goto entry_failure; } /* Check the JSObject pointer in the wrapper object. */ if (js_objp) { #ifdef PRESERVE_JSOBJECT_IDENTITY #if JS_BYTES_PER_LONG == 8 js_obj = (JSObject *)((*jEnv)->GetLongField(jEnv, java_wrapper_obj, njJSObject_long_internal)); #else js_obj = (JSObject *)((*jEnv)->GetIntField(jEnv, java_wrapper_obj, njJSObject_internal)); #endif #else /* !PRESERVE_JSOBJECT_IDENTITY */ js_obj = jsj_UnwrapJSObjectWrapper(jEnv, java_wrapper_obj); #endif /* PRESERVE_JSOBJECT_IDENTITY */ JS_ASSERT(js_obj); if (!js_obj) goto error; *js_objp = js_obj; } /* Get the per-thread state corresponding to the current Java thread */ jsj_env = jsj_MapJavaThreadToJSJavaThreadState(jEnv, &err_msg); if (!jsj_env) goto error; /* Get the JSContext that we're supposed to use for this Java thread */ cx = jsj_env->cx; if (!cx) { /* We called spontaneously into JS from Java, rather than from JS into Java and back into JS. Invoke a callback to obtain/create a JSContext for us to use. */ if (JSJ_callbacks && JSJ_callbacks->map_jsj_thread_to_js_context) { #ifdef OJI cx = JSJ_callbacks->map_jsj_thread_to_js_context(jsj_env, applet_obj, jEnv, &err_msg); #else cx = JSJ_callbacks->map_jsj_thread_to_js_context(jsj_env, jEnv, &err_msg); #endif if (!cx) goto error; } else { err_msg = JS_smprintf("Unable to find/create JavaScript execution " "context for JNI thread 0x%08x", jEnv); goto error; } } *cxp = cx; /* * Capture all JS error reports so that they can be thrown into the Java * caller as an instance of netscape.javascript.JSException. */ *old_error_reporterp = JS_SetErrorReporter(cx, capture_js_error_reports_for_java); #ifdef JSJ_THREADSAFE JS_BeginRequest(cx); #endif return jsj_env; error: /* Invoke callback, presumably used to implement concurrency constraints */ if (JSJ_callbacks && JSJ_callbacks->exit_js) JSJ_callbacks->exit_js(jEnv, cx); entry_failure: if (err_msg) { if (cx) JS_ReportError(cx, err_msg); else jsj_LogError(err_msg); free(err_msg); } return NULL; }
/* * This is a wrapper around JS_ReportError(), useful when an error condition * is the result of a JVM failure or exception condition. It appends the * message associated with the pending Java exception to the passed in * printf-style format string and arguments. */ static void vreport_java_error(JSContext *cx, JNIEnv *jEnv, const char *format, va_list ap) { jobject java_obj; jclass java_class; JavaClassDescriptor *class_descriptor; jthrowable java_exception; JSType wrapped_exception_type; jsval js_exception; java_obj = NULL; class_descriptor = NULL; /* Get the exception out of the java environment. */ java_exception = (*jEnv)->ExceptionOccurred(jEnv); if (!java_exception) { JSString *err_jsstr; char *err = JS_vsmprintf(format, ap); if (!err) return; err_jsstr = JS_NewString(cx, err, strlen(err)); if (!err_jsstr) return; JS_SetPendingException(cx, STRING_TO_JSVAL(err_jsstr)); return; } (*jEnv)->ExceptionClear(jEnv); /* Check for JSException */ if (njJSException && (*jEnv)->IsInstanceOf(jEnv, java_exception, njJSException)) { wrapped_exception_type = (*jEnv)->GetIntField(jEnv, java_exception, njJSException_wrappedExceptionType); /* (int) to suppress warning */ if ((int)wrapped_exception_type != JSTYPE_EMPTY) { java_obj = (*jEnv)->GetObjectField(jEnv, java_exception, njJSException_wrappedException); if ((java_obj == NULL) && (wrapped_exception_type == JSTYPE_OBJECT)) { js_exception = JSVAL_NULL; } else { java_class = (*jEnv)->GetObjectClass(jEnv, java_obj); class_descriptor = jsj_GetJavaClassDescriptor(cx, jEnv, java_class); /* OK to delete ref, since above call adds global ref */ (*jEnv)->DeleteLocalRef(jEnv, java_class); /* Convert native JS values back to native types. */ switch(wrapped_exception_type) { case JSTYPE_NUMBER: if (!jsj_ConvertJavaObjectToJSNumber(cx, jEnv, class_descriptor, java_obj, &js_exception)) goto error; break; case JSTYPE_BOOLEAN: if (!jsj_ConvertJavaObjectToJSBoolean(cx, jEnv, class_descriptor, java_obj, &js_exception)) goto error; break; case JSTYPE_STRING: if (!jsj_ConvertJavaObjectToJSString(cx, jEnv, class_descriptor, java_obj, &js_exception)) goto error; break; case JSTYPE_VOID: js_exception = JSVAL_VOID; break; case JSTYPE_OBJECT: case JSTYPE_FUNCTION: default: if ((*jEnv)->IsInstanceOf(jEnv, java_obj, njJSObject)) { js_exception = OBJECT_TO_JSVAL(jsj_UnwrapJSObjectWrapper(jEnv, java_obj)); if (!js_exception) goto error; } else { if (!jsj_ConvertJavaObjectToJSValue(cx, jEnv, java_obj, &js_exception)) goto error; } } } } /* Check for internal exception */ } else { if (!JSJ_ConvertJavaObjectToJSValue(cx, java_exception, &js_exception)) { goto error; } } /* Set pending JS exception and clear the java exception. */ JS_SetPendingException(cx, js_exception); goto done; error: JS_ASSERT(0); jsj_LogError("Out of memory while attempting to throw JSException\n"); done: if (class_descriptor) jsj_ReleaseJavaClassDescriptor(cx, jEnv, class_descriptor); if (java_obj) (*jEnv)->DeleteLocalRef(jEnv, java_obj); if (java_exception) (*jEnv)->DeleteLocalRef(jEnv, java_exception); }