+ Design Overview+ |
+
+
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 modules 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/Event Bus |
+ +---------------+ +----------------+ +-------------+ +-------------+ + | | | | | | | | + | 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)| + | | | | | | | | + +---------------+ +----------------+ +-------------+ +--------------+ ++
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 BusMember
s.
+
The EventBus
will dispatch any object of type
+ java.util.Event
, 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 EventObject
s to BusMember
s. The
+ purpose of this is to allow certain BusMember
instances
+ to see an event before others, and in the case of AntEvent
+ objects, keep the event from propogating onward. The
+ EventBus
class defines the interrupt level constants
+ VETOING=1
, MONITORING=5
, and RESPONDING=10
to
+ help define categories of members. The implied purpose being that:
+
-
+
+
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. +
+
+ MONITORING
: Just listens for events, like a logger + or status monitor. +
+
+ RESPONDING
: Process events in a default manner, + knowing that the event has passed anyVETOING
members. +
+
+
Within a specific interrupt level, the order in which members will
+ receive events is undefied. A BusMember
may be registered
+ at a level that is +/- of one of the defined levels, as long as it
+ follows the constraint MONITORING <= interruptLevel <=
+ MAX_INTERRUPT
.
+
+
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 BusMember
s. 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 Action
s 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 |
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. Right now the data model is encapsulated in the package
+ org.apache.tools.ant.gui.acs
(where "acs
" stands for "Ant Construction Set").
+
+
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.
+