4400 words

 
 
 
 
 
 
 
 
 

The Client is Dead... Long Live the Client

Richard Deadman





























     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.



Background

    We all know some reasons why Java has not lived up to its hype on the client.  Speed, memory footprint, incompatible VM versions, start-up latency, weak AWT widget set, incompatible client VMs to name a few.  In response, Sun has targeted most of these heavily, giving us such things as HotSpot, J2ME, the Java Computability tests, the Java plug-in, Jar files and Swing, among other changes.  But they can't so easily address the biggest obstacle to Java acceptance on the client: the dominance of Windows.

    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.

Why then Java?

    The common wisdom is that we don't need Java on the client after all.  We have web-pages with JavaScript.  Servlets or cgi scripts can be used to dish up customized yet mostly static pages.  Simple input validation can use drop-down list boxes; more complex validation can be achieved using JavaScript.  It's the web paradigm.

    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.

Options to Exploit

    All right, we know what has gone wrong.  If there is life and value in smart, updateable client applets, what do they need, and is it available?
  1. Configurable security.  The 1.1 and prior security model was an all-or-nothing affair.  You were either trusted (applications) or you were not (applets).  Untrusted code operated in a protected sandbox.  Sure this is better than ActiveX where you are either trusted or you don't run, but it is still rather limiting.  What if I want to grant permissions for a particular applet to read from but not write to by "/tmp" directory?

  2.  

     

    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.
     

  3. Installable packages.  Right now most Java applications and applets are built with all non-core code packaged together with the applet/application.  If two applications both use the same JGL collections or an XML parser, it does not matter; for applications your system ends up with duplicate jar files, for applets, you may download a jar file that already sits on the client to support an installed application.  Wouldn't it be nice if one could create a package name space such that applications could share common code?  Kind of like shared libraries or DLLs (with the shared memory contained within a JVM instance instead of the whole OS, however).

  4.  

     

    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.
     

  5. Dynamic downloading of Jar Modules.  Jar files solved the problem associated with applets individually loading hundreds of class files through HTTP.  This can lead to better loading time.  On the other hand, if an applet only needs a small percentage of those classes to actually start, or has whole sub-modules (i.e. a spell checker) that may never be called, the cost of preloading all files that might ever be used may be prohibitive.  One solution is to Jar up a core set of functionality and allow infrequently used classes to be loaded from the server individually.

  6.  

     

    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.
     

  7. Better extension management.  While the Java 2 version 1.2 extension mechanism allows one to break applications into Jar file "modules" and define dependencies between these modules, it does not provide for any intelligent support for Jar-file look-up.  This is especially important since lazy fetching of Jar files is supported.  Consider the applet that we discussed earlier composed of a core jar file as well as "look-and-feel", "spell" and "scripting".  The last three jars are not initially loaded until a class is requested that is not already available.  At this point, the list of dependent modules is sequentially downloaded and inspected until the class is resolved.  If the file is found in the scripting Jar file, all three must be downloaded before the scripting feature is available.  From a user's point of view, this can lead to a considerable, and unnecessary, delay in the applet.

  8.  

     

    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.
     

  9. JVM ubiquity.  One of the ongoing casualties of the browser wars and the Microsoft/Sun Java disagreements has been the balkanization of support for Java within the browser.  Let's not forget that one of the original clauses in the Sun/Microsoft licensing agreement was the Microsoft would make a Java VM available on all new Windows boxes.  On the browser front, it has been left to Netscape and Microsoft to provide Java support and this has not kept up to date with Java editions.  This can be blamed on the complexity of developing a Java VM (although on the server there seems to be plenty to choose from), Netscape's distractions or possible ulterior motives within Redmond.  For whatever reason, well over a year after Java 2 has been released, then, we still see the majority of applet development being done for the 1.1.6 version of Java.

  10.  

     

    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.
     

  11. Applet caching.  Traditionally browsers have cached their applets with the same policies as they cache web pages.  Of course for large, commonly used applets, the constant turn-over of the browser cache can lead to annoying delays as a seldom-changing applet is constantly being downloaded every time it is used.  The answer, it would seem, is to separate applet caching from regular browser caching and apply some intelligence to it.  Sun's Java Plug-in, version 1.3, does just that.

  12.  

     

    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.
     

  13. Applet self-updating.  Applets were initially touted for their ability to centrally manage code changes.  While this jump-started the whole "thin client" movement, it also lead to initialization latency problems that we have just addressed in the previous item.  One of the responses to the "thin client" movement was the development of self-managing code -- everything from RealPlayer's update option to the Windows 98 and Linux "Update" utilities.

  14.  

     

    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.
     

  15. Sandbox tunnelling.  The sandbox is great in that it limits the access that insecure applets or applications have to your system.  But can we give applets some controlled access to the system without jeopardizing system security?  Some examples might be:
  16. Well, it turns out that JLNP does support the slight opening of the sandbox.  In particular, it adds a ServiceManager that can be used to gain access to services that provide secure file open and save (through explicit dialog boxes) as well as the opening of URLs in a browser.  Local persistent store is not covered, but the architecture makes it easy to add such a service later (alternatively, this may be covered under JSP-10 "User Preferences" at some future date).
  17. Speed, Size... While some of Java's biggest drawbacks, the JVM vendor wars over speed (i.e. Sun's HotSpot) and memory footprint (i.e. the K virtual machine) are also well known.  Suffice it to say that things are moving in the right direction.

Still Needed

    As much as intelligent support for applications and, in particular, applets has improved dramatically with recent releases of Java, there are still some things that could be added to really help in supporting the rebirth of client-side Java.  One that comes immediately to mind is:
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.

Onward

    So, imagine that you want to build the ultimate web application, let's say an online brokerage application for the sake of argument.  It will feed us changes in the user's tracked stocks, alert us to sudden market changes and allow us to make trades.  For authorized users, it will also allow us to act as super-user and manipulate other client's accounts.  By answering a few questions we can see the architecture begin to take shape and define which enhanced client capabilities we are going to take advantage of.  For illustration purposes, we concentrate here on the client interface design and intentionally ignore the server architecture, which is a whole topic unto itself.
  1. Client.  This is one of the first decisions that must be made.  Since our system will be providing asynchronous notification of market and stock changes, as well as providing a responsive system and rich GUI for power-traders, we will need an applet or application instead of an HTML form.
  2. Interface Widget Set.  Are we going to rely on AWT or the more pleasing but less-available and more memory hungry Swing widgets.  The answer isn't simple, but we will opt for Swing, since it offers more powerful GUI controls.  Swing encourages the separation of state and presentation, which will be essential if we later decide to put a thin (i.e. non-Swing) GUI on the application for use from J2ME devices, like cell-phones and hand-helds.
  3. JVM version.  If we are using Swing, it makes sense to use Java 2, since in Java 2 Swing is a core component.  Prior to Java 2 we would need to include the 1.1 Swing classes with our applet or application.
  4. Deployment.  Applet or Application?  Well, why not have your cake and eat it too?  Our target audience includes occasional web users as well as power-user traders.  We will create the application as an JApplet class extension that can be embedded within a JFrame.  In this way, it can be run as either from the same code base.  Since we have decided on Java 2, we will package the applet up to use the Java Plugin.  For regular users, we will create a JNLP xml file that allows the application to be run from outside a browser from either a web link or a desktop icon.
  5. Network Protocol.  We will leave the decision of how the code communicates to the server as an exercise for the reader.  CORBA and RMI are two possible choices, but not the only ones.
  6. Caching.  While occasional users may find it acceptable to reload the applet if it has been flushed from the browser's cache, power-users will find this annoying.  Therefore we will turn on the Java Plugin or JNLP caching for the applets downloadable extensions.
  7. Version Control.  For applets, new versions of downloadable extensions will automatically be detected and installed in the Plugin cache.  For application usage, JNLP-compliant launchers will provide the same functionality.
  8. Packaging.  At what granularity should the application be partitioned?  Well, our paper prototypes and user surveys tell us that the administration function will only be used occasionally, and then only by a small subset of users.  This is a ripe candidate for partitioning as a dependent extension.  The lazy resolution of dependent extensions will guarantee that for the majority of applet users, the administration jar will not be downloaded and their user experience will not be unnecessarily slowed down.  In a later iteration, we may identify more smaller-grained extensions.  At that time, we can used the Jar Index capability to tell the ClassLoader which downloadable extension to download in order to fulfill a certain class request.
  9. Security.  Currently no secure functions are envisioned by the application/applet.  The user's profile and data will be stored on the server and the application has no need for local file access or random network access.
    We can see that our first pass at the architecture of our application has taken advantage of several new client capabilities: Jar caching, Jar version control, dependent extensions and lazy Jar fetching.  We have also circumvented JVM browser conflicts by relying on the Java Plugin or JNLP.  The result is a flexible (applet or application) client that efficiently manages automatic updating and also delays downloading of seldom-needed components.  With browser support for automatic Plugin installation, we have a program that can be easily installed onto any client platform, supports alternative usage patterns, updates itself and limits it download footprint.  This is an application which we can easily pitch to its intended audience.

Wrap Up

   A lot of the tools and framework pieces for the successful deployment of second generation client Java applets and applications are available today.  The market is ripening and suddenly expanding beyond the win32 world and demand is growing for services which can be downloaded into memory and storage-constrained web devices.  Its just a matter of time, luck and maybe some hard work to see if the original vision of Java as a OS-neutral, secure, networked, downloadable programming platform can re-emerge, like a phoenix, from its over-hyped past.


The End


1. U.S. vs. Microsoft: Finding of Fact.  Section III, Subsection A, Paragraph 35, http://www.usdoj.gov/atr/cases/f3800/msjudgex.htm.