The Source for Java Technology Collaboration
User: Password:
Register | Login help    

Search

Online Books:
java.net on MarkMail:


Architecting Applications 2: the Application class

Posted by zixle on January 30, 2006 at 3:03 PM PST
This is the second blog in a series on architecting applications. In the first blog I discussed the application I'm going to develop, how it would be architected, and briefly went over the model. In this second article I'll motivate the need for an Application class that is suitable for typical Swing based Apps, as well as the functionality it should provide.

Swing is an incredibly rich toolkit, but to date we haven't provided much guidance on how to structure your app. How should I start my app? Where should I place resource bundles in my project? How should I use preferences? Logging? ... The list goes on. While I'm not going to address all of these issues I'm going to focus on the first issue. How should I start my app? The first thing to comes to mind is something along the lines of:

public class Main {
  public static void main(String[] args) {
    JFrame frame = new JFrame(...);
    frame.pack();
    frame.show();
  }
}
Unfortunately this code can be problematic. Swing is not thread safe and unless otherwise mentioned in the javadoc all methods must be invoked on the event dispatch thread. As it's name implies, the main method is invoked on the main thread. The preceeding code calls into Swing widgets from this thread - the main thread. As such, it is entirely likely that wierd errors or exceptions can occur. Why you ask? Invoking various Swing/AWT methods can result in events getting posted to the event dispatch thread. If the thread scheduler happens to schedule processing of those events while the main thread is still invoking methods you'll have two threads interacting with the same Swing component at the same time - a definite no-no. Best case, it all works and you're fine, worst case you get random deadlocks!

We currently recommend an approach along the following lines:

public class Main {
  public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        createAndShowGUI();
      }
    });
  }
}
But this gets to be a bit painful to remember every time through. Ideally there would be a class that isolates you from the various Swing threading vagaries. Furthermore, it would be great if this class were seamlessly integrated with builders.

Here's how I would like to write main:

public class Main {
  public static void main(String[] args) {
    new MyApplication().start();
  }
}
And MyApplication would have methods intended to be overriden that are called on the event dispatch thread. This way I don't have to do the invokeLater everytime, it's handled for me. Beyond handling proper initialization there are a number of other features common across Swing apps. In no particular order they are:
  • Registering as the uncaught exception handler such that if an uncaught exception is received the application alerts the user and exits.
  • Using a ResourceBundle for localized resources. For small to mid size apps putting resources into a single resource bundle is fine, large apps will undoubtedly want finer granularity.
  • Using a PreferencesNode for persistant information. Again, for small to mid size apps using the same preferences nodes is fine, for large apps you will undoubtedly want finer granularity. There are problems with using preferences in webstart/plugin, but that's for another day.
  • A single point to exit the app, as well as the ability for listeners to cancel the exit.
  • Ability to block exiting until background threads have finished as well as displaying a dialog to the user while this is happening.
Is this everything? I'm sure there is more common functionality, but this is a good start.

I suspect anyone that's developed a number of Swing apps has already developed a similar class. You can find the version used in this article here, or peruse the doc of Application and ApplicationListener.

Application itself is an abstract class, a typical subclass, and the one for this blog series, looks like:

public class PasswordStoreApplication extends Application {
    public String getName() {
        return "PasswordStore";
    }

    protected void init() {
        JFrame frame = new JFrame(getName());
        frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
        frame.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                exit();
            }
        });
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        new PasswordStoreApplication().start();
    }
}
Notice main, it's now short and sweet. While not obvious, init is invoked on the event dispatch thread and I needn't worry about using invokeLater, it's all done for me! Similarly the look and feel is automatically set to the system look and feel for me from the preInit method.

Those that look at the code will notice a couple of hard code strings. Bad Scott, bad Scott! I did this to make it easier for folks to download the source and use, but this most definitely needs to come from a resource bundle. You've been warned.

I've tried to keep Application simple. It doesn't know about Frame or any other application specific components, that's up to subclasses. In fact it probably makes sense to have a subclass that knows about a single frame. Such a subclass would further reduce the code of PasswordStoreApplication as registering the window listener, packing and all that would be done for you.

One of the biggest open questions with a class like Application, is should it do dependency injection? That is, should Application contain meta information about your application that can be used in configuring it. For example, database style apps need to know what database to connect to. Does it make sense to have Application configure your connection settings so that there is a standard place for this meta information? I'm not sure, but I'm certainly interested in feedback from the community.

A related issue I mentioned is how this class would work with builders. Ideally one would be able to create a 'Swing Application' which in turn would configure things like the name of the application and perhaps a class to create on the EDT. In this way developers needn't subclass Application directly, the builders would do the wiring for you. More research is needed on this.

Hans suggested rather than using listeners you have the ability to register Runnables given a name, with the Runnables processed at well known points in the app life cycle. This would make for a more loosely specified init sequence, but one that allows for a bit more than listeners. I'll explore this in more detail later.

In the interest of keeping each blog short and sweet I'm going to wrap this one up here. I had hoped to have something running by this point, but I'll leave that to the next blog. In the next blog I'll create a controller class along with the UI that ties the model together and is started with the Application subclass. I promise that by the end of the next article you'll be able to click on a web start link to see the app running.

    -Scott

Related Topics >> Open JDK      
Comments
Comments are listed in date ascending order (oldest first)