The Java launchers can simplify complicated Java JAR deployments by leveraging the Multiple JRE feature of the launchers.
Background
Enterprise wide Java intranet applications may be deployed as JAR file(s)
containing classes and resources needed by an application. These JARs are
installed on a filesystem within an intranet. Typically these applications
are launched using Unix shell scripts or Windows batch files, using very simple commands such as "java -jar SomeApp.jar arg1 arg2 ......"
Not all Java applications are the same and some of these could require a specific version of the JRE. The Multiple JRE (MJRE) mechanism in the java launcher (as of 1.5) can be leveraged, so that different versions of JREs and JARs requiring them can peacefully co-exist on a system.
So what is this feature ?
The Java Launcher is a binary file "java" found in the "bin" directory of the JRE distribution. On Windows platform the launchers are "java.exe" and "javaw.exe", the former displays a Console window, during the execution of the application and the latter does not, however both are Java launchers.
Note that "javaws"(.exe) is Java Webstart, a Java application primarily used to launch Java applications over the network. The MJRE, in fact borrows several version-contraint semantics from Java Webstart, however these constraints in Java Webstart are specified in a different form, and not discussed here.
If applied correctly, the MJRE feature of the launcher can be extremely useful, consider the use case:
Suppose we have a user who has several applications ex: NotePad, PhotoEdit
etc.
The NotePad has been certified to work with JRE 1.5 by the application
vendor. The PhotoEdit application began to malfunction with JRE 1.5 due
to a graphics issue, and JRE 1.6 fixes the problem. So one can solve the problem of ensuring that the JREs co-exist, by doing the following:
Manifest for PhotoEdit:
Main-Class: PhotoEdit
JRE-version: 1.6+
Manifest for NotePad:
Main-Class: NotePad
JRE-version: 1.5*
The launcher uses 1.5.0_06 version of the JRE....
% java -jar NotePad.jar
NotePad-application
running with JRE-version 1.5.0_06
The same launcher as above uses 1.6.0 version of the JRE...
% java -jar PhotoEdit.jar
PhotoEdit-application
running with JRE-version 1.6.0
On Solaris 2.6 and newer one can execute the JAR file directly,
% chmod +x *.jar
% ./PhotoEdit.jar
PhotoEdit-application
running with JRE-version 1.6.0
% ./NotePad.jar
NotePad-application
running with JRE-version 1.5.0_06
The above works on Windows too, by double clicking the JAR file in Windows Explorer. See JAR Guide for more details.
Supposing the JARs are sealed and one can acheive the same end result by using command line syntax of the launcher as follows:
java -version:1.5* -jar NotePad.jar ..........
java -version:1.6+ -jar PhotoEdit.jar.......
Note: Its a very bad idea to tie to a specific release of the JRE insteand select a range ex: 1.5* to stay within the 1.5 and its updated releases or 1.5+ to simply select a newer version of the JRE than 1.5 if available.
So how does this all work ?
In order for the MJRE to reliably find other installed instances of J2SE it performs lookups, and the lookup varies depending on the platform, described as follows:
On Windows:
The Windows installer will update the Windows registry hive at "HKLM\SOFTWARE\JavaSoft\Java Runtime Environment". The JRE installer will also copy the launchers to "C:\Windows\system32\",
which is on the %PATH%, therefore invoking the command "java" will
execute the latest launcher, which in turn will invoke a JRE matching
the version constraint, specified in the Manifest or on the command
line.
On Solaris: The launcher behaves much like Windows, meaning, the launchers selects a suitable JRE satisfying the constraint. The launcher typically searches the /usr/jdk (installed by the Solaris pkgadd facility, typically by a Systems Administrator or persons having "root" access) and $HOME/jdk (a users private stash) for instances of the JRE.
On Linux: Similar to the Solaris launcher and will search the /usr/java repository, instead of /usr/jdk for any system wide instances of the JRE.
Summary:
The MJRE feature is extremely useful to constrain or select a suitable JRE for an application, provided the JREs are laid out in the filesystem correctly as described above. Noting that, its not at all a good idea to "over-constrain" the selection process, such that the selection is tied to a specific release. Over constraining will not allow the application to use updated versions of JREs, containing critical fixes.
References:
An Ant example script to test all of the above.
<project name="launcher_example" default="all" basedir="./">
<!-- Requires ant 1.7.0 and JDK 1.5 or better-->
<!-- set global properties for this build -->
<property name="src" value="src"/>
<property name="build" value="build"/>
<property name="dist" value="dist"/>
<target name="init">
<!-- Create the time stamp -->
<tstamp/>
<!-- Create the build directory structure used by compile -->
<mkdir dir="${src}"/>
<mkdir dir="${src}/NotePad"/>
<mkdir dir="${src}/PhotoEdit"/>
<mkdir dir="${build}"/>
<mkdir dir="${build}/NotePad"/>
<mkdir dir="${build}/PhotoEdit"/>
<mkdir dir="${dist}"/>
</target>
<target name="createNotePad">
<echo file="${src}/NotePad/NotePad.java">
public class NotePad {
public static void main(String[] args) {
System.out.println("NotePad-application");
System.out.print(" running with JRE-version ");
System.out.println(System.getProperty("java.version"));
System.exit(0);
}
} </echo>
</target>
<target name="createPhotoEdit">
<echo file="${src}/PhotoEdit/PhotoEdit.java">
public class PhotoEdit {
public static void main(String[] args) {
System.out.println("PhotoEdit-application");
System.out.print(" running with JRE-version ");
System.out.println(System.getProperty("java.version"));
System.exit(0);
}
}</echo>
</target>
<target name="notepad" depends="init, createNotePad">
<!-- Compile the java code from ${src} into ${build} -->
<javac
target="1.5"
srcdir="${src}/NotePad"
destdir="${build}/NotePad"
excludes="**/SCCS/*"
classpath=""
verbose="no"
/>
<jar destfile="${dist}/NotePad.jar">
<manifest>
<attribute name="Main-Class" value="NotePad"/>
<attribute name="JRE-version" value="1.5*"/>
</manifest>
<fileset dir="${build}/NotePad"/>
</jar>
</target>
<target name="photoedit" depends="init, createPhotoEdit">
<!-- Compile the java code from ${src} into ${build} -->
<javac
target="1.6"
srcdir="${src}/PhotoEdit"
destdir="${build}/PhotoEdit"
excludes="**/SCCS/*"
classpath=""
verbose="no"
/>
<jar destfile="${dist}/PhotoEdit.jar">
<manifest>
<attribute name="Main-Class" value="PhotoEdit"/>
<attribute name="JRE-version" value="1.5+"/>
</manifest>
<fileset dir="${build}/PhotoEdit"/>
</jar>
</target>
<target name="all" depends="photoedit, notepad">
<chmod perm="ugo+x">
<fileset dir="${dist}">
<include name="**/*.jar"/>
</fileset>
</chmod>
<exec executable="${dist}/PhotoEdit.jar"/>
<exec executable="${dist}/NotePad.jar"/>
</target>
<target name="clean">
<!-- Delete the ${build} and ${dist} directory trees -->
<delete dir="${src}"/>
<delete dir="${build}"/>
<delete dir="${dist}"/>
</target>
</project>


Posted by Sunny Chan on May 30, 2007 at 02:07 PM PDT #