Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'features/org.eclipse.equinox.executable.feature/library/eclipseJNI.c')
-rw-r--r--features/org.eclipse.equinox.executable.feature/library/eclipseJNI.c568
1 files changed, 568 insertions, 0 deletions
diff --git a/features/org.eclipse.equinox.executable.feature/library/eclipseJNI.c b/features/org.eclipse.equinox.executable.feature/library/eclipseJNI.c
new file mode 100644
index 000000000..845c646c6
--- /dev/null
+++ b/features/org.eclipse.equinox.executable.feature/library/eclipseJNI.c
@@ -0,0 +1,568 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2009 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Andrew Niefer
+ *******************************************************************************/
+
+#include "eclipseJNI.h"
+#include "eclipseCommon.h"
+#include "eclipseOS.h"
+#include "eclipseShm.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+
+static _TCHAR* failedToLoadLibrary = _T_ECLIPSE("Failed to load the JNI shared library \"%s\".\n");
+static _TCHAR* createVMSymbolNotFound = _T_ECLIPSE("The JVM shared library \"%s\"\ndoes not contain the JNI_CreateJavaVM symbol.\n");
+static _TCHAR* failedCreateVM = _T_ECLIPSE("Failed to create the Java Virtual Machine.\n");
+static _TCHAR* internalExpectedVMArgs = _T_ECLIPSE("Internal Error, the JVM argument list is empty.\n");
+static _TCHAR* mainClassNotFound = _T_ECLIPSE("Failed to find a Main Class in \"%s\".\n");
+
+static JNINativeMethod natives[] = {{"_update_splash", "()V", (void *)&update_splash},
+ {"_get_splash_handle", "()J", (void *)&get_splash_handle},
+ {"_set_exit_data", "(Ljava/lang/String;Ljava/lang/String;)V", (void *)&set_exit_data},
+ {"_set_launcher_info", "(Ljava/lang/String;Ljava/lang/String;)V", (void *)&set_launcher_info},
+ {"_show_splash", "(Ljava/lang/String;)V", (void *)&show_splash},
+ {"_takedown_splash", "()V", (void *)&takedown_splash}};
+
+/* local methods */
+static jstring newJavaString(JNIEnv *env, _TCHAR * str);
+static void registerNatives(JNIEnv *env);
+static int shouldShutdown(JNIEnv *env);
+static void JNI_ReleaseStringChars(JNIEnv *env, jstring s, const _TCHAR* data);
+static const _TCHAR* JNI_GetStringChars(JNIEnv *env, jstring str);
+static char * getMainClass(JNIEnv *env, _TCHAR * jarFile);
+static void setLibraryLocation(JNIEnv *env, jobject obj);
+
+static JavaVM * jvm = 0;
+static JNIEnv *env = 0;
+
+/* cache String class and methods to avoid looking them up all the time */
+static jclass string_class = NULL;
+#if !defined(UNICODE) && !defined(MACOSX)
+static jmethodID string_getBytesMethod = NULL;
+static jmethodID string_ctor = NULL;
+#endif
+
+/* JNI Callback methods */
+JNIEXPORT void JNICALL set_exit_data(JNIEnv * env, jobject obj, jstring id, jstring s){
+ const _TCHAR* data = NULL;
+ const _TCHAR* sharedId = NULL;
+ size_t length;
+
+ if(s != NULL) {
+ length = (*env)->GetStringLength(env, s);
+ if(!(*env)->ExceptionOccurred(env)) {
+ data = JNI_GetStringChars(env, s);
+ if (data != NULL) {
+ if(id != NULL) {
+ sharedId = JNI_GetStringChars(env, id);
+ if(sharedId != NULL) {
+ setSharedData(sharedId, data);
+ JNI_ReleaseStringChars(env, id, sharedId);
+ }
+ } else {
+ exitData = malloc((length + 1) * sizeof(_TCHAR*));
+ _tcsncpy( exitData, data, length);
+ exitData[length] = _T_ECLIPSE('\0');
+ }
+ JNI_ReleaseStringChars(env, s, data);
+ }
+ }
+ if(data == NULL && sharedId == NULL) {
+ (*env)->ExceptionDescribe(env);
+ (*env)->ExceptionClear(env);
+ }
+ }
+}
+
+JNIEXPORT void JNICALL set_launcher_info(JNIEnv * env, jobject obj, jstring launcher, jstring name){
+ const _TCHAR* launcherPath = NULL;
+ const _TCHAR* launcherName = NULL;
+
+ if (launcher != NULL) {
+ launcherPath = JNI_GetStringChars(env, launcher);
+ if (launcherPath != NULL) {
+ setProgramPath(_tcsdup(launcherPath));
+ JNI_ReleaseStringChars(env, launcher, launcherPath);
+ }
+ }
+
+ if (name != NULL) {
+ launcherName = JNI_GetStringChars(env, name);
+ if (launcherName != NULL) {
+ setOfficialName(_tcsdup(launcherName));
+ JNI_ReleaseStringChars(env, name, launcherName);
+ }
+ }
+}
+
+
+JNIEXPORT void JNICALL update_splash(JNIEnv * env, jobject obj){
+ dispatchMessages();
+}
+
+JNIEXPORT jlong JNICALL get_splash_handle(JNIEnv * env, jobject obj){
+ return getSplashHandle();
+}
+
+JNIEXPORT void JNICALL show_splash(JNIEnv * env, jobject obj, jstring s){
+ const _TCHAR* data = NULL;
+
+ setLibraryLocation(env, obj);
+
+ if(s != NULL) {
+ data = JNI_GetStringChars(env, s);
+ if(data != NULL) {
+ showSplash(data);
+ JNI_ReleaseStringChars(env, s, data);
+ } else {
+ (*env)->ExceptionDescribe(env);
+ (*env)->ExceptionClear(env);
+ }
+ }
+}
+
+JNIEXPORT void JNICALL takedown_splash(JNIEnv * env, jobject obj){
+ takeDownSplash();
+}
+
+/*
+ * On AIX we need the location of the eclipse shared library so that we
+ * can find the libeclipse-motif.so library. Reach into the JNIBridge
+ * object to get the "library" field.
+ */
+static void setLibraryLocation(JNIEnv * env, jobject obj) {
+ jclass bridge = (*env)->FindClass(env, "org/eclipse/equinox/launcher/JNIBridge");
+ if (bridge != NULL) {
+ jfieldID libraryField = (*env)->GetFieldID(env, bridge, "library", "Ljava/lang/String;");
+ if (libraryField != NULL) {
+ jstring stringObject = (jstring) (*env)->GetObjectField(env, obj, libraryField);
+ if (stringObject != NULL) {
+ const _TCHAR * str = JNI_GetStringChars(env, stringObject);
+ eclipseLibrary = _tcsdup(str);
+ JNI_ReleaseStringChars(env, stringObject, str);
+ }
+ }
+ }
+ if( (*env)->ExceptionOccurred(env) != 0 ){
+ (*env)->ExceptionDescribe(env);
+ (*env)->ExceptionClear(env);
+ }
+}
+
+static void registerNatives(JNIEnv *env) {
+ jclass bridge = (*env)->FindClass(env, "org/eclipse/equinox/launcher/JNIBridge");
+ if(bridge != NULL) {
+ int numNatives = sizeof(natives) / sizeof(natives[0]);
+ (*env)->RegisterNatives(env, bridge, natives, numNatives);
+ }
+ if( (*env)->ExceptionOccurred(env) != 0 ){
+ (*env)->ExceptionDescribe(env);
+ (*env)->ExceptionClear(env);
+ }
+}
+
+
+/* Get a _TCHAR* from a jstring, string should be released later with JNI_ReleaseStringChars */
+static const _TCHAR * JNI_GetStringChars(JNIEnv *env, jstring str) {
+ const _TCHAR * result = NULL;
+#ifdef UNICODE
+ /* GetStringChars is not null terminated, make a copy */
+ const _TCHAR * stringChars = (*env)->GetStringChars(env, str, 0);
+ int length = (*env)->GetStringLength(env, str);
+ _TCHAR * copy = malloc( (length + 1) * sizeof(_TCHAR));
+ _tcsncpy(copy, stringChars, length);
+ copy[length] = _T_ECLIPSE('\0');
+ (*env)->ReleaseStringChars(env, str, stringChars);
+ result = copy;
+#elif MACOSX
+ /* Use UTF on the Mac */
+ result = (*env)->GetStringUTFChars(env, str, 0);
+#else
+ /* Other platforms, use java's default encoding */
+ _TCHAR* buffer = NULL;
+ if (string_class == NULL)
+ string_class = (*env)->FindClass(env, "java/lang/String");
+ if (string_class != NULL) {
+ if (string_getBytesMethod == NULL)
+ string_getBytesMethod = (*env)->GetMethodID(env, string_class, "getBytes", "()[B");
+ if (string_getBytesMethod != NULL) {
+ jbyteArray bytes = (*env)->CallObjectMethod(env, str, string_getBytesMethod);
+ if (!(*env)->ExceptionOccurred(env)) {
+ jsize length = (*env)->GetArrayLength(env, bytes);
+ buffer = malloc( (length + 1) * sizeof(_TCHAR*));
+ (*env)->GetByteArrayRegion(env, bytes, 0, length, (jbyte*)buffer);
+ buffer[length] = 0;
+ }
+ (*env)->DeleteLocalRef(env, bytes);
+ }
+ }
+ if(buffer == NULL) {
+ (*env)->ExceptionDescribe(env);
+ (*env)->ExceptionClear(env);
+ }
+ result = buffer;
+#endif
+ return result;
+}
+
+/* Release the string that was obtained using JNI_GetStringChars */
+static void JNI_ReleaseStringChars(JNIEnv *env, jstring s, const _TCHAR* data) {
+#ifdef UNICODE
+ free((_TCHAR*)data);
+#elif MACOSX
+ (*env)->ReleaseStringUTFChars(env, s, data);
+#else
+ free((_TCHAR*)data);
+#endif
+}
+
+static jstring newJavaString(JNIEnv *env, _TCHAR * str)
+{
+ jstring newString = NULL;
+#ifdef UNICODE
+ size_t length = _tcslen(str);
+ newString = (*env)->NewString(env, str, length);
+#elif MACOSX
+ newString = (*env)->NewStringUTF(env, str);
+#else
+ size_t length = _tcslen(str);
+ jbyteArray bytes = (*env)->NewByteArray(env, length);
+ if(bytes != NULL) {
+ (*env)->SetByteArrayRegion(env, bytes, 0, length, (jbyte *)str);
+ if (!(*env)->ExceptionOccurred(env)) {
+ if (string_class == NULL)
+ string_class = (*env)->FindClass(env, "java/lang/String");
+ if(string_class != NULL) {
+ if (string_ctor == NULL)
+ string_ctor = (*env)->GetMethodID(env, string_class, "<init>", "([B)V");
+ if(string_ctor != NULL) {
+ newString = (*env)->NewObject(env, string_class, string_ctor, bytes);
+ }
+ }
+ }
+ (*env)->DeleteLocalRef(env, bytes);
+ }
+#endif
+ if(newString == NULL) {
+ (*env)->ExceptionDescribe(env);
+ (*env)->ExceptionClear(env);
+ }
+ return newString;
+}
+
+static jobjectArray createRunArgs( JNIEnv *env, _TCHAR * args[] ) {
+ int index = 0, length = -1;
+ jobjectArray stringArray = NULL;
+ jstring string;
+
+ /*count the number of elements first*/
+ while(args[++length] != NULL);
+
+ if (string_class == NULL)
+ string_class = (*env)->FindClass(env, "java/lang/String");
+ if(string_class != NULL) {
+ stringArray = (*env)->NewObjectArray(env, length, string_class, 0);
+ if(stringArray != NULL) {
+ for( index = 0; index < length; index++) {
+ string = newJavaString(env, args[index]);
+ if(string != NULL) {
+ (*env)->SetObjectArrayElement(env, stringArray, index, string);
+ (*env)->DeleteLocalRef(env, string);
+ } else {
+ (*env)->DeleteLocalRef(env, stringArray);
+ (*env)->ExceptionDescribe(env);
+ (*env)->ExceptionClear(env);
+ return NULL;
+ }
+ }
+ }
+ }
+ if(stringArray == NULL) {
+ (*env)->ExceptionDescribe(env);
+ (*env)->ExceptionClear(env);
+ }
+ return stringArray;
+}
+
+JavaResults * startJavaJNI( _TCHAR* libPath, _TCHAR* vmArgs[], _TCHAR* progArgs[], _TCHAR* jarFile )
+{
+ int i;
+ int numVMArgs = -1;
+ void * jniLibrary;
+ JNI_createJavaVM createJavaVM;
+ JavaVMInitArgs init_args;
+ JavaVMOption * options;
+ char * mainClassName = NULL;
+ JavaResults * results = NULL;
+
+ /* JNI reflection */
+ jclass mainClass = NULL; /* The Main class to load */
+ jmethodID mainConstructor = NULL; /* Main's default constructor Main() */
+ jobject mainObject = NULL; /* An instantiation of the main class */
+ jmethodID runMethod = NULL; /* Main.run(String[]) */
+ jobjectArray methodArgs = NULL; /* Arguments to pass to run */
+
+ results = malloc(sizeof(JavaResults));
+ memset(results, 0, sizeof(JavaResults));
+
+ jniLibrary = loadLibrary(libPath);
+ if(jniLibrary == NULL) {
+ results->launchResult = -1;
+ results->errorMessage = malloc((_tcslen(failedToLoadLibrary) + _tcslen(libPath) + 1) * sizeof(_TCHAR));
+ _stprintf(results->errorMessage, failedToLoadLibrary, libPath);
+ return results; /*error*/
+ }
+
+ createJavaVM = (JNI_createJavaVM)findSymbol(jniLibrary, _T_ECLIPSE("JNI_CreateJavaVM"));
+ if(createJavaVM == NULL) {
+ results->launchResult = -2;
+ results->errorMessage = malloc((_tcslen(createVMSymbolNotFound) + _tcslen(libPath) + 1) * sizeof(_TCHAR));
+ _stprintf(results->errorMessage, createVMSymbolNotFound, libPath);
+ return results; /*error*/
+ }
+
+ /* count the vm args */
+ while(vmArgs[++numVMArgs] != NULL) {}
+
+ if(numVMArgs <= 0) {
+ /*error, we expect at least the required vm arg */
+ results->launchResult = -3;
+ results->errorMessage = _tcsdup(internalExpectedVMArgs);
+ return results;
+ }
+
+ options = malloc(numVMArgs * sizeof(JavaVMOption));
+ for(i = 0; i < numVMArgs; i++){
+ options[i].optionString = toNarrow(vmArgs[i]);
+ options[i].extraInfo = 0;
+ }
+
+#ifdef MACOSX
+ init_args.version = JNI_VERSION_1_4;
+#else
+ init_args.version = JNI_VERSION_1_2;
+#endif
+ init_args.options = options;
+ init_args.nOptions = numVMArgs;
+ init_args.ignoreUnrecognized = JNI_TRUE;
+
+ if( createJavaVM(&jvm, &env, &init_args) == 0 ) {
+ registerNatives(env);
+
+ mainClassName = getMainClass(env, jarFile);
+ if (mainClassName != NULL) {
+ mainClass = (*env)->FindClass(env, mainClassName);
+ free(mainClassName);
+ }
+
+ if (mainClass == NULL) {
+ if ((*env)->ExceptionOccurred(env)) {
+ (*env)->ExceptionDescribe(env);
+ (*env)->ExceptionClear(env);
+ }
+ mainClass = (*env)->FindClass(env, "org/eclipse/equinox/launcher/Main");
+ }
+
+ if(mainClass != NULL) {
+ results->launchResult = -6; /* this will be reset to 0 below on success */
+ mainConstructor = (*env)->GetMethodID(env, mainClass, "<init>", "()V");
+ if(mainConstructor != NULL) {
+ mainObject = (*env)->NewObject(env, mainClass, mainConstructor);
+ if(mainObject != NULL) {
+ runMethod = (*env)->GetMethodID(env, mainClass, "run", "([Ljava/lang/String;)I");
+ if(runMethod != NULL) {
+ methodArgs = createRunArgs(env, progArgs);
+ if(methodArgs != NULL) {
+ results->launchResult = 0;
+ results->runResult = (*env)->CallIntMethod(env, mainObject, runMethod, methodArgs);
+ (*env)->DeleteLocalRef(env, methodArgs);
+ }
+ }
+ (*env)->DeleteLocalRef(env, mainObject);
+ }
+ }
+ } else {
+ results->launchResult = -5;
+ results->errorMessage = malloc((_tcslen(mainClassNotFound) + _tcslen(jarFile) + 1) * sizeof(_TCHAR));
+ _stprintf(results->errorMessage, mainClassNotFound, jarFile);
+ }
+ if((*env)->ExceptionOccurred(env)){
+ (*env)->ExceptionDescribe(env);
+ (*env)->ExceptionClear(env);
+ }
+
+ } else {
+ results->launchResult = -4;
+ results->errorMessage = _tcsdup(failedCreateVM);
+ }
+
+ /* toNarrow allocated new strings, free them */
+ for(i = 0; i < numVMArgs; i++){
+ free( options[i].optionString );
+ }
+ free(options);
+ return results;
+}
+
+static char * getMainClass(JNIEnv *env, _TCHAR * jarFile) {
+ jclass jarFileClass = NULL, manifestClass = NULL, attributesClass = NULL;
+ jmethodID jarFileConstructor = NULL, getManifestMethod = NULL, getMainAttributesMethod = NULL, closeJarMethod = NULL, getValueMethod = NULL;
+ jobject jarFileObject, manifest, attributes;
+ jstring mainClassString = NULL;
+ jstring jarFileString, headerString;
+ const _TCHAR *mainClass;
+
+ /* get the classes we need */
+ jarFileClass = (*env)->FindClass(env, "java/util/jar/JarFile");
+ if (jarFileClass != NULL) {
+ manifestClass = (*env)->FindClass(env, "java/util/jar/Manifest");
+ if (manifestClass != NULL) {
+ attributesClass = (*env)->FindClass(env, "java/util/jar/Attributes");
+ }
+ }
+ if ((*env)->ExceptionOccurred(env)) {
+ (*env)->ExceptionDescribe(env);
+ (*env)->ExceptionClear(env);
+ }
+ if (attributesClass == NULL)
+ return NULL;
+
+ /* find the methods */
+ jarFileConstructor = (*env)->GetMethodID(env, jarFileClass, "<init>", "(Ljava/lang/String;Z)V");
+ if(jarFileConstructor != NULL) {
+ getManifestMethod = (*env)->GetMethodID(env, jarFileClass, "getManifest", "()Ljava/util/jar/Manifest;");
+ if(getManifestMethod != NULL) {
+ closeJarMethod = (*env)->GetMethodID(env, jarFileClass, "close", "()V");
+ if (closeJarMethod != NULL) {
+ getMainAttributesMethod = (*env)->GetMethodID(env, manifestClass, "getMainAttributes", "()Ljava/util/jar/Attributes;");
+ if (getMainAttributesMethod != NULL) {
+ getValueMethod = (*env)->GetMethodID(env, attributesClass, "getValue", "(Ljava/lang/String;)Ljava/lang/String;");
+ }
+ }
+ }
+ }
+ if ((*env)->ExceptionOccurred(env)) {
+ (*env)->ExceptionDescribe(env);
+ (*env)->ExceptionClear(env);
+ }
+ if (getValueMethod == NULL)
+ return NULL;
+
+ /* jarFileString = new String(jarFile); */
+ jarFileString = newJavaString(env, jarFile);
+ /* headerString = new String("Main-Class"); */
+ headerString = newJavaString(env, _T_ECLIPSE("Main-Class"));
+ if (jarFileString != NULL && headerString != NULL) {
+ /* jarfileObject = new JarFile(jarFileString, false); */
+ jarFileObject = (*env)->NewObject(env, jarFileClass, jarFileConstructor, jarFileString, JNI_FALSE);
+ if (jarFileObject != NULL) {
+ /* manifest = jarFileObject.getManifest(); */
+ manifest = (*env)->CallObjectMethod(env, jarFileObject, getManifestMethod);
+ if (manifest != NULL) {
+ /*jarFileObject.close() */
+ (*env)->CallVoidMethod(env, jarFileObject, closeJarMethod);
+ if (!(*env)->ExceptionOccurred(env)) {
+ /* attributes = manifest.getMainAttributes(); */
+ attributes = (*env)->CallObjectMethod(env, manifest, getMainAttributesMethod);
+ if (attributes != NULL) {
+ /* mainClassString = attributes.getValue(headerString); */
+ mainClassString = (*env)->CallObjectMethod(env, attributes, getValueMethod, headerString);
+ }
+ }
+ }
+ (*env)->DeleteLocalRef(env, jarFileObject);
+ }
+ }
+
+ if (jarFileString != NULL)
+ (*env)->DeleteLocalRef(env, jarFileString);
+ if (headerString != NULL)
+ (*env)->DeleteLocalRef(env, headerString);
+
+ if ((*env)->ExceptionOccurred(env)) {
+ (*env)->ExceptionDescribe(env);
+ (*env)->ExceptionClear(env);
+ }
+
+ if (mainClassString == NULL)
+ return NULL;
+
+ mainClass = JNI_GetStringChars(env, mainClassString);
+ if(mainClass != NULL) {
+ int i = -1;
+ char *result = toNarrow(mainClass);
+ JNI_ReleaseStringChars(env, mainClassString, mainClass);
+
+ /* replace all the '.' with '/' */
+ while(result[++i] != '\0') {
+ if(result[i] == '.')
+ result[i] = '/';
+ }
+ return result;
+ }
+ return NULL;
+}
+
+void cleanupVM(int exitCode) {
+ JNIEnv * localEnv = env;
+ if (jvm == 0)
+ return;
+
+ if (secondThread)
+ (*jvm)->AttachCurrentThread(jvm, (void**)&localEnv, NULL);
+ else
+ localEnv = env;
+ if (localEnv == 0)
+ return;
+
+ /* we call System.exit() unless osgi.noShutdown is set */
+ if (shouldShutdown(env)) {
+ jclass systemClass = NULL;
+ jmethodID exitMethod = NULL;
+ systemClass = (*env)->FindClass(env, "java/lang/System");
+ if (systemClass != NULL) {
+ exitMethod = (*env)->GetStaticMethodID(env, systemClass, "exit", "(I)V");
+ if (exitMethod != NULL) {
+ (*env)->CallStaticVoidMethod(env, systemClass, exitMethod, exitCode);
+ }
+ }
+ if ((*env)->ExceptionOccurred(env)) {
+ (*env)->ExceptionDescribe(env);
+ (*env)->ExceptionClear(env);
+ }
+ }
+ (*jvm)->DestroyJavaVM(jvm);
+}
+
+static int shouldShutdown(JNIEnv * env) {
+ jclass booleanClass = NULL;
+ jmethodID method = NULL;
+ jstring arg = NULL;
+ jboolean result = 0;
+
+ booleanClass = (*env)->FindClass(env, "java/lang/Boolean");
+ if (booleanClass != NULL) {
+ method = (*env)->GetStaticMethodID(env, booleanClass, "getBoolean", "(Ljava/lang/String;)Z");
+ if (method != NULL) {
+ arg = newJavaString(env, _T_ECLIPSE("osgi.noShutdown"));
+ result = (*env)->CallStaticBooleanMethod(env, booleanClass, method, arg);
+ (*env)->DeleteLocalRef(env, arg);
+ }
+ }
+ if ((*env)->ExceptionOccurred(env)) {
+ (*env)->ExceptionDescribe(env);
+ (*env)->ExceptionClear(env);
+ }
+ return (result == 0);
+}
+
+

Back to the top