Swing started its life as a component library for rich-client Java applications. Developing rich-client Java apps, however, requires more than just a component library. Over the past few years, Swing addressed many additional client-developer needs, but much of that progress took place outside the core Swing libraries, in the context of various open-source projects. Swing aficionados admit that while all the pieces required for successful Swing client development are available today, it's hard to know just where to look and how to start.
The newly approved Swing Application Framework, JSR 296, aims to solve that problem by encapsulating best practices and common coding patterns for desktop applications. Hans Muller, JSR 296's spec lead, has led Sun's Swing team from the beginning, and has continued to focus on desktop Java. Artima interviewed Muller over email about how JSR 296 will help with common Swing development patterns.
Frank Sommers: What is the difference between a GUI toolkit and an application framework, and how does JSR 296's application framework relate to the core Swing API?
Hans Muller: The difference between building applications and providing a GUI toolkit can be vast. It's a bit like the difference between running a lumber yard and building houses. Both enterprises work with lumber, but the home builder needs additional skills, parts, and tools to get the job done efficiently. Swing has been around for quite some time, and although we've provided tutorials, examples, and a few parts and tools for application builders, today's application developer expects and needs more than that.
Generally speaking, application developers need a process to follow for analyzing their own requirements and creating an implementation design. They also need API support for essential application parts—resources, actions, tasks, sessions—and support for putting those parts together in IDEs.
Most experienced Swing developers have sorted these issues out for themselves, and many of them are justifiably proud of their own skills. Novice Swing developers, however, find the lack of guidance and support in these areas intimidating or frustrating. What we're trying to do in JSR 296 is to move desktop application construction from the realm of artisans and specialists to straight ahead engineering. If we're successful, more high quality Swing applications will be built by developers with less experience and less frustration than ever before.
Frank Sommers: Does JSR 296 support applet developers as well?
Hans Muller: Most of the work we're doing on JSR 296 applies equally well to conventionally installed applications, Web-started apps, and to applets. You might say that the issues that arise while building an applet are different because applets are often relatively small and special purpose. Applet games are a good example of this, although if you look closely at some of the most successful applet games, like Runescape—with 9 million active players, 850,000 of whom pay $5 a month—they're as sophisticated as any desktop application.
We hope that applet developers will begin with the application framework as well, because it's the easiest way to get an application going, and then stick with it as their applets grow, because it's easier to grow into a framework than to create one.
Frank Sommers: Swing evolved in the past few years far beyond the set of APIs available in the JDK. On the one hand are projects, such as SwingLabs, that aim to add components and features to the core Swing APIs, and, at the other end of the spectrum, are things like the NetBeans client platform, that more of less define a skeleton desktop application. Where do you see JSR 296 fit in that landscape?
Hans Muller: The SwingLabs[1] project is focused on prototyping new Swing components along with some application infrastructure. It's a large community effort. Some of the things that emerge in SwingLabs find their way into the JDK, or are taken up by the JCP. An example of the latter is data binding. Others end up with an independent life of their own.
The JSR 296 project differs most from SwingLabs in that the JSR's scope doesn't include new Swing components. However, the framework does include explicit support for actions and tasks—multi-threading—and those topics have been investigated by the SwingLabs community as well.
The NetBeans platform (NBP)[2] is much closer to the spirit of JSR 296, in the sense that it's also a framework within which one can build applications. However, the NetBeans platform is much broader in scope: In addition to addressing many of the issues that are fundamental to JSR 296, it defines a module system, a docking window system, and a very flexible persistence layer that resembles a file system.
An overall goal for JSR 296 is to make it easy for new Java developers to get a solid Swing application up and running. A corollary is that the API we define has to be modest in size and easy to learn. The NetBeans platform requires some study and commitment, and NBP novices may struggle a little at first, although the built-in support for building NBP applications in the NetBeans [IDE] helps ease developers over the hump.
That's not to say that JSR 296 doesn't envision applications built with modules, docking window systems, and persistence. Some of these features are being addressed by other JSRs that are underway right now. For example JSRs 277, 294, and 291 all focus on aspects of module support for Java SE. JSR 295, Beans Binding, supports automatic binding of Swing components to Java Beans that encapsulate application data, notably persistent application data.
Frank Sommers What are the top five developer frustrations when developing desktop Swing applications as of JDK 1.5? How will JSR 296 address those issues?
Hans Muller: Here's my take on the top five. While not all of these fall within the purview of JSR 296, they're all being pursued by one or more desktop Java groups.
For example, if you ask NetBeans to create a Java application for you, it will helpfully create something like this:
public class MyApplication { static void main(String[] args) { // your application here ... } }
This certainly gives developers a great deal of flexibility! The overall goal for JSR 296 is to provide an answer to that novice desktop developer that is easy to understand, and is supported by Java IDEs.
Action
objects. Actions encapsulate an ActionListener
, whose actionPerformed()
method is triggered by the Action
's component, as well as a collection of visual properties. The visual properties are automatically applied to the Action
's component, and some of them, like the enabled
property, affect both the component's appearance and its behavior. Given the importance of Actions
, JSR 296 adds support to make them easier to create and use, particularly in large applications.
JSR-296 includes an @Action
annotation that trivializes defining Action
methods as well as initializing the Action
's visual properties with localized resources. It also makes it possible to inject Application
parameters—for example, a reference to a shared data object—and to write actions that launch background tasks.
The JSR 296 Action
support also simplifies what we've called "proxy actions"— Action
s that delegate to an identically named Action
found in the ActionMap
of the keyboard focus owner. Proxy actions are used to define GUI stalwarts like cut, copy, and paste. The Application
framework automatically sets up such Actions
for all Swing text components.
Quite some time ago, a utility class called SwingWorker
was created to help developers move individual method calls off the EDT. JSR 296 is considering expanding SwingWorker
into the Application
realm by introducing two new classes: Task
, a subclass of SwingWorker
, and TaskService
, an encapsulation of java.util.concurrent.ExecutorService
.
Task
and TaskService
give the application developer a way to manage all of their Application
's threads as well as support for automatically monitoring them. Actions defined with the @Action
annotation can return a Task
, which is automatically executed and monitored by the application framework. An @Action
parameter lets the developer specify how the GUI should behave while the action's Task
is underway—for instance, by disabling the Action
or by blocking the app with a modal dialog.
pack200
, a compression technique that can reduce jar file download sizes by a factor or 7 or 8, and a Persistence Service that makes it possible for unsigned applications to store data on the target machine's file system. The reason this is a problem for developers is that many of them aren't aware of what's available, or have found it difficult to muster enough energy, as a desktop project nears completion, to do a good job at deployment. Other than documenting the deployment options and offering some recommendations and providing some explicit support for application session state, JSR 296 doesn't address this problem directly. However we are certainly doing our best to get tool vendors to do so. What I hope we'll get in a future revision of your favorite IDE, is a "Deploy with Java Web Start" button that takes care of everything from creating a JNLP file to uploading your application to a web server.
The best solution to the problem is to draw inspiration from the latest and greatest applications, and from people who are naturally good at this kind of thing. Although it's rare to find someone with GUI fashion sense and the ability to build GUIs, we have some wonderful exceptions in the Swing community, such as Karsten Lentzsch of JGoodies[3] and Romain Guy[4].
Given a good design, encoding it with a resizable layout has been a longstanding problem, because doing so can be difficult. This situation has improved in the past year or two with the introduction of layout tools like Matisse[5] or JFormDesigner[6].
Two GUI design problems that JSR 296 actually tries to tackle are resource management and managing large GUIs. Our support for resource management standardizes where ResourceBundles
are stored and how they're interpreted. It provides for resource injection as well type conversion, and even for string substitution. Resources can be defined per- locale, as usual, and can also be defined per platform. For example, one can specify a ResourceBundle
that's just for OS X, or one just for Windows XP.
At the moment, our approach to large GUI structure is still evolving. Two candidate ingredients are the Presentation Model and support for a general purpose event or message bus. The goal is to define a solution that helps developers factor GUI implementations into reasonably modular parts.
Frank Sommers Most non-trivial applications must access data from remote servers. The traditional browser-based model offers an advantage in that area: the user interface components are defined and instantiated on the server, which is where the data populating those components also resides. With Swing desktop applications, the user interface components are instantiated on the client, and those components often must ferry data back and forth between the client and server in the course of a user's interaction with the app. What are some of the techniques that you'd recommend developers follow in dealing with data in rich-client applications? Will there be any tools or APIs in JSR 296 that helps deal with data in the context of desktop Swing apps?
Hans Muller: That's a big question. I could quibble about the advantage you've given conventional browser applications. The typical browser application does benefit from having both GUI and logic in one place. However, efficiently maintaining the state of each user's session with some witches brew of browser cookies and server-side session state usually pretzels what would otherwise be a straightforward application architecture. Of course, today's cutting edge in browser app technology is AJAX, which basically means building conventional desktop applications, using JavaScript as a substitute for Java.
Most conventional applications do need a way to cache server data and efficiently communicate updates to and from the server. In a well-architected application this is unlikely to be done on a GUI component basis, and is more likely to be encapsulated by one or more data models that insulate the rest of the application from the fact that the model they're working with has a remote aspect.
And therein lies the Holy Grail of modern computing: creating the illusion that a distributed computation is no different from one executing locally. A new distributed computing paradigm seems to be heralded every year or so, and then forgotten by all but a few indefatigable apostles a few years later. I don't think the JSR 296 expert group will debut our own, despite the fact that, as you say, dealing with remote state is fundamental to most desktop applications. So, we're reduced to providing advice.
At this point the advice I've been considering, and this topic has not been taken up by the expert group, is to recommend that developers use Task
s and TaskService
s to encapsulate remote services, and in so doing, not hide the fact that the remote service is, well, remote. This is somewhat different from the rough and ready approach, where a developer creates a client-side API, typically a set of Java Beans, that encapsulate server state, and documents the fact that it would be unwise to read and write the properties on the event dispatching thread.
What the typical rough and ready API lacks is a way to monitor, interrupt, and explicitly thread, access to the server. To remedy that, one can define such an API in terms of Task
s, for the sake of monitoring and interrupting, and TaskService
s, for the sake of explicitly controlling threading.
For example, the Flickr-based demo app I'm writing depends on a method for loading an image from a URL. The rest of the application doesn't depend on the method, it depends on a Task
class, LoadImageTask
. The Tasks
's contract with the caller is more complicated than a simple method call because it supports monitoring—state, progress, messages—as well as cancellation.
To further abstract our client side model of this service, threading isn't defined by the caller but by the TaskService
to which LoadImageTask
is submitted. A TaskService
, such as ImageTaskService
, can limit how many parallel Task
s can run, and on how many threads, and in what order. A TaskService
is a simple encapsulation of an ExecutorService
, so it also provides a standard way of shutting down all its Tasks
, pending and running. One can name the TaskService
that will execute an @Action
's Task
with an annotation parameter:
@Action(service = "ImageTaskService") Task loadImage() { URL url = getGUI().getImageURL(); return new DoLoadImage(url); } private class DoLoadImage extends LoadImageTask { DoLoadImage(URL url) { super(url); } protected void done() { getGUI().showImage(get()); } }Resources
[1] The SwingLabs project
http://www.swinglabs.org[2] The NetBeans Client Platform
http://platform.netbeans.org[3] Karsten Lentzsch' The JGoodies Framework
http://www.jgoodies.com[4] Romain Guy's blog
http://www.jroller.com/page/gfx[5] NetBeans' Form Designer
http://form.netbeans.org[6] JFormDesigner
http://www.jformdesigner.comOther resources:
JSR 296
http://www.jcp.org/en/jsr/detail?id=296Hans Muller's blog post on JSR 296, including a demo Web Start app
http://weblogs.java.net/blog/hansmuller/archive/2006/06/jsr_296_bows_sw.htmlHans Muller's blog
http://weblogs.java.net/blog/hansmuller
Have an opinion? Readers have already posted 14 comments about this article. Why not add yours?
Frank Sommers is an Artima senior editor.
Artima provides consulting and training services to help you make the most of Scala, reactive
and functional programming, enterprise systems, big data, and testing.