|
Before rushing into the actual implementation I'd like to show you a 10000 feet view of the bus. Just in case you want to give some feedback/suggestions. What I am thinking of is something like this (click to enlarge):
So basically there're three parts:
- View: formed by the macro-components and, possibly, some "actuators" (more on this later).
- Controller: formed by the mediators. Contains the business logic. Has read/write access to
the model. Receives events from the components through the bus (component-events), through specific topics (XXX-event). Sends commands (application events) to the bus through specific topis (XXX-command)
Does not contain any instances of the view.
- Model: formed by data (current clipboard contents, currently selected file, whatever).
So what I am thinking of is something like this:
- 1. Components send components through their specific topics towards the controllers.
- 2. Controllers coordinate component events. May veto (discard) events depending on the
model. Controllers may modify the model.
- 3. Controllers create and send application events (commands) through specific channels in the bus. These events are business specific and need not be related to components.
- 4. Actuators receive application components from the bus and modify the view accordingly. These actuators are the only responsible for holding instances to components.
From my point of view controllers are what we've called "Type II aggregators" (no instances to the view, no dynamic dependencies) whereas actuators are "Type I aggregators" (instances to the view, dynamic dependencies).
(Well, I hope I've made myself clear. If not then just email me!)
Doubts, design decissions, help appreciated
- Vetoing. Shall we need actual vetoing of events? I think it's enough if controllers just ignore/react
to events depending on the model. Can you think of an example where I could need vetoing for events? Tim, any idea about this?
- No component-controller dynamic (runtime) dependencies. With the approach above I think we have dynamic decoupling of components and controllers. What I mean is that we don't need macro-components instantiated before controllers are instantiated. If components are absent then there's no problem for controllers. Controllers may be instantiated independently of components. This is right I think (am I right here?)
- Component-controller static (compile-time) dependencies. In order to compile the controllers I'll need to have component events in place. This is, there's a static dependency between components and controllers. I don't think this is an issue, unless you need to compile controllers and components independently. I can't think a reason why these static dependencies are an issue. Any scenarios you can think of?
(Diagrams are here, OpenOffice/StarOffice, 9Kb, right-click/Save As... to download).
Thanks for any ideas!
Antonio
|
Pending I can wrap my brain around it sometime soon, I'll say something... If its intelligent or not, thats to be seen! ;)
Enviado por Jeffrey Olson en septiembre 28, 2005 a las 12:02 AM CEST #
Enviado por Patrick Wright en septiembre 28, 2005 a las 11:05 AM CEST #
Enviado por Mark Murphy en septiembre 28, 2005 a las 12:06 PM CEST #
Thanks all for your comments. Some ideas that come to my mind.
InfoBus: Yes, we're aware of that. There're different event bus frameworks/examples we'be seen around: antidote, infobus, somnifugi, werx and elf.
Vetoing: Assume there's a WindowClosing event coming from the MainWindow macro-component (or an ActionEvent coming from the File/Exit menu in a MenuBar). These events are received by a ClosingMediator. Now, that ClosingMediator is able to see the model, see if any file is still not saved and, if so, ask the user for further info. If the user agrees to save without saving then a ApplicationExitEvent is sent to actuators. No vetoing needed, right? I mean, it's the controller mediators those responsible for vetoing (after all they contain the business logic). The decission on whether to save or not is contained in the controllers, not in the views, so there's no reason to implement vetoing in the actuators. Don't you think?
Deciding what is a macro-component. I'd say a macro-component is an isolated, independent component in the application. A "FileSystemViewer" may be a macro-component, but a service to talk SOAP to an external site may be a macro-component as well. It may or may not be a view. The level of granularity for macro-components is a design-time decission. Macro-components may be, of course, some other "applications" (possibly containing event buses themselves as well). To summarize: I'd define a macro-component as a component (visual or not) that is able to send events and receive commands. Now fit whatever you need in there.
Thanks!!
Antonio
Enviado por Antonio en septiembre 28, 2005 a las 01:20 PM CEST #
Enviado por Nicola Ken Barozzi en septiembre 28, 2005 a las 01:21 PM CEST #
Enviado por codecraig en septiembre 28, 2005 a las 02:29 PM CEST #
The idea of vetoing will come into play, I believe, because of the two situations when the Controller or Action needs to know whether of not an event (a command event) was successful.
1. When the user or state of the system (or component) precludes the completion of an event.
The first case could be a result of a user interaction. The scenario of the application closing (or opening a new file while an existing file needs saving) shows this.
Handling the Save functionality in the Closing Mediator doesn't seem the correct place, considering you will have to save during operations such as: OpenFile, NewFile?, SaveFile, and WindowClosing, etc..., and we would want to reuse code as much as possible (hence the idea of creating individual events)
WindowClosing would require you to send a saveEvent and if successful a closEvent to close the file, and then an AppExit event. For OpenFile you would have saveEvent, closeEvent, openEvent. A sequence of events will have to occur in an action or in a mediator, which may need to send events to other mediators in order to complete successfully. Either way, I think, you will have to have veto for flow control in an action or mediator. Actions and mediators are aggregators of command sequences.
2. An error while processing the event
The second example is if an error occurs while saving. Say you click the File Open action, you first command is saveFile for the existing file and it fails for some IO reason. I don't think you would want to discard changes to the file and press on. You would want to let the Action or mediator that fired savFile know not to continue with it's sequence of events (FileOpen). Make sense, or did I go off the deep end? Tim
Enviado por TIm Osten en septiembre 28, 2005 a las 03:13 PM CEST #
Enviado por Nascif A. Abousalh Neto en septiembre 28, 2005 a las 04:41 PM CEST #
Enviado por Jeffrey Olson en septiembre 28, 2005 a las 05:00 PM CEST #
When sending a command event (a directive event) we could always send the event async, then wait for the appropriate State Event to inform us as to the result of the command.
Send FILE.OPEN
Wait for FILE.OPENED or a (vetoish?) event with a reason (USER_CANCELLATION, ERROR, etc...) describing what happened so we can determine whether the next course of action.
When sending a state event (informative event) I think we could just send the event asnc as well.
Now we have all of our events being sent asynchronously and we only listen (synchronously or pseudo synchronously in the case of the EDT) for command events! I was against this at first because of the wait after Command events, but since we can deliver all of our events async that seems like decent tradeoff.
???
Tim
Enviado por 192.132.24.81 en septiembre 28, 2005 a las 05:44 PM CEST #
I thought event consumers would be notified using a callback like a generic Swing event listener. Should each event consumer have its own event queue? That would mean also a separate thread per consumer, instead of just one additional thread for the TopicManager queue. Perhaps we can have both...
Enviado por Nascif A. Abousalh Neto en septiembre 28, 2005 a las 11:41 PM CEST #