In this chapter, we present design rationales for a generic, object-oriented architecture for tools. Tools constructed according to this architecture will meet both end-user and environment builder requirements as discussed in Chapter 2. The architecture is based on using an object database. Documents are represented as subgraphs of a project-wide abstract syntax graph according to the discussions in Section 3.1. These abstract syntax graphs are stored in an object database according to the considerations in Section 4.4.
For the underlying notation for the architectural considerations in this chapter, we slightly modify1the concepts and the notation that have been suggested for the Groupie system [ES94].
They trace back to [Lew88]. As we are developing an object-oriented architecture, we only use abstract data type modules. Abstract data type modules are, moreover, used in a restricted way so that they only export one type with a set of operations. We, therefore, consider these modules as classes in the following chapters. The use relationship between classes is displayed as a solid arrow. Dashed arrows represent a special kind of use relationship which we denote as call-back relationship. Inheritance relationships are represented by dotted arrows. A class inheriting from another class is a subclass. Operations may be deferred in the sense that they must be redened in subclasses. A class that has a deferred operation is referred to as deferred class. Besides the exported operations, classes may also dene hidden operations. In a graphical depiction, classes are represented as rectangles. In order to deal with the complexity of this architecture and thus perform the discussion at several levels of abstraction, we use the concept of subsystems. A subsystem is graphically represented by a rectangle with an underlying shadow. At a higher-level of abstraction, subsystems represent a set of classes or even subsystems. In a subsystem's renement, some classes are declared to be exported by the subsystem. In the graphical notation, this is marked with a small black square in the upper left corner of the rectangle. The other classes are internal to the subsystem and cannot be used by subsystems or classes contained in other subsystems. Hence, the information hiding paradigm is applied not only to instance variables and operations contained in classes, but also at a more coarse-grained level to classes contained in subsystems. A use relationship between two subsystems means that classes in the source subsystem can import classes that are exported by the target subsystem.
1A more thorough investigation of these modications is provided in [Bay95].
Layout Computation Control uses calls−back subsystem Legend: class UserInterface UIMS ODBS ToolSpecific Services Message Router Interface Tool Kernel Tool Schema SoftwareProcess Communication Protocol Tool API Command Execution
Figure 5.1: Architecture of Tools based on Object Databases
Figure 5.1 displays a rst overview of the tool's architecture. We will rene it further in this chapter. TheToolSchema is a subsystem of classes dened in an object-oriented schema de-
nition language. These classes implement the structure and the available operations for those subgraphs of the project-wide abstract syntax graphs that represent documents, which are per- sistently stored in an object database. All other components will be implemented in C++. The
ToolAPI subsystem, therefore, provides the other components with a programming interface
to the schema. The LayoutComputation class arranges for textual or graphical representa-
tion of the abstract syntax graph. The CommandExecutionsubsystem is capable of computing
pop-up menus based on the current selection context and of executing a user's choice. The
UserInterfacesubsystem exports a number of tool-specic window classes, the construction
of which are based on a user interface management system (UIMS). The ToolKernelsubsystem
encapsulates the basic tool functionality. It can create new documents, open documents, delete documents, keep track of the currently opened editors, create pop-up menus and arrange for command execution. Moreover, it uses the transaction mechanism exported by ODBSin order
to preserve integrity and execute commands concurrently. The ToolSpecificServices class
exports operations that can be used to implement tool-specic services. It imports from a
SoftwareProcessCommunicationProtocolthat, in turn, uses an interface to a message router,
such as Sun ToolTalk. Finally, the Control class controls the tool execution and translates
various incoming events, such as user-input, requests of tool services or a deadlock in the database, into calls of operations exported by underlying components.
As discussed in Subsection 2.4, we are faced with the requirement of ecient tool generation. In order to meet this requirement, the tool architecture is constructed in such a way that a substantial number of components can be reused in arbitrary tools. During the course of this chapter, we will explain why each component can or cannot be reused. The distinction between reusable and tool-specic classes is shown in Figure 5.1. Rectangles representing reusable components are shaded in grey. If a subsystem does not only consist of reusable classes, it is only partly shaded in grey. In fact, the strategy to simplify tool construction based on reusing components is not new, but has been applied to earlier approaches to tool generation as well. Editors generated by the Centaur system, for instance, share a virtual tree processor, a user interface library and a rule interpreter [BCD+88].
5.1 Control
The architecture contains a number of external components, which we obtain from third party suppliers, which means that we cannot change them. These components are the UIMS, the ODBS and the MessageRouterInterface. These components need to interact with the internal
components of the architecture. They are not only called by internal components, but also need to call internal components.
Situations in which external components have to notify internal components about particular incidents are called events. The common way to implement them is to pass a call-back op- eration, as an argument, to a registration operation supplied by the external component and thus associate the call-back with the event. If the external component detects the event, the registered operation is called back.
From an architectural point of view, the relationship between an external component and a call-back operation could be considered as a use-relationship, since the external component uses the call-back operation when an event is detected. The immediate consequence, however, is cyclic use-relationships, which should be avoided. These cause problems, for instance, during the determination of an order for compiling components when the components depend on each other.
We, therefore, mark those usages that lead to cyclic use-relationships explicitly as call-back relationships and only use them with external components, i.e. when they cannot be avoided. Thus, the use-relationship between all internal architecture components remains acyclic. In addition, we declare all the call-back operations within a single class so that call-backs are not distributed over the whole architecture. This class is the Control class.
For reasons that will become clear in Section 5.5, there are events that are caused by user-input and are detected by the UIMS. Some of these events cannot be handled by the UIMS but have
to be communicated to higher-level architecture components. Therefore, we require call-back operations for reaction to user-input events in the Control class.
Most ODBSs follow a two-phase lock protocol. As already discussed in Section 3.6, this protocol may cause a transaction to wait for the completion of another concurrent transaction. Furthermore, it is not deadlock-free. These situations are detected as events by the ODBS system. If these events occur, an operation of the Control class will be called back. This
operation can then invoke operations exported by theToolKernelsubsystem in order to notify
If a service is requested from a tool, this request will be detected as an event by the message router interface. It then invokes a call-back in the Control class. This operation investigates
the request to see whether the requested service is generic or tool-specic. If it is a generic service such as creating a document, deriving a version or opening a document in an editor, it will call operations exported by the ToolKernelsubsystem. If the requested service is tool-
specic, it will call an operation exported by ToolSpecificServices, which implements the
particular service.
5.2 Tool Kernel
As discussed in Subsection 2.2.2, a user may want to display or edit multiple documents simultaneously. A tool must, therefore, be seen as a number of editors, each of which is used to display or edit one opened document. One of the purposes of the ToolKernel subsystem,
is to meet this requirement by managing the set of editors that are displayed by the tool. Furthermore, theToolKernelsubsystem implements the command execution cycle as discussed
in Figure 3.4 on Page 31. In doing so, it oers operations to theControl class that are used
for reacting to user-input as well as to service requests. Finally, it oers an operation to the
Control class for reacting to events detected by the database engine. All these tasks remain
the same for arbitrary tools. Therefore, the whole ToolKernel subsystem is constructed in
such a way that it can be reused among arbitrary tools and it is included in our reuse library.