Annotations, dynamic proxies and talking models

Since it's a long time since my last (interesting) post I thought I could give you all a little update on the current status of affairs. What I've been reading and how things are going.

I'm receiving comments and email from many of you. Let me comment on (some of) these. And let me talk again about the bus driver.

Annotations, what for?

Ingo (who is currently writing his master thesis, good luck, Ingo!) has asked me why and where do I want to use Annotations for the event bus.

Well, to be honest annotations are not really needed at all. You can use plain old listeners for event handling.

But although not neccessary they may be useful. Let me briefly explain why I think they may be of interest.

Handling events in Swing is easy but, from my point of view, requires lots of code. You have to create a listener, whether anonymous or not, and then make the listener do what you want. And then remove it in case of need. That requires several lines of code. We can make things easier (note that writing less code is not always a good idea if you write less legible code. But discussing that will require another entry ;-) ).

Easier event handling I: dynamic proxies

One way to make things easier is by using Dynamic Proxies. These "Dynamic Proxies" are a way to build classes dynamically (i.e., while the application is running) that implement some interface you want. Say you have an ActionListener interface. You can dinamically build an object (a dynamic proxy) that intercepts all calls to methods in the ActionListener interface. So when someone calls the method "actionPerformed( ActionEvent ae )" the dynamic proxy will intercept that call. Then you can do whatever you want there. Say send the ActionEvent to a bus of events, for instance.

The small UITopics implementation we talked about earlier just does this. It dynamically builds listeners for those interfaces you want and redirects all events there to a topic in the bus. So the call:


JButton myButton = ...;
TopicManager tm = ...;
tm.addEventSource( myButton, "mybutton.events", ActionListener.class, MouseListener.class );

(If you're new to UITopics just think that TopicManager is a weird, unappropiate name of the Event Bus).

That code builds two proxies, one that intercepts calls to all methods of ActionListener and another one that intercepts calls to all methods of MouseListener.class. And then redirects all events to the "mybutton.events" topic in the TopicManager.

To clarify. The code above is rougly equivalent to this:


JButton myButton = ...;
TopicManager tm = ...;

myButton.addActionListener( new ActionListener() 
{
  public void actionPerformed( ActionEvent ae )
  {
    tm.sendEvent( myButton, "mybutton.events", ae );
  }
} );

myButton.addMouseListener( new MouseListener() 
{
  public void mousePressed( MouseEvent me )
  {
    tm.sendEvent( myButton, "mybutton.events", me );
  }
  ... // idem mouseReleased, etc.
  public void mouseClicked( MouseEvent me )
  {
    tm.sendEvent( myButton, "mybutton.events", me );
  }
} ();

Note that the three lines above using dynamic proxies are equivalent much more lines using normal listeners.

Using dynamic proxies for event handling is a very old technique. More info can be found at java.sun.com and www.javaworld.com (1999).

Easier event handling II: annotations

The second way to make things easier in event handling is by using annotations. Since dynamic proxies are built dinamically for building listeners, why not take advantage of annotations to dinamically (too) define how listeners expect events to be received?

UITopics uses annotations to define how listeners want to receive events. From which topic, and on which thread. That makes things easier to code.


@TopicListener( topicName="mybutton.events", isAsynchronous="true" )
public void myMethod( TopicManager tm, ActionEvent ae )
{
  ... // asynchronously handle ActionEvent
}

Note that by using dynamic things you (may?) loose strong typing. Applications may fail at runtime if these are not correctly tested. By using dynamic things you make things easier to develop at the expense of static (compile-time) safety (you've been warned ;-)).

There's an interesting article on using annotations for event handling at JavaWorld. Note that the article is dated October 2005. As you can see things are moving in this field. The article contains interesting ways to annotate listeners. (Interesting ideas for the bus, too).

Event driver revisited: is it MVC or MVP or PM or what?

In my last post I suggested we could use the model to send events to the views through the bus. I am still digesting one of the latest (Aug. 2005, PDF, English) of Karsten Lentzsch's articles entitled "Desktop Patterns and Data Binding for Swing". You may know Karsten because of all JGoodies goodies (including the Looks Look and Feel, his Binding and Validation and tons of other good stuff).

Karsten is one of my gurus. Reading his articles is always interesting. That one of Aug. 2005 is also interesting. He shows the differences between MVC, Swing MVC, Model View Presenter (MVP) and the Presentation Model.

I like Model View Presenter. I like hearing that "MVP holds the GUI state once", whereas "PM holds it twice".

For further reading you can see a nice description of MVP or even see how to build an application using MVP. Note that

It is much cleaner to design and build the core of the system, the domain model, first and then to add the user interface classes subsequently.

I agree. I think we all do. The model should be the bus driver.

Listen: the model is talking

So, if the model is so important, how should the bus listen to it? If the model is changed, how is it supposed to notify the bus? Which topics/channels/interrupt levels should be updated? How should we name them? What is the easiest way to do this?

Most Swing models talk themselves:

  • javax.swing.Document talks javax.swing.event.DocumentEvents to javax.swing.event.DocumentListeners.
  • And javax.swing.tree.TreeModels talk javax.swing.event.TreeModelEvents to javax.swing.event.TreeModelListeners.
  • (include the Swing model you want here)

So one way to plug-in these events to the bus is using Dynamic Proxies as well. Dynamically building event listeners that automagically redirect the events to the bus. The first approach could be:


TopicManager tm = ...;
javax.swing.Document document = ...;
tm.addEventSource( document, "document.events", DocumentListener.class );

As we did above with components. The code above will make the model redirect all DocumentEvent's from the given document to the "document.events" topic. Make your Swing components listen to these topics (using the actuators we talked about earlier) and you're done.

But, is there any easiest way to connect the model to the bus? A different way? Simpler? More effective? ...

Talking beans?

... I think there is, but I'm not sure if this is a good idea or not. Let me explain it to you and please provide feedback on it.

Imagine you build your model with Java Beans (i.e., POJOs; also known as Value Objects or Transfer Objects). You may use a PropertyChangeSupport to fire property change events whenever you "set" any property in your bean.

Using PropertyChangeSupport and firing property changes is way more easy, from my point of view, that building custom events (DocumentEvent, TreeEvent, ListSelectionEvent, etc.) and listeners and the methods used to work with those (fireDocumentEvent, etc.).

Now, wouldn't it be interesting to attach those Java beans to the bus? What about adding PropertyChangeListeners to the bus and using the property names as a suffix for topic names? We could use the property names as part of the topic name.

Take for instance you have a "Person" JavaBean that models your user data. Say that the "Person" JavaBean has two properties: name and lastName. The idea is to attach "Person" to the bus on topic "user" and have the "setName()" and "setLastName()" automagically send PropertyChangeEvents through the "user.name" and "user.lastName" topics.

Summary and next steps

So in this post I've explained a way to attach objects to the bus. Event sources (such as Swing components, macro-components or the model) can be attached to the bus using dynamic proxies. Event listeners can be attached to the bus by using annotations. More work is needed to find a set of interesting annotations. As Tim suggested in previous comments, we could explore SYNC, ASYNC, SYNC_SWING, ASYNC_SWING for threading.

In the coming weeks (I'm too busy right now with different customers) I'll try to experiment how well the model is being attached to the bus (using those PropertyChangeSupport objects). Always trying to make things simple.

After that, once the model can be easily plugged into the event bus, I think we could experiment on threading and vetoing.

Any ideas, critics and suggestions are, of course, welcome.

Happy swinging,
Antonio

Comentarios:

Thank your very much. :)
I'm not quite sure if compile-time safety isn't more important, but now i understand your reasons why you like Annotations.

Enviado por Ingo Siebert en octubre 13, 2005 a las 06:07 AM CEST #

Enviar un comentario:
Los comentarios han sido deshabilitados.
About

swinger

Search

Archives
« abril 2014
lunmarmiéjueviesábdom
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
    
       
Hoy