Skip to main content

Swing Application Framework is back again

Posted by alexfromsun on March 2, 2009 at 12:02 PM PST

I know this is not good to disappear for a long time from blogging and SAF mail aliases, I am sorry about that. This happened because Swing team had some urgent temporary tasks to work on. The good news is that most of the tasks are completed and Swing team has returned to its primary goal - Swing library.

I should say that this time I have really come back to SAF and this project is currently #1 priority for the Swing team. We organized a little team to move SAF further and now working on schedule. My team mates asked me what problems with the current SAF code come to my head straightway and how I envision the "ideal Swing Application Framework".

This blog is written to start the conversation about those issues, it is intended not only for my colleagues but for all Swing programmers who are very welcome to comment.

Existing code

The "singleton problem"

Static method Application.launch() saves the current application instance to the static field and returns it with Application.getInstance()

This prevents using Application inside one JVM but from different AppContexts. Imagine that two applets on the same html page launch an applicaiton, they will likely to be run inside one JVM so they will share static data of any class, so an applet can't use static Applicaiton.getInstance() to access to its own application instance.

Design of the View class

Let's look at the the class' javadoc:

 * A View encapsulates a top-level Application GUI component, like a JFrame
* or an Applet, and its main GUI elements: a menu bar, tool bar, component,
* and a status bar.  All of the elements are optional (although a View without
* a main component would be unusual).

Class View has methods like getMenuBar()/setMenuBar(), getToolBar()/setToolbar() and getRootPane().

This works fine for a MDI applicaiton where each view is operated by its own frame and each frame can have its own menu bar. This is exactly like most of the native application on Windows or *nix work.
However a good framework must support SDI applications as well, on Mac OS all application's view shares one menu bar and it is better to let the view customize the "main" menu bar rather than having one menu bar per a view. It is also not unusual for a Mac application to have a "view" with a menu bar but with no main component.

SingleFrameApplication class

SingleFrameApplication is bound with JFrame.

A good framework should be friendly with IDE, let's say I want to build a SingleFrameApplication in my favorite IDE designer. In this case I shouldn't explicitly use classes like JFrame or JDialog because it is very difficult for an IDE to control and design a real JFrame.

Applets is the more obvious example, it should be as easy to run a SingleFrameApplication as an applet as a standalone application.
The common pattern here is to provide all the data that required to build a JFrame but don't explicitly create it. It will allow the different view containers to show the view in a different way.

Lack of flexible menu support

I am not a Mac user, so I was really impressed when I knew how difficult it is to make a Swing application look like native on Mac.
The menu bar is one of the main issue, it is totally different on Mac, please see this article for details. There is no need to say that SAF should automatically solve this kind of problems.

The ideal framework

It is small but very flexible, any part of its functionality can be easily overridden. For example, if you don't like the implementation of LocalStorage, it is easy to plug in your own implementation. It is free from all mentioned problem and knows how an application should look like on a particular OS.

The question of the day

I mentioned only a few problems with the current SAF to start a discussion. What do you think about the problems I mentioned and what is your list of features that SAF must have?

note: don't forget that SAF is supposed to be a small framework.


I am looking forward for your comments

It won't take a half a year for the next blog, I promise.

alexp

Related Topics >>

Comments

I'm glad to see that platform dependencies are now on the radar for SAF, even if it is only the Mac OS X menu problem at the moment. In my view the general solution to platform dependency is to isolate it behind a series of factory interfaces and make the factories extensible (by plugging in platform-dependent JARs as needed). I don't think you can expect developers to do things like "if (isMac) {} else {}" because non-Mac developers won't be aware that they have to do this. The factory should do it for you. The same applies to other platforms too (Gnome and KDE have slightly differing menu conventions and both are different from Windows and Mac). Most developers are not fully aware of all the conventions on their own platforms, let alone all the other platforms out there. And who wants programs littered with "if (isMac) {} else if (isLinux) {} else ... {}" statements anyway? It's a debugger's or maintainer's nightmare :-) A further advantage of of abstracting the platform dependencies into factory interfaces is that the implementation for each platform can be devolved into separate projects, which will avoid further delay to SAF and allow specialist communities to concentrate on the appropriate implementation for their platform. This would allow SAF to concentrate on its "core business". I use a nascent framework for my own development which works along these lines. If anyone is interested, I'll share the details.

I am using the current state of AppFramework in a Swing project and I like it, nevertheless it makes some problems. (1) I would like to be able to create my own type of Action, ApplicationAction is good but needs more in some cases; in other words, an overridable factory method (generally more framework quality) is needed (2) I have severe problems with test-coverage, because class Application seems to be not mockable, and instantiating it brings up a GraphicsEnvironment and I get a HeadlessException Best would be to provide all parts of AppFramework in separate packages, so that you can use it piece by piece, independently of each other. Mind that the "Commands" project could also be a part of this.

One thing I noticed by using SAF: How do you change on the fly the language of an application? As I live in Switzerland, a small country with 4 national languages, it is a common needed feature. I always misses the possibility to change the application language from German to French and back. It would be nice to have this too.

I would really like to see some sort of binding to model properties and actions in the framework. I have been toying around with such an approach by naming all UI elements (also great for testing) and then binding the UI elements through an EL to the model. The naming of the UI elements also helps with automated testing.

I agree with janaudy I can leave without a docking framework, there some that you can use as is, but a plugin mechanisem would be nice.

Alex, I think it would really help if you guys joined in on the discussion on the appframework mailing list on a semi-daily basis. Your absence there is a big concern... Apart from that focus on the basics, don't try to solve everything at once. The current API is a very good start. -- Harald K

Well, I have not delved too deep into SAF, but I tend to agree with karsten, especially on 1 and 3. Best, S.

Is it possible to refactor the view classes to introduce interfaces? I need some different Views for the NetBeans platform (like DocumentView, DockingView, OptionPanelView, PaletteView). But the implementation of View hurts me (e.g. final methods). The SAF should be divided into SPI and implementation. br, josh. NBDT

1) Focus on the topics we've already agreed to be the core of the JSR 296: life-cycle, Actions, resources, background tasks. That's difficult enough 2) Work with the expert group. After this long pause, you may need to re-setup the expert group. 3) Fix the ActionMap bug, because the fix requires an API change that will affect almost every framework user. 4) Work towards an early draft according to the JSR process. 5) Exclude views from the framework, as explained in the appframework mailing list.

Hello, I've started using the Swing Application Framework within a netbeans environment. I've had a lot of success with it. Currently I use the SingleFrameApplication and launch my application either through Java Web Start, or as a desktop application. I need to refactor my application to support a third entry point using an Applet. My current application structure is typical: class MainApp extends SingleFrameApplication { public static void main(String[] args) { launch(MainApp.class, args); } } Within my startup method I instantiate a FrameView of the form: public class MainView extends FrameView { } My simple thought is that I create a new class, perhaps of the following form: MainApplet extends JApplet { } and that this would somehow invoke MainApp, and everything else would "stay the same". I'm looking for a simple example to begin to understand how to launch my application either through the standard "main" entry point, or alternatively, as an Applet. So far I have not found an example. Can someone please point me to such an example? I apologize if this is the wrong blog to post this request to. Please let me know if there is a better forum for this question. Thanks in advance.

- Do not include in core jdk - Have a nice docking framework - Have the notion of plugins

Hi Alex (and the other Swing developers), Welcome back to SAF! Here is my wish list for the SAF: * I think it would be nice to have it or part of it included in Java 7. So if there are still a lot of discussions, the JCP should agree on the part of the SAF to be included in Java 7 and have this part easily extendable to be able to have libraries for the framework or extra features in upcoming release. * Here is my old wishing list for the SAF: https://appframework.dev.java.net/servlets/ReadMsg?list=users&msgNo=1361 (maybe point 2 is not relevant as the View class handles it) * SessionStorage an LocalStorage Here I don't understand why the Preference API (java.util.prefs) is not used instead. If the default implementation doesn't store at the desired location, provide a PreferencesFactory that does. It would also allow developer to provide their own PreferencesFactory in case they want something else (e.g. AppletPreferencesFactory). Anthony

@Thomas Kuenneth I second that. JSR-296 fixes the scope of SAF. Several comments to this post are going far beyond that initial scope. People should refrain from adding new points to the official scope, or that will definitely bury this JSR (maybe this is what Sun wants?) For the time being, it would be good if Alex could work on the numerous bugs reported in SAF issues list, rather than asking everyone what they would like to see in SAF. When most critical bugs/RFE get fixed then we can discuss and see if other features would be useful (provided they are still in scope of course). Just my 2 cents Jean-Francois

I always felt that the scope of SAF was well-choosen, as it covers a bunch of key issues all Swing developers face and concentrates on them. My humble wish is to further follow this path. Though it is true that Swing lacks some GUI components, we should not bloat the idea of a basic application framework. Therefor, when asking for improvements we have to consider if such improvements really touch SAF or if they are improvements to other areas of Swing. Still, several companions to SAF are desperately missed, for example JSR-295 oder language-level support for properties, but again, these are not part of an application framework. So, if a tweaked, finetuned and bugfixed version of SAF is part of Java 7, that would be a big step forward for client Java. Regards Thomas Kuenneth

Look at this application http://jfxstudio.wordpress.com/2009/02/18/something-usefull/ This is JavaFX text editor based on CRUDfx SDK CRUDfx SDK implements all requirements from jsr296 (http://jcp.org/en/jsr/detail?id=296) Localization - the GUI has 3 languages and can be translated to other ones by editing of a XML file The user properties - the size and position of windows, a folder for the files, the chosen language, the chosen skin and so on are kept in a home directory of the current user Themed GUI - the user can choose any Substance theme

Hi Alexander! It's a good news!! After some experiments with Qt Jambi I have some suggestions: - There are some params in @Action, may be it would be better to put all possible params inside? So you will use same action from menus and buttons in different places with same icon and text. Here are some of my experiments (btw inspired by appframework): http://code.google.com/p/heresylabs/source/browse/trunk/qedit/src/org/he... http://code.google.com/p/heresylabs/source/browse/trunk/qedit/src/org/he... - Initialize some resource bundle and create method like tr(String) that will return localised string. - Qt has a status bar and possibility to show LONG_DESCRIPTION in status bar, and it helps. - May be add some icon conventions? Like add String icon to @Action, and it will load LARGE_ICON from resources/large folder and SMALL_ICON from resources/small folder. Also add possibility to specify icons for platform, like resources/kde/small, resources/win/small and so on, so application will have different icons on different platforms?

On the View problem, given that you have only have 2 sub-cases, why not simply split it into MDI_View and SDI_View? On the Mac problem, I don't think it unreasonable to provide a set of simple support classes and make developers do something like : if (MacSupport.isMac()) { // do mac specific stuff } else { // do normal stuff } This is pretty much how SWT operates.

I certainly hope that SAF will not be over-engineered to the point of inflexibility and complexity. Been a a long-time Swing developer, I have my wish list in SAF. These are the following features that I have frequently used in desktop swing application that will hope to see in SAF -- Single application instance Use Case: This is important as some applications are best designed with single instance in mind. For example, it will make sense to have a single instance in Media player so that sound will be overlapped. When a user double-click on a audio file, it should playback in existing running MediaPlayer. Currently, widespread implementation of Single instance is to use a thread to read in file for parameter periodically. If there is content in the file, it will launch another application instance which in the main method write the parameter into the file and then exit the instance, which then pick by the first instance to do whatever with the parameter. Launching a duplicated instance takes time, and it will be better handled if the OS's native call is used instead. Hopefully, SAF will have this feature. -- OS-dependent User profile Use Case: OS has a active user profile. If SAF could implement user profile management that work in tandem with the OS then SAF application will not need to handle "hanging" user profile settings. -- Add installation and deployment modules Like application server which handles installation, deployment and execution of web application, SAF application could benefit from reference implementation ( Sun reference implementation) too of open-source installation and deployment tools that work easily and integrate with SAF eg JSmooth - Java Executable Wrapper (http://jsmooth.sourceforge.net/) and Lzpack (http://izpack.org/).

I want Sun to work on Swing. I'm just not sure that the Swing Application Framework is the way forward. I don't need a framework to help me build a specific kind of desktop application, but rather across-the-board improvements in Swing to make it easier to customize widgets and bundle common widgets like Date Picker. Frankly I'd like to see Swing 2.0 (not the one currently being proposed). I'm looking for design-level changes to make Swing easier to customize without getting lost in tons of the spaghetti code that is lurking underneath the hood. Swing components shouldn't be extensible only by those in Sun. In short, I am saying Swing's existing design has too much internal coupling and doesn't lend itself well to extending.

Hi Alex, welcome back! Swing is probably the most successful cross-platform GUI toolkit that we have. Now that we all learned how to use and not use the EDT, let's make it even easier to use! And please don't forget the user's migrating from Windows to Linux. Java+Swing+OpenGL is a great way to make the transition less painful!

btw, what was the "urgent temporary tasks"?! They must have been .. heavy.

Quick comment: The framework should be flexible enough to fully support IoCing everything, it should be possible to have several instances of the same application run in the same JVM (pretty much "just because"), and it should be possible to fully "reboot" an appliction live without any lost memory (My app has a button that does a reboot (drop current "app context", spawn a new), and it makes a whole slew of development aspects have much shorter "roundtrip times"), and it should cleanly exit without invoking System.exit()..! Basically, all resources should be accounted and contained.

That's good news! Alex, there was allready a discussion about needed changes and wishes some months ago on the appframework mailing list (started by you). It would be nice when you and your team could take care of those mails too. It wouldn't make sense to copy all of them to this comments block. Once again: At the moment it's not very easy to use dependency injection frameworks. The use of mock objects for unit testing is also sometimes too tricky. It would be much simpler without singletons and when all componts of the SAF would use interfaces. Bye, Stefan

Alex, I wanted to forward this bug to you that was discussed a while back. "Actions can lose their state (enabled, text, icon, etc.) when used with the current public appframework code." It was ruled a serious bug that has not been fixed. thanks, Anil _________________ Are you planning to kill yourself? Stop! listen to this song broadband version: http://www.youtube.com/watch?v=pLHHB4YZucI dial-up version: http://www.youtube.com/watch?v=xL5WyBenUpM --- On Thu, 2/12/09, Anil Philip wrote: From: Anil Philip Subject: Re: What is the status of SAF ? To: users@appframework.dev.java.net Date: Thursday, February 12, 2009, 1:17 PM I am using Netbeans 6.5. The GUI designer uses SAF version 1.03. In the generated code which cannot be edited, I see javax.swing.ActionMap actionMap = org.jdesktop.application.Application.getInstance(com.juwo.nodepad.NodePad.class).getContext().getActionMap(NodePadView.class, this); what should one do instead? thanks, Anil _________________ for good news go to http://goodnewsforyou.tripod.com --- On Thu, 2/12/09, Karsten Lentzsch wrote: From: Karsten Lentzsch Subject: Re: What is the status of SAF ? To: users@appframework.dev.java.net Date: Thursday, February 12, 2009, 7:31 AM Chiovari Cristian Sergiu wrote: > Well if there is a show stopper it must be something serious ! Actions can loose their state (enabled, text, icon, etc.) when used with the current public appframework code. > So then I wonder how it can be used in a production environment ? I've fixed that in my 296 implementations and have described how to fix it: a) have hard references to ActionMaps and let developers clear ActionMaps when they are no longer used (the latter to avoid memory leaks), or b) turn #getActionMap into #createActionMap that doesn't hold the ActionMap; the developer then holds the ActionMap where appropriate, for example in an Presentation Model instance. -Karsten

In my eyes, an important issue is to create it extensible: lets say we create a very generic framework, it should be easy (not a nightmare) by extending (inheriting), to create an MDI framework, or others.

One current problem I encountered is that it is impossible to override certain "factory" methods or classes. I needed to create my own implementation of ApplicationAction (which adds security via jaas) but I had to fork my own version to do that, since I had to replace the default ApplicationContext (which is final and created in the constructor of Application).

I usually encapsulate user actions in events that are sent to a central EventManager. In this manager diferent EventListeners can be registered during startup depending on the type of event , so the same event can be routed to one or more listeners, or to none. In this way, it is easy to change the behaviour of a certain action and to reuse it between different controllers. Following what cdandoy said, each view could have a different EventManager (controller) with a different set of listeners, which can be reused or not. Apart of listeners that manage the toolbar buttons, I'd include in the list of desirable listeners an undo/redo manager, for instance.

May I suggest a different approach to actions? The JDeveloper platform has the notion of Controller associated with Views and the controller is responsible for handling the actions. A View can contain a View and the platform respects the hierarchy of controllers. The platform not only calls the controller when an action is performed but it also asks the controller to update visible actions. The advantages are that * the actions are easily shared between views (Edit>Delete may do something different in each view) * it drastically reduces the number of listeners required to maintain the state of each action (enabled/checked) * Only visible actions are updated (for example when the user opens down a menu) In my experience the controller approach has huge benefits over the ActionListener approach. There is more details here: http://blog.dandoy.org/2008/06/05/eclipse-rcp-%E2%80%93-missing-controll...

That's only partly true. Actions appear to be stored & retrieve via their Class object in ActionManager. Like a lot of the AppFramework classes you cant create your own ActionManager, it has a 1:1 relationship with AppContext. Using Class object as keys essentially makes them all Singletons (cant distinsh between two instances of same Class but with differeing state) for each classloader and your classloader options are more limited in web start. Or at least going down that route (replacing JWS security manager & installing custom classloaders) makes life super-complicated for the application developer which is the opposite of what the framework is supposed to offer. There's a lot of core classes with private/protected constructors and/or static factories that prevent you from most attempts to deviate from the classic SingleFrame model. Very quickly I found various things start breaking down, ActionManager, parent chaining lookups, resource injection (because of parent issue).. Actually this should really be moved to the AppFramework mailing lists, doubt there's that many developers looking at Alexs blog after 6 months+ of inactivity. What's the remit here a long term commitment to get AppFramework right? or a quick fix to get something into JDK7 (abandoning the 1.5 compatible codebase) before moving on?

Yes, that's more or less what I meant, but it should be possible to have multiple instances of AppContext (or whatever class your getAppContext() method is returning), not just the one returned by the static method. By the way, it could be nice to have an AppContext.setInstance() method so that we are able to switch between global contexts. I'm sure that I've come across one or two cases where this has been handy. Another option could be to store statically different AppContexts for different views, such as in AppContext.forView(VIEW_NAME).get(PRIVATE_KEY)

Actually, there no the "singleton problem". You can replace static field with the following construction:
AppContext.getAppContext().gett(PRIVATE_KEY);
AppContext.getAppContext().put(PRIVATE_KEY, value);

RE: Singletons: I don't know if I misunderstood the problem, but what about using a non-static AppContext class, and a static GlobalAppContext that holds an AppContext instance? It wouldn't be a pure singleton, but will allow the best of both worlds: for simple applications it would be possible to just use the Global, and if you have an MDI, each View would have its own AppContext, which may or may not be the same as the one stored in the GlobalAppContext. And as for features of the framework, I've always felt that it's a shame that Swing doesn't have a docking system by itself, or even an abstraction layer that can be used to plug-in third party docking libraries.

Good to know that the project is still Alive Alexander! I thought SAF was dead. What were the urgent tasks you've worked on.

Very good to heard this ;) I would like that SAF would be able to manage the skins on an (semi)automatic way. Something like identifying each look-and-fell and its themes, and providing a menu with sub-items for each laf. I hope it is not much to ask. Best regards, Roger

Hans, Re: Singletons: What about multiple document interfaces? Multiple instances of the same classes, in the same JVM, but with differing state. The Singleton ApplicationContext and the Action caching by Class objects gave me a lot of problems last time I tried. MDI interfaces as in InternalFrame are generally considered old hat these days. Most go for multiple windows. Also the ApplicationContext per classloader wasn't a practical solution for anybody wanting to use Java Web Start.

great to see you blogging again ;)

are there efforts to talk to the netbeans team about interoperability with the nb platform? The NetBeans platform supports out of the box persistence, tasks, actions defined in xml layers, module life cycle (but i think most of ModuleInstall methods were deprecated :P) etc. which matches the features i found by browsing through the SAF javadoc

it would be a pity if it wouldn't be possible to map some of the features nb already provides to SAF because of implementation detail X. It would see it as killer feature if we would be able to drop a app written with SAF into the netbeans platform with minimal code changes and see it nicely integrating in some areas. (aka scalability for desktop apps)

What I would like to see is a framework that is usable for writing Swing Applications in languages other than The Java(tm) Programming Language. Think JavaFX Script, Groovy, Ruby, Python, Clojure, Fan, et al. There needs to be some way to access the core of the framework that doesn't depend on features that don't map directly to other programming models. Particular to that is the reliance on some annotations to do some of the magic. For example, requiring annotated methods to be the only way to add Actions to the ApplicaitonActionMap is a particular problem. It's fine to do some particularly snazzy stuff for The Java(tm) Programming Language, just don't make it the single gateway to access the APIs, or else the growing JVM languages community may have to bypass it when they write their own desktop applications. You don't need to ship the other language bindings with SAF but an equal degree of access would speed/enable adoption.

Per the "singleton problem": the Application singleton does not prevent multiple applications per JVM nor does it prevent running multiple Application applets in the browser. Statics are per class-loader not per JVM. This topic was discussed at some length about a year and a half ago: https://appframework.dev.java.net/servlets/BrowseList?list=users&by=thre... Having multiple Applications share one ApplicationContext was never a goal. Applications weren't intended to be modules.

I think what's missing is a good, relatively complete UI framework for Swing, something similar to the eclipse rich client platform or netbeans, but much lighter weight.