Antidites, I have completed a rough overview of my thoughts behind the architecture of the Antidote application, (attached below). It currently reflects the approach that is defined by the current source code. I'm interested in any thoughts or recommendations you might have.
Of particular concern to me (in terms of getting a discussion going) is the relationship between the GUI and the Ant "data model", as defined by the Project, Target, and Task classes. I believe that the GUI should rely heavily on these rather than "mirroring" them, but this gets into the issue of how much we should allow the GUI levy requirements on the Ant data model (or other Ant classes for that matter). For example, a data model for a GUI often supports the generation of "PropertyChangeEvent" objects whenever one of the data object's properties/state values changes. This allows multiple views to register interest in a sigle data object, and be gauranteed to be kept in sync with changes in the data. This is only one example of potentially many where the GUI needs to impose changes to the Ant data model, or instead mirror the data model in its own code base. Obviously there are pros and cons to both approaches, but that is why there needs to be a discussion here at some point on this. Hopefully this document should aid in allowing others to start contributing. The next thing I plan to do is start a TODO doc that should help define what initial efforts should focus on. Conor: would you mind checking this document into the jakarta-ant/src/antidote/docs directory? Thanks, Simeon ===== Mustard Seed Software mailto:[EMAIL PROTECTED] __________________________________________________ Do You Yahoo!? From homework help to love advice, Yahoo! Experts has your answer. http://experts.yahoo.com/Title: Antidote Design Overview
Antidote Design Overview
Version 0.1 (2000/11/02)
Authors: Simeon H.K. Fitch
Introduction
The purpose of this document is to communicate the overall structure and design patters used in Antidote, the GUI for Ant. This document is a work in progress, as well as a living document, and it is most likely not be in full synchronization with the source code. Therefore, if there is any doubt, view the source ;-)
Overview
The Antidote architecture design aims to provide a high level of modularity and extensibility. Ideally the components of Antidote will be able to be assembled in different configurations to provide the type of application or plug-in desired.
To acheive this modularity, a high level of decoupling is necessary. The standard UI design approach of providing separation of view (presentation) from model (data) is applied, leveraging the built-in Ant data model where possible, as well as the predifined Swing model interfaces. Furthermore, the architecture is highly event driven, whereby modules communicate via a shared communications channel.
To a large extent, the configuration of application modules is driven by localized configuration files, allowing new editors or data views to be added, as well as providing multi-language support.
The diagram below conveys a high altitude view of the
application's structure. As the application grows, new components
will be plugged in to what will be described as the EventBus.
Antidote Component Architecture
+---------------+ +----------------+ +-------------+ +-------------+
| | | | | | | |
| ActionManager | | EventResponder | | AntEditor | | AntEditor |
| | | | |(ProjectNav) | |(SourceEdit) |
+---------------+ +----------------+ +-------------+ +-------------+
| ^ ^ ^
| | | |
ActionEvent EventObject AntEvent AntEvent
| | | |
v v v v
/---------------------------------------------------------------------\
/ \
< EventBus >
\ /
\---------------------------------------------------------------------/
| ^ ^ ^
| | | |
EventObject ChangeEvent BuildEvent EventObject
| | | |
v | | v
+---------------+ +----------------+ +-------------+ +--------------+
| | | | | | | |
| Console | | ProjectProxy | | Ant | | (Your Module)|
| | | | | | | |
+---------------+ +----------------+ +-------------+ +--------------+
Event Bus
The backbone of the application is the EventBus. Any component of the application can post events to the EventBus. Components that wish to receive events are called BusMembers.
The EventBus will dispatch any object of type java.util.EventBus, which means that Ant BuildEvent objects, as well as AWTEvent objects can be posted (if desired). A new class of events called AntEvent is defined for Antidote specific events, which have the additional capability of being cancelled mid-dispatch.
Each BusMember must provide a BusFilter instance, which is the members' means of telling the bus which events it is interested in. This allows a BusMember to, say, only receive AntEvent objects.
When a BusMember registers itself with the EventBus, it must provide a (so called) interrupt level which is a integer value defining a relative ordering for dispatching EventObjects to BusMembers. The purpose of this is to allow certain BusMember instances to see an event before others, and in the case of AntEventEventBus class defines the interrupt level constants MONITORING=1, VETOING=5, and RESPONDING=10 to help define categories of members. The implied purpose being that:
- MONITORING: Just listens for events, like a logger or status monitor.
- VETOING: Listens for certain types of events, and may process them in a non-default manner to determine if the event should be cancelled before being dispatched to the RESPONDING group. An example of this might be to handle a SaveAs event, whereby a VETOING member will check to see if the file exists, and ask the user if they are sure they want to overwrite the existing file. The SaveAs event could then be cancelled before the operation is executed.
- RESPONDING: Process events in a default manner, knowing that the event has passed any VETOING members.
Actions and ActionManager
Extensive use of the javax.swing.Action interface is made for defining the set of menu and tool bar options that are available. The configuration file action.properties exists to define what should appear in the menu and toolbar, how it is displayed, and the Action command name that is dispatched when the user invokes that action. A class called ActionManager exists for not only processing the configuration file, but also for dispatching invoked action events to the EventBus, and for controlling the enabled state of an Action. When a new menu item or toolbar button is desired, first it is added to the action.properties file, and then the code to respond to it is added to the EventResponder (see below).
Commands and EventResponder
At some point in the stages of event processing, an event may require the data model to be modified, or some other task be performed. The Command interface is defined to classify code which performs some task or operation. This is distinct from an Action, which is a user request for an operation. A Command class is the encapsulation of the operation itself.
When an Action generates an ActionEvent, the event is posted to the EventBus which delivers the event to all interested BusMembers. It eventually makes it to the EventResponder instance (registered at the RESPONDING interrupt level), which is responsible for translating specific events into Command objects, and then executing the Command object. For example, when the user selects the "Open..." menu option, an ActionEvent is generated by the Swing MenuItem class, which is then posted to the EventBus by the ActionManager. The ActionEvent is delivered to the EventResponder, which converts the ActionEvent into a Command instance. The EventResponder then calls the method Command.execute() to invoke the command (which displays a dialog for selecting a file to open).
When adding new Actions or general tasks to the application, a Command object should be created to encapsulate the behavior. This includes most operations which modify the state of the data model.
The purpose of this encapsulation is to allow the clean separation of making a request, and servicing a request. Due to various conditions in the application state, the actualy response to a request may change, as well as who services it. This design approach facilitates that.
Data Model and Views
The data model is mainly defined by the Ant application, primarily through the Project, Target, and Task classes.
However, Antidote defines the class ProjectProxy to act not only as a proxy to the real Project class, but also as creator of GUI views of the Project. A view is essentially a flyweight or data proxy; it provides an orgainizational perspective on the actual Project structure. For example, to render a JTree version of the Project, one would call the method ProjectProxy.getTreeModel(). Similarly, to get a Document version of the Project, the ProjectProxy,getDocument() method is used.
NB: This part of the architecture is not fleshed out very well. There needs to be a discussion of the degree to which the Antidote development should be able to impose changes on the Ant data model, and to what level that model should be mirrored in the Antidote code base. The coupling between them should be kept low, and at the same time changes to one should affect the other minimally. Still, features like property change events and bean introspection (or BeanInfo) may be needed to be added to the Ant data model. Having each view into the data go to the ProjectProxy for its data model may not be the best approach. In other words, lots of thought needs to occur here.
Application Context
In order to keep the coupling amoung application modules to a minimum, a single point of reference is needed for coordination and data sharing. The class AppContext is the catch-all class for containing the application state. Most modules and Command classes require an instance of the AppContext class. Because all state information in contained in an AppContext instance, multiple instances of Antidote can run inside the same JVM as long as each has it's own AppContext. (Interestingly, two instances of the Antidote could conceivably share an AppContext instance through RMI, allowing remote interaction/collaboration.)
Configuration and ResourceManager
Full "i18n" support should be assumed in modern applications, and all user viewable strings should be defined in a configuration file. For Antidote this configuraiton file is antidote.properties, which is located (with other UI resources) in the subpackage "resources".
To aid in the lookup of text properties, as well as other resources like icons, a class called ResourceManager is defined. There are various convenience methods attached to this class, which will likely grow to make looking up configuration values as easy as possible.
The organization of configuration properties is based on the fully qualifed path of the class that requires the property. For example, the "about" box contains a messages, so it looks for the property "org.apache.tools.ant.gui.About.message" for the text message it should display. Therefore, the ResourceManager method getString() takes a Class instance as well as a String key. Please see the ResourceManager documentation for more information. Given this support, no user visible strings should appear in the source code itself.
