Welcome!

Java Authors: Maureen O'Gara, Liz McMillan, Walter H. Pinson, III, Yakov Werde, Tony Bishop

Related Topics: Java

Java: Article

Restoring the "Delegate" Concept To Java

Had the "Delegate" Become Part of Java, Would Swing Programming Be Easier?

Delegate's primary purpose is to serve as a bridge between an event-driven front-end and a multithreaded middle tier. In Swing, when an event is triggered, it does not execute right away. Instead, it joins the event queue (java.awt.EventQueue) where it waits along with other events to be executed by the Event-Dispatch Thread (EDT). The EDT pulls events off the queue and services them one-by-one.

An event that requires a significant time to complete - either because it's computationally intensive or because it makes blocking calls - holds up the rest of the queue, causing the user interface to seem sluggish. In fact, since repaint requests traverse the queue as well, expensive events typically cause components to appear as lifeless solid-colored rectangles.

If an event can't be processed in a timely fashion, it should forward the request to a worker thread. That's the reason why Delegate provides invokeAsync(). invokeAsync() is called just like invoke(), but it dispatches a java.util.concurrent.ThreadPoolExecutor thread to execute the method. Since it's an asynchronous call, it returns immediately without a return value. To see this in use, here's an indirect call to println() on a different thread:


Delegate delegate = new Delegate(
  System.out, "println");
delegate.invokeAsync("Hello World!");

Now, Swing components aren't thread-safe; they were designed to be accessed exclusively by the EDT. To safely call Swing methods from worker threads, Delegate provides invokeUI(). If invokeUI() is called by the EDT, the method is invoked directly. Otherwise, a request to execute the method is placed in the event queue. Since the call is potentially asynchronous, invokeUI() doesn't return a value. On the other hand, Delegate.invokeUIAndWait() enqueues the request, blocks until the EDT fulfills it, and then returns the result. The following example demonstrates how to obtain a JTextField value safely from any thread:


Delegate delegate = new Delegate(
  textField, "getText");
String text = (String)delegate
  .invokeUIAndWait();

A Listener Delegate
To join Swing events with methods, I combined delegates with a dynamic proxy. The dynamic proxy is an often-overlooked concept that's been available since Java 1.3. Before I discuss it, let's quickly review the proxy pattern.

A proxy acts as a middleman, serving as a stand-in for another object. Typically that other object and the proxy share a common interface. In the case of Remote Method Invocation (RMI), for example, you access a remote object living in a JVM on a different machine across the network via a local proxy. Internally, the local proxy forwards all method calls to the remote counterparts. The proxy effectively creates the illusion that the remote class is accessible locally.

For Swing components, I needed a proxy with the ability to stand-in for any event listener. I could have created a class that implements all of the listener interfaces in java.awt.event and forwards the calls to Delegate.invoke() accordingly, but that would have required way too much typing.

Luckily, java.lang.reflect.Proxy provides a static newProxyInstance() method for generating a proxy class on-the-fly that implements a specified set of interfaces - hence the term "dynamic proxy." newProxyInstance() requires a ClassLoader, a list of interfaces as a Class[], and a reference to an InvocationHandler implementation. InvocationHandler contains a single method with this signature:


public Object invoke(Object proxy, 
  Method method, Object[] args) 
    throws Throwable

All calls on the dynamically created proxy funnel down to InvocationHandler.invoke() where the Method parameter contains a description of the invoked proxy method. It's a simple matter to use it along with args to make a Delegate.invoke() call.

To generate dynamic proxies, I created a factory class called UIDelegate. Listing 2 shows one of its static create() methods. The return type, UIDelegateListener, is an interface that extends all of the interfaces in java.awt.event. UIDelegateProxy is an inner class that implements InvocationHandler.

The create() method accepts an arbitrary number of arguments in groups of four, each corresponding to a method of an event listener interface. A group consists of the object with a handler method, the name of the event method, the name of the handler method, and the technique to call the handler. The last parameter is a boolean: true indicates that the handler is invoked asynchronously and false causes the EDT to invoke it directly. The following example shows how to associate a handleOK() method with a button:


okButton.addActionListener(UIDelegate
  .create(this, "actionPerformed", 
    "handleOK", true));

The referenced handleOK() method must accept an ActionEvent.

For those listeners with multiple methods, you only need to specify the methods that you're interested in. For example, MouseListener provides five methods, but if you only need to respond to enter and exit events on the EDT, you can do it like this (see Figure 2):


panel.addMouseListener(new UIDelegate(
  this, "mouseEntered", "handleEnter", 
  false, this, "mouseExited", 
  "handleExit", false));

More Stories By Michael Birken

Michael Birken is actively involved in the design and research of emerging trading technologies at a Manhattan-based financial software company. He's a Sun Certified Java programmer and developer. Michael holds a BS in computer engineering from Columbia University.

Comments (9) View Comments

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.


Most Recent Comments
Black007_pl 05/20/08 10:28:41 AM EDT

Hi!
I don't really see the point of using delegates in java. The code with ActionListeners is more clear to me than using some function pointer, and passing them into UI elements. It implements observer/obesrvable pattern, and it's more objective for me than delegates... You can easily implement your won calls that will implement this pattern just by having a list of objects that implemet some interface and invoking it's method, nothing more....
And when I saw how my collegue tries to implemet his won delegates in C# it was very difficult to me to understand what his trying to do (he also didn't know it... :D )

Have a nice day

Tom 04/13/05 09:10:30 AM EDT

Oh, another suggestion is to use a more Microsoft alike approach. For example when instead of:

container.add(button)

the following is writen:

container.add(SwingEventDispatcher.wrap(button, "store", this));

This line still adds the button to the container, but also names the button "store" and binds it to "this" by searching for methods with a particular pattern, for example:

public void store_actionPerformed(ActionEvent e)

Note the "store_" prefix. To make the source more readable this method may also be written as:

public void store_clicked(ActionEvent e)

And some intelligence is added also:

public void store_singleClick(ActionEvent e)
public void store_doubleClick(ActionEvent e)
public void store_tripleClick(ActionEvent e)
public void store_multiClick(ActionEvent e)

It makes sure that on a double click only xxx_doubleClick is called and not xxx_singleClick also.

The same trick works with all events:

mybean_propertyChanged(PropertyChangeEvent e)
mylist_selectionChanged(...)
...

Tom 04/13/05 08:46:16 AM EDT

A cleaner solution (IMHO) are closures. Using closures would result in something like:

JButton button = new JButton();
button.addActionListener() { e | button.setText("bla"); }

Closures basically are inner classes that can access its context without having to use final (the local variable button is used in the inner class). Groovy provides a (hopefully soon) standard way to do this, but at least Groovy is fully Java compatible.

A Wolfe 04/12/05 11:21:22 AM EDT

Maybe I'm not following the argument here, but I guess I wonder why someone would prefer to pass around function pointers rather than interfaces. Can't the dispatch code just as easily invoke a method through an interface as through a Delegate class?

I guess I am uncomfortable with the modularity here. First of all, actual implementation classes have a sort of rigidity from the standpoint of the client and the programmer. So I like having interfaces anyway. But the other issue is that a method may start out being 'standalone', but then it may need to be called as part of a sequence of other methods. If you delegate through Interfaces, then it would seem you could add those other methods very easily.

Finally, variable argument lists are prone to incorrect use in all circumstances; but in this one there is no commonalties among the arguments. The classic 'printf' variety of variable argument lists was very clear -- each of the variable arguments is intended to be rendered as text. In this case it can be results of embedded function calls or anything. I guess I don't understand why one would want to suppress type checking.

Anyway I have really not gotten the idea or the benefit of this technique. Sometimes it's worthwhile to emulate one language's constructs in another language, but I don't see it here.

Ross Judson 04/12/05 09:08:06 AM EDT

There's nothing wrong with inner classes per se; they represent a superset of the functionality of delegates or method pointers. The problem is the Java language itself, and the lack of lightweight anonymous function/class declaration, and the lack the type inferencing. Fix those two things and the ugly part of inner classes (the declaration syntax) goes away.

Scala does lightweight functional syntax very nicely. If func takes something like an action listener, you can call it like this (for arrow read greater-equals):

func(event "arrow" event.getComponent().setSelected(true));

Scala knows the expected type for the call and builds the scaffolding necessary. Under the covers you end up with:

func(new ActionListener() {
public void actionPerformed(Event event) {
event.getComponent().setSelected(true)
}});

Michael Abernethy 04/11/05 01:01:16 PM EDT

The Buoy package contains some things similar to what you've outlined in your article. Although I have not worked with, reading the examples makes it appear that your goals of making the event handling code easier exists already in Buoy.

Kevin Timm 04/11/05 10:16:11 AM EDT

One of the things I miss the most about C is the lack of pointers to functions. Used correctly, these are fantastically useful. Hopefully, some of that can be added back (or implemented as is shown here) for the greater good of all.

Remember too, the 'Evil Empire' did not invent this desire (as noted by a previous respondent) they only implemented a shortcoming that they saw. This is not a bad thing.

Javanaut 04/11/05 07:15:38 AM EDT

### Dennis Farr commented ...
Great article. I have been haunted by the thought that not all differences between C# and Java were abberations, and your article shows how to take advantage of the good ideas coming out of the evil empire and use them inside Java. ###

The idea is certain to provoke widepsread discussion - it reminds how close C# and Java are.

Dennis Farr 04/10/05 01:23:31 PM EDT

Great article. I have been haunted by the thought that not all differences between C# and Java were abberations, and your article shows how to take advantage of the good ideas coming out of the evil empire and use them inside Java. Java is at least open enough to discuss and use ideas from outside Sun, as I hope yours will be.