|
- <?xml version="1.0"?>
- <!--
- Copyright 2003-2004 The Apache Software Foundation
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
- <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 achieve 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
- predefined 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 <code>EventBus</code>. 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
- canceled 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 propagating 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 canceled 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 undefined. 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 actually 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 among 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 configuration file is
- <code>antidote.properties</code>, which is located (with other UI
- resources) in the sub-package "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 qualified 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>
|