Skip to content
This repository was archived by the owner on Feb 4, 2023. It is now read-only.

Commit 6040cab

Browse files
committed
first version 0.1
1 parent 188da35 commit 6040cab

2 files changed

Lines changed: 329 additions & 1 deletion

File tree

README.md

Lines changed: 123 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,126 @@
1-
myJavaApplicationStub
1+
universalJavaApplicationStub
22
=====================
33

44
A shellscript JavaApplicationStub for Java Apps on Mac OS X that works with both Apple's and Oracle's plist format.
5+
6+
7+
Why
8+
---
9+
10+
Whilst developing some Java apps for Mac OS X I was facing the problem of supporting two different Java versions – the "older" Apple versions and the "newer" Oracle versions.
11+
12+
**Is there some difference, you might ask?** Yes, there is!
13+
14+
1. The spot in the file system where the JRE or JDK is stored is different:
15+
* Apple Java 1.5/1.6: `/System/Library/Java/JavaVirtualMachines/`
16+
* Oracle Java 1.7/1.8: `/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/`
17+
18+
2. Mac Apps built with tools designed for Apple's Java (like Apple's JarBundler or the [ANT task "Jarbundler"](http://informagen.com/JarBundler/)) won't work on Macs with Oracle Java 7 and no Apple Java installed.
19+
* This is because the Apple `JavaApplicationStub` only works for Apple's Java and their `Info.plist` style to store Java properties.
20+
* To support Oracle Java 7 you would need to built a separate App package with Oracles [ANT task "Appbundler"](https://java.net/projects/appbundler).
21+
* Thus you would need the user to know which Java distribution he has installed on his Mac. Not very user friendly...
22+
23+
3. Oracle uses a different syntax to store Java properties in the applications `Info.plist` file. A Java app packaged as a Mac app with Oracles Appbundler also needs a different `JavaApplicationStub` and therefore won't work on systems with Apple's Java...
24+
25+
*So why, oh why, couldn't Oracle just use the old style of storing Java properties in `Info.plist` and offer a universal JavaApplicationStub?!* :rage:
26+
27+
Well, since I can't write such a script in C, C# or whatever fancy language, I wrote it as a shell script. And it works! ;-)
28+
29+
How it works
30+
------------
31+
32+
You don't need a native `JavaApplicationStub` file anymore...
33+
34+
The shell script reads JVM properties from `Info.plist` regardless of which format they have, Apple or Oracle, and feeds it to a commandline `java` call:
35+
36+
```Bash
37+
# execute Java and set
38+
# - classpath
39+
# - dock icon
40+
# - application name
41+
# - JVM options
42+
# - JVM default options
43+
# - main class
44+
# - JVM arguments
45+
exec "$JAVACMD" \
46+
-cp "${JVMClasspath}" \
47+
-Xdock:icon="$PROGDIR/../Resources/${CFBundleIconFile}" \
48+
-Xdock:name="${CFBundleName}" \
49+
"${JVMOptions}" \
50+
"${JVMDefaultOptions}" \
51+
"${JVMMainClass}" \
52+
"${JVMArguments}"
53+
```
54+
55+
It sets the classpath, the dock icon, the *AboutMenuName* (in Xdock style) and then every *JVMOptions*, *JVMDefaultOptions* or *JVMArguments* found in the `Info.plist` file.
56+
57+
The name of the *main class* is also retrieved from `Info.plist`. If no *main class* could be found, an applescript error dialog is shown and the script exits with *exit code 1*.
58+
59+
Also, there is some *foo* happening to determine which Java version is installed. Here's the list in which order system properties are checked:
60+
61+
1. system variable `$JAVA_HOME`
62+
2. `/usr/libexec/java_home` symlinks
63+
3. symlink for old Apple Java: `/Library/Java/Home/bin/java`
64+
4. hardcoded fallback to Oracle's JRE Plugin: `/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/bin/java`
65+
66+
If none of these could be found or executed, an applescript error dialog is shown saying that Java need to be installed.
67+
68+
What you need to do
69+
-------------------
70+
71+
Use whichever ANT task you like:
72+
* the great opensource ["Jarbundler"](http://informagen.com/JarBundler/)
73+
* my JarBundler [fork on github](https://github.com/tofi86/Jarbundler) which supports *MixedLocalization*
74+
* Oracle's opensource ["Appbundler"](https://java.net/projects/appbundler)
75+
76+
### JarBundler example
77+
Just place the `universalJavaApplicationStub` from this repo in your build resources folder and link it in your ANT task (attribute `stubfile`):
78+
```XML
79+
<jarbundler
80+
name="Your-App"
81+
shortname="Your Application"
82+
icon="${resources.dir}/icon.icns"
83+
stubfile="${resources.dir}/universalJavaApplicationStub"
84+
... >
85+
86+
</jarbundler>
87+
```
88+
89+
The ANT task will care about the rest...
90+
91+
You should get a fully functional Mac Application Bundle working with both Java distributions from Apple and Oracle.
92+
93+
94+
### Appbundler example
95+
Just place the `universalJavaApplicationStub` from this repo in your build resources folder and link it in your ANT task (attribute `executableName`):
96+
```XML
97+
<appbundler
98+
name="Your-App"
99+
displayname="Your Application"
100+
icon="${resources.dir}/icon.icns"
101+
executableName="${resources.dir}/universalJavaApplicationStub"
102+
... >
103+
104+
</appbundler>
105+
```
106+
107+
108+
The ANT task will care about the rest...
109+
110+
You should get a fully functional Mac Application Bundle working with both Java distributions from Apple and Oracle.
111+
112+
113+
Missing Features
114+
----------------
115+
116+
At the moment, there's no support for
117+
* required JVM architecture (like `x86_64`, etc.)
118+
* required JVM version (like `1.6+`, etc.)
119+
* etc...
120+
121+
An AppleScript dialog would be nice to prevent Java execution if the requirements aren't met.
122+
123+
License
124+
-------
125+
126+
*universalJavaApplicationStub* is released under the MIT License.

universalJavaApplicationStub

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
#!/bin/sh
2+
3+
##################################################################################
4+
# #
5+
# universalJavaApplicationStub #
6+
# #
7+
# #
8+
# A shellscript JavaApplicationStub for Java Apps on Mac OS X #
9+
# that works with both Apple's and Oracle's plist format. #
10+
# #
11+
# Inspired by Ian Roberts stackoverflow answer #
12+
# at http://stackoverflow.com/a/17546508/1128689 #
13+
# #
14+
# #
15+
# @author Tobias Fischer #
16+
# @url https://github.com/tofi86/myJavaApplicationStub #
17+
# @date 2014-03-09 #
18+
# @version 0.1 #
19+
# #
20+
# #
21+
##################################################################################
22+
# #
23+
# #
24+
# The MIT License (MIT) #
25+
# #
26+
# Copyright (c) 2014 Tobias Fischer #
27+
# #
28+
# Permission is hereby granted, free of charge, to any person obtaining a copy #
29+
# of this software and associated documentation files (the "Software"), to deal #
30+
# in the Software without restriction, including without limitation the rights #
31+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell #
32+
# copies of the Software, and to permit persons to whom the Software is #
33+
# furnished to do so, subject to the following conditions: #
34+
# #
35+
# The above copyright notice and this permission notice shall be included in all #
36+
# copies or substantial portions of the Software. #
37+
# #
38+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR #
39+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, #
40+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE #
41+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER #
42+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, #
43+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE #
44+
# SOFTWARE. #
45+
# #
46+
##################################################################################
47+
48+
49+
50+
51+
#
52+
# resolve symlinks
53+
#####################
54+
55+
PRG=$0
56+
57+
while [ -h "$PRG" ]; do
58+
ls=`ls -ld "$PRG"`
59+
link=`expr "$ls" : '^.*-> \(.*\)$' 2>/dev/null`
60+
if expr "$link" : '^/' 2> /dev/null >/dev/null; then
61+
PRG="$link"
62+
else
63+
PRG="`dirname "$PRG"`/$link"
64+
fi
65+
done
66+
67+
PROGDIR=`dirname "$PRG"`
68+
69+
70+
71+
72+
#
73+
# read Info.plist and extract JVM options
74+
############################################
75+
76+
# set Apple's Java folder
77+
AppleJavaFolder="$PROGDIR/../Resources/Java/"
78+
79+
# set Oracle's Java folder
80+
OracleJavaFolder="$PROGDIR/../Java/"
81+
82+
# set path to Info.plist in bundle
83+
InfoPlistFile="$PROGDIR/../Info.plist"
84+
85+
86+
# read the program name from CFBundleName
87+
CFBundleName=`/usr/libexec/PlistBuddy -c "print :CFBundleName" ${InfoPlistFile}`
88+
89+
# read the icon file name
90+
CFBundleIconFile=`/usr/libexec/PlistBuddy -c "print :CFBundleIconFile" ${InfoPlistFile}`
91+
92+
93+
# read Info.plist in Apple style
94+
if [ -d "${AppleJavaFolder}" ]; then
95+
96+
# set classpath
97+
JVMClasspath="${AppleJavaFolder}*"
98+
99+
# read the MainClass name
100+
JVMMainClass=`/usr/libexec/PlistBuddy -c "print :Java:MainClass" ${InfoPlistFile}`
101+
102+
# read the JVM Options
103+
JVMOptions=`/usr/libexec/PlistBuddy -c "print :Java:Properties" ${InfoPlistFile} | grep " =" | sed 's/^ */-D/g' | tr '\n' ' ' | sed 's/ */ /g' | sed 's/ = /=/g'`
104+
105+
# read the JVM Default Options
106+
JVMDefaultOptions=`/usr/libexec/PlistBuddy -c "print :Java:VMOptions" ${InfoPlistFile}`
107+
108+
# read the JVM Arguments
109+
JVMArguments=`/usr/libexec/PlistBuddy -c "print :Java:Arguments" ${InfoPlistFile}`
110+
111+
112+
# read Info.plist in Oracle style
113+
elif [ -d "${OracleJavaFolder}" ]; then
114+
115+
# set classpath
116+
JVMClasspath="${OracleJavaFolder}*"
117+
118+
# read the MainClass name
119+
JVMMainClass=`/usr/libexec/PlistBuddy -c "print :JVMMainClassName" ${InfoPlistFile}`
120+
121+
# read the JVM Options
122+
JVMOptions=`/usr/libexec/PlistBuddy -c "print :JVMOptions" ${InfoPlistFile} | grep " -" | tr '\n' ' ' | sed 's/ */ /g'`
123+
124+
# read the JVM Default Options
125+
JVMDefaultOptions=`/usr/libexec/PlistBuddy -c "print :JVMDefaultOptions" ${InfoPlistFile} | grep -o "\-.*" | tr '\n' ' '`
126+
127+
# read the JVM Arguments
128+
JVMArguments=`/usr/libexec/PlistBuddy -c "print :JVMArguments" ${InfoPlistFile} | tr '\n' ' ' | sed -E 's/Array \{ *(.*) *\}/\1/g' | sed 's/ */ /g'`
129+
130+
fi
131+
132+
133+
134+
135+
#
136+
# find installed Java versions
137+
#################################
138+
139+
# first check system variable "$JAVA_HOME"
140+
if [ -n "$JAVA_HOME" ]; then
141+
JAVACMD="$JAVA_HOME/bin/java"
142+
143+
# otherwise check "/usr/libexec/java_home" symlinks
144+
elif [ -x /usr/libexec/java_home ]; then
145+
JAVACMD="`/usr/libexec/java_home`/bin/java"
146+
147+
# otherwise check Java standard symlink (old Apple Java)
148+
elif test -h /Library/Java/Home; then
149+
JAVACMD="/Library/Java/Home/bin/java"
150+
151+
# fallback: public JRE plugin (Oracle Java)
152+
else
153+
JAVACMD="/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/bin/java"
154+
fi
155+
156+
# fallback fallback: /usr/bin/java
157+
# but this would prompt to install deprecated Apple Java 6
158+
159+
160+
161+
162+
#
163+
# execute JAVA commandline and do some pre-checks
164+
####################################################
165+
166+
# display error message if MainClassName is empty
167+
if [ ${JVMMainClass} == "" ]; then
168+
# display error message with applescript
169+
osascript -e "tell application \"System Events\" to display dialog \"ERROR launching ${CFBundleName}!\n\nNo MainClassName 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)"
170+
# exit with error
171+
exit 1
172+
173+
174+
# check whether $JAVACMD is executable
175+
elif [ -x "$JAVACMD" ]; then
176+
177+
178+
# execute Java and set
179+
# - classpath
180+
# - dock icon
181+
# - application name
182+
# - JVM options
183+
# - JVM default options
184+
# - main class
185+
# - JVM arguments
186+
exec "$JAVACMD" \
187+
-cp "${JVMClasspath}" \
188+
-Xdock:icon="$PROGDIR/../Resources/${CFBundleIconFile}" \
189+
-Xdock:name="${CFBundleName}" \
190+
"${JVMOptions}" \
191+
"${JVMDefaultOptions}" \
192+
"${JVMMainClass}" \
193+
"${JVMArguments}"
194+
195+
196+
else
197+
198+
# display error message with applescript
199+
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)"
200+
201+
# and open java.com
202+
open http://java.com
203+
204+
# exit with error
205+
exit 1
206+
fi

0 commit comments

Comments
 (0)