Spring RichClient, TargetableActionCommands and the EDT
So I’m working diligently on my first Spring Rich Client project.
Oh yeah, it’s nice.
Friends don’t let friends develop Swing without Spring Rich.
I’ve discovered a specific feature of Spring Rich that I really like, but I think could be slightly improved. I’m really new to Spring Rich (as anyone who’s tried it, I guess), so it’s not unlikely that this idea has already been chewed over and discarded due to some flaw. I welcome feedback.
The idea once again centers around the concept of allowing a container of some type to manage the basic multi-threading concerns of your swing application. There has been a fair amount of abstract discussion on the topic, which is good.
I’d like to make the discussion a little more concrete by humbly suggesting a specific opportunity for Spring Rich to implement the concept in one of its existing features. Spring Rich already has all of the pieces in place to make this happen… one simple change would add yet another powerful feature to Spring Rich: Transparent EDT management for asynchronous event handlers.
First, I’ll try to explain the existing Spring Rich feature that I think could be extended:
TargetableActionCommands.
Keep in mind this is very new material for me… and documentation is still scarce, so don’t expect this to be too thorough or even correct ;).
So what is a TargetableActionCommand? I’ll start by describing the traditional Swing concept I suspect this feature was meant to improve/replace.
Swing introduced the Action API whereby it was possible to create an Action subclass that packaged up event handling functionality in a nice, oo package. This was cool, because you could easily associate the same action with multiple user-interface widgets, a decorative icon, and a label string (like “Save As” or something) in an object with supporting methods and fields. This was an improvement over what was offered in the AWT.
For your Action subclass to do anything interesting, you would override the actionPerformed method, adding all of your business logic. Say you were creating a file uploader client:
public void actionPerformed(ActionEvent evt) {
Files f = getFilesToUpload();
String username = getUsername();
String password = getPassword();
...
NetworkClient client = new NetworkClient();
client.setURL("example.com");
...
client.execute("upload",username,password,f);
}
Let’s momentarily ignore the obvious problem that we are executing some significant network activity on the EDT here, which is obviously a no-no. A better design than the method above would decouple the business logic from the Action, and keep the actionPerformed method as small as possible. Again, I’m not talking about EDT- or concurrency-related concerns yet, just basic organizational considerations. It would probably be much better to encapsulate file uploading functionality in a FileUploadService class, rather than allowing client code (the Action) do the driving.
public void actionPerformed(ActionEvent evt) {
getFileUploadService().execute();
}
You’ll notice that our Action class has now become rather trivial… All it really does is forward notification of the user interface event to a business object. Wouldn’t it be nice if you didn’t even have to code this silly little class? What if you could — using a configuration file — bind the GUI widgets directly with methods of your business objects? Additionally, wouldn’t it be great if your business object didn’t have to subclass any particular class in your framework to make this work? Thus you could freely change frameworks in the future without even needing to recompile the business objects. If you’ve used JSF, all this should sound very familiar…
It seems that this need inspired the org.springframework.richclient.command.TargetableActionCommand class. Instances of this class can be associated with a GUI widget and configured to execute a method on an arbitrary target (a business object, probably) of your choice. You don’t subclass this class, or reference it in your code, you simply bind it to an object of your choice in one of your Spring config files. With one caveat, the class to which it’s bound must implement the org.springframework.richclient.command.ActionCommandExecutor interface and implement its single method execute.
First create your business object:
import org.springframework.richclient.command.ActionCommandExecutor;
public class FileUploadService implements ActionCommandExecutor {
private FileUploader uploader;
...
public void setFileUploader(final FileUploader u) {
uploader = u;
}
public void execute() {
System.out.println("In EDT? : " +
javax.swing.SwingUtilities.isEventDispatchThread());
uploader.upload(getUsername(),getPassword(),getFile());
}
...
}
This class implements the Spring Rich ActionCommandExecutor interface, and implements its lone execute method. When I register this bean in my Spring context config file, I’ll arrange for this method to be invoked by a Command object that I’ll also define in a config file. Then that Command can be associated with multiple GUI widgets also described in the config file.
Notice how the Spring framework has crept into my domain object here? Wouldn’t it be better if Spring Rich allowed you to execute an arbitrary method in an arbitrary class without the requirement of implementing a Spring interface? That’s something JSF offers… more flexible binding. Did the Spring Rich guys consider this? Was it determined to not be desirable?
Okay, back to work…
Like any Spring application, a Spring Rich app typically makes use of many XML config files, one of which configures all of your application’s business objects. We add the FileUploadService bean to such a file:
<bean id="fileUploadService"
class="org.ditchnet.fileupload.client.app.FileUploadService">
<property name="fileUploader">
<ref bean="fileUploader"/>
</property>
</bean>
The fileUploader bean is defined elsewhere using an instance of org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean which allows incredibly easy-to-setup but powerful remoting functionality for client-server apps. That’s another article though…
Now let’s configure the Command itself. What is a Command? The mental model that has worked for me so far is that a Command is the Action class that you would normally write in a Swing app for connecting user interface events to business logic, that you don’t have to write because Spring Rich takes care of this for you. Here’s a sample fragment from a possible commands-context.xml file for the app:
<bean id="uploadCommand"
class="org.springframework.richclient.command.TargetableActionCommand">
<property name="commandExecutor">
<ref bean="fileUploadService"/>
</property>
</bean>
Here I’ve defined a Command called uploadCommand with a property named commandExecutor that is a reference to our familiar fileUploadService bean. This is how you define a TargetableActionCommand. I can now associate this Command with multiple GUI widgets, and when those widgets are activated (clicked, keypressed, etc), the execute method of a singleton FileUploadService instance will be called. AWESOME!. Some benefits:
- Nowhere in the code do I have to instantiate a
FileUploadServiceobject. - I didn’t have to write an Action class, and manually associate it with GUI widgets.
- I didn’t have to code some kind of action registry or write lookup code to find a
FileUploadServiceinstance in order to call methods on it.
That is really brilliant stuff. That’s Spring.
Okay, so let’s move on to the reason I wrote this article… look again at the execute method of the FileUploadService class (which remember, implements ActionCommandExecutor).
public void execute() {
System.out.println("In EDT? : " +
javax.swing.SwingUtilities.isEventDispatchThread());
service.putFile(getUsername(),getPassword(),getFile());
}
When I first wrote this code, I was very hopeful that the wonderful Spring Rich guys where hip to the thread-managing container ideas mentioned in the articles linked above.
Obviously, you don’t want make a remote call like service.putFile in the EDT… that would be likely to leave the UI unresponsive for several seconds (or longer) while the network communication takes place. Clearly, the execute method should be invoked in a separate thread.
I was really hoping that Spring Rich would automatically (or perhaps via a config option) invoke this method in a new (non-EDT) thread, without requiring the programmer to do it manually. Unfortunately, it currently does not. The SwingUtilities.isEventDispatchThread() method returns true.
I strongly think that the Spring Rich guys should evaluate the opportunity to significantly enhance the power of the framework in this specific instance. Offering the ability to configure asynchronous method execution (or making it the default) would be so cool. This one small change would be a major step forward for the idea of container-managed Swing, and put Spring Rich on the map as the only thread-managing Swing container (AFAIK).
You might argue that it wouldn’t be too hard to just spawn a new thread, or perhaps use some of the fancy new java.util.concurrent classes to manage this:
public void execute() {
new Thread() {
public void run() {
service.putFile(getUsername(),getPassword(),getFile());
}
}.start();
}
And you’d be right. It wouldn’t be too hard. But as discussed in the articles above, I think everyone will agree that thread-management by the container is something that Swing could definitely benefit from.
Comments are closed
Comments are currently closed on this entry.