Previous column

Next column


Project Initium: Programmatic Deployment

Douglas Lyon, Fairfield University, Fairfield CT, U.S.A.

space COLUMN

PDF Icon
PDF Version

In theory,
there is no difference between
theory and practice;
In practice, there is
.

- Chuck Reid

Abstract

This paper describes the design and use of a Java Web Start framework called Initium. Initium generates a jar file that minimizes the number of included classes by performing a static class dependency analysis. It then prompts the programmer for security parameters that enable the programmatic signing of the jar file, for the purpose of authentication. Initium generates a local Java Network Launch Protocol file (JNLP file) for the purpose of testing, as well as a remote JNLP file, for deployment. Finally, Initium programmatically uploads both the JNLP and jar files to the web server, to complete the deployment cycle.
The signing of a jar file enables web start clients to execute a Java application in a trusted and distributed manner. Trusted jar files can be executed outside of the “sandbox” and thus be given access to files, or be able to open connections to hosts other than the web host on the target system.
Initium is a Latin word that means: “at the start”. It is part of an on-going project at both the DocJava Inc. skunk works and Fairfield University.


1 THE DEPLOYMENT PROBLEM

We are given a client-side application, written in Java, which is ready for deployment. Our goal is to find a way to deploy the application to any target desktop, upon demand. The solution to this problem is subject to the constraint that: the application is allowed to run while the target system is offline, the application has no security restrictions, and the application be automatically updated. Further, we seek to minimize the time and effort needed by the programmer to perform deployment and to minimize the time and effort users need to download the application.

The approach that we use for application deployment is to make use of existing compaction; signing and Java web start technologies. Java web start is a standard adopted by Sun Microsystems that has been bundled with their Java development kit since JDK1.4 [Sun 2004].

The motivation for addressing the deployment of Java is that deployment appears to be the weak link in the development chain. Programmers that attempt to deploy their client-side applications using applets already know the hardship of trying to predict the run-time environment. Distributed computing on an open Internet is fraught with difficulties. How do we up-load our applications to the web server? Should it be a push or a pull technology? How can we make sure that the client has all the classes that it needs in order to run the computation?

There are several possible answers to these questions. To up-load our applications to the web server, I have selected a secure copy mechanism. Other techniques might work as well (or even better). For example, if security is not an issue, ftp might work with less overhead. On the other hand, there are compelling arguments to keep the transmission secure (particularly since a password and user id are sent in the clear, with ftp).

I use a push technology (SCP) to upload my applications, but a pull technology (Java Webstart) to download and run them. In this way, computers that are behind a firewall and are otherwise unreachable, can run the applications. This is the topic of Section 4.2.

In order to make sure that the client has all the classes needed to run the application, I take the approach of creating a jar file. The jar file incorporates all the classes that are probably needed. This is done by making use of a “smart” linker, the topic of Section 3.1.

2 TARGET SYSTEM REQUIREMENTS

The first assumption is that the target system has Java web start (JAWS) installed. This is a critical assumption, since without JAWS; deployment using web start technology will fail. In a non-geographically co-located computation environment, the target system may well be located far away and behind a firewall. It is typical for the target system to be running with a non-routable IP address and thus quite difficult to administrate remotely. In fact, such a situation probably describes the majority of target systems in the corporate world. Employees are often prevented from installing current versions of software (Java or otherwise) without a system administrators’ password.

Thus, environment configuration is not just a technical problem; it is a security issue. Further, since Microsoft has elected not to distribute Java with its windows operating system, the issue also becomes political.

Even worse, once JAWS is installed, it must be configured to work. If the configuration is not correct, JAWS will spit out a cryptic error and the user will be left wondering what happened. Clearly, this is not an optimal situation.

We can verify the correctness of environment configuration, before allowing installation to proceed. We can even inform the user of what needs to be installed in order to correctly configure the environment. However, it is beyond our power (or authority) to configure the target system for the user. Installing a current version of Java will generally also install JAWS. However, that may not be sufficient for getting JAWS to work.

2.1 Proxy Webserver Setup

It is typical for companies to filter web downloads and requests through a logging web proxy server. This is designed to monitor web usage. This section describes how to configure a JAWS client that is behind the company proxy web server.

Often, the browser is already pre-configured to use the proxy in order to obtain access to the web. JAWS, however, is not. For target machines behind a proxy web server, you must alter the settings options on the JAWS Management Console. Select “File:Preferences…”, as shown in Figure 1.

Figure 1. Select File:Preferences...

This will cause the Java Web Start - Preferences dialog box to appear. Select the General tab and select Use Browser, as shown in Figure 2.

Figure 2. Use the proxy settings in the Browser

Once the setup is completed, the user should not have to alter it again. The question of how to automate this set-up remains open. For example, from within Java, one can tunnel HTTP requests through the proxy web server by putting properties into the System class. However, setting these properties is always something that is done at run-time. Generally by some sort of helper method. For example:

Frequently, a GUI is presented to the user to prompt for these parameters. This could be classified as a network administration task that is being performed by the end-user. Such configuration tasks are cumbersome and error-prone, at best. So far, the best practice is to educate the user of the JAWS technology about proxy web server set-ups, as a routine part of deployment! See [Sun 2004a] to learn more about networking properties.

In the simpler case, when users are not required to make use of proxy web servers to gain access to the web, a simpler solution is to make use of a JavaScript that can detect the configuration of the target machine an advise the user accordingly.

2.2 Testing Java Webstart

Testing JAWS is performed by making use of it from a known good JAWS site. For example, demos can be run at http://java.sun.com/products/javawebstart/demos.html.

Some windows users report errors about a bad installation when running JAWS. An example of such an error is shown in Figure 3.

Figure 3. Error during execution

Such users need to uninstall their current version of Java and then re-install it. This can require administrative access. Thus, webstart must be verified and installed on a per-user basis. On the other hand, some systems, like Mac OS X, come pre-installed with JAWS (though testing should still be performed).

3 PROGRAMMATIC DEPLOYMENT

This section describes the 4 steps toward programmatic deployment of a Java application. The first subsection describes how to create a jar file from within a working project so that the jar file only contains those classes that are needed in order to run the application. The second subsection describes how to sign the jar file so that it can be trusted. The third subsection describes how to programmatically synthesize the JNLP script that will launch the application from the local machine, for the purpose of testing. The forth and final subsection describes the interface and testing function available to the programmer.

3.1 Packing the Jar File

Jar deployment is typically performed by programmers who seek to distribute their applications. Typically, programmers will use the Sun-supplied jar tool in order to deploy their applications. It is left, therefore, to the programmer to decide what classes to include and which ones to exclude. For example, my present project, including all the classes, results in a compressed jar file that is nearly 3 MB in size. However, with proper packing and dependency analysis, I can trim this down to 7.2 KB, a improvement by a factor of 40.
How is this possible? How can I take an existing set of 2,106 classes in a project and reduce to just 4 class files (a 500:1 improvement). The answer is in static dependency analysis (SDA). SDA has the advantage of creating very small jar files by being a “smart” linker that does static association discovery. However, SDA can also fail to work properly. It is nearly impossible to do static dependency analysis in a language that can dynamically load classes based on the contents of a string. For example:

Class c = Class.forName(“theClassWeMissed”);

is missed by the SDA and causes a ClassNotFoundException at run time. In my project, Class.forName occurs in 34 files out of 1,585 files (1 file in 46). So, while rare, at least in my own code, I am aware that this does happen. Further, for projects that are smaller than mine, there may be little benefit to packing optimally for size. So SDA is not for every application.

On the other hand, in grid computing, lowering communication overhead can impact how and where we partition a job. It can also impact our use of limited network and CPU resources when a job is distributed and run (that is, we can reduce start-up times). There is a significant computational cost to SDA, but it is paid only once, at upload time, and will speedup every download and all the start-up times, if done correctly.

The pack task is an optional task available in Ant. Users can invoke the pack task from within Ant, after a proper configuration. However, I am interested in performing my packing programmatically, and as a result, I have created a facade to the pack task. For example:

Will create 5 size-optimized jar files containing the manifest files that enable the classes to be invoked by the JVM (Java Virtual Machine). It is thus a requirement that the named classes contain a proper main method. Invoking the packTask, on a 400 Mhz G4, took over 85 seconds for all 5 jar files. There were over 2100 classes to select from, and the output jar files ranged in size from 5kbyte to 750 kbytes. With larger projects, most of the time is spent in dependency analysis. As an added feature, I have created a simplified interface that will input a class and print out all classes that it depends upon. This requires a recursive search, since class A can depend on class B, and class B can depend on class C. Thus all classes, A, B and C are formed in the list. For example:

Outputs:

These are the classes needed to run a Dhrystone benchmark and display the results in a Swing frame. For those programmers that are worried about missing classes, there are options available to direct some classes (and even jar files) to be included. As an alternative, there is always sun.tools.jar.Main, which enables the programmer to include all the class files in a given directory, ignoring the SDA.

3.2 Signing the Jar File

This section describes how to programmatically sign a jar file from within a live Java program. This is a far more difficult a problem than it would first appear. There has been some excellent work on the programmatic signing of jar files. Scott Oaks has some code for signing jar files [Oaks 2001]. However, it is not compliant with the JDK tool for signing jar files (called jarsigner). In fact Scott confirms this, claiming that programmatic signing of jar files is “problematic” since none of the classes that sign the jar files are public [Oaks 2004].

Raffi Krikorian has an excellent article on signing jar files programmatically, however, it has several problems with the code [Krikorian]. First the code would not compile cleanly, even after applying the bug fix mentioned at http://www.oreillynet.com/cs/user/view/cs_msg/4433. Second, run-time errors appear in the code, preventing actual signing from occurring. The author was contacted, but a bug fix was not forthcoming.

As a hack, and last resort, I made my own mechanism up for signing jar files. Sun has a non-public jar-signing tool in sun.security.tools.JarSigner. The only interface to this class is the main method. The following code shows a static method for jar signing (based on the facade design pattern):

As of JDK 1.5, the JarSigner was removed from the sun.security.tools package. This makes a homebrew implementation of the JarSigner even more urgent (and so becomes a topic of current research). Scott Oaks [Oaks 2004] has expressed his preference for making use of the Runtime.exec() to invoke the JarSigner tool.

A jar file can be verified using:

The following code shows how to combine the pack, sign and verification processes into a single invocation:

One drawback of verification is that it terminates the callers’ thread of execution. This is a pity, since verification is just the beginning of what needs to be done at the clients’ end (before execution of the jar file begins). Another drawback is that these signing elements are in the Sun private package, and thus can change without notice. A final drawback of this code is that the error output and the information output are hard to parse and directed at the console. Ideally, this should be called through lower-level method invocations, giving the caller a chance to catch exceptions and perform error-correction.

For the purpose of verification, there is a JarVerifier in the java.util.jar package. However, it is not public. The stable, public API for this is the java.util.jar.JarFile, which invokes the JarVerifier. Ideally, the JarVerifier API should be a public one so that it can be invoked directly. As of JDK1.5, beta, JarVerifier is still not public. Probably the safest solution is to make use of the JarFile instance and allow the built in verifier to verify the jar file.

3.3 Synthesizing the JNLP Code

This section shows how to reuse the packing and signing parameters to help formulate a Java Network Launch Protocol (JNLP) file. For the purpose of testing, a JNLP file is placed on the local file system with a set of hard-coded parameters. Included in these parameters are the file name, path name, class name, resource requirements, title, vendor, homepage, etc. An example JNLP file, generated programmatically, follows:

It is both tedious and error-prone for the programmer to have to write these JNLP files. It is much easier, for the programmer, to invoke a simplified interface that synthesizes the JNLP file automatically:

Many of the writeJnlp parameters are reused from the packing and signing process. Thus we are able to pack, sign and synthesize the JNLP file using a single method invocation:

Programmers can hard-code as many (or as few) of these parameters as is appropriate. For other parameters (like the password), it is probably a good idea to use a GUI to prompt the programmer. ANT enables the hard coding of passwords in the build script (and this is probably a wrong-headed thing to do). As I have a strong preference for keeping passwords out of source code and computer files, I prefer a GUI prompt me for a password, when needed (something ANT does not do).

The following example mixes hard-coded parameters with GUI prompts to keep the program secure, while reducing unneeded interactions:

A simple dialog box is used to prompt the programmer for a password, as shown in Figure 4.

Figure 4. Prompt for a Password

A similar dialog box is used to prompt the programmer for a secure copy password, as described in Section 4.

3.4 Testing the output

Since there is a danger of SDA failure, I strongly suggest that the output of the process be tested before being deployed. The output of Section 3.3 consists of two files, a signed jar file called: dhry.Main.jar and a JNLP file called dhry.Main.jnlp. JAWS is started when the programmer selects dhry.Main.jnlp. A window appears, as shown in Figure 5.

Figure 5. The Jar file Loads on demand

JAWS forms a jar cache and will only reload the jar file if it has been touched since the application was last run. Thus JAWS downloads updates upon demand. After the second run, JAWS will offer to create a shortcut on the desktop.

4 DEPLOYMENT

This section is divided up into two subsections. Section 4.1 describes how to set up a web server for proper file distribution by adding new MIME types to configuration files. Section 4.2 describes how to use the Secure Copy (SCP) API to programmatically upload the files to the web server. While not everyone will have a web server that makes use of secure copy for transferring files, it is probably a good idea to make use of some type of security, and SCP appears to be commonplace.

4.1 Setting up the system for distribution

MIME (Multi-purpose Internet Mail Extensions) is used to permit the transport of non-text message bodies via e-mail. It has been extended to map to a number of different applications. The browser must understand the supplied MIME-TYPE. Often browsers have helper applications or plug-ins that assist them in interpreting data of a specific MIME Type. See http://trade.chonbuk.ac.kr/~leesl/rfc/rfc1521.html for more information about MIME types. JAWS is no different in that a MIME type is associated with JNLP files. These MIME-types help to invoke JAWS, when appropriate.

As pointed out by [Rohaly] and [Sun 2000], running Apache under Fedora (a freely available version of RedHat Linux), requires modification of the mime type list. The /etc/mime.types file can be altered, but only if you have super-user abilities. The following two lines were added to this file:

Many modern web servers already incorporate these mime-types in their configuration, and so this step may be unneeded.

4.2 SCP Integration

This section shows how to synthesize a JNLP file suitable for uploading, then shows how to programmatically upload t, using a secure copy, to the web server. It also uploads the jar file needed for deployment. The heart of the secure copy facility is an SSH API available from http://www.jcraft.com/.

An example method that I use for uploading the JNLP files follows:

Figure 6. A Simple Password Prompt

Figure 6 shows the second dialog box requiring interaction with the programmer. This password is needed to perform the secure copy, and is also the password needed to access the remote account. As a matter of policy, I decided that no passwords should ever be embedded in the source code (thus requiring some means of input, like a GUI). Further, most of the parameters (like keystore location, home page, etc., are hard coded, where appropriate, to simplify the synthesis of the JNLP, as well as the uploading.

5 CONCLUSION

Programmatic signing is not new [Krikorian]. Nor is the practice of reducing jar size via static dependency analysis [Sadun]. However, integrating deployment (using Java Webstart) along with programmatic signing, jar optimization and secure uploading to a server is new.

One area of possible future work is in the area of programmatic signing of code. It is clear that calling the sun.util.JarSigner API is not optimal for several reasons: 1. The class resides in the sun.util package, and this package is not generally stable (nor even endorsed for general use!). Additionally, the sun.util.JarSigner is only intended to be used from the command line.

The verification mechanism, as implemented in the JarSigner, terminates the callers’ thread of execution. This is an unexpected, and unwelcome, side effect of a method invocation. The entire JarSigner class needs a rewrite so that it can be invoked from a public API.

In Section 1 we posed several questions that we are now in a position to address: How do we up-load our applications to the compute server? The Initium answer is to enable secure copying over the Internet so that uploads can be accomplished from any location. This requires a specific hard location be known for the destination files, in advance of their synthesis. Perhaps that is not an optimal situation. Hard coded JNLP HREFs are known to change, from time to time, and this can cause fragility. Probably, a better solution, would be to use one of the server-side technologies available to JNLP systems, such as JBoss (http://www.developer.com/java/ent/print.php/3343761).

One of the open problems that remains with JAWS is the set-up problem. Manually setting the proxy web server setting in the JAWS preferences is both error-prone and tedious for users. Worse still, is the long download time needed to install the Java SDK or JRE. Most alarming is the inability to install these things without an administrator’s password under Window. To add insult to injury, Windows requires a reboot after the installation (at least under Windows Professional). I have observed that Windows users reboot regularly (I think they actually like rebooting).

SDA can fail to work properly. It would be really nice if dynamic dependency analysis could be performed. The question of how to do this remains open. One possible answer might be to log classes as they are being loaded, in order to keep a record of which ones are needed at run-time.

The Initium project has already been used to upload a series of applications. We are working to extend the ideas presented in the paper to help with clusters and grid computing.

The Initium project is an open-source project freely available at http://www.docjava.com.

 

REFERENCES

[Krikorian] Raffi Krikorian: “Programmatically Signing Jar Files”, OnJava.com, http://www.onjava.com/lpt/a/761, April 12, 2001.

[Oaks 2004] Private e-mail correspondence with Scott Oaks, 2004.

[Oaks 2001] Scott Oaks: “Java Security, 2nd Edition”, O’Reilly & Associates, Inc., Sebastopol, CA, 2001.

[Rohaly] Tim Rohaly: “Client-side Java makes a comeback”, in Javaword, http://www.javaworld.com/javaone00/j1-00-webstart_p.html

[Sadun] Christiano Sadun: “The Ant Pack Task Source Code”, open source library available from http://sadun-util.sourceforge.net/

[Sun 2000] Technical Session TS1473 “Introducing Java Web Start: Delivering Java Technology-based Applications Over the Web’ Thursday June 8, 5:15-6:15 p.m.: http://jsp.java.sun.com/javaone/javaone2000/event.jsp?eventId=1473

[Sun 2004] Sun Microsystems: “Java Web Start”, http://java.sun.com/products/javawebstart/developers.html

[Sun 2004a] Sun Microsystems: “Networking Properties”, http://java.sun.com/j2se/1.4.2/docs/guide/net/properties.html

 

 

About the author



space After receiving his Ph.D. from Rensselaer Polytechnic Institute, Dr. Lyon worked at AT&T Bell Laboratories. He has also worked for the Jet Propulsion Laboratory at the California Institute of Technology. He is currently the Chairman of the Computer Engineering Department at Fairfield University, a senior member of the IEEE and President of DocJava, Inc., a consulting firm in Connecticut. E-mail Dr. Lyon at Lyon@DocJava.com. His website is http://www.DocJava.com.

Cite this column as follows: Doug Lyon: “Project Initium: Programmatic Deployment”, in Journal of Object Technology, vol. 3, no. 8, September-October 2004, pp. 55-69. http://www.jot.fm/issues/issue_2004_09/column6


Previous column

Next column