1/* 2 * JavaAppLauncher: a simple Java application launcher for Mac OS X. 3 * StartJava.cpp 4 * 5 * Paul J. Lucas [paul@lightcrafts.com] 6 * 7 * This code is based on: 8 * http://developer.apple.com/samplecode/simpleJavaLauncher/simpleJavaLauncher.html 9 * http://developer.apple.com/samplecode/JavaSplashScreen/JavaSplashScreen.html 10 */ 11 12// standard 13#include <jni.h> 14#include <pthread.h> 15#include <sys/types.h> 16#include <sys/resource.h> /* for getrlimit(2) */ 17#ifdef DEBUG 18#include <iostream> 19#endif 20 21// local 22#include "JavaParamBlock.h" 23#include "LC_JNIUtils.h" 24#include "UI.h" 25 26using namespace std; 27using namespace LightCrafts; 28 29JavaVM *g_jvm; 30 31/** 32 * Convert the array of char* pointers of the main() arguments to a Java 33 * String[]. 34 */ 35static jobjectArray convertMainArgs( JNIEnv *env, JavaParamBlock const *jpb ) { 36 jclass jString_class = env->FindClass( "java/lang/String" ); 37 if ( !jString_class ) 38 LC_die( @"Unexpected", @"Missing java.lang.String" ); 39 40 jobjectArray jArgs = 41 env->NewObjectArray( jpb->main_argc, jString_class, 0 ); 42 if ( !jArgs ) 43 LC_die( @"Unexpected", @"Could not allocate main() array" ); 44 if ( jpb->main_argc ) { 45 for ( int i = 0; i < jpb->main_argc; ++i ) { 46 auto_jstring jArg( env, env->NewStringUTF( jpb->main_argv[i] ) ); 47 if ( !jArg ) 48 LC_die( @"Unexpected", @"Could not allocate main() string" ); 49 env->SetObjectArrayElement( jArgs, i, jArg ); 50 } 51 } else { 52 // 53 // No "Arguments" key was found so leave the array empty and use that 54 // for "no arguments" to main(). 55 // 56 } 57 58 return jArgs; 59} 60 61/** 62 * This method is called when the Java application is ready to open files. 63 */ 64JNIEXPORT void JNICALL readyToOpenFiles( JNIEnv*, jclass ) { 65#ifdef DEBUG 66 cout << "*** In readyToOpenFiles()" << endl; 67#endif 68 extern bool g_javaIsReady; 69 g_javaIsReady = true; 70} 71 72/** 73 * Start the JVM. This must be called in its own thread. 74 */ 75void startJava( JavaParamBlock const *jpb, jclass *pLauncher_class ) { 76 // 77 // Start a JVM. 78 // 79 JNIEnv *env; 80 if ( JNI_CreateJavaVM( &g_jvm, (void**)&env, (void*)&jpb->jvm_args ) != 0 ) 81 LC_die( @"Unexpected", @"Error starting JVM" ); 82 83 // 84 // Find the application's main class. 85 // 86 *pLauncher_class = env->FindClass( jpb->main_className ); 87 if ( LC_exceptionOccurred( env ) || !*pLauncher_class ) 88 LC_die( @"Corrupted", @"Missing main()" ); 89 *pLauncher_class = (jclass)env->NewGlobalRef( *pLauncher_class ); 90 91 // 92 // Find the main class's main() method. 93 // 94 jmethodID const jMain_methodID = env->GetStaticMethodID( 95 *pLauncher_class, "main", "([Ljava/lang/String;)V" 96 ); 97 if ( LC_exceptionOccurred( env ) || !jMain_methodID ) 98 LC_die( @"Corrupted", @"Missing main() method" ); 99 100 // 101 // Register native methods. 102 // 103 JNINativeMethod const jMethod = { 104 "readyToOpenFiles", "()V", reinterpret_cast<void*>( &readyToOpenFiles ) 105 }; 106 if ( env->RegisterNatives( *pLauncher_class, &jMethod, 1 ) < 0 ) 107 LC_die( @"Unexpected", @"RegisterNatives() failed" ); 108 109 // 110 // Call the main class's main() method. 111 // 112 env->CallStaticVoidMethod( 113 *pLauncher_class, jMain_methodID, convertMainArgs( env, jpb ) 114 ); 115 if ( LC_exceptionOccurred( env ) ) 116 LC_die( @"Unexpected", @"main() threw exception" ); 117 118 // 119 // Detach the current thread so that it appears to have exited when the 120 // Java application's main() method exits. 121 // 122 if ( g_jvm->DetachCurrentThread() != 0 ) 123 LC_die( @"Unexpected", @"Could not detach thread" ); 124 125 // 126 // Unloads a Java VM and reclaims its resources. Only this thread can 127 // unload the VM. This call blocks until this thread is only remaining 128 // user thread before it destroys the VM. 129 // 130 g_jvm->DestroyJavaVM(); 131} 132 133/* vim:set et sw=4 ts=4: */ 134