|
Wow! This is warming up. Thanks all for your comments, emails, and for taking the bus with me!
There're lots of interesting things in your comments so I'll try to review them all,
as time permits, and express what I think. So please correct me if I'm wrong.
Get ready for one of the biggest blog entries in the Internet! (Sorry by that :-()
Event Buses and Event Queues
As Kevin points out there're similarities between event buses and the AWT Event Queue.
After all, let's be honest, both are ways to deliver events to listeners!
In fact I think that taking control of the event queue may be of great help
in GUI development. It allows you to be asynchronous. It allows you to take
control on event delivery. I've taken a look at
foxtrot (as you know foxtrot is a
well known framework for handling asynchronous operations in Swing) and found that...
they're taking control of the event queue too!! See:
In contrast, Foxtrot lets the Event Dispatch Thread enter but not return from the listener method, instead rerouting the Event Dispatch Thread to continue dequeuing events from the Event Queue and processing them. Once the worker thread has finished, the Event Dispatch Thread is rerouted again, returning from the listener method.
But, wait, there're many more examples out there! As Jonny (thanks, Jonny, I didn't know about it!)
kindly pointed out we have the Event-Listener Framework (ELF), too.
So it seems taking control of the event queue is key to ease things.
Taking control of the event queue seems a powerful idiom.
Now, what is the
difference between an event bus and a controlled event queue? Don't they both deliver
events?
Well, as far as I understand, the main difference may be explained with this drawing...
+---------------+ +----------------+ +-------------+ +-------------+
| | | | | | | |
| ActionManager | | EventResponder | | AntModule | | AntModule |
| | | | |(ProjectNav) | |(SourceEdit) |
+---------------+ +----------------+ +-------------+ +-------------+
| ^ ^ ^
| | | |
ActionEvent EventObject AntEvent AntEvent
| | | |
v v v v
/---------------------------------------------------------------------\
/ \
< EventBus >
\ /
\---------------------------------------------------------------------/
| ^ ^ ^
| | | |
EventObject ChangeEvent BuildEvent EventObject
| | | |
v | | v
+---------------+ +----------------+ +-------------+ +--------------+
| | | | | | | |
| Console | | ProjectProxy | | Ant | | (Your Module)|
| | | | | | | |
+---------------+ +----------------+ +-------------+ +--------------+
... that I've copied (without permission!! ;-)) from the antidote design document (antidote is a GUI for Apache's ant).
This is, I think that the event bus delivers events the same way an event queue does, but it's the
single point of contact between components. Or, as the Antidote design
document nicely explains:
"In order to keep the coupling among application modules to a minimum, a single
point of reference is needed for coordination and data sharing."
(Note that this is exactly what ELF does, too).
Topics, Channels and ... interrupt levels!
Note as well that the Antidote design document describes different topics
(or channels) to deliver events. They call them "interrupt levels".
If you read carefully you'll see a VETOING topic, a MONITORING topic, and a RESPONDING interrupt level.
Now, don't these look similar to the ones Tim has been suggesting since the very first day?
Add to these interrupt levels a "COMMAND" topic (where the Open/Save/Close events are delivered)
and a "STATE" topic (where the Opened/Saved/Closed events are delivered) and you're
(I think) pretty much solving Tim's concerns (Am I right here, Tim?)
Note, though, that Antidote seems to deliver events (interrupt levels) to all
bus components. Whether they're interested in listening or not. We may refine
this a little bit to avoid bothering components with events they're not intersted in.
Traffic lights for bus lines
And here we come to the tough part. Decide how to coordinate that
event traffic. Decide which events go in which bus lines. Define how many
topics. Place some traffic lights somewhere.
After all, as Ronan
Bradley (CEO, PolarLake) clearly stated, the ESB is just a communication mechanism. The mediation,
the orchestration, is the tough part.
So I can think of different mechanisms and I would like your feedback on this.
I. Event aggregators as event sinks
The very first approach is having one or more listeners of the bus holding instances of
other components. These aggregators will receive different events from
different components in the bus. And will then orchestrate them, making direct
method calls on those components. Note that these are listen-only aggregators.
- One of these aggregators (status bar aggregator) would listen the bus for the "FileSelected" and "FileOpen"
events and then invoke the "statusBar.setMessage(...)" on the status bar.
- Another of these aggregators (editor aggregator, say) would listen the bus for the "FileOpen" event
(coming from either the menu bar or the filesystem viewer) and then invoke
the "editor.open(...)" method of the editor.
Building such aggregators is simple. All macro-components
have a single listener: the event bus. And the event bus, in turn, has one
or more listeners: the aggregators.
Furthermore, aggregators can talk themselves through the bus.
So they're event sinks, but may produce (simulating) events from
the components to fire action in another aggregator. For instance,
an aggregator could post a "FileOpen" event in the bus, so the
"editor aggregator" workflow above will be executed.
This approach is modular too. You can add different aggregators.
Adding new features to the GUI requires new aggregators. All
control logic is in the aggregators, that manipulate
the data model and deliver pieces to components. Components are just pasive views
between the user and the controller.
In this approach macro-components are loosely coupled. You don't mix
listeners between components. You don't have the status bar listening
the filesystem viewer, nor the editor listening the menu bar. One-to-one
listeners are gone. Instead
all components have a single listener: the event bus.
With this approach there's no need to deliver command events to components, either,
because aggregators invoke methods on them directly.
So there's no need to veto events. No command events.
No need to worry about locking problems:
the order of reactions to events is fully controlled, in Java, in the aggregators.
I think this approach architects all this event handling in three layers. See:
- A view layer, with
macro-components, responsible for visual display of data and primary user event
handling.
- A bus layer, responsible for routing events from components to aggregators.
Events may be delivered either synchronously or asynchronously.
- An aggregator (controller) layer, responsible for handling events from components,
coordinating them and manipulating the data model.
Maybe a small diagram clarifies things a little bit?
II. Event aggregators as event producers
The second approach I can think of is similar to the previous one.
"Type II" aggregators will listen the bus for component events, too. But will *not*
have any instances pointing to the components. Instead of making direct method calls
these aggregators would just send events, command events, to components.
- The "status bar aggregator" could receive the "FileSelected" and "FileOpen"
events from the bus and then send a "setMessage" event through the
"statusbar" "command" channel.
- And another of these aggregators, the "editor aggregator",
could receive the "FileOpen" coming
from the menu bar of the filesystem viewer and then send an "open" command
event through the "editor" "command" channel.
This approach seems to be very powerful (does it not, Tim? ;-)).
Since there's not a direct link
between macro-components, these may be replaced (by mock macro-components in order
to do some gradual functional tests) or may even be absent (and command events
would then be simply ignored).
You could even run the whole aggregators with a bus... without a GUI!. Replace all
macro-components with mock objects (responsible for receiving and sending events)
and you could exercise the whole controller logic.
You could even substitute
the presentation logic and reuse the controller logic. So you could have a view layer
with SWT and another view layer with Swing, and swap between them both without touching
a single line of the controller logic.
Note also that I say "statusbar" "command" channel and "editor" "command" channel, so
I suggest having different "command" channels for different components, and not just
a single "command" channel to all components. By doing so I think we get rid of
vetoing and the lock problems Tim points out (am I right here)?
So, to summarize, these "Type II" aggregators would just replace direct
method calls (and instances) with command events directly delivered to components
(through each component's command channel).
These "Type II" aggregators would be similar to state machines.
You would need for these something similar to Antidote's "ApplicationContext" to keep
track of state. You could even program them
with, say, the SMC's FSM language (instead of
using BPEL, which is only for orchestrating web services in ESBs).
Or you could use some sort of Workflow engine. After all an aggregator just receives
and sends events (and keeps state and access the model for data). So some sort of
workflow mechanism may be helpful here?
May be is that the future of GUI development? Using some sort of declarative
language to manipulate GUI behaviour, once a good set of macro-components is in place?
Having workflow editors to program GUIs? Who knows. Maybe we'll have something similar to
NetBeans
MIDP Visual Editor for building J2SE GUI Applications.
This is a long one
Sorry for such a long post. It's lots of things to think of!
Now, what do you think? Which one would you prefer? Type I aggregators or Type II aggregators?
You may already know my preference: I like simple things! ;-)
I'm wishing to discuss. Come on, participate.
I'm working for a draft implementation and I'll let you know whenever is ready.
Happy Swinging,
Antonio
|
Enviado por codecraig en septiembre 23, 2005 a las 01:53 PM CEST #
Yes, as you may know blogs.sun.com is still growing, these guys are building new great features in it. It seems we've been having trouble with uploads (during a few days I couldn't upload jar files, nor png files, etc.) and with comments too. These have been solved. Since the UITopics in java.net is under approval I'll release the source today for you to see.
Yes, Type II are the way to go. But maybe it's a long way, right? I'll think of it.
Cheers,<b/> Antonio
Enviado por Antonio en septiembre 23, 2005 a las 07:16 PM CEST #