1#!/bin/sh 2################################################################################## 3# # 4# universalJavaApplicationStub # 5# # 6# # 7# A shellscript JavaApplicationStub for Java Apps on Mac OS X # 8# that works with both Apple's and Oracle's plist format. # 9# # 10# Inspired by Ian Roberts stackoverflow answer # 11# at http://stackoverflow.com/a/17546508/1128689 # 12# # 13# # 14# @author Tobias Fischer # 15# @url https://github.com/tofi86/universalJavaApplicationStub # 16# @date 2015-05-15 # 17# @version 0.9.0 # 18# # 19# # 20################################################################################## 21# # 22# # 23# The MIT License (MIT) # 24# # 25# Copyright (c) 2015 Tobias Fischer # 26# # 27# Permission is hereby granted, free of charge, to any person obtaining a copy # 28# of this software and associated documentation files (the "Software"), to deal # 29# in the Software without restriction, including without limitation the rights # 30# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # 31# copies of the Software, and to permit persons to whom the Software is # 32# furnished to do so, subject to the following conditions: # 33# # 34# The above copyright notice and this permission notice shall be included in all # 35# copies or substantial portions of the Software. # 36# # 37# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # 38# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # 39# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # 40# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # 41# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # 42# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # 43# SOFTWARE. # 44# # 45################################################################################## 46 47 48 49 50# 51# resolve symlinks 52##################### 53 54PRG=$0 55 56while [ -h "$PRG" ]; do 57 ls=`ls -ld "$PRG"` 58 link=`expr "$ls" : '^.*-> \(.*\)$' 2>/dev/null` 59 if expr "$link" : '^/' 2> /dev/null >/dev/null; then 60 PRG="$link" 61 else 62 PRG="`dirname "$PRG"`/$link" 63 fi 64done 65 66# set the directory abspath of the current shell script 67PROGDIR=`dirname "$PRG"` 68 69 70 71 72# 73# set files and folders 74############################################ 75 76# the absolute path of the app package 77cd "$PROGDIR"/../../ 78AppPackageFolder=`pwd` 79 80# the base path of the app package 81cd .. 82AppPackageRoot=`pwd` 83 84# set Apple's Java folder 85AppleJavaFolder="${AppPackageFolder}"/Contents/Resources/Java 86 87# set Apple's Resources folder 88AppleResourcesFolder="${AppPackageFolder}"/Contents/Resources 89 90# set Oracle's Java folder 91OracleJavaFolder="${AppPackageFolder}"/Contents/Java 92 93# set Oracle's Resources folder 94OracleResourcesFolder="${AppPackageFolder}"/Contents/Resources 95 96# set path to Info.plist in bundle 97InfoPlistFile="${AppPackageFolder}"/Contents/Info.plist 98 99# set the default JVM Version to a null string 100JVMVersion="" 101 102 103 104# 105# read Info.plist and extract JVM options 106############################################ 107 108 109# read the program name from CFBundleName 110CFBundleName=`/usr/libexec/PlistBuddy -c "print :CFBundleName" "${InfoPlistFile}"` 111 112# read the icon file name 113CFBundleIconFile=`/usr/libexec/PlistBuddy -c "print :CFBundleIconFile" "${InfoPlistFile}"` 114 115 116# check Info.plist for Apple style Java keys -> if key :Java is present, parse in apple mode 117/usr/libexec/PlistBuddy -c "print :Java" "${InfoPlistFile}" > /dev/null 2>&1 118exitcode=$? 119JavaKey=":Java" 120 121# if no :Java key is present, check Info.plist for universalJavaApplication style JavaX keys -> if key :JavaX is present, parse in apple mode 122if [ $exitcode -ne 0 ]; then 123 /usr/libexec/PlistBuddy -c "print :JavaX" "${InfoPlistFile}" > /dev/null 2>&1 124 exitcode=$? 125 JavaKey=":JavaX" 126fi 127 128 129# read Info.plist in Apple style if exit code returns 0 (true, :Java key is present) 130if [ $exitcode -eq 0 ]; then 131 132 # set Java and Resources folder 133 JavaFolder="${AppleJavaFolder}" 134 ResourcesFolder="${AppleResourcesFolder}" 135 136 APP_PACKAGE="${AppPackageFolder}" 137 JAVAROOT="${AppleJavaFolder}" 138 USER_HOME="$HOME" 139 140 141 # read the Java WorkingDirectory 142 JVMWorkDir=`/usr/libexec/PlistBuddy -c "print ${JavaKey}:WorkingDirectory" "${InfoPlistFile}" 2> /dev/null | xargs` 143 144 # set Working Directory based upon Plist info 145 if [[ ! -z ${JVMWorkDir} ]]; then 146 WorkingDirectory="${JVMWorkDir}" 147 else 148 # AppPackageRoot is the standard WorkingDirectory when the script is started 149 WorkingDirectory="${AppPackageRoot}" 150 fi 151 152 # expand variables $APP_PACKAGE, $JAVAROOT, $USER_HOME 153 WorkingDirectory=`eval "echo ${WorkingDirectory}"` 154 155 156 # read the MainClass name 157 JVMMainClass=`/usr/libexec/PlistBuddy -c "print ${JavaKey}:MainClass" "${InfoPlistFile}" 2> /dev/null` 158 159 # read the JVM Options 160 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` 161 162 # read StartOnMainThread 163 JVMStartOnMainThread=`/usr/libexec/PlistBuddy -c "print ${JavaKey}:StartOnMainThread" "${InfoPlistFile}" 2> /dev/null` 164 if [ "${JVMStartOnMainThread}" == "true" ]; then 165 echo ${JVMStartOnMainThread} > ~/Desktop/test.txt 166 JVMOptions+=" -XstartOnFirstThread" 167 fi 168 169 # read the ClassPath in either Array or String style 170 JVMClassPath_RAW=`/usr/libexec/PlistBuddy -c "print ${JavaKey}:ClassPath" "${InfoPlistFile}" 2> /dev/null` 171 if [[ $JVMClassPath_RAW == *Array* ]] ; then 172 JVMClassPath=.`/usr/libexec/PlistBuddy -c "print ${JavaKey}:ClassPath" "${InfoPlistFile}" 2> /dev/null | grep " " | sed 's/^ */:/g' | tr -d '\n' | xargs` 173 else 174 JVMClassPath=${JVMClassPath_RAW} 175 fi 176 # expand variables $APP_PACKAGE, $JAVAROOT, $USER_HOME 177 JVMClassPath=`eval "echo ${JVMClassPath}"` 178 179 # read the JVM Default Options 180 JVMDefaultOptions=`/usr/libexec/PlistBuddy -c "print ${JavaKey}:VMOptions" "${InfoPlistFile}" 2> /dev/null | xargs` 181 182 # read the JVM Arguments 183 JVMArguments=`/usr/libexec/PlistBuddy -c "print ${JavaKey}:Arguments" "${InfoPlistFile}" 2> /dev/null | xargs` 184 185 # read the Java version we want to find 186 JVMVersion=`/usr/libexec/PlistBuddy -c "print ${JavaKey}:JVMVersion" "${InfoPlistFile}" 2> /dev/null | xargs` 187 188# read Info.plist in Oracle style 189else 190 191 # set Working Directory and Java and Resources folder 192 JavaFolder="${OracleJavaFolder}" 193 ResourcesFolder="${OracleResourcesFolder}" 194 WorkingDirectory="${OracleJavaFolder}" 195 196 APP_ROOT="${AppPackageFolder}" 197 198 # read the MainClass name 199 JVMMainClass=`/usr/libexec/PlistBuddy -c "print :JVMMainClassName" "${InfoPlistFile}" 2> /dev/null` 200 201 # read the JVM Options 202 JVMOptions=`/usr/libexec/PlistBuddy -c "print :JVMOptions" "${InfoPlistFile}" 2> /dev/null | grep " -" | tr -d '\n' | sed 's/ */ /g' | xargs` 203 # replace occurances of $APP_ROOT with it's content 204 JVMOptions=`eval "echo ${JVMOptions}"` 205 206 JVMClassPath="${JavaFolder}/*" 207 208 # read the JVM Default Options 209 JVMDefaultOptions=`/usr/libexec/PlistBuddy -c "print :JVMDefaultOptions" "${InfoPlistFile}" 2> /dev/null | grep -o "\-.*" | tr -d '\n' | xargs` 210 211 # read the JVM Arguments 212 JVMArguments=`/usr/libexec/PlistBuddy -c "print :JVMArguments" "${InfoPlistFile}" 2> /dev/null | tr -d '\n' | sed -E 's/Array \{ *(.*) *\}/\1/g' | sed 's/ */ /g' | xargs` 213 # replace occurances of $APP_ROOT with it's content 214 JVMArguments=`eval "echo ${JVMArguments}"` 215fi 216 217 218 219 220# 221# find installed Java versions 222################################# 223 224# first check system variable "$JAVA_HOME" 225if [ -n "$JAVA_HOME" ] ; then 226 JAVACMD="$JAVA_HOME/bin/java" 227 228# check for specified JVMversion in "/usr/libexec/java_home" symlinks 229elif [ ! -z ${JVMVersion} ] && [ -x /usr/libexec/java_home ] && /usr/libexec/java_home -F; then 230 231 if /usr/libexec/java_home -F -v ${JVMVersion}; then 232 JAVACMD="`/usr/libexec/java_home -F -v ${JVMVersion} 2> /dev/null`/bin/java" 233 else 234 # display error message with applescript 235 osascript -e "tell application \"System Events\" to display dialog \"ERROR launching '${CFBundleName}'\n\nNo suitable Java version found on your system!\nThis program requires Java ${JVMVersion}\nMake sure you install the required Java version.\" with title \"${CFBundleName}\" buttons {\" OK \"} default button 1 with icon path to resource \"${CFBundleIconFile}\" in bundle (path to me)" 236 # exit with error 237 exit 3 238 fi 239 240# otherwise check "/usr/libexec/java_home" symlinks 241elif [ -x /usr/libexec/java_home ] && /usr/libexec/java_home -F; then 242 JAVACMD="`/usr/libexec/java_home 2> /dev/null`/bin/java" 243 244# otherwise check Java standard symlink (old Apple Java) 245elif [ -h /Library/Java/Home ]; then 246 JAVACMD="/Library/Java/Home/bin/java" 247 248# fallback: public JRE plugin (Oracle Java) 249else 250 JAVACMD="/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/bin/java" 251fi 252 253# fallback fallback: /usr/bin/java 254# but this would prompt to install deprecated Apple Java 6 255 256 257 258 259# 260# execute JAVA commandline and do some pre-checks 261#################################################### 262 263# display error message if MainClassName is empty 264if [ -z ${JVMMainClass} ]; then 265 # display error message with applescript 266 osascript -e "tell application \"System Events\" to display dialog \"ERROR launching '${CFBundleName}'!\n\n'MainClass' isn't specified!\nJava application cannot be started!\" with title \"${CFBundleName}\" buttons {\" OK \"} default button 1 with icon path to resource \"${CFBundleIconFile}\" in bundle (path to me)" 267 # exit with error 268 exit 2 269 270 271# check whether $JAVACMD is a file and executable 272elif [ -f "$JAVACMD" ] && [ -x "$JAVACMD" ] ; then 273 274 # enable drag&drop to the dock icon 275 export CFProcessPath="$0" 276 277 # change to Working Directory based upon Apple/Oracle Plist info 278 cd "${WorkingDirectory}" 279 280 # execute Java and set 281 # - classpath 282 # - dock icon 283 # - application name 284 # - JVM options 285 # - JVM default options 286 # - main class 287 # - JVM arguments 288 exec "$JAVACMD" \ 289 -cp "${JVMClassPath}" \ 290 -Xdock:icon="${ResourcesFolder}/${CFBundleIconFile}" \ 291 -Xdock:name="${CFBundleName}" \ 292 ${JVMOptions:+$JVMOptions }\ 293 ${JVMDefaultOptions:+$JVMDefaultOptions }\ 294 ${JVMMainClass}\ 295 ${JVMArguments:+ $JVMArguments} 296 297 298else 299 300 # display error message with applescript 301 osascript -e "tell application \"System Events\" to display dialog \"ERROR launching '${CFBundleName}'!\n\nYou need to have JAVA installed on your Mac!\nVisit http://java.com for more information...\" with title \"${CFBundleName}\" buttons {\" OK \"} default button 1 with icon path to resource \"${CFBundleIconFile}\" in bundle (path to me)" 302 303 # and open java.com 304 open http://java.com 305 306 # exit with error 307 exit 1 308fi 309