|
@@ -0,0 +1,244 @@ |
|
|
|
|
|
<?xml version="1.0"?> |
|
|
|
|
|
<document> |
|
|
|
|
|
|
|
|
|
|
|
<properties> |
|
|
|
|
|
<index value="1"/> |
|
|
|
|
|
<author email="simeon@fitch.net">Simeon H. K. Fitch</author> |
|
|
|
|
|
<author email="christoph.wilhelms@t-online.de">Christoph Wilhelms</author> |
|
|
|
|
|
<title>Design Overview</title> |
|
|
|
|
|
</properties> |
|
|
|
|
|
|
|
|
|
|
|
<body> |
|
|
|
|
|
|
|
|
|
|
|
<section name="Introduction"> |
|
|
|
|
|
<p>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 |
|
|
|
|
|
;-) |
|
|
|
|
|
</p> |
|
|
|
|
|
</section> |
|
|
|
|
|
|
|
|
|
|
|
<section name="Overview"> |
|
|
|
|
|
<p>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. |
|
|
|
|
|
</p> |
|
|
|
|
|
<p>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. |
|
|
|
|
|
</p> |
|
|
|
|
|
<p>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. |
|
|
|
|
|
</p> |
|
|
|
|
|
<p>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 <code>EventBus</code> |
|
|
|
|
|
</p> |
|
|
|
|
|
</section> |
|
|
|
|
|
<section name="Antidote Component Architecture/Event Bus"> |
|
|
|
|
|
<source> |
|
|
|
|
|
+---------------+ +----------------+ +-------------+ +-------------+<br/> |
|
|
|
|
|
| | | | | | | |<br/> |
|
|
|
|
|
| ActionManager | | EventResponder | | AntModule | | AntModule |<br/> |
|
|
|
|
|
| | | | |(ProjectNav) | |(SourceEdit) |<br/> |
|
|
|
|
|
+---------------+ +----------------+ +-------------+ +-------------+<br/> |
|
|
|
|
|
| ^ ^ ^<br/> |
|
|
|
|
|
| | | |<br/> |
|
|
|
|
|
ActionEvent EventObject AntEvent AntEvent<br/> |
|
|
|
|
|
| | | |<br/> |
|
|
|
|
|
v v v v<br/> |
|
|
|
|
|
/---------------------------------------------------------------------\<br/> |
|
|
|
|
|
/ \<br/> |
|
|
|
|
|
< EventBus ><br/> |
|
|
|
|
|
\ /<br/> |
|
|
|
|
|
\---------------------------------------------------------------------/<br/> |
|
|
|
|
|
| ^ ^ ^<br/> |
|
|
|
|
|
| | | |<br/> |
|
|
|
|
|
EventObject ChangeEvent BuildEvent EventObject<br/> |
|
|
|
|
|
| | | |<br/> |
|
|
|
|
|
v | | v<br/> |
|
|
|
|
|
+---------------+ +----------------+ +-------------+ +--------------+<br/> |
|
|
|
|
|
| | | | | | | |<br/> |
|
|
|
|
|
| Console | | ProjectProxy | | Ant | | (Your Module)|<br/> |
|
|
|
|
|
| | | | | | | |<br/> |
|
|
|
|
|
+---------------+ +----------------+ +-------------+ +--------------+ |
|
|
|
|
|
</source> |
|
|
|
|
|
<p>The backbone of the application is the <TT>EventBus</TT>. Any |
|
|
|
|
|
component of the application can post events to the |
|
|
|
|
|
<code>EventBus</code>. Components that wish to receive events are |
|
|
|
|
|
called <code>BusMember</code>s. |
|
|
|
|
|
</p> |
|
|
|
|
|
|
|
|
|
|
|
<p>The <code>EventBus</code> will dispatch any object of type |
|
|
|
|
|
<code>java.util.Event</code>, which means that Ant <code>BuildEvent</code> |
|
|
|
|
|
objects, as well as <code>AWTEvent</code> objects can be posted (if desired). A |
|
|
|
|
|
new class of events called <code>AntEvent</code> is defined for Antidote |
|
|
|
|
|
specific events, which have the additional capability of being |
|
|
|
|
|
cancelled mid-dispatch. |
|
|
|
|
|
</p> |
|
|
|
|
|
|
|
|
|
|
|
<p>Each <code>BusMember</code> must provide a <code>BusFilter</code> instance, |
|
|
|
|
|
which is the members' means of telling the bus which |
|
|
|
|
|
events it is interested in. This allows a <code>BusMember</code> to, |
|
|
|
|
|
say, only receive <code>AntEvent</code> objects. |
|
|
|
|
|
</p> |
|
|
|
|
|
|
|
|
|
|
|
<p>When a <code>BusMember</code> registers itself with the |
|
|
|
|
|
<code>EventBus</code>, it must provide a (so called) <i>interrupt |
|
|
|
|
|
level</i> which is a integer value defining a relative ordering |
|
|
|
|
|
for dispatching <code>EventObject</code>s to <code>BusMember</code>s. The |
|
|
|
|
|
purpose of this is to allow certain <code>BusMember</code> instances |
|
|
|
|
|
to see an event before others, and in the case of <code>AntEvent</code> |
|
|
|
|
|
objects, keep the event from propogating onward. The |
|
|
|
|
|
<code>EventBus</code> class defines the interrupt level constants |
|
|
|
|
|
<code>VETOING=1</code>, <code>MONITORING=5</code>, and <code>RESPONDING=10</code> to |
|
|
|
|
|
help define categories of members. The implied purpose being that: |
|
|
|
|
|
</p> |
|
|
|
|
|
<ul> |
|
|
|
|
|
|
|
|
|
|
|
<li><code>VETOING</code>: 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 |
|
|
|
|
|
<code>RESPONDING</code> group. |
|
|
|
|
|
</li> |
|
|
|
|
|
|
|
|
|
|
|
<li><code>MONITORING</code>: Just listens for events, like a logger |
|
|
|
|
|
or status monitor. |
|
|
|
|
|
</li> |
|
|
|
|
|
|
|
|
|
|
|
<li><code>RESPONDING</code>: Process events in a default manner, |
|
|
|
|
|
knowing that the event has passed any <code>VETOING</code> members. |
|
|
|
|
|
</li> |
|
|
|
|
|
|
|
|
|
|
|
</ul> |
|
|
|
|
|
|
|
|
|
|
|
<p>Within a specific interrupt level, the order in which members will |
|
|
|
|
|
receive events is undefied. A <code>BusMember</code> may be registered |
|
|
|
|
|
at a level that is +/- of one of the defined levels, as long as it |
|
|
|
|
|
follows the constraint <code>MONITORING <= interruptLevel <= |
|
|
|
|
|
MAX_INTERRUPT</code>. |
|
|
|
|
|
</p> |
|
|
|
|
|
</section> |
|
|
|
|
|
|
|
|
|
|
|
<section name="Actions and ActionManager"> |
|
|
|
|
|
<p>Extensive use of the <code>javax.swing.Action</code> interface is |
|
|
|
|
|
made for defining the set of menu and tool bar options that are |
|
|
|
|
|
available. The configuration file <code>action.properties</code> |
|
|
|
|
|
exists to define what should appear in the menu and toolbar, how |
|
|
|
|
|
it is displayed, and the <code>Action</code> command name that is |
|
|
|
|
|
dispatched when the user invokes that action. A class called |
|
|
|
|
|
<code>ActionManager</code> exists for not only processing the |
|
|
|
|
|
configuration file, but also for dispatching invoked action events |
|
|
|
|
|
to the <code>EventBus</code>, and for controlling the enabled state of |
|
|
|
|
|
an <code>Action</code>. When a new menu item or toolbar button is |
|
|
|
|
|
desired, first it is added to the <code>action.properties</code> file, |
|
|
|
|
|
and then the code to respond to it is added to the |
|
|
|
|
|
<code>EventResponder</code> (see below). |
|
|
|
|
|
</p> |
|
|
|
|
|
</section> |
|
|
|
|
|
<section name="Commands and EventResponder"> |
|
|
|
|
|
<p>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 <code>Command</code> interface is defined to classify |
|
|
|
|
|
code which performs some task or operation. This is distinct from |
|
|
|
|
|
an <code>Action</code>, which is a user request for an operation. A |
|
|
|
|
|
<code>Command</code> class is the encapsulation of the operation |
|
|
|
|
|
itself. |
|
|
|
|
|
</p> |
|
|
|
|
|
|
|
|
|
|
|
<p>When an <code>Action</code> generates an <code>ActionEvent</code>, the |
|
|
|
|
|
event is posted to the <code>EventBus</code> which delivers the event |
|
|
|
|
|
to all interested <code>BusMember</code>s. It eventually makes it to |
|
|
|
|
|
the <code>EventResponder</code> instance (registered at the |
|
|
|
|
|
<code>RESPONDING</code> interrupt level), which is responsible for |
|
|
|
|
|
translating specific events into <code>Command</code> objects, and |
|
|
|
|
|
then executing the <code>Command</code> object. For example, when the |
|
|
|
|
|
user selects the "Open..." menu option, an <code>ActionEvent</code> is |
|
|
|
|
|
generated by the Swing <code>MenuItem</code> class, which is then |
|
|
|
|
|
posted to the <code>EventBus</code> by the <code>ActionManager</code>. The |
|
|
|
|
|
<code>ActionEvent</code> is delivered to the <code>EventResponder</code>, |
|
|
|
|
|
which converts the <code>ActionEvent</code> into a <code>Command</code> |
|
|
|
|
|
instance. The <code>EventResponder</code> then calls the method |
|
|
|
|
|
<code>Command.execute()</code> to invoke the command (which displays a |
|
|
|
|
|
dialog for selecting a file to open). |
|
|
|
|
|
</p> |
|
|
|
|
|
|
|
|
|
|
|
<p>When adding new <code>Action</code>s or general tasks to the |
|
|
|
|
|
application, a <code>Command</code> object should be created to |
|
|
|
|
|
encapsulate the behavior. This includes most operations which |
|
|
|
|
|
modify the state of the data model. |
|
|
|
|
|
</p> |
|
|
|
|
|
|
|
|
|
|
|
<p>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. |
|
|
|
|
|
</p> |
|
|
|
|
|
</section> |
|
|
|
|
|
<section name="Data Model and Views"> |
|
|
|
|
|
<p><i>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 |
|
|
|
|
|
<code>org.apache.tools.ant.gui.acs</code> (where "<code>acs</code>" stands for "Ant Construction Set").</i> |
|
|
|
|
|
</p> |
|
|
|
|
|
</section> |
|
|
|
|
|
<section name="Application Context"> |
|
|
|
|
|
<p>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 <code>AppContext</code> is the catch-all |
|
|
|
|
|
class for containing the application state. Most modules and |
|
|
|
|
|
<code>Command</code> classes require an instance of the |
|
|
|
|
|
<code>AppContext</code> class. Because all state information in |
|
|
|
|
|
contained in an <code>AppContext</code> instance, multiple instances |
|
|
|
|
|
of Antidote can run inside the same JVM as long as each has it's |
|
|
|
|
|
own <code>AppContext</code>. (Interestingly, two instances of the |
|
|
|
|
|
Antidote could conceivably share an <code>AppContext</code> instance |
|
|
|
|
|
through RMI, allowing remote interaction/collaboration.) |
|
|
|
|
|
</p> |
|
|
|
|
|
</section> |
|
|
|
|
|
<section name="Configuration and ResourceManager"> |
|
|
|
|
|
<p>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 |
|
|
|
|
|
<code>antidote.properties</code>, which is located (with other UI |
|
|
|
|
|
resources) in the subpackage "resources". |
|
|
|
|
|
</p> |
|
|
|
|
|
|
|
|
|
|
|
<p>To aid in the lookup of text properties, as well as other |
|
|
|
|
|
resources like icons, a class called <code>ResourceManager</code> 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. |
|
|
|
|
|
</p> |
|
|
|
|
|
|
|
|
|
|
|
<p>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 "<code>org.apache.tools.ant.gui.About.message</code>" for the text |
|
|
|
|
|
message it should display. Therefore, the <code>ResourceManager</code> |
|
|
|
|
|
method <code>getString()</code> takes a <code>Class</code> instance as |
|
|
|
|
|
well as a <code>String</code> key. Please see the |
|
|
|
|
|
<code>ResourceManager</code> documentation for more information. Given |
|
|
|
|
|
this support, no user visible strings should appear in the source |
|
|
|
|
|
code itself. |
|
|
|
|
|
</p> |
|
|
|
|
|
</section> |
|
|
|
|
|
|
|
|
|
|
|
</body> |
|
|
|
|
|
</document> |
|
|
|
|
|
|