From 2e2a34e77eab7a5da51ac6a21a891018f03f7855 Mon Sep 17 00:00:00 2001 From: "T. Joseph Carter" Date: Mon, 30 Oct 2017 06:14:13 -0700 Subject: [PATCH] mac: Use universalJavaApplicationStub MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Here's a (very rough) implementation of a macBundle task using the universalJavaApplicationStub and jarbundler. Jarbundler's support files (ant build system and docs) are suffering bitrot, and I don't grok maven yet, so I'm really flying blind with it, so basically I'm committing it in a "baseline" working (if ugly) state. So ... _why_ use this? The old way of bundling Java apps doesn't work anymore. It tells you to get Apple's (compromised/unsafe) Java 6 and when you do it throws an error because your code compiled on Oracle JDK 8/9 won't run on it anymore. You're supposed to duplicate the JRE in each Java program you bundle as you would a private/custom framework. Yes, really. This solves the dependency issues at the cost of heavy resource waste. Except every new JDK generation changes HOW you do that, and the current method is totally proprietary to Oracle's JDK. For cross-platform development, it is NOT fun. So there's uJAS, which is literally a complex shell script to magically do the equivalent of typing java -jar from the command line—which does work BTW if all your dependencies are properly in your default classpath, etc. There used to be a couple of application bundler options, but the one that still works (only with uJAS if you have the most recent JDKs), is jarbundler. TODO: Clean this up, restore original functionality (zipball), include the commandline jar, etc. committing it in this state is that jarbundler's repo is a bit of a mess. The current version (and the version we need) is 3.3.0, the "latest" from 2015. The docs, examples, and the ant build system are all literally bitrotting from version 2.x, and do not work without some fixes. So in other words, I'm committing this in a state that I got to work so that if I screw it up, since I'm flying blind, I'll have a messy but working fallback. Okay, so _why_ use any of this at all? If you create an ACBuild.properties file and run ant, you can get AppleCommander.app to build, but it won't run. It tells you that you need to download Apple's legacy Java 6 which is neither safe nor supported anymore. If you install this, it will still give you an error because the generated code can't run under Java 6. What you're supposed to do now is bundle your JRE with every Java application bundle, which means multiple copies of libs on disk and in memory. Yes, really. Except Oracle keeps changing how you do this with each new JDK generation, and the current way is pretty much totally proprietary so that you're locked in to Oracle's JDK and couldn't use OpenJDK or something if that were an option. That's what universalJavaApplicationStub resolves—it builds an app bundle that uses whatever JDK/JRE you have installed from 6 onwards. And it in turn needs jarbundler or something like it. Except all of the "something like it" solutions are dead or deprecated save the latest release of jarbundler which was modified to support uJAS and then promptly left more or less untouched since. But it "works". --- build/build.xml | 28 +- mac/jarbundler-core-3.3.0.jar | Bin 0 -> 22946 bytes mac/universalJavaApplicationStub | 535 +++++++++++++++++++++++++++++++ 3 files changed, 562 insertions(+), 1 deletion(-) create mode 100644 mac/jarbundler-core-3.3.0.jar create mode 100755 mac/universalJavaApplicationStub diff --git a/build/build.xml b/build/build.xml index 7f00836..89c561b 100644 --- a/build/build.xml +++ b/build/build.xml @@ -29,6 +29,10 @@ + + @@ -128,21 +132,43 @@ + + + + + + @@ -203,4 +229,4 @@ - \ No newline at end of file + diff --git a/mac/jarbundler-core-3.3.0.jar b/mac/jarbundler-core-3.3.0.jar new file mode 100644 index 0000000000000000000000000000000000000000..f31c4783a5f2079579f6b25c58af07b0092f77ab GIT binary patch literal 22946 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 YT?rNOQU?GKAwIK+B(E63^8o<<2RCW^@&Et; literal 0 HcmV?d00001 diff --git a/mac/universalJavaApplicationStub b/mac/universalJavaApplicationStub new file mode 100755 index 0000000..0d4ad9e --- /dev/null +++ b/mac/universalJavaApplicationStub @@ -0,0 +1,535 @@ +#!/bin/bash +################################################################################## +# # +# universalJavaApplicationStub # +# # +# # +# A shellscript JavaApplicationStub for Java Apps on Mac OS X # +# that works with both Apple's and Oracle's plist format. # +# # +# Inspired by Ian Roberts stackoverflow answer # +# at http://stackoverflow.com/a/17546508/1128689 # +# # +# # +# @author Tobias Fischer # +# @url https://github.com/tofi86/universalJavaApplicationStub # +# @date 2017-07-28 # +# @version 2.1.0 # +# # +# # +################################################################################## +# # +# # +# The MIT License (MIT) # +# # +# Copyright (c) 2017 Tobias Fischer # +# # +# Permission is hereby granted, free of charge, to any person obtaining a copy # +# of this software and associated documentation files (the "Software"), to deal # +# in the Software without restriction, including without limitation the rights # +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # +# copies of the Software, and to permit persons to whom the Software is # +# furnished to do so, subject to the following conditions: # +# # +# The above copyright notice and this permission notice shall be included in all # +# copies or substantial portions of the Software. # +# # +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # +# SOFTWARE. # +# # +################################################################################## + + + +# +# resolve symlinks +############################################ + +PRG=$0 + +while [ -h "$PRG" ]; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '^.*-> \(.*\)$' 2>/dev/null` + if expr "$link" : '^/' 2> /dev/null >/dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi +done + +# set the directory abspath of the current shell script +PROGDIR=`dirname "$PRG"` + + + +# +# set files and folders +############################################ + +# the absolute path of the app package +cd "$PROGDIR"/../../ +AppPackageFolder=`pwd` + +# the base path of the app package +cd .. +AppPackageRoot=`pwd` + +# set Apple's Java folder +AppleJavaFolder="${AppPackageFolder}"/Contents/Resources/Java + +# set Apple's Resources folder +AppleResourcesFolder="${AppPackageFolder}"/Contents/Resources + +# set Oracle's Java folder +OracleJavaFolder="${AppPackageFolder}"/Contents/Java + +# set Oracle's Resources folder +OracleResourcesFolder="${AppPackageFolder}"/Contents/Resources + +# set path to Info.plist in bundle +InfoPlistFile="${AppPackageFolder}"/Contents/Info.plist + +# set the default JVM Version to a null string +JVMVersion="" + + + +# +# read Info.plist and extract JVM options +############################################ + +# read the program name from CFBundleName +CFBundleName=`/usr/libexec/PlistBuddy -c "print :CFBundleName" "${InfoPlistFile}"` + +# read the icon file name +CFBundleIconFile=`/usr/libexec/PlistBuddy -c "print :CFBundleIconFile" "${InfoPlistFile}"` + + +# check Info.plist for Apple style Java keys -> if key :Java is present, parse in apple mode +/usr/libexec/PlistBuddy -c "print :Java" "${InfoPlistFile}" > /dev/null 2>&1 +exitcode=$? +JavaKey=":Java" + +# if no :Java key is present, check Info.plist for universalJavaApplication style JavaX keys -> if key :JavaX is present, parse in apple mode +if [ $exitcode -ne 0 ]; then + /usr/libexec/PlistBuddy -c "print :JavaX" "${InfoPlistFile}" > /dev/null 2>&1 + exitcode=$? + JavaKey=":JavaX" +fi + + +# read Info.plist in Apple style if exit code returns 0 (true, :Java key is present) +if [ $exitcode -eq 0 ]; then + + # set Java and Resources folder + JavaFolder="${AppleJavaFolder}" + ResourcesFolder="${AppleResourcesFolder}" + + APP_PACKAGE="${AppPackageFolder}" + JAVAROOT="${AppleJavaFolder}" + USER_HOME="$HOME" + + + # read the Java WorkingDirectory + JVMWorkDir=`/usr/libexec/PlistBuddy -c "print ${JavaKey}:WorkingDirectory" "${InfoPlistFile}" 2> /dev/null | xargs` + + # set Working Directory based upon Plist info + if [[ ! -z ${JVMWorkDir} ]]; then + WorkingDirectory="${JVMWorkDir}" + else + # AppPackageRoot is the standard WorkingDirectory when the script is started + WorkingDirectory="${AppPackageRoot}" + fi + + # expand variables $APP_PACKAGE, $JAVAROOT, $USER_HOME + WorkingDirectory=`eval "echo ${WorkingDirectory}"` + + + # read the MainClass name + JVMMainClass=`/usr/libexec/PlistBuddy -c "print ${JavaKey}:MainClass" "${InfoPlistFile}" 2> /dev/null` + + # read the SplashFile name + JVMSplashFile=`/usr/libexec/PlistBuddy -c "print ${JavaKey}:SplashFile" "${InfoPlistFile}" 2> /dev/null` + + # read the JVM Options + JVMOptions=`/usr/libexec/PlistBuddy -c "print ${JavaKey}:Properties" "${InfoPlistFile}" 2> /dev/null | grep " =" | sed 's/^ */-D/g' | tr '\n' ' ' | sed 's/ */ /g' | sed 's/ = /=/g' | xargs` + # replace occurences of $APP_ROOT with its content + JVMOptions=`eval "echo ${JVMOptions}"` + + # read StartOnMainThread + JVMStartOnMainThread=`/usr/libexec/PlistBuddy -c "print ${JavaKey}:StartOnMainThread" "${InfoPlistFile}" 2> /dev/null` + if [ "${JVMStartOnMainThread}" == "true" ]; then + JVMOptions+=" -XstartOnFirstThread" + fi + + # read the ClassPath in either Array or String style + JVMClassPath_RAW=`/usr/libexec/PlistBuddy -c "print ${JavaKey}:ClassPath" "${InfoPlistFile}" 2> /dev/null` + if [[ $JVMClassPath_RAW == *Array* ]] ; then + JVMClassPath=.`/usr/libexec/PlistBuddy -c "print ${JavaKey}:ClassPath" "${InfoPlistFile}" 2> /dev/null | grep " " | sed 's/^ */:/g' | tr -d '\n' | xargs` + else + JVMClassPath=${JVMClassPath_RAW} + fi + # expand variables $APP_PACKAGE, $JAVAROOT, $USER_HOME + JVMClassPath=`eval "echo ${JVMClassPath}"` + + # read the JVM Default Options in either Array or String style + JVMDefaultOptions_RAW=`/usr/libexec/PlistBuddy -c "print ${JavaKey}:VMOptions" "${InfoPlistFile}" 2> /dev/null | xargs` + if [[ $JVMDefaultOptions_RAW == *Array* ]] ; then + JVMDefaultOptions=`/usr/libexec/PlistBuddy -c "print ${JavaKey}:VMOptions" "${InfoPlistFile}" 2> /dev/null | grep " " | sed 's/^ */ /g' | tr -d '\n' | xargs` + else + JVMDefaultOptions=${JVMDefaultOptions_RAW} + fi + + # read the JVM Arguments + JVMArguments=`/usr/libexec/PlistBuddy -c "print ${JavaKey}:Arguments" "${InfoPlistFile}" 2> /dev/null | xargs` + # replace occurences of $APP_ROOT with its content + JVMArguments=`eval "echo ${JVMArguments}"` + + # read the Java version we want to find + JVMVersion=`/usr/libexec/PlistBuddy -c "print ${JavaKey}:JVMVersion" "${InfoPlistFile}" 2> /dev/null | xargs` + +# read Info.plist in Oracle style +else + + # set Working Directory and Java and Resources folder + JavaFolder="${OracleJavaFolder}" + ResourcesFolder="${OracleResourcesFolder}" + WorkingDirectory="${OracleJavaFolder}" + + APP_ROOT="${AppPackageFolder}" + + # read the MainClass name + JVMMainClass=`/usr/libexec/PlistBuddy -c "print :JVMMainClassName" "${InfoPlistFile}" 2> /dev/null` + + # read the SplashFile name + JVMSplashFile=`/usr/libexec/PlistBuddy -c "print :JVMSplashFile" "${InfoPlistFile}" 2> /dev/null` + + # read the JVM Options + JVMOptions=`/usr/libexec/PlistBuddy -c "print :JVMOptions" "${InfoPlistFile}" 2> /dev/null | grep " -" | tr -d '\n' | sed 's/ */ /g' | xargs` + # replace occurences of $APP_ROOT with its content + JVMOptions=`eval "echo ${JVMOptions}"` + + # read the ClassPath in either Array or String style + JVMClassPath_RAW=`/usr/libexec/PlistBuddy -c "print JVMClassPath" "${InfoPlistFile}" 2> /dev/null` + if [[ $JVMClassPath_RAW == *Array* ]] ; then + JVMClassPath=.`/usr/libexec/PlistBuddy -c "print JVMClassPath" "${InfoPlistFile}" 2> /dev/null | grep " " | sed 's/^ */:/g' | tr -d '\n' | xargs` + # expand variables $APP_PACKAGE, $JAVAROOT, $USER_HOME + JVMClassPath=`eval "echo ${JVMClassPath}"` + + elif [[ ! -z ${JVMClassPath_RAW} ]] ; then + JVMClassPath=${JVMClassPath_RAW} + # expand variables $APP_PACKAGE, $JAVAROOT, $USER_HOME + JVMClassPath=`eval "echo ${JVMClassPath}"` + + else + #default: fallback to OracleJavaFolder + JVMClassPath="${JavaFolder}/*" + # Do NOT expand the default App.app/Contents/Java/* classpath (#42) + fi + + # read the JVM Default Options + JVMDefaultOptions=`/usr/libexec/PlistBuddy -c "print :JVMDefaultOptions" "${InfoPlistFile}" 2> /dev/null | grep -o " \-.*" | tr -d '\n' | xargs` + + # read the JVM Arguments + JVMArguments=`/usr/libexec/PlistBuddy -c "print :JVMArguments" "${InfoPlistFile}" 2> /dev/null | tr -d '\n' | sed -E 's/Array \{ *(.*) *\}/\1/g' | sed 's/ */ /g' | xargs` + # replace occurences of $APP_ROOT with its content + JVMArguments=`eval "echo ${JVMArguments}"` +fi + + + +# +# internationalized messages +# +############################################ + +LANG=`defaults read -g AppleLocale` + +# French localization +if [[ $LANG == fr* ]] ; then + MSG_ERROR_LAUNCHING="Erreur au lancement de '${CFBundleName}'." + MSG_MISSING_MAINCLASS="'MainClass' n'est pas spécifié.\nL'application Java ne peut pas être lancée." + MSG_NO_SUITABLE_JAVA="La version de Java installée sur votre système ne convient pas.\nCe programme nécessite Java" + MSG_JAVA_VERSION_OR_LATER="ou ultérieur" + MSG_JAVA_VERSION_LATEST="(dernière mise à jour)" + MSG_NO_SUITABLE_JAVA_CHECK="Merci de bien vouloir installer la version de Java requise." + MSG_INSTALL_JAVA="Java doit être installé sur votre système.\nRendez-vous sur java.com et suivez les instructions d'installation..." + MSG_LATER="Plus tard" + MSG_VISIT_JAVA_DOT_COM="Visiter java.com" + +# German localization +elif [[ $LANG == de* ]] ; then + MSG_ERROR_LAUNCHING="FEHLER beim Starten von '${CFBundleName}'." + MSG_MISSING_MAINCLASS="Die 'MainClass' ist nicht spezifiziert!\nDie Java-Anwendung kann nicht gestartet werden!" + MSG_NO_SUITABLE_JAVA="Es wurde keine passende Java-Version auf Ihrem System gefunden!\nDieses Programm benötigt Java" + MSG_JAVA_VERSION_OR_LATER="oder neuer" + MSG_JAVA_VERSION_LATEST="(neuste Unterversion)" + MSG_NO_SUITABLE_JAVA_CHECK="Stellen Sie sicher, dass die angeforderte Java-Version installiert ist." + MSG_INSTALL_JAVA="Auf Ihrem System muss die 'Java'-Software installiert sein.\nBesuchen Sie java.com für weitere Installationshinweise." + MSG_LATER="Später" + MSG_VISIT_JAVA_DOT_COM="java.com öffnen" + +# English default localization +else + MSG_ERROR_LAUNCHING="ERROR launching '${CFBundleName}'." + MSG_MISSING_MAINCLASS="'MainClass' isn't specified!\nJava application cannot be started!" + MSG_NO_SUITABLE_JAVA="No suitable Java version found on your system!\nThis program requires Java" + MSG_JAVA_VERSION_OR_LATER="or later" + MSG_JAVA_VERSION_LATEST="(latest update)" + MSG_NO_SUITABLE_JAVA_CHECK="Make sure you install the required Java version." + MSG_INSTALL_JAVA="You need to have JAVA installed on your Mac!\nVisit java.com for installation instructions..." + MSG_LATER="Later" + MSG_VISIT_JAVA_DOT_COM="Visit java.com" +fi + + + +# helper function: +# extract Java version string from `java -version` command +# works for both old (1.8) and new (9) version schema +########################################################## +function extractJavaVersionString() { + # second sed command strips " and -ea from the version string + echo `"$1" -version 2>&1 | awk '/version/{print $NF}' | sed -E 's/"//g;s/-ea//g'` +} + + +# helper function: +# extract Java major version from java version string +# - input '1.7.0_76' returns '7' +# - input '1.8.0_121' returns '8' +# - input '9-ea' returns '9' +# - input '9.0.3' returns '9' +########################################################## +function extractJavaMajorVersion() { + java_ver=$1 + # Java 6, 7, 8 starts with 1.x + if [ ${java_ver:0:2} == "1." ] ; then + echo ${java_ver} | sed -E 's/1\.([0-9])[0-9_.]{2,6}/\1/g' + else + # Java 9+ starts with x using semver versioning + echo ${java_ver} | sed -E 's/([0-9]+)(-ea|(\.[0-9]+)*)/\1/g' + fi +} + + +# helper function: +# return comparable version for java version string +# basically just strip punctuation and leading '1.' +########################################################## +function comparableJavaVersionNumber() { + echo $1 | sed -E 's/^1\.//g;s/[[:punct:]]//g' +} + + +# function: +# Java version tester checks whether a given java version +# satisfies the given requirement +# - parameter1: the java major version (6, 7, 8, 9, etc.) +# - parameter2: the java requirement (1.6, 1.7+, etc.) +# - return: 0 (satiesfies), 1 (does not), 2 (error) +########################################################## +function JavaVersionSatisfiesRequirement() { + java_ver=$1 + java_req=$2 + + # matches requirements with * modifier + # e.g. 1.8*, 9*, 9.1*, 9.2.4*, 10*, 10.1*, 10.1.35* + if [[ ${java_req} =~ ^[0-9]+(\.[0-9]+)*\*$ ]] ; then + # remove last char (*) from requirement string for comparison + java_req_num=${java_req::${#java_req}-1} + if [ ${java_ver} == ${java_req_num} ] ; then + return 0 + else + return 1 + fi + + # matches requirements with + modifier + # e.g. 1.8+, 9+, 9.1+, 9.2.4+, 10+, 10.1+, 10.1.35+ + elif [[ ${java_req} =~ ^[0-9]+(\.[0-9]+)*\+$ ]] ; then + java_req_num=$(comparableJavaVersionNumber ${java_req}) + java_ver_num=$(comparableJavaVersionNumber ${java_ver}) + if [ ${java_ver_num} -ge ${java_req_num} ] ; then + return 0 + else + return 1 + fi + + # matches standard requirements without modifier + # e.g. 1.8, 9, 9.1, 9.2.4, 10, 10.1, 10.1.35 + elif [[ ${java_req} =~ ^[0-9]+(\.[0-9]+)*$ ]] ; then + if [ ${java_ver} == ${java_req} ] ; then + return 0 + else + return 1 + fi + + # not matching any of the above patterns + # results in an error + else + return 2 + fi +} + + + +# +# find installed Java versions +############################################ + +apple_jre_plugin="/Library/Java/Home/bin/java" +apple_jre_version=$(extractJavaMajorVersion $(extractJavaVersionString "${apple_jre_plugin}")) +oracle_jre_plugin="/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/bin/java" +oracle_jre_version=$(extractJavaMajorVersion $(extractJavaVersionString "${oracle_jre_plugin}")) + +# first check system variable "$JAVA_HOME" +if [ -n "$JAVA_HOME" ] ; then + + # PR 26: Allow specifying "$JAVA_HOME" relative to "$AppPackageFolder" + # which allows for bundling a custom version of Java inside your app! + if [[ $JAVA_HOME == /* ]] ; then + # if "$JAVA_HOME" starts with a Slash it's an absolute path + JAVACMD="$JAVA_HOME/bin/java" + else + # otherwise it's a relative path to "$AppPackageFolder" + JAVACMD="$AppPackageFolder/$JAVA_HOME/bin/java" + fi + +# check for a specific Java version, specified in JVMversion Plist key +elif [ ! -z ${JVMVersion} ] ; then + + # first check "/usr/libexec/java_home" symlinks + if [ -x /usr/libexec/java_home ] && /usr/libexec/java_home -F -v ${JVMVersion} > /dev/null 2>&1 ; then + JAVACMD="`/usr/libexec/java_home -F -v ${JVMVersion} 2> /dev/null`/bin/java" + JAVACMD_version=$(comparableJavaVersionNumber $(extractJavaVersionString "${JAVACMD}")) + fi + + # then additionally check the Oracle JRE plugin whether it's a higher/newer compatible version + if [ -x "${oracle_jre_plugin}" ] && JavaVersionSatisfiesRequirement ${oracle_jre_version} ${JVMVersion} ; then + this_java_ver=$(comparableJavaVersionNumber $(extractJavaVersionString "${oracle_jre_plugin}")) + # use this compatible version only if the above returned empty or if the version number is higher + if [ -z ${JAVACMD} ] || [ ${this_java_ver} -ge ${JAVACMD_version} ] ; then + JAVACMD="${oracle_jre_plugin}" + JAVACMD_version=${this_java_ver} + fi + fi + + # then additionally check the Apple JRE plugin whether it's a higher/newer compatible version + if [ -x "${apple_jre_plugin}" ] && JavaVersionSatisfiesRequirement ${apple_jre_version} ${JVMVersion} ; then + this_java_ver=$(comparableJavaVersionNumber $(extractJavaVersionString "${apple_jre_plugin}")) + # use this compatible version only if the above returned empty or if the version number is higher + if [ -z ${JAVACMD} ] || [ ${this_java_ver} -ge ${JAVACMD_version} ] ; then + JAVACMD="${apple_jre_plugin}" + JAVACMD_version=${this_java_ver} + fi + fi + + if [ -z "$JAVACMD" ] ; then + # display human readable java version (#28) + java_version_hr=`echo ${JVMVersion} | sed -E 's/[0-9]\.([0-9+*]+)/ \1/g' | sed "s/+/ ${MSG_JAVA_VERSION_OR_LATER}/" | sed "s/*/ ${MSG_JAVA_VERSION_LATEST}/"` + # display error message with applescript + osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_NO_SUITABLE_JAVA}${java_version_hr}.\n${MSG_NO_SUITABLE_JAVA_CHECK}\" with title \"${CFBundleName}\" buttons {\" OK \", \"${MSG_VISIT_JAVA_DOT_COM}\"} default button \"${MSG_VISIT_JAVA_DOT_COM}\" with icon path to resource \"${CFBundleIconFile}\" in bundle (path to me)" \ + -e "set response to button returned of the result" \ + -e "if response is \"${MSG_VISIT_JAVA_DOT_COM}\" then open location \"http://java.com\"" + # exit with error + exit 3 + fi + +# otherwise check "/usr/libexec/java_home" and Oracle and Apple JRE paths and use highest version available +else + + # first check "/usr/libexec/java_home" symlinks + if [ -x /usr/libexec/java_home ] && /usr/libexec/java_home -F > /dev/null 2>&1 ; then + JAVACMD="`/usr/libexec/java_home 2> /dev/null`/bin/java" + JAVACMD_version=$(comparableJavaVersionNumber $(extractJavaVersionString "${JAVACMD}")) + fi + + # then additionally check the Oracle JRE plugin whether it's a higher/newer compatible version + if [ -x "${oracle_jre_plugin}" ] ; then + this_java_ver=$(comparableJavaVersionNumber $(extractJavaVersionString "${oracle_jre_plugin}")) + # use this compatible version only if the above returned empty or if the version number is higher + if [ -z ${JAVACMD} ] || [ ${this_java_ver} -ge ${JAVACMD_version} ] ; then + JAVACMD="${oracle_jre_plugin}" + JAVACMD_version=${this_java_ver} + fi + fi + + # then additionally check the Apple JRE plugin whether it's a higher/newer compatible version + if [ -x "${apple_jre_plugin}" ] ; then + this_java_ver=$(comparableJavaVersionNumber $(extractJavaVersionString "${apple_jre_plugin}")) + # use this compatible version only if the above returned empty or if the version number is higher + if [ -z ${JAVACMD} ] || [ ${this_java_ver} -ge ${JAVACMD_version} ] ; then + JAVACMD="${apple_jre_plugin}" + JAVACMD_version=${this_java_ver} + fi + fi +fi + +# fallback fallback: /usr/bin/java +# but this would prompt to install deprecated Apple Java 6 + + + +# +# execute JAVA commandline and do some pre-checks +#################################################### + +# display error message if MainClassName is empty +if [ -z ${JVMMainClass} ]; then + # display error message with applescript + osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_MISSING_MAINCLASS}\" with title \"${CFBundleName}\" buttons {\" OK \"} default button 1 with icon path to resource \"${CFBundleIconFile}\" in bundle (path to me)" + # exit with error + exit 2 + + +# check whether $JAVACMD is a file and executable +elif [ -f "$JAVACMD" ] && [ -x "$JAVACMD" ] ; then + + # enable drag&drop to the dock icon + export CFProcessPath="$0" + + # remove Apples ProcessSerialNumber from passthru arguments (#39) + if [[ $@ == -psn* ]] ; then + ArgsPassthru="" + else + ArgsPassthru=$@ + fi + + # change to Working Directory based upon Apple/Oracle Plist info + cd "${WorkingDirectory}" + + # execute Java and set + # - classpath + # - dock icon + # - application name + # - JVM options + # - JVM default options + # - main class + # - JVM arguments + exec "$JAVACMD" \ + -cp "${JVMClassPath}" \ + -splash:"${ResourcesFolder}/${JVMSplashFile}" \ + -Xdock:icon="${ResourcesFolder}/${CFBundleIconFile}" \ + -Xdock:name="${CFBundleName}" \ + ${JVMOptions:+$JVMOptions }\ + ${JVMDefaultOptions:+$JVMDefaultOptions }\ + ${JVMMainClass}\ + ${JVMArguments:+ $JVMArguments}\ + ${ArgsPassthru:+ $ArgsPassthru} + + +else + + # display error message with applescript + osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_INSTALL_JAVA}\" with title \"${CFBundleName}\" buttons {\"${MSG_LATER}\", \"${MSG_VISIT_JAVA_DOT_COM}\"} default button \"${MSG_VISIT_JAVA_DOT_COM}\" with icon path to resource \"${CFBundleIconFile}\" in bundle (path to me)" \ + -e "set response to button returned of the result" \ + -e "if response is \"${MSG_VISIT_JAVA_DOT_COM}\" then open location \"http://java.com\"" + + # exit with error + exit 1 +fi