Bringing Swing to the Web

Swing's all-Java drawing approach makes it easy to convert components to Java2D images, and when you do that on the server side, you gain the ability to put Swing components into a web application. Jacobus Steenkamp shows how this approach works and what you can achieve.

There is no doubt that the Java platform has been experiencing something of a revival on the desktop since the release of Java SE 5.0 (Tiger). At no time during Java's history did Swing and the third-party libraries around it generate such an interest and improve at such a rapid pace. You don't need to look far to find evidence of this--there are numerous excellent open source libraries available here on Java.net and on sites such as SourceForge. Some examples of these include the Substance look and feel[2] (shown in Figure 1) used to improve the visual appearance of your application, JGraph[3] (Figure 2) for rendering graph structures, and the excellent set of SwingX[4] components (Figure 3) made available by SwingLabs[5].

Figure 1. The Substance look and feel

Figure 2. A JGraph

Figure 3. One of the latest additions to SwingX: JXGraph

Unless you are implementing a thick enterprise client such as an applet or a Java Web Start[6] application--options which have their own sets of size, deployment, and compatibility issues--you might think that there is not that much scope for using Swing within web applications, or indeed Java EE. You would, however, be making a mistake; there is no reason why web and Swing development should be mutually exclusive. In this article, we will look at putting one of Swing's most overlooked (and basic) features to work inside a web application.

JComponents as Images

Because of Swing's lightweight approach to component rendering--all visual components are drawn with Java code rather than by the operating system or native code--it is possible to "draw" virtually any component onto an image rather than the screen. This means that any subclass of JComponent[7], which forms the base of all Swing components, can be rendered to an image.

Accomplishing this is not as difficult as you might think, and requires only a few lines of code. Below is an excerpt of the SwingImageCreator utility class, which we will use to convert Swing components into images.

...public class SwingImageCreator {

/** * Creates a buffered image of type TYPE_INT_RGB * from the supplied component. This method will * use the preferred size of the component as the * image's size. * @param component the component to draw * @return an image of the component */ public static BufferedImage createImage(JComponent component){ return createImage(component, BufferedImage.TYPE_INT_RGB); }

The class contains two overloaded methods that accept a JComponent[7] and produce a BufferedImage[8] instance. The system will default to the TYPE_INT_RGB image type if none is specified.

Once you have successfully created a BufferedImage[8] instance, exporting it to a file is a breeze with the ImageIO[9] library. Below are a few examples that demonstrate how to export the image in PNG format to either a file or an OutputStream[10]:

//Rendering a Buffered Image to a File ImageIO.write(bufferedImage,"png",new File("my-exported-png-file.png"));

//Rendering a Buffered Image to an OutputStreamByteArrayOutputStream bout = new ByteArrayOutputStream();ImageIO.write(bufferedImage,"png",bout);

Putting It All Together: Rendering Components to the Browser

Although we now know how to transform Swing components into images, we still need to put this knowledge to good use and render the images to the browser. In this article, we will be using servlets for drawing these dynamic images. It is, however, also worth noting that if your application is based on Java Server Faces[11], it is also possible to render these images using a PhaseListener[12]. The PhaseListener image renderer is a useful approach when you are developing a third-party Java Server Faces library, as your end users would not be required to change their web.xml configuration file in order to use your components. The servlet approach, however, is a lot more familiar and also easier to get started with.

The SwingButtonServlet

A common requirement in many web applications is to have image buttons with "mouse over" effects. If these are done in the standard way, as static images, it can quickly become very tedious to maintain both a normal and an "active" (mouse over) version of each of the buttons. You also start running into problems when their labels need to change or if the application needs to be translated into a different language.

Instead, we will be drawing our image buttons dynamically using a servlet that simply picks up the label of the button from an URL parameter. With the buttons being drawn dynamically and from a central place, it becomes straightforward to change the "theme" of all of the buttons at once or to drive the button labels from a resource bundle/database.

Below is an excerpt of the JSP code that you can use to take advantage of these buttons--note how we have utilized a resource bundle to dynamically assign the labels.

In order to draw these buttons' images on the server side, we need to take the following steps:

Set the appropriate Swing look and feel. The Substance look and feel[2] is currently one of the best-designed around and is freely available under an open source license; a perfect fit for our example.

Create the button and determine whether it is in the active (selected) state or not. This will be determined by whether or not the "active" parameter has been passed through on the URL request. In our example, the active (selected) state of the button will be used as the "hover over" image.

Convert the Swing button into an image using our SwingImageCreator utility class.

//Check whether the button should be drawn in the active state boolean active = request.getParameter("active") != null; //Create the button with the 'title' parameter as it's label String title = request.getParameter("title"); JToggleButton imageButton = new JToggleButton(title,active); imageButton.setSize(imageButton.getPreferredSize());

Figure 4 shows the final result of our labors: image buttons being drawn on the fly.

Figure 4. Image buttons being drawn on the fly

Drawing More Complex Components

The technique we have just used are not limited to only Swing components available in the standard Java libraries. It is also possible to draw more complex components by using third-party libraries. In Figure 5, we used the popular JGraph library[13] to draw a hierarchical organizational diagram:

Figure 5. A more complex example: representing hierarchical data

The basic recipe for drawing the above remains the same: build the component in memory and then render it to the browser as an image. The code for this GraphServlet is in fact shorter than what was required in the SwingButtonServlet. The reason for this is that building up a hierarchical data structure is a complex task that normally occurs as part of the business logic of your application (and is slightly beyond the scope of this article). However, you can download the full source code for this article from the link in the Resources section, should you want to investigate the OrganizationGraphModel further and see how this is done.

//Create the graph model. //In a real application you would probably get the model //from the session where it was set by something like //a JSF bean / Struts Action GraphModel model = new OrganizationGraphModel();

Animated Images

So far, all of the images that we have drawn have been static. The next logical step is to make these images dynamically update themselves and appear to be "animated" from an end user's point of view.

Although this is not achievable using pure HTML, it is possible to implement it using a small amount of JavaScript. The JavaScript will basically instruct the browser to continually poll the server for the latest version of the image. To ensure that the browser does not cache the image, a unique URL parameter is passed to the server on each request:

We need to ensure that the server draws a new image every time it is invoked. In the servlet example below, we will simply use an attribute in the user's session (HttpSession) to keep track of the previous request and ensure that the new component is different. The component we are using--JXGraph--has only recently been contributed[14] to SwingLabs[15], though it is already clear that there is a huge amount of applications that can benefit from its features.

Figure 6 shows one frame of this animated graph as seen in the browser.

Figure 6. The final result: a dynamic (animated) image

Ideas for the Future

We have only covered the tip of the iceberg in terms of what is possible with Swing on the server side. For instance, by adding in a bit more logic around the rendering of the components, it would be possible to calculate the location of each of the elements (i.e., the "CEO" box in our organizational chart example in Figure 5) on the image. These locations can then be used to create an HTML image map[16], which can add additional interactivity in the browser.

Despite the various AJAX frameworks available on the Web today, there still seems to be no easy way to draw images using JavaScript. The best JavaScript client-side solution currently available seems to be the HTML Canvas[17] offered by Mozilla. This solution suffers from the drawback that it is non-standard and will probably not be supported by the other major browsers for some time to come.

By combining JavaScript on the client side with the rendering of Swing components on the server side, it would be possible to overcome these problems. A JavaScript component could, for instance, compute and send a request to the server specifying the exact type of component image it requires. The result would be a library that would be a thin client with a number of advanced Swing components and compatibility across a number of different browsers. The only real rival would be an actual desktop Swing application.

Conclusion

If you were take only one thing away from reading this article, then I would hope that it would be the realization that Swing is a technology that is not only useful in desktop applications, but also in enterprise/web development. In this article, I offered Java EE developers some insights on how it is possible to take advantage of the huge strides made by Swing in recent years and to use its advanced "desktop" components in enterprise/web applications.

Resources

Source code[18] for this article. Please refer to the dependencies.txt file for details of the JARs you require.