1 /*
   2  * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
   3  */
   4 
   5 #import <Cocoa/Cocoa.h>
   6 #include <jni.h>
   7 
   8 #define JAVA_LAUNCH_ERROR "JavaLaunchError"
   9 
  10 #define JAVA_KEY "Java"
  11 #define RUNTIME_KEY "Runtime"
  12 #define MAIN_CLASS_NAME_KEY "MainClassName"
  13 #define OPTIONS_KEY "Options"
  14 #define ARGUMENTS_KEY "Arguments"
  15 
  16 // TODO Remove these; they are defined by the makefile
  17 #define FULL_VERSION "1.7.0"
  18 #define DOT_VERSION "1.7.0"
  19 #define DEFAULT_POLICY 0
  20 
  21 typedef int (JNICALL *JLI_Launch_t)(int argc, char ** argv,
  22                                     int jargc, const char** jargv,
  23                                     int appclassc, const char** appclassv,
  24                                     const char* fullversion,
  25                                     const char* dotversion,
  26                                     const char* pname,
  27                                     const char* lname,
  28                                     jboolean javaargs,
  29                                     jboolean cpwildcard,
  30                                     jboolean javaw,
  31                                     jint ergo);
  32 
  33 int launch(char *);
  34 int jli_launch(char *, NSURL *, NSString *, NSString *, NSString *, NSArray *, NSArray *);
  35 
  36 int main(int argc, char *argv[]) {
  37     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  38 
  39     int result;
  40     @try {
  41         launch(argv[0]);
  42         result = 0;
  43     } @catch (NSException *exception) {
  44         NSLog(@"%@: %@", exception, [exception callStackSymbols]);
  45         result = 1;
  46     }
  47 
  48     [pool drain];
  49 
  50     return result;
  51 }
  52 
  53 int launch(char *commandName) {
  54     // Get the main bundle
  55     NSBundle *mainBundle = [NSBundle mainBundle];
  56     NSDictionary *infoDictionary = [mainBundle infoDictionary];
  57 
  58     NSString *javaPath = [[mainBundle bundlePath] stringByAppendingString:@"/Contents/Java"];
  59 
  60     // Get the Java dictionary
  61     NSDictionary *javaDictionary = [infoDictionary objectForKey:@JAVA_KEY];
  62     if (javaDictionary == nil) {
  63         [NSException raise:@JAVA_LAUNCH_ERROR format:@"%@ is required.", @JAVA_KEY];
  64     }
  65 
  66     // Get the runtime bundle URL
  67     NSString *runtime = [javaDictionary objectForKey:@RUNTIME_KEY];
  68 
  69     // TODO If unspecified, use default runtime location
  70 
  71     NSURL *runtimeBundleURL = [[mainBundle builtInPlugInsURL] URLByAppendingPathComponent:runtime];
  72 
  73     // Get the main class name
  74     NSString *mainClassName = [javaDictionary objectForKey:@MAIN_CLASS_NAME_KEY];
  75     if (mainClassName == nil) {
  76         [NSException raise:@JAVA_LAUNCH_ERROR format:@"%@ is required.", @MAIN_CLASS_NAME_KEY];
  77     }
  78 
  79     // Set the class path
  80     NSString *classPathFormat = @"-Djava.class.path=%@/Classes";
  81     NSMutableString *classPath = [[NSString stringWithFormat:classPathFormat, javaPath] mutableCopy];
  82 
  83     NSFileManager *defaultFileManager = [NSFileManager defaultManager];
  84     NSArray *javaDirectoryContents = [defaultFileManager contentsOfDirectoryAtPath:javaPath error:nil];
  85     if (javaDirectoryContents == nil) {
  86         [NSException raise:@JAVA_LAUNCH_ERROR format:@"Could not enumerate Java directory contents."];
  87     }
  88 
  89     for (NSString *file in javaDirectoryContents) {
  90         if ([file hasSuffix:@".jar"]) {
  91             [classPath appendFormat:@":%@/%@", javaPath, file];
  92         }
  93     }
  94 
  95     // Set the library path
  96     NSString *libraryPathFormat = @"-Djava.library.path=%@";
  97     NSString *libraryPath = [NSString stringWithFormat:libraryPathFormat, javaPath];
  98 
  99     // Get the VM options
 100     NSArray *options = [javaDictionary objectForKey:@OPTIONS_KEY];
 101     if (options == nil) {
 102         options = [NSArray array];
 103     }
 104 
 105     // Get the application arguments
 106     NSArray *arguments = [javaDictionary objectForKey:@ARGUMENTS_KEY];
 107     if (arguments == nil) {
 108         arguments = [NSArray array];
 109     }
 110 
 111     return jli_launch(commandName, runtimeBundleURL,
 112                       mainClassName, classPath, libraryPath,
 113                       options, arguments);
 114 }
 115 
 116 int jli_launch(char *commandName, NSURL *runtimeBundleURL,
 117                NSString *mainClassName, NSString *classPath, NSString *libraryPath,
 118                NSArray *options, NSArray *arguments) {
 119     // Load the runtime bundle
 120     CFBundleRef runtimeBundle = CFBundleCreate(NULL, (CFURLRef)runtimeBundleURL);
 121 
 122     NSError *bundleLoadError = nil;
 123     Boolean runtimeBundleLoaded = CFBundleLoadExecutableAndReturnError(runtimeBundle, (CFErrorRef *)&bundleLoadError);
 124     if (bundleLoadError != nil || !runtimeBundleLoaded) {
 125         [NSException raise:@JAVA_LAUNCH_ERROR format:@"Could not load JRE from %@.", bundleLoadError];
 126     }
 127 
 128     // Get the JLI_Launch() function pointer
 129     JLI_Launch_t JLI_LaunchFxnPtr = CFBundleGetFunctionPointerForName(runtimeBundle, CFSTR("JLI_Launch"));
 130     if (JLI_LaunchFxnPtr == NULL) {
 131         [NSException raise:@JAVA_LAUNCH_ERROR format:@"Could not get function pointer for JLI_Launch."];
 132     }
 133 
 134     // Initialize the arguments to JLI_Launch()
 135     int argc = 1 + [options count] + 2 + [arguments count] + 1;
 136     char *argv[argc];
 137 
 138     int i = 0;
 139     argv[i++] = commandName;
 140     argv[i++] = strdup([classPath UTF8String]);
 141     argv[i++] = strdup([libraryPath UTF8String]);
 142 
 143     for (NSString *option in options) {
 144         argv[i++] = strdup([option UTF8String]);
 145     }
 146 
 147     argv[i++] = strdup([mainClassName UTF8String]);
 148 
 149     for (NSString *argument in arguments) {
 150         argv[i++] = strdup([argument UTF8String]);
 151     }
 152 
 153     // Invoke JLI_Launch()
 154     return JLI_LaunchFxnPtr(argc, argv,
 155                             0, NULL,
 156                             0, NULL,
 157                             FULL_VERSION,
 158                             DOT_VERSION,
 159                             "java",
 160                             "java",
 161                             FALSE,
 162                             TRUE,
 163                             FALSE,
 164                             DEFAULT_POLICY);
 165 }