Skip to main content

Synth Week, Load Themes From Anywhere

Posted by gfx on September 21, 2005 at 3:10 AM PDT

Chase Away Those Fierce Nightmares

In Tiger and early Mustang builds, Synth falls short providing a versatile, efficient and easy to use way to load a theme. Only one method is offered to load a Synth theme, the mischievous SynthLookAndFeel.load(). Albeit easy to use, this method suffers from critical limitations.

When your program invokes it, two parameters must be specified: an input stream containing the XML theme and a Class used to resolve resources path. If the theme declares using the picture “images/button_pressed.png”, the path to the PNG file will be constructed from the .class file of the specificed Class. For instance, here is how you would load a Synth theme from within the jar containing your application:

SynthLookAndFeel.load(getClass().getResourceAsStream(“synth.xml”),
                      getClass());

This snippet fits very well in most applications, those in which Synth themes are embedded. Unfortunately this method implies that you must ship a .class file with your theme, even if no Java code is required. Even worse, it is very difficult to let the users load a new theme from an arbitrary location, especially a directory or a compressed archive. I am sure many developers have been flummoxed by the uncanny experience of attempting to load a theme from a directory.


Fig. 1. A pissed developer.

Mustang beta will hopefully chase away your worst nightmares; at least if you are insane enough to dream of cunning and bad tempered Synth look and feels. Whether you don't sleep at night or you just want to know more about Synth, behold the new load() method, capable of fetching a Synth theme from an URL:

public void load(URL url) throws ParseException, IOException

Thus Freed from the Darkness, You Shall Prevail

But a greater peril lies ahead! To achieve your journey you will need to tame an ancient beast, the URL class. Silently lurking in its den, the java.net package, this class seems so old and simple that even the frailest insane elderly should be able to bend it to his will. Alas! Those ancient creatures are astute and disingenuous and they will lure you into a trap of great complexity.


Fig. 2. A developer approaching the dreaded deadline.

With the addition of this single new method you can now load Synth themes from pretty much anywhere. At one condition, you must know how to use URL in Java. Here is a short list of possible locations for your themes:

  • A local file ;
  • Files scattered on an HTTP server ;
  • A local jar file ;
  • A jar file on an HTTP server ;
  • A servlet.

Possibilities are endless and they all prove to be very interesting. You can for instance imagine a servlet dynamically generating Synth files and resources. Whenever you load a theme from a URL, Synth will find the required resources by generating paths relative to the base URL you specify. Actually, Synth doesn't do much of the work here, thanks to the mighty URL class. Most of the aforementioned examples are easy to implement. The following code snippet shows for instance how to load a theme from a local file:

SynthLookAndFeel laf = new SynthLookAndFeel();
laf.load(new URL("file:///C:/java/synth/laf/laf.xml"));
UIManager.setLookAndFeel(laf);

Loading the same look and feel from an HTTP server, or a servlet for that matter, is exactly as easy:

laf.load(new URL("http://host/laf.xml"));

I stressed the fact the URL class can be difficult to use and it was for a good reason: now try, all by yourself, to find the URL required to load a Synth theme from a jar... Even if a majority of people reading this blog might now the answer, I'm pretty sure some of you are bemused. Don't panic and read the following snippet:

laf.load(new URL("jar:file:///C:/synth-laf.jar!/laf.xml"));

The “jar:” protocol can be used to access a specific file within a jar. Thus, the first part of the URL is another URL, pointing to the jar file itself, and the second part, beginning with an exclamation mark, is a path to the requested file. In this example we tell Synth to load the file “synth.xml” in the jar “synth-laf.jar”. If you look closely at the file path, you'll notice it's an absolute path. You must not forget the leading slash or you might encounter a cryptic exception. Don't worry about the paths specified in the XML file itself as you can use relative and absolute paths.

Even tough the latest example uses a local jar file this is not the only kind of location you can reach. Remember the first part of a “jar:” location is a full URL. That means you can write this to load the theme from a jar delivered by an HTTP server:

laf.load(new URL("jar:http://host/synth-laf.jar!/laf.xml"));

This is Your New Power, Use it Wisely

The new load() method as little, if none, drawbacks at this time. They also open a whole new range of possibilities for Synth. If your application is not WebStart enabled you can distribute the look and feel across the network and change it very easily without redeploying anything.

Default protocols in Java SE should prove to be enough for most applications. Nevertheless, if you need to support an exotic protocol or if you need to create your very own (what about “db:” to load from a database or “kde:” to generate a look and feel from a KDE theme) do not forget you can plug your own protocol handlers in the JDK. I won't enter in the details here but you basically need to create a new URLStreamHandler and alter the "java.protocol.handler.pkgs" system property to prepend or append the package containing your handlers.

This new feature will be available in Mustang b53 and is brought to you by bug fix #5056424.

Related Topics >>