It's a strange thing, really. A technology that was designed from the ground up as a small, platform-neutral, distributed, network-centric, updateable device programming language is now primarily touted for server usage. The server, where code size, run-time portability and unknown code security are really not important issues. For many, the client has been abandoned as an early shot-in-the-dark that, well, didn't really work out.
But maybe we've given up the battle too early. Maybe the technology was pushed too early, in the wrong way, into the wrong types of spaces. Maybe the problem that Java was designed to address is only now starting to emerge. Maybe, just maybe, Java on the client can be more than just a pipe-dream.
This article will lay out why we may still want or need a Java client, what may be needed to bring the Java client back, how the technology has changed since the early days and some patterns for deploying Java clients successfully.
This last issue is probably one of the most overlooked reasons for Java failure on the client. By the time Java came along, everyone had more-or-less dealt with the incompatible desktop issue by crowning Windows the winning OS. When one OS owns well over 80% of the market*, there is less of a need for a OS-neutral application platform. Why target a virtual machine caught up in browser-incompatibility wars when you can deliver you application to a real machine that represents 95% of your market?
Of course Java has other advantages, but the Windows world hasn't been complacent. Microsoft has done a lot to allow its desktops to be centrally managed, in direct response to the threat of network computers. WinAmp, Real Player, Icq and a slew of other network-centric applications offer various forms of dynamic update, similar to the original promise of Java and of Marimba's Castanet. We even see the emergence of "themes" in many applications, giving some of the same functionality as Swing's pluggable Look-and-Feel.
For more complex client applications, such as media streaming and presentation, image manipulation and complex client validation, the web paradigm becomes rather stilted. We all know the advantages of Real, QuickTime or MP3 over things such as animated gifs or embedded audio files for audio or video presentation. Quality does matter. And web pages are not capable or providing asynchronous notification, key to messaging tools like Icq. Finally, while it my be a good design to allow someone to buy an airline ticket through a web page, forcing travel agents to use such a system would be unacceptable. If nothing else, the submit latency would drive them crazy.
So, without Java, we either get network-delivered behaviour with limited capabilities (web pages) or we get high capabilities at the cost of security, installation and OS lock-in. Of course, as I mentioned earlier, OS lock-in on the client has not been a big issue up until now. But things are changing.
The web is about to undergo a huge shift in how it is used, and by whom. The business interface (i.e. from a computer) has been pretty much saturated; instead everyone is betting that the internet will grow into your cellphone, home phone, pocket organizer, T.V. and who knows what? Your cereal bowl? It will "cross the chasm" from the geek on his computer in his basement to the retired couple making dinner reservations from he 8th hole of their golf club. It will become our new communications medium, the much-heralded "convergence" of telephones, television and data.
And there are a lot of industry players who want to get a piece of the action. The early leaders are the cell phone companies, and 3Com's PalmPilot. The Transmeta Crusoe processor, released at the beginning of the year, is targeted directly at low-power mobile devices. These are going to be devices for the masses with limited memory and local storage. Which means they will have to be able to fetch services, they will have to be secure against rogue code and they will have to be stable.
Microsoft, of course, has come out swinging with Windows CE and its children as well as the purchase of WebTV and its evolution into an X-Box. They, of course, argue that we can have mobile applications if we just have a Windows CE OS everywhere. The cell companies, coming from a telephony obsession with stability, have other ideas. So do the growing hoards of Linux enthusiasts. It's a fool's game to predict the future, best left to politicians and political pundits, but it is likely that no one OS platform will dominate the web appliance market, as Windows has dominated the desktop market. Given the wider range of uses, from web rings to set-top boxes, this should not be surprising.
Indeed, lately we have seen new and innovative uses of Java clients even in the traditional desktop realm. Damango offers a ASP service built using an updateable Speiros Java client from Cyrus Intersoft. ThinkFree offers a web-centric office suite built in Java. WorkSpot provides virtual Linux sessions accessed through a web browser using a Java "vnc" client developed by AT&T's UK research labs. Similarly, WeirdX is an open source pure Java X server (which, in X lingo, really means client). While the latter two examples are really uses of Java to provide remote graphical session access as opposed to Java applications, they show some of the spaces in which Java clients can successfully fill a need.
With the recent client-oriented additions to Java 2, version 1.3, as well as the Java Network Launching Protocol and API, there may be hope yet for a distributable, secure, platform-neutral application language. Not XML, which is a data content syntax, but a real application language defining behaviour.
I hope I'm not enlightening too many people when I say that this is one of the great additions to Java 2. Understanding the Java 2 security model and its management of code signing keys and permissions (policies) is a large topic in and of itself, deserving of a whole article. In a nutshell, applets may be signed with keys that identify their authority domain. For each client, policies can be configured that grant permissions, or capabilities, to code from certain host or signage domains. When a protected function is called, the stack of the application is inspected to see what the calling code's permissions are and the method is either permitted or a runtime exception is thrown.
While powerful, this framework can still be frustratingly restrictive,
as most users do not want to figure out a policy tool and manually manage
their system permissions just to install a new MP3 player. From a
security standpoint, this restrictiveness may be quite beneficial.
On the other hand there may be yet more that can be built into the Java
framework, as we shall see later in the article.
Well it turns out that in Java 2 there was introduced the concept of a "package" installation space. This is part of the Java Extension Mechanism, a poorly understood addition to Java 2. Installed extensions are jar files that have been placed in a particular shared directory for use by all applications. Using version and vendor information from the Manifest file, an installer program or applet class loader can ensure that a newer version of the extension is not over-written. Once an jar is added to the extension directory, its classes appear as part of the JVM libraries. The jar itself does not need to be added to a classpath. In fact, in Java 2, the whole meaning of classpath has changed. It no longer indicates the whole set of available Java classes, now it indicates the classes that are not shared by all Java applications. Core Java packages and installed extensions do not need to be explicitly listed in the classpath any longer.
For applications, this means that one jar can be shared easily between applications without them knowing about each other. For applets, it means that the number of jar or class files fetched from a server can be significantly reduced if the client's machine has the appropriate extensions installed. As we shall see in the next section, it is possible for applets to install extensions the first time the applet is downloaded and enable subsequent usages of the applet to be started much more quickly.
Related to this, in Java 2 version 1.3, the Plugin added support
for permanently installing insecure Java applet support classes.
These are much like installed extensions, allowing applets to be started
much more quickly without compromising the system security.
Another little-known option, available since Java 2, is the ability
to define dependent Jar files within the Manifest of a Jar file, using
the "Class-Path:" statement. In many regards, these are much like
Installed extensions in that once retrieved by the ClassLoader they effectively
become part of the currently available extensions for the applet.
On the other hand, "dependent extensions" are not cached any differently
than any applet Jar file and are not shared between applets.
The ClassLoader uses the Manifest "Class-Path:" information as part of its Class file look-up algorithm. If a Class file cannot be found in the core or installed extension or its currently loaded Jar files, it will check the Manifest "Class-Path:" lists of its downloaded Jar files to create an ordered lists of Jars to fetch and inspect for the class. If no unresolved downloadable extensions remain, the ClassLoader will default to checking on the remote server for the individual class file.
Say you have an application that you have partitioned into several components: a core set, an alternate look-and-feel, a spell-checker and scripting. Initially the application would load only the core set of classes. When a user selects "spell-check", the spell-checker Jar file would be fetched. The spell-checker would be able to load the Thesaurus component on demand, as well. Thus, the application packager would be able to trade-off the start-up vs. run-time performance of an application by choosing a packaging granularity somewhere between a single monolithic Jar file and hundreds of Class files.
As of Java 2 version 1.3, the Jar file Manifest supports version and vendor information, as well as implementation URLs. Together these attributes can be used to check if a compatible version of an installed extension is already available. If it isn't, the class loader can use the implementation-URL attribute to download and install a new version of an extension. The ClassLoader will even look for a "Main-Class" attribute and use this as an "installer" for the extension, if the installed extension needs to install any native code. Native code, you ask? How does the ClassLoader load the appropriate Installed Extension if that extension uses native code? Well, it turns out that the "Implementation-URL" attribute can substitute in the Java "os-name" property if it needs to in order to create the appropriate installed extension URL for the platform.
With this support, both installed and dependent extensions can now
be automatically fetched and installed as needed by an applet.
In Java 2 version 1.3, this problem was fixed. Now the applet's
root Jar file may contain an INDEX.LIST file in the META-INF directory.
This file is a class-to-Jar lookup index that the ClassLoader can use to
intelligently fetch the appropriate Jar file to fulfill a class request.
Actually, with some exceptions, the file actually maps packages to Jar
files, not classes. This is an optimization to reduce index size.
Since it is good practice not to break packages up across Jar files, this
optimization can be easily justified.
Now consider our applet that has several dependent extensions. When a user invokes "scripting" in the applet, the ClassLoader doesn't have to waste the user's time sequentially downloading all dependent extensions for the applet until one contains the root scripting class. Instead the INDEX.LIST file can be consulted to look-up which Jar file should contain the root scripting class. If the class is "com.printeverywhere.script.Pascal" and the INDEX.LIST notes that "scripting.jar" contains the package "com.printeverywhere.script", then the scripting.jar file will be downloaded and used to load the "Pascal" class.
With this extension management capability, an applet can ensure
that its parts are optimally downloaded as the applet is used. No
longer do we have to make a tradeoff between one huge Jar file and hundreds
of individual class files.
To fix this, Sun has taken a couple of approaches. One has
been the development of the Java 2 Plugin, which may be attached to a browser
on the fly to add support for Java 2 applets using the <OBJECT> (or
for netscape <EMBED>) tags. Plugins are available for win32, Linux,
Tru64 Unix, Solaris, Mac, Irix and HP-UX, and Sun ships an applet tag convertor
that does all the weird Javascript insertion to convert your applet tag
to a plug-in tag. Note that for non-windows machines, the generated
Javascript and tags may need to be hacked at some. While considerable
effort has gone into making the plug-in download as lean as possible, it
is still a multi-megabyte download the first time it is used, which may
be to much for many users.
In a way the Java plug-in is just a temporary patch until the Open Java Interface is supported by browsers. OJI promises to decouple the browser from the JVM implementation such that one can be upgraded independently of the other. AOL and Netscape have promised support for the OJI, as well as the mass shipment of Java 2 in general. While the OJI is supported in Netscape 6.0, Internet Explorer support is not likely soon. In the mean-time, and possibly the long term, the Java Plugin will still be required.
The other tack Sun has taken for increasing Java 2 availability
is to partner with companies such as AOL and get them to agree to ship
Java 2 JVMs on their CD-ROMs. Similarly, Linux support has suddenly grown
within Sun and Sun is courting Linux distributors and new web device manufacturers.
The hope is that such creative distribution work will increase the universal
availability of up-to-date JVM implementations.
Basically the plug-in provides two extra "PARAM" values, one defining a cache policy (none, browser, intelligent) and the other a list Jars to intelligently cache. If the cache policy is set to "Plugin", then the applet's Jar files will essentially be installed as Plug-in extensions, only being updated when the version of the Jar file on the server changes. For the user this means that applets now look and feel more like installed programs (which themselves often support dynamic update capabilities), with applets only requiring downloading when an update occurs.
There is a downside to this. Essentially the applet Jar cache is never purged, no matter how long since the applet Jar file was used. Without some manual "uninstall" capability or least-recently-used/upper-cache-size policy, it is possible for the Plug-in cache to slowly and permanently gobble up more and more of a device's hard-disk space.
Related to this is the new Java Network Launching Protocol and API
(JNLP) announced at JavaOne earlier this year. It essentially provides
a framework for launching secure, updatable web applications from a browser
(or not), even while off-line. The Java Web Start applications was
released as an early-access demonstration of this new protocol. Jav
Web Start allows for the caching and management of applications, including
cache management.
With Java applets, the whole tricky area of managing code parcel
versions and updating them has been removed from the applet itself and
given to the Java framework. With the Java Plug-in, for instance,
a newer version of a Jar file, identified on the server, can be downloaded
and installed in the Plug-in cache when it appears. Similarly, for
an application with installed extension packages, the installer can ensure
that it does not install an older version of a Jar file over a newer version.
JNLP and commercial packages such as Bea's ZAC and Marimba's Castanet offer
similar features.
Dynamic Permission Granting. One thing that the current Java 2 framework does not support is the dynamic granting of authorization. Netscape provides such a capability in its custom security framework. Basically the problem is one of balancing off the security needs of an environment versus the desire to have highly functioning applications. Signing Jars is not too difficult. What is more difficult, especially in an uncontrolled internet environment, is managing the authorization policies for signed Jars.Normally the paradigm used in the Java 2 Security framework is that a security administrator will import a public key for a Jar and assign the appropriate permissions for the key. Considering the ramifications of improperly giving out permissions, this is a task that should be done with some care. It is not surprising, then, that the JDK policytool is clearly not end-user oriented. The effect of this is that non-default security policies are only generally set-up for well known and trusted applets, and only generally in a intranet environment that can share a policy file.
But how does a user of a new applet that offers an MP3 off-site archiving utility grant the utility the correct read permissions on her disk drive. If the applet is targeted at the Netscape Security framework, a request for read permission will cause the Netscape VM to pop up a "Grant" window that identifies the signer, what specific rights the applet is requesting, and the security issues regarding these rights. The user can choose to grant, temporarily or permanently, the access rights.
Java 2 currently has no API support for such a on-the-fly permission granting utility. Certainly it is open to some risk from careless uses, but maybe this could be constrained by imposing a default set of on-the-fly user-grantable permissions within the more secure policy file.