Пример #1
0
/* Completes a lazy connection to the host Java VM. */
static JSBool
jsj_ConnectToJavaVM(JSJavaVM *jsjava_vm)
{
    if (!jsjava_vm->java_vm) {
        JSBool ok;
        JS_ASSERT(JSJ_callbacks->create_java_vm);
        JS_ASSERT(JSJ_callbacks->destroy_java_vm);

        ok = JSJ_callbacks->create_java_vm(&jsjava_vm->java_vm,
                                           &jsjava_vm->main_thread_env,
                                           jsjava_vm->init_args);
        if (!ok) {
            jsj_LogError("Failed to create Java VM\n");
            return JS_FALSE;
        }

        /* Remember that we created the VM so that we know to destroy it later */
        jsjava_vm->jsj_created_java_vm = JS_TRUE;
    }

    if (!jsjava_vm->jsj_inited_java_vm) {
        /*
         * JVM initialization for netscape.javascript.JSObject is performed
         * independently of the other classes that are initialized in
         * init_java_VM_reflection, because we allow it to fail.  In the case
         * of failure, LiveConnect is still operative, but only when calling
         * from JS to Java and not vice-versa.
         */
        init_netscape_java_classes(jsjava_vm, jsjava_vm->main_thread_env);

        /* Load the Java classes, and the method and field descriptors required for
           Java reflection. */
        if (!init_java_VM_reflection(jsjava_vm, jsjava_vm->main_thread_env) ||
                !jsj_InitJavaObjReflectionsTable()) {
            jsj_LogError("LiveConnect was unable to reflect one or more components of the Java runtime.\nGo to http://bugzilla.mozilla.org/show_bug.cgi?id=5369 for details.\n");
            /* This function crashes when called from here.
               Check that all the preconditions for this
               call are satisfied before making it. [jd]
               JSJ_DisconnectFromJavaVM(jsjava_vm); */
            return JS_FALSE;
        }

        jsjava_vm->jsj_inited_java_vm = JS_TRUE;
    }

    return JS_TRUE;
}
Пример #2
0
/* This shutdown routine discards all JNI references to Java objects
   that have been reflected into JS, even if there are still references
   to them from JS. */
void
jsj_DiscardJavaClassReflections(JNIEnv *jEnv)
{
    JSJavaThreadState *jsj_env;
    char *err_msg;
    JSContext *cx;

    /* Get the per-thread state corresponding to the current Java thread */
    jsj_env = jsj_MapJavaThreadToJSJavaThreadState(jEnv, &err_msg);
    JS_ASSERT(jsj_env);
    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->map_jsj_thread_to_js_context) {
#ifdef OJI
            cx = JSJ_callbacks->map_jsj_thread_to_js_context(jsj_env,
                                                             NULL, /* FIXME: What should this argument be ? */
                                                             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;
        }
    }

    if (java_class_reflections) {
        JSJ_HashTableEnumerateEntries(java_class_reflections,
                                      enumerate_remove_java_class,
                                      (void*)jsj_env);
        JSJ_HashTableDestroy(java_class_reflections);
        java_class_reflections = NULL;
    }

    return;

error:
    JS_ASSERT(!cx);
    if (err_msg) {
        jsj_LogError(err_msg);
        JS_smprintf_free(err_msg);
    }
}
Пример #3
0
/*
 * Called once per Java VM, this function initializes the classes, fields, and
 * methods required for Java reflection.  If java_vm is NULL, a new Java VM is
 * created, using the provided classpath in addition to any default classpath.
 * The classpath argument is ignored, however, if java_vm_arg is non-NULL.
 */
JSJavaVM *
JSJ_ConnectToJavaVM(SystemJavaVM *java_vm_arg, void* initargs)
{
    SystemJavaVM* java_vm;
    JSJavaVM *jsjava_vm;
    JNIEnv *jEnv;

    JS_ASSERT(JSJ_callbacks);
    JS_ASSERT(JSJ_callbacks->attach_current_thread);
    JS_ASSERT(JSJ_callbacks->detach_current_thread);
    JS_ASSERT(JSJ_callbacks->get_java_vm);

    jsjava_vm = (JSJavaVM*)malloc(sizeof(JSJavaVM));
    if (!jsjava_vm)
        return NULL;
    memset(jsjava_vm, 0, sizeof(JSJavaVM));

    java_vm = java_vm_arg;

    /* If a Java VM was passed in, try to attach to it on the current thread. */
    if (java_vm) {
        jEnv = JSJ_callbacks->attach_current_thread(java_vm);
        if (jEnv == NULL) {
            jsj_LogError("Failed to attach to Java VM thread\n");
            free(jsjava_vm);
            return NULL;
        }

        jsjava_vm->java_vm = java_vm;
        jsjava_vm->main_thread_env = jEnv;
    } else {
        jsjava_vm->init_args = initargs;
    }
       
#ifdef JSJ_THREADSAFE
    if (jsjava_vm_list == NULL) {
        thread_list_monitor =
            (struct PRMonitor *) PR_NewMonitor();
    }
#endif	/* JSJ_THREADSAFE */

    /* Put this VM on the list of all created VMs */
    jsjava_vm->next = jsjava_vm_list;
    jsjava_vm_list = jsjava_vm;

    return jsjava_vm;
}
Пример #4
0
/*
 * At certain times during initialization, there may be no JavaScript context
 * available to direct error reports to, in which case the error messages
 * are sent to this function.  The caller is responsible for free'ing
 * the js_error_msg argument.
 */
static void
report_java_initialization_error(JNIEnv *jEnv, const char *js_error_msg)
{
    const char *error_msg, *java_error_msg;

    java_error_msg = NULL;

    if (jEnv) {
        java_error_msg = jsj_GetJavaErrorMessage(jEnv);
        (*jEnv)->ExceptionClear(jEnv);
    }

    if (java_error_msg) { 
        error_msg = JS_smprintf("initialization error: %s (%s)\n",
                                js_error_msg, java_error_msg);
        free((void*)java_error_msg);
    } else {
        error_msg = JS_smprintf("initialization error: %s\n",
                                js_error_msg);
    }

    jsj_LogError(error_msg);
    free((void*)error_msg);
}
Пример #5
0
/*
 * This utility function is called just prior to returning into Java from JS.
 */
JSBool
jsj_exit_js(JSContext *cx, JSJavaThreadState *jsj_env, JSErrorReporter original_reporter)
{
    JNIEnv *jEnv;

#ifdef JSJ_THREADSAFE
    JS_EndRequest(cx);
#endif

    /* Restore the JS error reporter */
    JS_SetErrorReporter(cx, original_reporter);

    jEnv = jsj_env->jEnv;

#ifdef DEBUG
    /* Any Java exceptions should have been noticed and reported already */
    if ((*jEnv)->ExceptionOccurred(jEnv)) {
        JS_ASSERT(0);
        jsj_LogError("Unhandled Java exception detected");
        return JS_FALSE;
    }
#endif

    /*
     * Convert reported JS errors to JSExceptions, unless the errors were
     * themselves the result of Java exceptions, in which case the original
     * Java exception is simply propagated.
     */
    throw_any_pending_js_error_as_a_java_exception(jsj_env);

    /* Invoke callback, presumably used to implement concurrency constraints */
    if (JSJ_callbacks && JSJ_callbacks->exit_js)
        JSJ_callbacks->exit_js(jEnv, cx);

    return JS_TRUE;
}
Пример #6
0
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;
}
Пример #7
0
/*
 * This is called upon returning from JS back into Java.  Any JS errors
 * reported during that time will be converted into Java exceptions.  It's
 * possible that a JS error was actually triggered by Java at some point, in
 * which case the original Java exception is thrown.
 */
static void
throw_any_pending_js_error_as_a_java_exception(JSJavaThreadState *jsj_env)
{
    CapturedJSError *error;
    JNIEnv *jEnv;
    jstring message_jstr, linebuf_jstr, filename_jstr;
    jint index, lineno;
    JSErrorReport *report;
    JSContext *cx;
    jsval pending_exception; 
    jobject java_obj;
    int dummy_cost;
    JSBool is_local_refp;
    JSType primitive_type;
    jthrowable java_exception;

    message_jstr = linebuf_jstr = filename_jstr = java_exception = NULL;

    /* Get the Java JNI environment */
    jEnv = jsj_env->jEnv;

    cx = jsj_env->cx;
    /* Get the pending JS exception if it exists */
    if (cx&&JS_IsExceptionPending(cx)) {
        if (!JS_GetPendingException(cx, &pending_exception))
            goto out_of_memory;

        /* Find out the JSTYPE of this jsval. */
        primitive_type = JS_TypeOfValue(cx, pending_exception);
        
        /* Convert jsval exception to a java object and then use it to
           create an instance of JSException. */ 
        if (!jsj_ConvertJSValueToJavaObject(cx, jEnv, 
                                            pending_exception, 
                                            jsj_get_jlObject_descriptor(cx, jEnv),
                                            &dummy_cost, &java_obj, 
                                            &is_local_refp))
            goto done;
        
        java_exception = (*jEnv)->NewObject(jEnv, njJSException, 
                                            njJSException_JSException_wrap,
                                            primitive_type, java_obj);
        if (is_local_refp)
            (*jEnv)->DeleteLocalRef(jEnv, java_obj);
        if (!java_exception) 
            goto out_of_memory;
        
        /* Throw the newly-created JSException */
        if ((*jEnv)->Throw(jEnv, java_exception) < 0) {
            JS_ASSERT(0);
            jsj_LogError("Couldn't throw JSException\n");
            goto done;
        }    
        JS_ClearPendingException(cx);
        return;
    }
    if (!jsj_env->pending_js_errors) {
#ifdef DEBUG
        /* Any exception should be cleared as soon as it's detected, so there
           shouldn't be any pending. */
        if ((*jEnv)->ExceptionOccurred(jEnv)) {
            /* A Java exception occurred, but nobody in JS-land noticed. */
            JS_ASSERT(0);
            (*jEnv)->ExceptionClear(jEnv);
        }
#endif
        return;
    }

    /* Get the deepest (oldest) saved JS error */
    /* XXX - What's the right thing to do about newer errors ?
       For now we just throw them away */
    error = jsj_env->pending_js_errors;
    while (error->next)
        error = error->next;
    
    /*
     * If the JS error was originally the result of a Java exception, rethrow
     * the original exception.
     */
    if (error->java_exception) {
        (*jEnv)->Throw(jEnv, error->java_exception);
        goto done;
    }

    /* Propagate any JS errors that did not originate as Java exceptions into
       Java as an instance of netscape.javascript.JSException */

    /* First, marshall the arguments to the JSException constructor */
    message_jstr = NULL;
    if (error->message) {
        message_jstr = (*jEnv)->NewStringUTF(jEnv, error->message);
        if (!message_jstr)
            goto out_of_memory;
    }

    report = &error->report;

    filename_jstr = NULL;
    if (report->filename) {
        filename_jstr = (*jEnv)->NewStringUTF(jEnv, report->filename);
        if (!filename_jstr)
            goto out_of_memory;
    }

    linebuf_jstr = NULL;
    if (report->linebuf) {
        linebuf_jstr = (*jEnv)->NewStringUTF(jEnv, report->linebuf);
        if (!linebuf_jstr)
            goto out_of_memory;
    }

    lineno = report->lineno;
    index = report->linebuf ? report->tokenptr - report->linebuf : 0;

    /* Call the JSException constructor */
    java_exception = (*jEnv)->NewObject(jEnv, njJSException, njJSException_JSException,
                                        message_jstr, filename_jstr, lineno, linebuf_jstr, index);
    if (!java_exception)
        goto out_of_memory;

    /* Throw the newly-created JSException */
    if ((*jEnv)->Throw(jEnv, java_exception) < 0) {
        JS_ASSERT(0);
        jsj_UnexpectedJavaError(cx, jEnv, "Couldn't throw JSException\n");
    }
    goto done;

out_of_memory:
    /* No recovery possible */
    JS_ASSERT(0);
    jsj_LogError("Out of memory while attempting to throw JSException\n");

done:
    jsj_ClearPendingJSErrors(jsj_env);
    /*
     * Release local references to Java objects, since some JVMs seem reticent
     * about collecting them otherwise.
     */
    if (message_jstr)
        (*jEnv)->DeleteLocalRef(jEnv, message_jstr);
    if (filename_jstr)
        (*jEnv)->DeleteLocalRef(jEnv, filename_jstr);
    if (linebuf_jstr)
        (*jEnv)->DeleteLocalRef(jEnv, linebuf_jstr);
    if (java_exception)
        (*jEnv)->DeleteLocalRef(jEnv, java_exception);
}
Пример #8
0
/*
 * 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);
}