diff --git a/CHANGELOG.md b/CHANGELOG.md
index 280abe2..e960c81 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,22 @@
ChangeLog
---------
+### v3.0.0 (2018-02-25)
+* Completeley overhauled algorithm for JVM detection (JRE and JDK)
+ * JDK has no longer precedence over JRE
+ * All Java Virtual Machines on the system are taken into account
+ * See Readme section 'How the script works' for more details
+* NEW special syntax in Plist key `JVMVersion` to specify a maximum JVM version requirement in addition to the minimum requirement.
+ * See issue #51 for examples
+* Support `JVMVersion` also in Oracle PList style (#59)
+* Implemented logging to `syslog` facility which can be viewed via `Console.app` (#49)
+* Translation of messages to Chinese (PR #55, Thanks to @acely for his contribution)
+* Added a table with 'Supported PList keys' to the Readme file
+* Refactoring of functions, bash syntax, etc... (#46, #50, #56)
+* Bugfix: pass JVM options with spaces correctly to the java exec call (#14)
+* Bugfixes: better handling of MainClass arguments with spaces (#57, #58)
+* Bugfixes: issues #47, #48, #52
+
### v2.1.0 (2017-07-28)
* Support for Java 9 which introduces a new version number schema (fixes #43)
diff --git a/LICENSE b/LICENSE
index 41218bb..fe1f190 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2015 Tobias Fischer
+Copyright (c) 2014-2018 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
@@ -18,4 +18,4 @@ 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.
\ No newline at end of file
+SOFTWARE.
diff --git a/README.md b/README.md
index db629a2..6a87ca5 100644
--- a/README.md
+++ b/README.md
@@ -1,57 +1,62 @@
universalJavaApplicationStub
-=====================
+============================
[![Current release](https://img.shields.io/github/release/tofi86/universalJavaApplicationStub.svg)](https://github.com/tofi86/universalJavaApplicationStub/releases) [![Join the chat at https://gitter.im/tofi86/universalJavaApplicationStub](https://badges.gitter.im/tofi86/universalJavaApplicationStub.svg)](https://gitter.im/tofi86/universalJavaApplicationStub?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
-A BASH based *JavaApplicationStub* for Java Apps on Mac OS X that works with both Apple's and Oracle's plist format. It is released under the MIT License.
+A BASH based *JavaApplicationStub* for Java Apps on Mac OS X that works with both Apple's and Oracle's plist format. It is released under the [MIT License](https://github.com/tofi86/universalJavaApplicationStub/blob/master/LICENSE).
+
+See the [CHANGELOG](https://github.com/tofi86/universalJavaApplicationStub/blob/master/CHANGELOG.md) for a Release History and feature details.
Why
---
-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.
+Whilst developing some Java Apps for Mac OS X I was facing the problem of supporting two different kinds of Java versions – the old Apple versions and the new Oracle versions.
**Is there some difference, you might ask?** Yes, there is!
1. The installation directory differs:
- * Apple Java 1.5/1.6: `/System/Library/Java/JavaVirtualMachines/`
+ * Apple Java 1.5/1.6: `/System/Library/Java/JavaVirtualMachines/` or `/Library/Java/Home/bin/java`
* Oracle JRE 1.7/1.8: `/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/`
* Oracle JDK 1.7/1.8: `/System/Library/Java/JavaVirtualMachines/`
2. Mac Apps built with tools designed for Apple's Java (like Apple's *JarBundler* or the OpenSource [ANT task "Jarbundler"](https://github.com/UltraMixer/JarBundler)) won't work on Macs with Oracle Java 7 and no Apple Java installed.
- * This is because Apple's `JavaApplicationStub` only works for Apple's Java and their style to store Java properties in the `Info.plist` file.
- * To support Oracle Java 7 you would need to built a separate App package with [Oracles ANT task "Appbundler"](https://java.net/projects/appbundler).
- * Thus you would need the user to know which Java distribution he has installed on his Mac. Not very user friendly...
+ * This is because Apple's `JavaApplicationStub` only works for Apple's Java and their *style* to store Java properties in the `Info.plist` file.
+ * To support Oracle Java 7 you would need to built a separate App package with [Oracle's ANT task "Appbundler"](https://java.net/projects/appbundler).
+ * Thus you would need the user to know which Java distribution he has installed on their Mac. Not very user friendly...
-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...
+3. Oracle uses a different syntax to store Java properties in the applications `Info.plist` file. A Java Application packaged as a Mac App with Oracle's Appbundler also needs a different `JavaApplicationStub` and therefore won't work on systems with Apple's old Java...
4. Starting with Mac OS X 10.10 *(Yosemite)*, Java Apps won't open anymore if they contain the *deprecated* Plist dictionary `Java`. This isn't confirmed by Apple, but [issue #9](https://github.com/tofi86/universalJavaApplicationStub/issues/9) leads to this assumption:
- * Apple seems to declare the `Java` dictionary as *deprecated* and ties it to the old Apple Java 6. If you have a newer version installed the app won't open.
+ * Apple seems to declare the `Java` dictionary as *deprecated* and ties it to their old Apple Java 6. If you have a newer Oracle Java version installed the app won't open.
* If Java 7/8 is installed, Apple doesn't accept those java versions as suitable
* Apple prompts for JRE 6 download even before the `JavaApplicationStub` is executed. This is why we can't intercept at this level and need to replace the `Java` dictionary by a `JavaX` dictionary key.
* This requires to use the latest [JarBundler](https://github.com/UltraMixer/JarBundler/) version (see below for more details)
-*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:
+TL;DR: Since there is no universally working JavaApplicationStub for Java 6, 7 and above, and because Apple and Oracle really screwed things up during their Java transition phase, I was in need of a new Stub file.
+And well, since I can't write such a script in C, C# or whatever fancy language, I wrote it as a Bash script. And it works!
+The original script was inspired by [Ian Roberts stackoverflow answer](http://stackoverflow.com/a/17546508/1128689). Thanks, Ian!
-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!
How the script works
--------------------
-You don't need a native `JavaApplicationStub` file anymore. The Shell script needs to be executable – that's all.
+You don't need a native `JavaApplicationStub` file anymore. The Bash script needs to be executable – that's all.
-The script reads JVM properties from `Info.plist` regardless of whether it's Apple or Oracle flavour and feeds it to a commandline `java` call like the following:
+The script reads JVM properties from `Info.plist` regardless of whether it's Apple or Oracle syntax and feeds them to a commandline `java` call like the following:
```Bash
# execute Java and set
-# - classpath
-# - dock icon
-# - application name
-# - JVM options
-# - JVM default options
-# - main class
-# - JVM arguments
-exec "$JAVACMD" \
+# - classpath
+# - splash image
+# - dock icon
+# - app name
+# - JVM options
+# - JVM default options
+# - main class
+# - main arguments
+# - passthru arguments
+exec "${JAVACMD}" \
-cp "${JVMClassPath}" \
-splash:"${ResourcesFolder}/${JVMSplashFile}" \
-Xdock:icon="${ResourcesFolder}/${CFBundleIconFile}" \
@@ -59,15 +64,15 @@ exec "$JAVACMD" \
${JVMOptions:+$JVMOptions }\
${JVMDefaultOptions:+$JVMDefaultOptions }\
${JVMMainClass}\
- ${JVMArguments:+ $JVMArguments}\
+ ${MainArgs:+ $MainArgs}\
${ArgsPassthru:+ $ArgsPassthru}
```
-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.
+It sets the classpath, the dock icon, the *AboutMenuName* (as Xdock parameter) and then every *JVMOptions*, *JVMDefaultOptions* or *JVMArguments* found in the `Info.plist` file. See the table below for more supported Plist keys.
-The WorkingDirectory is either retrieved from Apple's Plist key `Java/WorkingDirectory` or set to the JavaRoot directory within the app bundle.
+The *WorkingDirectory* is either retrieved from Apple's Plist key `Java/WorkingDirectory` or set to the JavaRoot directory within the app bundle.
-The name of the *main class* is also retrieved from `Info.plist`. If no *main class* is found, an applescript error dialog is shown and the script exits with *exit code 1*.
+The name of the *main class* is also retrieved from `Info.plist`. If no *main class* is found, an AppleScript error dialog is shown and the script exits with *exit code 1*.
There is some *foo* happening to determine which Java versions are installed – here's the list in which order system properties are checked:
@@ -78,14 +83,16 @@ There is some *foo* happening to determine which Java versions are installed –
* `/usr/libexec/java_home` symlinks
* Oracle's JRE Plugin: `/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/bin/java`
* Symlink for old Apple Java: `/Library/Java/Home/bin/java`
-3. If you require a specific Java version with the Plist key `JVMVersion` the script will try to find a matching JDK or JRE in all of the above locations
+3. If you require a specific to-the-point Java version or a **minimum requirement** with the Plist key `JVMVersion` the script will try to find a matching JDK or JRE in all of the above locations
* if multiple matching JVM's are found, the script will pick the latest (highest version number)
+ * starting from version 3.0 of this script you can use a special syntax in Plist key `JVMVersion` to specify a **max requirement**. See [issue #51](https://github.com/tofi86/universalJavaApplicationStub/issues/51) for examples.
-If none of these could be found or executed the script shows an applescript error dialog saying that Java needs to be installed:
+If none of these can be found or executed the script shows an AppleScript error dialog saying that Java needs to be installed:
![Error Dialog No Java Found](/docs/java-error.png?raw=true)
-Messages are localized and displayed either in English (Default), French or German. Language contributions are very welcome!
+Messages are **localized** and displayed either in English (Default), French, German or Chinese. Language contributions are very welcome! Thank you!
+
What you need to do
-------------------
@@ -117,7 +124,7 @@ Then place the `universalJavaApplicationStub` from this repo in your build resou
```
-The ANT task will care about the rest...
+The ANT task will take care of all the rest... But of course you can specify more options. Please check the JarBundler docs.
You should get a fully functional Mac Application Bundle working with both Java distributions from Apple and Oracle and all Mac OS X versions.
@@ -134,20 +141,48 @@ Just place the `universalJavaApplicationStub` from this repo in your build resou
```
-
-The ANT task will care about the rest...
+The ANT task will take care of all the rest... But of course you can specify more options. Please check the Appbundler docs.
You should get a fully functional Mac Application Bundle working with both Java distributions from Apple and Oracle and all Mac OS X versions.
+Supported PList keys
+--------------------
+
+| Function | Apple PList key | Oracle PList key |
+|---------------------------------|------------------------|-----------------------|
+| **App Name** (Dock Name) | `:CFBundleName` | `:CFBundleName` |
+| **App Icon** (Dock Icon) | `:CFBundleIconFile` | `:CFBundleIconFile` |
+| **Working Directory** | `:Java(X):WorkingDirectory`
fallback to `name.app/`
support for variables `$APP_PACKAGE`, `$JAVAROOT`, `$USER_HOME` | *not supported*
default: `name.app/Contents/Java/` |
+| **Java Min/Max[*](https://github.com/tofi86/universalJavaApplicationStub/issues/51) Version Requirement** | `:Java(X):JVMVersion` | `:JVMVersion` |
+| **Java ClassPath** (`-cp …`) | `:Java(X):ClassPath` | `:JVMClassPath` |
+| **Java Main Class** | `:Java(X):MainClass` | `:JVMMainClassName` |
+| **Splash Image** (`-splash:…`) | `:Java(X):SplashFile` | `:JVMSplashFile` |
+| **Java VM Options** (`-X…`) | `:Java(X):VMOptions` | `:JVMDefaultOptions` |
+| **`-XstartOnFirstThread`** [*](https://stackoverflow.com/questions/28149634/what-does-the-xstartonfirstthread-vm-argument-do-mean) | `:Java(X):StartOnMainThread` | *not supported* |
+| **Java Properties** (`-D…`) | `:Java(X):Properties` | `:JVMOptions` |
+| **Main Class Arguments** | `:Java(X):Arguments` | `:JVMArguments` |
+
+
+Logging
+-------
+
+Starting with version 3.0 `universalJavaApplicationStub` logs data to the `syslog` facility which can be easily accessed with the `Console.app` utility by searching for *syslog*:
+
+![Example log data in Console.app](/docs/ConsoleAppLogging.png?raw=true)
+
+Log data includes debug information of the JVM search strategy, App name, language, selected JVM, WorkingDirectory and exec call.
+
+
Missing Features
----------------
At the moment, there's no support for
* required JVM architecture (like `x86_64`, etc.)
+* prefer JDK over JRE or vice versa
License
-------
-*universalJavaApplicationStub* is released under the MIT License.
+*universalJavaApplicationStub* is released under the [MIT License](https://github.com/tofi86/universalJavaApplicationStub/blob/master/LICENSE).
diff --git a/docs/ConsoleAppLogging.png b/docs/ConsoleAppLogging.png
new file mode 100644
index 0000000..b7f20a9
Binary files /dev/null and b/docs/ConsoleAppLogging.png differ
diff --git a/src/universalJavaApplicationStub b/src/universalJavaApplicationStub
index 0d4ad9e..85f8e2a 100755
--- a/src/universalJavaApplicationStub
+++ b/src/universalJavaApplicationStub
@@ -3,26 +3,22 @@
# #
# universalJavaApplicationStub #
# #
-# #
-# A shellscript JavaApplicationStub for Java Apps on Mac OS X #
+# A BASH based 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 #
-# #
+# @date 2018-02-25 #
+# @version 3.0.0 #
# #
##################################################################################
# #
-# #
# The MIT License (MIT) #
# #
-# Copyright (c) 2017 Tobias Fischer #
+# Copyright (c) 2014-2018 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 #
@@ -46,38 +42,52 @@
+# function 'stub_logger()'
#
-# resolve symlinks
+# A logger which logs to the macOS Console.app using the 'syslog' command
+#
+# @param1 the log message
+# @return void
+################################################################################
+function stub_logger() {
+ syslog -s -k \
+ Facility com.apple.console \
+ Level Notice \
+ Sender "$(basename "$0")" \
+ Message "[$$][${CFBundleName:-$(basename "$0")}] $1"
+}
+
+
+
+# set the directory abspath of the current
+# shell script with symlinks being resolved
############################################
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
+ 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"`
+PROGDIR=$(dirname "$PRG")
+stub_logger "[StubDir] $PROGDIR"
-#
# set files and folders
############################################
# the absolute path of the app package
-cd "$PROGDIR"/../../
-AppPackageFolder=`pwd`
+cd "$PROGDIR"/../../ || exit 11
+AppPackageFolder=$(pwd)
# the base path of the app package
-cd ..
-AppPackageRoot=`pwd`
+cd .. || exit 12
+AppPackageRoot=$(pwd)
# set Apple's Java folder
AppleJavaFolder="${AppPackageFolder}"/Contents/Resources/Java
@@ -96,18 +106,43 @@ InfoPlistFile="${AppPackageFolder}"/Contents/Info.plist
# set the default JVM Version to a null string
JVMVersion=""
+JVMMaxVersion=""
+# function 'plist_get()'
+#
+# read a specific Plist key with 'PlistBuddy' utility
#
+# @param1 the Plist key with leading colon ':'
+# @return the value as String or Array
+################################################################################
+plist_get(){
+ /usr/libexec/PlistBuddy -c "print $1" "${InfoPlistFile}" 2> /dev/null
+}
+
+# function 'plist_get_java()'
+#
+# read a specific Plist key with 'PlistBuddy' utility
+# in the 'Java' or 'JavaX' dictionary ()
+#
+# @param1 the Plist :Java(X):Key with leading colon ':'
+# @return the value as String or Array
+################################################################################
+plist_get_java(){
+ plist_get ${JavaKey:-":Java"}$1
+}
+
+
+
# read Info.plist and extract JVM options
############################################
# read the program name from CFBundleName
-CFBundleName=`/usr/libexec/PlistBuddy -c "print :CFBundleName" "${InfoPlistFile}"`
+CFBundleName=$(plist_get ':CFBundleName')
# read the icon file name
-CFBundleIconFile=`/usr/libexec/PlistBuddy -c "print :CFBundleIconFile" "${InfoPlistFile}"`
+CFBundleIconFile=$(plist_get ':CFBundleIconFile')
# check Info.plist for Apple style Java keys -> if key :Java is present, parse in apple mode
@@ -123,8 +158,9 @@ if [ $exitcode -ne 0 ]; then
fi
-# read Info.plist in Apple style if exit code returns 0 (true, :Java key is present)
+# read 'Info.plist' file in Apple style if exit code returns 0 (true, ':Java' key is present)
if [ $exitcode -eq 0 ]; then
+ stub_logger "[PlistStyle] Apple"
# set Java and Resources folder
JavaFolder="${AppleJavaFolder}"
@@ -136,65 +172,68 @@ if [ $exitcode -eq 0 ]; then
# read the Java WorkingDirectory
- JVMWorkDir=`/usr/libexec/PlistBuddy -c "print ${JavaKey}:WorkingDirectory" "${InfoPlistFile}" 2> /dev/null | xargs`
-
- # set Working Directory based upon Plist info
+ JVMWorkDir=$(plist_get_java ':WorkingDirectory' | xargs)
+ # set Working Directory based upon PList value
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}"`
+ WorkingDirectory=$(eval echo "${WorkingDirectory}")
# read the MainClass name
- JVMMainClass=`/usr/libexec/PlistBuddy -c "print ${JavaKey}:MainClass" "${InfoPlistFile}" 2> /dev/null`
+ JVMMainClass="$(plist_get_java ':MainClass')"
# read the SplashFile name
- JVMSplashFile=`/usr/libexec/PlistBuddy -c "print ${JavaKey}:SplashFile" "${InfoPlistFile}" 2> /dev/null`
+ JVMSplashFile=$(plist_get_java ':SplashFile')
- # 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 JVM Properties as an array and retain spaces
+ IFS=$'\t\n'
+ JVMOptions=($(xargs -n1 <<<$(plist_get_java ':Properties' | grep " =" | sed 's/^ */-D/g' | sed -E 's/ = (.*)$/="\1"/g')))
+ unset IFS
+ # post processing of the array follows further below...
# read the ClassPath in either Array or String style
- JVMClassPath_RAW=`/usr/libexec/PlistBuddy -c "print ${JavaKey}:ClassPath" "${InfoPlistFile}" 2> /dev/null`
+ JVMClassPath_RAW=$(plist_get_java ':ClassPath' | xargs)
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`
+ JVMClassPath=.$(plist_get_java ':ClassPath' | grep " " | sed 's/^ */:/g' | tr -d '\n' | xargs)
else
JVMClassPath=${JVMClassPath_RAW}
fi
# expand variables $APP_PACKAGE, $JAVAROOT, $USER_HOME
- JVMClassPath=`eval "echo ${JVMClassPath}"`
+ 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`
+ # read the JVM Options in either Array or String style
+ JVMDefaultOptions_RAW=$(plist_get_java ':VMOptions' | 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`
+ JVMDefaultOptions=$(plist_get_java ':VMOptions' | 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 StartOnMainThread and add as -XstartOnFirstThread
+ JVMStartOnMainThread=$(plist_get_java ':StartOnMainThread')
+ if [ "${JVMStartOnMainThread}" == "true" ]; then
+ JVMDefaultOptions+=" -XstartOnFirstThread"
+ fi
+
+ # read the JVM Arguments as an array and retain spaces
+ IFS=$'\t\n'
+ MainArgs=($(xargs -n1 <<<$(plist_get_java ':Arguments')))
+ unset IFS
+ # post processing of the array follows further below...
# read the Java version we want to find
- JVMVersion=`/usr/libexec/PlistBuddy -c "print ${JavaKey}:JVMVersion" "${InfoPlistFile}" 2> /dev/null | xargs`
+ JVMVersion=$(plist_get_java ':JVMVersion' | xargs)
+ # post processing of the version string follows below...
+
-# read Info.plist in Oracle style
+# read 'Info.plist' file in Oracle style
else
+ stub_logger "[PlistStyle] Oracle"
# set Working Directory and Java and Resources folder
JavaFolder="${OracleJavaFolder}"
@@ -204,59 +243,90 @@ else
APP_ROOT="${AppPackageFolder}"
# read the MainClass name
- JVMMainClass=`/usr/libexec/PlistBuddy -c "print :JVMMainClassName" "${InfoPlistFile}" 2> /dev/null`
+ JVMMainClass="$(plist_get ':JVMMainClassName')"
# read the SplashFile name
- JVMSplashFile=`/usr/libexec/PlistBuddy -c "print :JVMSplashFile" "${InfoPlistFile}" 2> /dev/null`
+ JVMSplashFile=$(plist_get ':JVMSplashFile')
- # 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 JVM Options as an array and retain spaces
+ IFS=$'\t\n'
+ JVMOptions=($(plist_get ':JVMOptions' | grep " " | sed 's/^ *//g'))
+ unset IFS
+ # post processing of the array follows further below...
# read the ClassPath in either Array or String style
- JVMClassPath_RAW=`/usr/libexec/PlistBuddy -c "print JVMClassPath" "${InfoPlistFile}" 2> /dev/null`
+ JVMClassPath_RAW=$(plist_get ':JVMClassPath')
if [[ $JVMClassPath_RAW == *Array* ]] ; then
- JVMClassPath=.`/usr/libexec/PlistBuddy -c "print JVMClassPath" "${InfoPlistFile}" 2> /dev/null | grep " " | sed 's/^ */:/g' | tr -d '\n' | xargs`
+ JVMClassPath=.$(plist_get ':JVMClassPath' | grep " " | sed 's/^ */:/g' | tr -d '\n' | xargs)
# expand variables $APP_PACKAGE, $JAVAROOT, $USER_HOME
- JVMClassPath=`eval "echo ${JVMClassPath}"`
+ JVMClassPath=$(eval echo "${JVMClassPath}")
elif [[ ! -z ${JVMClassPath_RAW} ]] ; then
JVMClassPath=${JVMClassPath_RAW}
# expand variables $APP_PACKAGE, $JAVAROOT, $USER_HOME
- JVMClassPath=`eval "echo ${JVMClassPath}"`
+ JVMClassPath=$(eval echo "${JVMClassPath}")
else
#default: fallback to OracleJavaFolder
JVMClassPath="${JavaFolder}/*"
- # Do NOT expand the default App.app/Contents/Java/* classpath (#42)
+ # Do NOT expand the default 'AppName.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`
+ JVMDefaultOptions=$(plist_get ':JVMDefaultOptions' | grep -o " \-.*" | tr -d '\n' | xargs)
+
+ # read the Main Arguments from JVMArguments key as an array and retain spaces (see #46 for naming details)
+ IFS=$'\t\n'
+ MainArgs=($(xargs -n1 <<<$(plist_get ':JVMArguments' | tr -d '\n' | sed -E 's/Array \{ *(.*) *\}/\1/g' | sed 's/ */ /g')))
+ unset IFS
+ # post processing of the array follows further below...
- # 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}"`
+ # read the Java version we want to find
+ JVMVersion=$(plist_get ':JVMVersion' | xargs)
+ # post processing of the version string follows below...
fi
-#
+# JVMVersion: post processing and optional splitting
+if [[ ${JVMVersion} == *";"* ]]; then
+ minMaxArray=(${JVMVersion//;/ })
+ JVMVersion=${minMaxArray[0]//+}
+ JVMMaxVersion=${minMaxArray[1]//+}
+fi
+stub_logger "[JavaRequirement] JVM minimum version: ${JVMVersion}"
+stub_logger "[JavaRequirement] JVM maximum version: ${JVMMaxVersion}"
+
+# MainArgs: replace occurences of $APP_ROOT with its content
+MainArgsArr=()
+for i in "${MainArgs[@]}"
+do
+ MainArgsArr+=("$(eval echo "$i")")
+done
+
+# JVMOptions: replace occurences of $APP_ROOT with its content
+JVMOptionsArr=()
+for i in "${JVMOptions[@]}"
+do
+ JVMOptionsArr+=("$(eval echo "$i")")
+done
+
+
# internationalized messages
-#
############################################
-LANG=`defaults read -g AppleLocale`
+LANG=$(defaults read -g AppleLocale)
+stub_logger "[Language] $LANG"
# French localization
if [[ $LANG == fr* ]] ; then
- MSG_ERROR_LAUNCHING="Erreur au lancement de '${CFBundleName}'."
+ 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_JVMVERSION_REQ_INVALID="La syntaxe de la version Java demandée est invalide: %s\nVeuillez contacter le développeur de l'application."
+ MSG_NO_SUITABLE_JAVA="La version de Java installée sur votre système ne convient pas.\nCe programme nécessite Java %s"
MSG_JAVA_VERSION_OR_LATER="ou ultérieur"
MSG_JAVA_VERSION_LATEST="(dernière mise à jour)"
+ MSG_JAVA_VERSION_MAX="à %s"
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"
@@ -266,21 +336,39 @@ if [[ $LANG == fr* ]] ; then
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_JVMVERSION_REQ_INVALID="Die Syntax der angeforderten Java-Version ist ungültig: %s\nBitte kontaktieren Sie den Entwickler der App."
+ MSG_NO_SUITABLE_JAVA="Es wurde keine passende Java-Version auf Ihrem System gefunden!\nDieses Programm benötigt Java %s"
MSG_JAVA_VERSION_OR_LATER="oder neuer"
MSG_JAVA_VERSION_LATEST="(neuste Unterversion)"
+ MSG_JAVA_VERSION_MAX="bis %s"
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"
+# Simplifyed Chinese localization
+elif [[ $LANG == zh* ]] ; then
+ MSG_ERROR_LAUNCHING="无法启动 '${CFBundleName}'."
+ MSG_MISSING_MAINCLASS="没有指定 'MainClass'!\nJava程序无法启动!"
+ MSG_JVMVERSION_REQ_INVALID="Java版本参数语法错误: %s\n请联系该应用的开发者。"
+ MSG_NO_SUITABLE_JAVA="没有在系统中找到合适的Java版本!\n必须安装Java %s才能够使用该程序!"
+ MSG_JAVA_VERSION_OR_LATER="及以上版本"
+ MSG_JAVA_VERSION_LATEST="(最新版本)"
+ MSG_JAVA_VERSION_MAX="最高为 %s"
+ MSG_NO_SUITABLE_JAVA_CHECK="请确保系统中安装了所需的Java版本"
+ MSG_INSTALL_JAVA="你需要在Mac中安装Java运行环境!\n访问 java.com 了解如何安装。"
+ MSG_LATER="稍后"
+ MSG_VISIT_JAVA_DOT_COM="访问 java.com"
+
# 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_JVMVERSION_REQ_INVALID="The syntax of the required Java version is invalid: %s\nPlease contact the App developer."
+ MSG_NO_SUITABLE_JAVA="No suitable Java version found on your system!\nThis program requires Java %s"
MSG_JAVA_VERSION_OR_LATER="or later"
MSG_JAVA_VERSION_LATEST="(latest update)"
+ MSG_JAVA_VERSION_MAX="up to %s"
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"
@@ -289,247 +377,398 @@ fi
-# helper function:
-# extract Java version string from `java -version` command
+# function 'get_java_version_from_cmd()'
+#
+# returns 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'`
+#
+# @param1 path to a java JVM executable
+# @return the Java version number as displayed in 'java -version' command
+################################################################################
+function get_java_version_from_cmd() {
+ # 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
+# function 'extract_java_major_version()'
+#
+# extract Java major version from a version string
+#
+# @param1 a Java version number ('1.8.0_45') or requirement string ('1.8+')
+# @return the major version (e.g. '7', '8' or '9', etc.)
+################################################################################
+function extract_java_major_version() {
+ echo $(echo "$1" | sed -E 's/^1\.//;s/^([0-9]+)(-ea|(\.[0-9_.]{1,7})?)[+*]?$/\1/')
}
-# 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 'get_comparable_java_version()'
+#
+# return comparable version for a Java version number or requirement string
+#
+# @param1 a Java version number ('1.8.0_45') or requirement string ('1.8+')
+# @return an 8 digit numeral ('1.8.0_45'->'08000045'; '9.1.13'->'09001013')
+################################################################################
+function get_comparable_java_version() {
+ # cleaning: 1) remove leading '1.'; 2) remove 'a-Z' and '-*+' (e.g. '-ea'); 3) replace '_' with '.'
+ local cleaned=$(echo "$1" | sed -E 's/^1\.//g;s/[a-zA-Z+*\-]//g;s/_/./g')
+ # splitting at '.' into an array
+ local arr=( ${cleaned//./ } )
+ # echo a string with left padded version numbers
+ echo "$(printf '%02s' ${arr[0]})$(printf '%03s' ${arr[1]})$(printf '%03s' ${arr[2]})"
}
-# 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
+# function 'is_valid_requirement_pattern()'
+#
+# check whether the Java requirement is a valid requirement pattern
+#
+# supported requirements are for example:
+# - 1.6 requires Java 6 (any update) [1.6, 1.6.0_45, 1.6.0_88]
+# - 1.6* requires Java 6 (any update) [1.6, 1.6.0_45, 1.6.0_88]
+# - 1.6+ requires Java 6 or higher [1.6, 1.6.0_45, 1.8, 9, etc.]
+# - 1.6.0 requires Java 6 (any update) [1.6, 1.6.0_45, 1.6.0_88]
+# - 1.6.0_45 requires Java 6u45 [1.6.0_45]
+# - 1.6.0_45+ requires Java 6u45 or higher [1.6.0_45, 1.6.0_88, 1.8, etc.]
+# - 9 requires Java 9 (any update) [9.0.*, 9.1, 9.3, etc.]
+# - 9* requires Java 9 (any update) [9.0.*, 9.1, 9.3, etc.]
+# - 9+ requires Java 9 or higher [9.0, 9.1, 10, etc.]
+# - 9.1 requires Java 9.1 (any update) [9.1.*, 9.1.2, 9.1.13, etc.]
+# - 9.1* requires Java 9.1 (any update) [9.1.*, 9.1.2, 9.1.13, etc.]
+# - 9.1+ requires Java 9.1 or higher [9.1, 9.2, 10, etc.]
+# - 9.1.3 requires Java 9.1.3 [9.1.3]
+# - 9.1.3* requires Java 9.1.3 (any update) [9.1.3]
+# - 9.1.3+ requires Java 9.1.3 or higher [9.1.3, 9.1.4, 9.2.*, 10, etc.]
+# - 10-ea requires Java 10 (early access release)
+#
+# unsupported requirement patterns are for example:
+# - 1.2, 1.3, 1.9 Java 2, 3 are not supported
+# - 1.9 Java 9 introduced a new versioning scheme
+# - 6u45 known versioning syntax, but unsupported
+# - 9-ea*, 9-ea+ early access releases paired with */+
+# - 9., 9.*, 9.+ version ending with a .
+# - 9.1., 9.1.*, 9.1.+ version ending with a .
+# - 9.3.5.6 4 part version number is unsupported
+#
+# @param1 a Java requirement string ('1.8+')
+# @return boolean exit code: 0 (is valid), 1 (is not valid)
+################################################################################
+function is_valid_requirement_pattern() {
+ local java_req=$1
+ java8pattern='1\.[4-8](\.0)?(\.0_[0-9]+)?[*+]?'
+ java9pattern='(9|1[0-9])(-ea|[*+]|(\.[0-9]+){1,2}[*+]?)?'
+ # test matches either old Java versioning scheme (up to 1.8) or new scheme (starting with 9)
+ if [[ ${java_req} =~ ^(${java8pattern}|${java9pattern})$ ]]; then
+ return 0
+ else
+ return 1
+ fi
}
-#
-# find installed Java versions
+# determine which JVM to use
############################################
+# default Apple JRE plugin path (< 1.6)
apple_jre_plugin="/Library/Java/Home/bin/java"
-apple_jre_version=$(extractJavaMajorVersion $(extractJavaVersionString "${apple_jre_plugin}"))
+apple_jre_version=$(get_java_version_from_cmd "${apple_jre_plugin}")
+# default Oracle JRE plugin path (>= 1.7)
oracle_jre_plugin="/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/bin/java"
-oracle_jre_version=$(extractJavaMajorVersion $(extractJavaVersionString "${oracle_jre_plugin}"))
+oracle_jre_version=$(get_java_version_from_cmd "${oracle_jre_plugin}")
+
-# first check system variable "$JAVA_HOME"
+# first check system variable "$JAVA_HOME" -> has precedence over any other System JVM
+stub_logger '[JavaSearch] Checking for $JAVA_HOME ...'
if [ -n "$JAVA_HOME" ] ; then
+ stub_logger "[JavaSearch] ... found JAVA_HOME with value $JAVA_HOME"
- # 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}"))
+ # 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
+ JAVACMD_version=$(get_comparable_java_version $(get_java_version_from_cmd "${JAVACMD}"))
+else
+ stub_logger "[JavaSearch] ... didn't found JAVA_HOME"
+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
+# check for any other or a specific Java version
+# also if $JAVA_HOME exists but isn't executable
+if [ -z "${JAVACMD}" ] || [ ! -x "${JAVACMD}" ] ; then
+ stub_logger "[JavaSearch] Checking for JavaVirtualMachines on the system ..."
+ # reset variables
+ JAVACMD=""
+ JAVACMD_version=""
+
+ # first check whether JVMVersion string is a valid requirement string
+ if [ ! -z "${JVMVersion}" ] && ! is_valid_requirement_pattern ${JVMVersion} ; then
+ MSG_JVMVERSION_REQ_INVALID_EXPANDED=$(printf "${MSG_JVMVERSION_REQ_INVALID}" "${JVMVersion}")
+ # log exit cause
+ stub_logger "[EXIT 4] ${MSG_JVMVERSION_REQ_INVALID_EXPANDED}"
+ # display error message with AppleScript
+ osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_JVMVERSION_REQ_INVALID_EXPANDED}\" with title \"${CFBundleName}\" buttons {\" OK \"} default button 1 with icon path to resource \"${CFBundleIconFile}\" in bundle (path to me)"
+ # exit with error
+ exit 4
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
+ # then check whether JVMMaxVersion string is a valid requirement string
+ if [ ! -z "${JVMMaxVersion}" ] && ! is_valid_requirement_pattern ${JVMMaxVersion} ; then
+ MSG_JVMVERSION_REQ_INVALID_EXPANDED=$(printf "${MSG_JVMVERSION_REQ_INVALID}" "${JVMMaxVersion}")
+ # log exit cause
+ stub_logger "[EXIT 5] ${MSG_JVMVERSION_REQ_INVALID_EXPANDED}"
+ # display error message with AppleScript
+ osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_JVMVERSION_REQ_INVALID_EXPANDED}\" with title \"${CFBundleName}\" buttons {\" OK \"} default button 1 with icon path to resource \"${CFBundleIconFile}\" in bundle (path to me)"
+ # exit with error
+ exit 5
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}"))
+ # find installed JavaVirtualMachines (JDK + JRE)
+ allJVMs=()
+ # read JDK's from '/usr/libexec/java_home -V' command
+ while read -r line; do
+ version=$(echo $line | awk -F $',' '{print $1;}')
+ path=$(echo $line | awk -F $'" ' '{print $2;}')
+ path+="/bin/java"
+ allJVMs+=("$version:$path")
+ done < <(/usr/libexec/java_home -V 2>&1 | grep '^[[:space:]]')
+ # unset while loop variables
+ unset version path
+
+ # add Apple JRE if available
+ if [ -x "${apple_jre_plugin}" ] ; then
+ allJVMs+=("$apple_jre_version:$apple_jre_plugin")
fi
- # then additionally check the Oracle JRE plugin whether it's a higher/newer compatible version
+ # add Oracle JRE if available
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
+ allJVMs+=("$oracle_jre_version:$oracle_jre_plugin")
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}
+ # debug output
+ for i in "${allJVMs[@]}"
+ do
+ stub_logger "[JavaSearch] ... found JVM: $i"
+ done
+
+
+ # determine JVMs matching the min/max version requirement
+ minC=$(get_comparable_java_version ${JVMVersion})
+ maxC=$(get_comparable_java_version ${JVMMaxVersion})
+ matchingJVMs=()
+
+ for i in "${allJVMs[@]}"
+ do
+ # split JVM string at ':' delimiter to retain spaces in $path substring
+ IFS=: arr=($i) ; unset IFS
+ # [0] JVM version number
+ ver=${arr[0]}
+ # comparable JVM version number
+ comp=$(get_comparable_java_version $ver)
+ # [1] JVM path
+ path="${arr[1]}"
+ # construct string item for adding to the "matchingJVMs" array
+ item="$comp:$ver:$path"
+
+ # pre-requisite: current version number needs to be greater than min version number
+ if [ "$comp" -ge "$minC" ] ; then
+
+ # perform max version checks if max version requirement is present
+ if [ ! -z ${JVMMaxVersion} ] ; then
+
+ # max version requirement ends with '*' modifier
+ if [[ ${JVMMaxVersion} == *\* ]] ; then
+
+ # use the '*' modifier from the max version string as wildcard for a 'starts with' comparison
+ # and check whether the current version number starts with the max version wildcard string
+ if [[ ${ver} == ${JVMMaxVersion} ]]; then
+ matchingJVMs+=("$item")
+
+ # or whether the current comparable version is lower than the comparable max version
+ elif [ "$comp" -le "$maxC" ] ; then
+ matchingJVMs+=("$item")
+ fi
+
+ # max version requirement ends with '+' modifier -> always add this version if it's greater than $min
+ # because a max requirement with + modifier doesn't make sense
+ elif [[ ${JVMMaxVersion} == *+ ]] ; then
+ matchingJVMs+=("$item")
+
+ # matches 6 zeros at the end of the max version string (e.g. for 1.8, 9)
+ # -> then the max version string should be treated like with a '*' modifier at the end
+ #elif [[ ${maxC} =~ ^[0-9]{2}0{6}$ ]] && [ "$comp" -le $(( ${maxC#0} + 999 )) ] ; then
+ # matchingJVMs+=("$item")
+
+ # matches 3 zeros at the end of the max version string (e.g. for 9.1, 10.3)
+ # -> then the max version string should be treated like with a '*' modifier at the end
+ #elif [[ ${maxC} =~ ^[0-9]{5}0{3}$ ]] && [ "$comp" -le "${maxC}" ] ; then
+ # matchingJVMs+=("$item")
+
+ # matches standard requirements without modifier
+ elif [ "$comp" -le "$maxC" ]; then
+ matchingJVMs+=("$item")
+ fi
+
+ # no max version requirement:
+
+ # min version requirement ends with '+' modifier
+ # -> always add the current version because it's greater than $min
+ elif [[ ${JVMVersion} == *+ ]] ; then
+ matchingJVMs+=("$item")
+
+ # min version requirement ends with '*' modifier
+ # -> use the '*' modifier from the min version string as wildcard for a 'starts with' comparison
+ # and check whether the current version number starts with the min version wildcard string
+ elif [[ ${JVMVersion} == *\* ]] ; then
+ if [[ ${ver} == ${JVMVersion} ]] ; then
+ matchingJVMs+=("$item")
+ fi
+
+ # compare the min version against the current version with an additional * wildcard for a 'starts with' comparison
+ # -> e.g. add 1.8.0_44 when the requirement is 1.8
+ elif [[ ${ver} == ${JVMVersion}* ]] ; then
+ matchingJVMs+=("$item")
+ fi
fi
- fi
+ done
+ # unset for loop variables
+ unset arr ver comp path item
+
+ # debug output
+ for i in "${matchingJVMs[@]}"
+ do
+ stub_logger "[JavaSearch] ... ... matches all requirements: $i"
+ done
+
+
+ # sort the matching JavaVirtualMachines by version number
+ # https://stackoverflow.com/a/11789688/1128689
+ IFS=$'\n' matchingJVMs=($(sort -nr <<<"${matchingJVMs[*]}"))
+ unset IFS
+
+
+ # get the highest matching JVM
+ for ((i = 0; i < ${#matchingJVMs[@]}; i++));
+ do
+ # split JVM string at ':' delimiter to retain spaces in $path substring
+ IFS=: arr=(${matchingJVMs[$i]}) ; unset IFS
+ # [0] comparable JVM version number
+ comp=${arr[0]}
+ # [1] JVM version number
+ ver=${arr[1]}
+ # [2] JVM path
+ path="${arr[2]}"
+
+ # use current value as JAVACMD if it's executable
+ if [ -x "$path" ] ; then
+ JAVACMD="$path"
+ JAVACMD_version=$comp
+ break
+ fi
+ done
+ # unset for loop variables
+ unset arr comp ver path
fi
-# fallback fallback: /usr/bin/java
-# but this would prompt to install deprecated Apple Java 6
+# log the Java Command and the extracted version number
+stub_logger "[JavaCommand] '$JAVACMD'"
+stub_logger "[JavaVersion] $(get_java_version_from_cmd "${JAVACMD}")${JAVACMD_version:+ / $JAVACMD_version}"
-#
-# execute JAVA commandline and do some pre-checks
-####################################################
+if [ -z "${JAVACMD}" ] || [ ! -x "${JAVACMD}" ] ; then
-# 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
+ # different error messages when a specific JVM was required
+ if [ ! -z "${JVMVersion}" ] ; then
+ # display human readable java version (#28)
+ java_version_hr=$(echo ${JVMVersion} | sed -E 's/^1\.([0-9+*]+)$/ \1/g' | sed "s/+/ ${MSG_JAVA_VERSION_OR_LATER}/;s/*/ ${MSG_JAVA_VERSION_LATEST}/")
+ MSG_NO_SUITABLE_JAVA_EXPANDED=$(printf "${MSG_NO_SUITABLE_JAVA}" "${java_version_hr}").
+ if [ ! -z "${JVMMaxVersion}" ] ; then
+ java_version_hr=$(extract_java_major_version ${JVMVersion})
+ java_version_max_hr=$(echo ${JVMMaxVersion} | sed -E 's/^1\.([0-9+*]+)$/ \1/g' | sed "s/+//;s/*/ ${MSG_JAVA_VERSION_LATEST}/")
+ MSG_NO_SUITABLE_JAVA_EXPANDED="$(printf "${MSG_NO_SUITABLE_JAVA}" "${java_version_hr}") $(printf "${MSG_JAVA_VERSION_MAX}" "${java_version_max_hr}")"
+ fi
-# check whether $JAVACMD is a file and executable
-elif [ -f "$JAVACMD" ] && [ -x "$JAVACMD" ] ; then
+ # log exit cause
+ stub_logger "[EXIT 3] ${MSG_NO_SUITABLE_JAVA_EXPANDED}"
- # enable drag&drop to the dock icon
- export CFProcessPath="$0"
+ # display error message with AppleScript
+ osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_NO_SUITABLE_JAVA_EXPANDED}\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
- # remove Apples ProcessSerialNumber from passthru arguments (#39)
- if [[ $@ == -psn* ]] ; then
- ArgsPassthru=""
else
- ArgsPassthru=$@
+ # log exit cause
+ stub_logger "[EXIT 1] ${MSG_ERROR_LAUNCHING}"
+ # 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
-
- # 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}
+fi
-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\""
+# MainClass check
+############################################
+if [ -z "${JVMMainClass}" ]; then
+ # log exit cause
+ stub_logger "[EXIT 2] ${MSG_MISSING_MAINCLASS}"
+ # 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 1
+ exit 2
+fi
+
+
+
+# execute $JAVACMD and do some preparation
+############################################
+
+# 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}" || exit 13
+stub_logger "[WorkingDirectory] ${WorkingDirectory}"
+
+# execute Java and set
+# - classpath
+# - splash image
+# - dock icon
+# - app name
+# - JVM options
+# - JVM default options
+# - main class
+# - main arguments
+# - passthru arguments
+stub_logger "[Exec] \"$JAVACMD\" -cp \"${JVMClassPath}\" -splash:\"${ResourcesFolder}/${JVMSplashFile}\" -Xdock:icon=\"${ResourcesFolder}/${CFBundleIconFile}\" -Xdock:name=\"${CFBundleName}\" ${JVMOptionsArr:+$(printf "'%s' " "${JVMOptionsArr[@]}") }${JVMDefaultOptions:+$JVMDefaultOptions }${JVMMainClass}${MainArgsArr:+ $(printf "'%s' " "${MainArgsArr[@]}")}${ArgsPassthru:+ $(printf "'%s' " "${ArgsPassthru[@]}")}"
+exec "${JAVACMD}" \
+ -cp "${JVMClassPath}" \
+ -splash:"${ResourcesFolder}/${JVMSplashFile}" \
+ -Xdock:icon="${ResourcesFolder}/${CFBundleIconFile}" \
+ -Xdock:name="${CFBundleName}" \
+ ${JVMOptions:+"$JVMOptions[@]}" }\
+ ${JVMDefaultOptions:+$JVMDefaultOptions }\
+ "${JVMMainClass}"\
+ ${MainArgsArr:+ "${MainArgsArr[@]}"}\
+ ${ArgsPassthru:+ "${ArgsPassthru[@]}"}
diff --git a/test/java-version-tester.sh b/test/java-version-tester.sh
index 141891e..01fa7c9 100755
--- a/test/java-version-tester.sh
+++ b/test/java-version-tester.sh
@@ -1,95 +1,155 @@
#!/bin/bash
-# Java JRE version tester
-# tofi86 @ 2017-06-12
+# Tests for the functions used in universalJavaApplicationStub script
+# tofi86 @ 2018-02-12
-# helper function:
-# extract Java version string from `java -version` command
+# function 'get_java_version_from_cmd()'
+#
+# returns 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'`
+#
+# @param1 path to a java JVM executable
+# @return the Java version number as displayed in 'java -version' command
+################################################################################
+function get_java_version_from_cmd() {
+ # 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
+# function 'extract_java_major_version()'
+#
+# extract Java major version from a version string
+#
+# @param1 a Java version number ('1.8.0_45') or requirement string ('1.8+')
+# @return the major version (e.g. '7', '8' or '9', etc.)
+################################################################################
+function extract_java_major_version() {
+ echo $(echo "$1" | sed -E 's/^1\.//;s/^([0-9]+)(-ea|(\.[0-9_.]{1,7})?)[+*]?$/\1/')
}
-# 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 'get_comparable_java_version()'
+#
+# return comparable version for a Java version number or requirement string
+#
+# @param1 a Java version number ('1.8.0_45') or requirement string ('1.8+')
+# @return an 8 digit numeral ('1.8.0_45'->'08000045'; '9.1.13'->'09001013')
+################################################################################
+function get_comparable_java_version() {
+ # cleaning: 1) remove leading '1.'; 2) remove 'a-Z' and '-*+' (e.g. '-ea'); 3) replace '_' with '.'
+ local cleaned=$(echo "$1" | sed -E 's/^1\.//g;s/[a-zA-Z+*\-]//g;s/_/./g')
+ # splitting at '.' into an array
+ local arr=( ${cleaned//./ } )
+ # echo a string with left padded version numbers
+ echo "$(printf '%02s' ${arr[0]})$(printf '%03s' ${arr[1]})$(printf '%03s' ${arr[2]})"
}
-# function:
-# Java version tester checks whether a given java version
+# function 'is_valid_requirement_pattern()'
+#
+# check whether the Java requirement is a valid requirement pattern
+#
+# supported requirements are for example:
+# - 1.6 requires Java 6 (any update) [1.6, 1.6.0_45, 1.6.0_88]
+# - 1.6* requires Java 6 (any update) [1.6, 1.6.0_45, 1.6.0_88]
+# - 1.6+ requires Java 6 or higher [1.6, 1.6.0_45, 1.8, 9, etc.]
+# - 1.6.0 requires Java 6 (any update) [1.6, 1.6.0_45, 1.6.0_88]
+# - 1.6.0_45 requires Java 6u45 [1.6.0_45]
+# - 1.6.0_45+ requires Java 6u45 or higher [1.6.0_45, 1.6.0_88, 1.8, etc.]
+# - 9 requires Java 9 (any update) [9.0.*, 9.1, 9.3, etc.]
+# - 9* requires Java 9 (any update) [9.0.*, 9.1, 9.3, etc.]
+# - 9+ requires Java 9 or higher [9.0, 9.1, 10, etc.]
+# - 9.1 requires Java 9.1 (any update) [9.1.*, 9.1.2, 9.1.13, etc.]
+# - 9.1* requires Java 9.1 (any update) [9.1.*, 9.1.2, 9.1.13, etc.]
+# - 9.1+ requires Java 9.1 or higher [9.1, 9.2, 10, etc.]
+# - 9.1.3 requires Java 9.1.3 [9.1.3]
+# - 9.1.3* requires Java 9.1.3 (any update) [9.1.3]
+# - 9.1.3+ requires Java 9.1.3 or higher [9.1.3, 9.1.4, 9.2.*, 10, etc.]
+# - 10-ea requires Java 10 (early access release)
+#
+# unsupported requirement patterns are for example:
+# - 1.2, 1.3, 1.9 Java 2, 3 are not supported
+# - 1.9 Java 9 introduced a new versioning scheme
+# - 6u45 known versioning syntax, but unsupported
+# - 9-ea*, 9-ea+ early access releases paired with */+
+# - 9., 9.*, 9.+ version ending with a .
+# - 9.1., 9.1.*, 9.1.+ version ending with a .
+# - 9.3.5.6 4 part version number is unsupported
+#
+# @param1 a Java requirement string ('1.8+')
+# @return boolean exit code: 0 (is valid), 1 (is not valid)
+################################################################################
+function is_valid_requirement_pattern() {
+ local java_req=$1
+ java8pattern='1\.[4-8](\.0)?(\.0_[0-9]+)?[*+]?'
+ java9pattern='(9|1[0-9])(-ea|[*+]|(\.[0-9]+){1,2}[*+]?)?'
+ # test matches either old Java versioning scheme (up to 1.8) or new scheme (starting with 9)
+ if [[ ${java_req} =~ ^(${java8pattern}|${java9pattern})$ ]]; then
+ return 0
+ else
+ return 1
+ fi
+}
+
+
+# function 'does_java_version_satisfy_requirement()'
+#
+# this function checks whether a given java version number
# 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
+#
+# the function returns with an error (exit 2) if the requirement string
+# is not supported
+#
+# @param1 the java version in plain form as 'java -version' returns it
+# @param2 the java requirement (1.6, 1.7+, 9, 9.1*, 9.2.3, etc.)
+# @return an exit code: 0 (satiesfies), 1 (does not), 2 (invalid requirement)
+################################################################################
+function does_java_version_satisfy_requirement() {
+ # update short versions (9, 9.1, 10) to semver form (9.0.0, 9.1.0, 10.0.0)
+ local java_ver=$(pad_short_version_to_semver $1)
+ local java_req=$2
+
+ if ! is_valid_requirement_pattern ${java_req} ; then
+ return 2
+
+ # requirement ends with * modifier
+ # e.g. 1.8*, 9*, 9.1*, 9.2.4*, 10*, 10.1*, 10.1.35*
+ elif [[ ${java_req} == *\* ]] ; then
+ # use the * modifier from the requirement string as wildcard for a 'starts with' comparison
+ if [[ ${java_ver} == ${java_req} ]] ; then
+ return 0
+ else
+ return 1
+ fi
+
+ # requirement ends with + modifier
+ # e.g. 1.8+, 9+, 9.1+, 9.2.4+, 10+, 10.1+, 10.1.35+
+ elif [[ ${java_req} == *+ ]] ; then
+ local java_req_num=$(get_comparable_java_version ${java_req})
+ local java_ver_num=$(get_comparable_java_version ${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
+ else
+ # java version equals requirement string (1.8.0_45 == 1.8.0.45)
+ if [ ${java_ver} == ${java_req} ] ; then
+ return 0
+ # java version starts with requirement string (1.8.0_45 == 1.8)
+ elif [[ ${java_ver} == ${java_req}* ]] ; then
+ return 0
+ else
+ return 1
+ fi
+
+ fi
}
@@ -97,174 +157,229 @@ function JavaVersionSatisfiesRequirement() {
# test function:
-# tests the extractJavaMajorVersion() function
+# tests the extract_java_major_version() function
##########################################################
function testExtractMajor() {
- java_version=$1
- expected_major=$2
- actual_major=`extractJavaMajorVersion $java_version`
- if [ ${expected_major} == ${actual_major} ] ; then
- echo "[TEST OK] Extracted Java major version '${actual_major}' for Java '${java_version}'"
- else
- echo "[TEST FAILED] Extracted Java major version '${actual_major}' for Java '${java_version}' but expected '${expected_major}'"
- fi
+ local java_version=$1
+ local expected_major=$2
+ local actual_major=$(extract_java_major_version "$java_version")
+ if [ ${expected_major} == ${actual_major} ] ; then
+ echo "[TEST OK] Extracted Java major version '${actual_major}' for Java '${java_version}'"
+ else
+ echo "[TEST FAILED] Extracted Java major version '${actual_major}' for Java '${java_version}' but expected '${expected_major}'"
+ fi
}
echo ""
echo "########################################################"
-echo "Testing function extractJavaMajorVersion()"
+echo "Testing function extract_java_major_version()"
echo ""
echo "Tests with Java 1.6:"
-testExtractMajor 1.6.0 6
-testExtractMajor 1.6.0_07 6
-testExtractMajor 1.6.0_45 6
+testExtractMajor "1.6" "6"
+testExtractMajor "1.6+" "6"
+testExtractMajor "1.6.0" "6"
+testExtractMajor "1.6.0_07" "6"
+testExtractMajor "1.6.0_45" "6"
echo ""
echo "Tests with Java 1.7:"
-testExtractMajor 1.7.0 7
-testExtractMajor 1.7.0_09 7
-testExtractMajor 1.7.0_79 7
+testExtractMajor "1.7" "7"
+testExtractMajor "1.7*" "7"
+testExtractMajor "1.7.0" "7"
+testExtractMajor "1.7.0_09" "7"
+testExtractMajor "1.7.0_79" "7"
echo ""
echo "Tests with Java 1.8:"
-testExtractMajor 1.8.0 8
-testExtractMajor 1.8.0_05 8
-testExtractMajor 1.8.0_91 8
-testExtractMajor 1.8.0_131 8
+testExtractMajor "1.8" "8"
+testExtractMajor "1.8+" "8"
+testExtractMajor "1.8.0" "8"
+testExtractMajor "1.8.0_05" "8"
+testExtractMajor "1.8.0_91" "8"
+testExtractMajor "1.8.0_131" "8"
echo ""
echo "Tests with Java 9:"
-testExtractMajor 9-ea 9
-testExtractMajor 9.0.1 9
-testExtractMajor 9.0.23 9
-testExtractMajor 9.10.120 9
+testExtractMajor "9" "9"
+testExtractMajor "9-ea" "9"
+testExtractMajor "9.1*" "9"
+testExtractMajor "9.0.1" "9"
+testExtractMajor "9.0.1+" "9"
+testExtractMajor "9.0.23" "9"
+testExtractMajor "9.10.120" "9"
+testExtractMajor "9.10.120+" "9"
+testExtractMajor "9.100.120+" "9"
echo ""
echo "Tests with Java 10:"
-testExtractMajor 10-ea 10
-testExtractMajor 10.0.1 10
-testExtractMajor 10.0.23 10
-testExtractMajor 10.10.120 10
+testExtractMajor "10" "10"
+testExtractMajor "10-ea" "10"
+testExtractMajor "10.1+" "10"
+testExtractMajor "10.0.1" "10"
+testExtractMajor "10.0.1*" "10"
+testExtractMajor "10.0.23" "10"
+testExtractMajor "10.10.120" "10"
+testExtractMajor "10.10.120+" "10"
+testExtractMajor "10.100.120+" "10"
+
# test function:
-# tests the JavaVersionSatisfiesRequirement() function
+# tests the get_comparable_java_version() function
##########################################################
-function testCompare() {
- java_version=$1
- java_requirement=$2
- expected_result=$3
- actual_result=`JavaVersionSatisfiesRequirement $java_version $java_requirement ; echo $?`
- if [ ${expected_result} == ${actual_result} ] ; then
- case $expected_result in
- 0)
- echo "[TEST OK] [${expected_result}==${actual_result}] Java version ${java_version} satisfies requirement ${java_requirement}"
- ;;
- 1)
- echo "[TEST OK] [${expected_result}==${actual_result}] Java version ${java_version} does not satisfy requirement ${java_requirement}"
- ;;
- 2)
- echo "[TEST OK] [${expected_result}==${actual_result}] Invalid Java version requirement ${java_requirement}"
- ;;
- esac
- else
- echo "[TEST FAILED] [${expected_result}!=${actual_result}] Java version: ${java_version} ; Requirement ${java_requirement} ; Expected: ${expected_result} ; Actual: ${actual_result}"
- fi
+function testComparable() {
+ local version=$1
+ local expected=$2
+ local actual=$(get_comparable_java_version $version)
+ if [ "$actual" == "$expected" ] ; then
+ echo "[TEST OK] Version number '$version' has comparable form '$actual' (matches expected result '$expected')"
+ else
+ echo "[TEST FAILED] Version number '$version' has comparable form '$actual' (DOES NOT MATCH expected result '$expected')"
+ fi
}
echo ""
echo ""
echo "########################################################"
-echo "Testing function JavaVersionSatisfiesRequirement()"
+echo "Testing function get_comparable_java_version()"
echo ""
echo "Tests with Java 1.6:"
-testCompare 1.6 1.6 0
-testCompare 1.6 1.6+ 0
-testCompare 1.6 1.6* 0
-testCompare 1.6 1.6.0_45 2
-testCompare 1.6 1.7 1
-testCompare 1.6 1.7+ 1
-testCompare 1.6 1.7* 1
-testCompare 1.6 1.7.0_71 2
-testCompare 1.6 1.8 1
-testCompare 1.6 1.8+ 1
-testCompare 1.6 1.8* 1
-testCompare 1.6 1.8.0_121 2
-testCompare 1.6 9 1
-testCompare 1.6 9+ 1
-testCompare 1.6 9* 1
-testCompare 1.6 9.1.2 1
+testComparable "1.6" "06000000"
+testComparable "1.6+" "06000000"
+testComparable "1.6.0_45" "06000045"
+testComparable "1.6.0_100" "06000100"
+testComparable "1.6.1_87" "06001087"
echo ""
echo "Tests with Java 1.7:"
-testCompare 1.7 1.6 1
-testCompare 1.7 1.6+ 0
-testCompare 1.7 1.6* 1
-testCompare 1.7 1.6.0_45 2
-testCompare 1.7 1.7 0
-testCompare 1.7 1.7+ 0
-testCompare 1.7 1.7* 0
-testCompare 1.7 1.7.0_71 2
-testCompare 1.7 1.8 1
-testCompare 1.7 1.8+ 1
-testCompare 1.7 1.8* 1
-testCompare 1.7 1.8.0_121 2
-testCompare 1.7 9 1
-testCompare 1.7 9+ 1
-testCompare 1.7 9* 1
-testCompare 1.7 9.1.2 1
+testComparable "1.7.0_76" "07000076"
+testComparable "1.7.0_144" "07000144"
echo ""
echo "Tests with Java 1.8:"
-testCompare 1.8 1.6 1
-testCompare 1.8 1.6+ 0
-testCompare 1.8 1.6* 1
-testCompare 1.8 1.6.0_45 2
-testCompare 1.8 1.7 1
-testCompare 1.8 1.7+ 0
-testCompare 1.8 1.7* 1
-testCompare 1.8 1.7.0_71 2
-testCompare 1.8 1.8 0
-testCompare 1.8 1.8+ 0
-testCompare 1.8 1.8* 0
-testCompare 1.8 1.8.0_121 2
-testCompare 1.8 9 1
-testCompare 1.8 9+ 1
-testCompare 1.8 9* 1
-testCompare 1.8 9.1.2 1
+testComparable "1.8" "08000000"
+testComparable "1.8*" "08000000"
+testComparable "1.8.0_98" "08000098"
+testComparable "1.8.0_151" "08000151"
echo ""
echo "Tests with Java 9:"
-testCompare 9 1.6 1
-testCompare 9 1.6+ 0
-testCompare 9 1.6* 1
-testCompare 9 1.6.0_45 2
-testCompare 9 1.7 1
-testCompare 9 1.7+ 0
-testCompare 9 1.7* 1
-testCompare 9 1.7.0_71 2
-testCompare 9 1.8 1
-testCompare 9 1.8+ 0
-testCompare 9 1.8* 1
-testCompare 9 1.8.0_121 2
-testCompare 9 9 0
-testCompare 9 9+ 0
-testCompare 9 9* 0
-testCompare 9 9.1.2 1
+testComparable "9" "09000000"
+testComparable "9+" "09000000"
+testComparable "9-ea" "09000000"
+testComparable "9.2" "09002000"
+testComparable "9.2*" "09002000"
+testComparable "9.0.1" "09000001"
+testComparable "9.0.13" "09000013"
+testComparable "9.1.3" "09001003"
+testComparable "9.11" "09011000"
+testComparable "9.10.23" "09010023"
+testComparable "9.10.101" "09010101"
echo ""
echo "Tests with Java 10:"
-testCompare 10 1.6 1
-testCompare 10 1.6+ 0
-testCompare 10 1.6* 1
-testCompare 10 1.6.0_45 2
-testCompare 10 1.7 1
-testCompare 10 1.7+ 0
-testCompare 10 1.7* 1
-testCompare 10 1.7.0_71 2
-testCompare 10 1.8 1
-testCompare 10 1.8+ 0
-testCompare 10 1.8* 1
-testCompare 10 1.8.0_121 2
-testCompare 10 9 1
-testCompare 10 9+ 0
-testCompare 10 9* 1
-testCompare 10 9.1.2 1
-testCompare 10 10 0
-testCompare 10 10+ 0
-testCompare 10 10* 0
-testCompare 10 10.0.13 1
+testComparable "10" "10000000"
+testComparable "10*" "10000000"
+testComparable "10-ea" "10000000"
+testComparable "10.1" "10001000"
+testComparable "10.1+" "10001000"
+testComparable "10.0.1" "10000001"
+testComparable "10.0.13" "10000013"
+testComparable "10.1.3" "10001003"
+testComparable "10.12" "10012000"
+testComparable "10.10.23" "10010023"
+testComparable "10.10.113" "10010113"
+
+
+
+# test function:
+# tests the is_valid_requirement_pattern() function
+##########################################################
+function testValidReqPattern() {
+ local pattern=$1
+ local expected=$2
+ local actual=$(is_valid_requirement_pattern "$pattern" ; echo $?)
+ if [ "$expected" == "$actual" ] ; then
+ case $expected in
+ 0)
+ echo "[TEST OK] [${expected}==${actual}] Requirement pattern '$pattern' is valid"
+ ;;
+ 1)
+ echo "[TEST OK] [${expected}==${actual}] Requirement pattern '$pattern' is not valid"
+ ;;
+ esac
+ else
+ echo "[TEST FAILED] [${expected}!=${actual}] Requirement ${pattern} ; Expected: ${expected} ; Actual: ${actual}"
+ fi
+}
+
+
+echo ""
+echo ""
+echo "########################################################"
+echo "Testing function is_valid_requirement_pattern()"
+echo ""
+echo "Tests with old version scheme (valid requirements):"
+testValidReqPattern "1.4" "0"
+testValidReqPattern "1.5" "0"
+testValidReqPattern "1.6" "0"
+testValidReqPattern "1.6*" "0"
+testValidReqPattern "1.6+" "0"
+testValidReqPattern "1.6.0" "0"
+testValidReqPattern "1.6.0*" "0"
+testValidReqPattern "1.6.0+" "0"
+testValidReqPattern "1.6.0_45" "0"
+testValidReqPattern "1.6.0_45+" "0"
+testValidReqPattern "1.6.0_100" "0"
+testValidReqPattern "1.6.0_100+" "0"
+echo ""
+echo "Tests with old version scheme (invalid requirements):"
+testValidReqPattern "1.2" "1"
+testValidReqPattern "1.3" "1"
+testValidReqPattern "1.9" "1"
+testValidReqPattern "1.9*" "1"
+testValidReqPattern "1.9+" "1"
+testValidReqPattern "1.9.0_20" "1"
+testValidReqPattern "1.9.0_20*" "1"
+testValidReqPattern "1.9.0_20+" "1"
+testValidReqPattern "6u45" "1"
+echo ""
+echo "Tests with new version scheme (valid requirements):"
+testValidReqPattern "9" "0"
+testValidReqPattern "9*" "0"
+testValidReqPattern "9+" "0"
+testValidReqPattern "9-ea" "0"
+testValidReqPattern "9.1" "0"
+testValidReqPattern "9.1*" "0"
+testValidReqPattern "9.1+" "0"
+testValidReqPattern "9.1.3" "0"
+testValidReqPattern "9.1.3*" "0"
+testValidReqPattern "9.1.3+" "0"
+testValidReqPattern "9.0.13" "0"
+testValidReqPattern "9.11" "0"
+testValidReqPattern "9.11*" "0"
+testValidReqPattern "9.11+" "0"
+testValidReqPattern "9.10.23" "0"
+testValidReqPattern "9.10.101" "0"
+testValidReqPattern "10" "0"
+testValidReqPattern "10*" "0"
+testValidReqPattern "10-ea" "0"
+testValidReqPattern "10.1" "0"
+testValidReqPattern "10.1*" "0"
+testValidReqPattern "10.1+" "0"
+testValidReqPattern "10.0.1" "0"
+testValidReqPattern "10.0.1*" "0"
+testValidReqPattern "10.0.1+" "0"
+testValidReqPattern "10.0.13" "0"
+testValidReqPattern "10.1.3" "0"
+testValidReqPattern "10.12" "0"
+testValidReqPattern "10.10.23" "0"
+testValidReqPattern "10.10.113" "0"
+echo ""
+echo "Tests with new version scheme (invalid requirements):"
+testValidReqPattern "9-ea*" "1"
+testValidReqPattern "9-ea+" "1"
+testValidReqPattern "9." "1"
+testValidReqPattern "9.*" "1"
+testValidReqPattern "9.+" "1"
+testValidReqPattern "9.1." "1"
+testValidReqPattern "9.1.*" "1"
+testValidReqPattern "9.1.+" "1"
+testValidReqPattern "9.2.15." "1"
+testValidReqPattern "9.2.15.*" "1"
+testValidReqPattern "9.2.15.+" "1"
+testValidReqPattern "9.3.5.6" "1"