JOHANNES KEPLER UNIVERSITÄT LINZ INSTITUT FÜR WIRTSCHAFTSINFORMATIK CD-LABOR FÜR SOFTWARE ENGINEERING
Software Engineering
O. UNIV.-PROF. DR. G. POMBERGER
R. Weinreich
A Component Framework for Direct-Manipulation Editors
Copyright Copyright 1998 IEEE. Published in the Proceedings of TOOLS-25’97, November 24-28,1997 in Melbourne, Australia. Personal use of this material is permitted. However, permission to reprint/republish this material for advertising or promotional purposes or for creating new collective works for resale or redistribution to servers or lists, or to reuse any copyrighted component of this work in other works, must be obtained from the IEEE. Contact: Manager, Copyrights and Permissions / IEEE Service Center / 445 Hoes Lane / P.O. Box 1331 / Piscataway, NJ 08855-1331, USA. Telephone: + Intl. 908-562-3966.
TR-SE 97.16
A Component Framework for Direct-Manipulation Editors
Rainer Weinreich Institut für Wirtschaftsinformatik C. Doppler Laboratory for Software Engineering Johannes Kepler Universität Linz, A-4040 Linz, Austria
[email protected]
Abstract Object-oriented software technology has some significant flaws that are addressed with component technology. The foundations of software component technology and the possible and useful kinds of software composition are still an open issue of ongoing research. After a clarification of important issues of component technology and component composition, we present an object-oriented component framework that was developed to serve as the basis for an adaptable software development environment. The framework supports the construction of applications with a direct-manipulation user interface (especially graphic editors) and a code-generation back-end. It uses a trading mechanism for component integration at run time, facilitates the separation of component adaptation and component composition, and incorporates an architecture that supports system evolution to a certain degree.
1: Introduction and overview Object technology (OT) has significantly improved software construction and is the basic technology for state-of-the-art software. The most often cited benefits of OT are increased extensibility and reusability [1]. These benefits are usually associated with the basic concepts that make a language object-oriented: data abstraction, inheritance and polymorphism. Since concepts like inheritance allow the construction of semi-finished programs and program parts (frameworks), they are sometimes even said to be the key to reuse (see, e.g., [2]). Although reuse is a main emphasis of OT, a global software market as envisioned by Cox [3], where software “components” in the form of objects and classes are traded, has failed to become reality with this technology (yet). Instead, other approaches, like the VBX technology provided by Microsoft, have succeeded [4]. This has lead to the introduction of a component-based software technology. The foundations of this technology and the possible and useful kinds of software composition are still the subjects of ongoing research. In the next section we present our perception of the term software component and relate it to object technology. In Section 3 we provide an overview of different kinds of component composition and discuss component frameworks. In Section 4 we describe the main principles of a component framework for editors with a graphical, directmanipulation user interface. The description includes the architecture of the framework, the types of components supported, the mechanism used for component composition and management, and the kinds of component interfaces.
2: Software components The word component denotes a part of something [5]. This is very general and may be the reason for the still vague and diverse descriptions of software components in many publications. For example, in the Dictionary of Object Technology [6] a component is described very generally as a “reusable entity”. Nierstrasz [7] and Sametinger [8] also provide general definitions of components that include mixins, macros, functions, templates, modules, etc. as valid examples of software components. Following the example of “component-based” environments like VisualBasic, central characteristics of components that are often mentioned are properties, an event mechanism, scripting and the use of a visual builder tool for component composition. An example of this point of view is the JavaBeans™ specification, where a bean (which is a component in this model) is defined as a “reusable software component that can be manipulated visually in a builder tool” [9]. As we argue below, some of these features are an indication of the requirements on components, but they do not sufficiently describe what a component is and are no prerequisite for a componentbased environment. In order to describe the structure of and the requirements on software components, we must investigate why a global software market was not established using object technology. The reasons are both conceptual and technical in nature. One problem is the use of implementation inheritance as one of the basic reuse mechanisms in object-oriented libraries. This problem is twofold. Firstly, inheritance is a statically defined relationship that cannot be changed at run time; this sometimes prevents flexible component composition. Secondly, coupling two classes by means of implementation inheritance implicitly defines a contract between these classes [10]. On the one hand, subclasses usually rely on overridden methods to be called in a certain sequence from predefined template methods in their base class; changes to the implementation of the base class may break the contract with these subclasses. On the other hand, subclasses overriding template methods may also violate this contract and break the implementation of their superclass. (This problem is called the semantic fragile base class problem in [11] and [12].) We argue that methods of the base class that are intended for overriding may be viewed as an outgoing interface from the point of view of the base class; but this interface is implicitly and thus not clearly specified. For this reason a creator of a subclass usually needs to know the implementation and thus the source code of the base class in order to decide which method to override. The consequence is that software vendors are often forced to supply the source code in order to make integration possible on a source-code level. This may be one of the reasons why a global software market based on OT does not exist, because providing the source code means revealing the implementation know-how and proprietary secrets [13]. Thus software components have to be distributed in some form, e.g., in some binary format, that makes it very hard, or even impossible, to reconstruct the implementation know-how. However, shipping parts of software in a binary form raises other problems with many objectoriented languages. Due to an inflexible binary object model, changes to a base class often require recompilation of existing subclasses (and thus the availability of both the source code and the development tools used for creating the binaries). But the binary formats used by different compilers are not only inflexible but also inhomogeneous. Binaries of different languages and even binaries generated from the same language (but with different compilers) are incompatible [14]. A binary standard such as IBM’s SOM™ or Microsoft’s COM™ can be used to lessen the first and to solve the second problem. We view software components as parts of software in binary form intended for composition to other components and finally to whole applications. This requires interoperability standards
on a binary level. Implementation inheritance has to be avoided as a means for composition (although it may still be used for implementing components). Instead, the outgoing interfaces of a component have to be specified more clearly and incorporated in the design and construction process. Possible specifications are operation sets a component is able to use (called connection points in COM [15]) or descriptions of events a component is able to emit. To allow the composition of binary components, information about a component’s properties, incoming and outgoing interfaces, etc. (sometimes called meta-information) has to be provided to composition environments and component frameworks. Another important issue in a component-based system is the need for evolution support and version management. Such a system has to support the addition of new components, the removal of specific components, and the replacement of certain components by newer versions on a binary level (sometimes even at run time). The system has to deal with situations where a new version of a component no longer supports a certain functionality and where a component to be used is an old version that does not support a certain functionality yet. In other words, it has to perform validity checks that are performed by tools like compilers and linkers in non-component-based systems. Components, classes, objects and modules Components are sometimes related to objects or classes in the literature (e.g., [16]). From the above discussion follows that components are not objects (see also [12]). Like classes, components are program parts that may be used for creating objects and for defining an object’s interfaces and implementation. The main difference between a class and a component is that a class is a (language-specific) source-code entity, whereas a component is a binary program part. However, a component may be implemented with (usually multiple) classes. Both components and modules require clear specification of external dependencies. However, a component is not a module as used in languages like Modula-2, where a module is also a compilation unit. Components may be large and complex, and developing components thus requires division of labor and the ability to split up its source code into separately compilable units. This means that a component may be made up of several modules.
3: Component composition We mentioned above that implementation inheritance, which is used in most object-oriented frameworks, is not suited for component composition. Instead, composition takes place on the binary level and requires meta-information about a component’s interfaces and properties in order to support tools in component composition. Such meta-information is provided by type libraries in COM [17], interface/implementation repositories in CORBA-based environments [18], and introspection and dedicated info-classes in the JavaBeans environment [9]. We distinguish four means of component composition: • • • •
system languages scripting or glue languages visual programming component frameworks
Each of these approaches has advantages and disadvantages, and we consider all of them useful in combination.
According to Ousterhout [19], scripting languages (like VisualBasic and Tcl) are more appropriate for component composition than system languages (like C++, Pascal and Java). This is because scripting languages are intended for plugging components together and thus operate on a higher level of abstraction than system languages. The most important differences between system languages and scripting languages are that system languages are usually statically typed, compiled and more efficient, while scripting languages tend to be typeless, interpreted and more expressive since a single statement does more work on average (see[19]). Still on a higher level of abstraction than scripting languages are visual programming environments like IBM’s VisualAge™ [20]. Schiffer [21] identifies the lack of density and structure and the effort involved in applying graphic editing and layout operations as the main disadvantages of such environments. An in-depth discussion of the potential and limits of visual programming approaches is beyond the scope of this paper and can be found in [21]. The disadvantage of all of these approaches is that the glue code has to be written (or specified graphically) from scratch. This means that component composition needs an equivalent to object-oriented application frameworks, where the glue code between classes would be already predefined for a specific application domain. This equivalent is a component framework, which is a standard architecture for a specific domain where the interaction among components (more accurately, among objects that are created by means of components) is already predefined. There are significant differences between an object-oriented application framework and a component framework. The former is implemented in an object-oriented language; this is a possibility but not a must for the latter. An object-oriented framework is often customized by subclassing and overriding hook methods [2][22], while a component framework is customized by plugging in binary components. This composition on the source-code level makes an objectoriented framework language dependent, while the parts that are used for customizing a component framework may be implemented in different languages. A component framework is itself a component if it offers its functionality to clients by means of a clearly defined interface. In other words, a component that is customized by plugging in other components is actually a component framework (see also [12]). From this point of view, an application may be composed from components, which may be component frameworks that are customized using other components (which in turn may be component frameworks themselves, etc.).
4: The Combo framework One of the main emphases at the C. Doppler Laboratory for Software Engineering is research in tool support for developing object-oriented software. The component framework that is presented in the following was implemented to serve as the basis for an adaptable development environment named the Framework Architecture Assistent. This environment is intended to facilitate the visualization and manipulation of framework-based, object-oriented architectures. Since graphical editing functionality is important in this environment, the component framework supports the implementation of applications where data are edited graphically by means of direct manipulation. Examples of applications to be supported are graphical desktops, E/R editors, vector drawing programs and user-interface builders. The framework is called Combo (short for Composition Board) and was implemented in C++ based on the object-oriented application framework ET++ [23]. Thus it lacks some fundamental characteristics of a general component system because its object model is limited to the object model defined by C++/ET++. However, it incorporates a component-ready design and we use clearly defined incoming- and outgoing-interfaces instead of implementation inheritance for component composition. The primary customization technique used in the framework is plug-
ging in of binary components. The selection of an appropriate component for a specific task is performed by means of a trading mechanism at run time (see Section 4.3). In the following section we give an overview of the basic functionality and structure of the framework and of its main components. In Section 4.2 we describe how components are represented and outline the kinds of interfaces that are supported by components. In Section 4.3 we concentrate on component selection and object creation, which is performed by means of component managers. Finally, we provide examples of applications that were implemented using the framework in Section 4.4 and present related work in Section 4.5. 4.1: Basic functionality and architecture The Combo framework provides basic functionality for directly manipulating elements in a drawing view. This includes drag and drop functionality, cut, copy, paste, alignment, grouping, etc. Most of the functionality that is associated with these operations is not part of the basic component framework (or framework component), but is provided by plugable components. The basic components that are to be plugged into the framework are depicted in Figure 1. The relationships that are illustrated in this figure are relations between components, not objects. An arrow with a filled circle denotes a one-to-many relation, an arrow without circle a one-to-one relation. For example, a Combo application may consist of one component implementing the domain model, but of many visualizer components. Concrete components are gray, e.g., an operation for editing properties of objects that are displayed in the drawing view. Combo
Model
Visualizers
Direct Manipulation Editors
Menu Operations
Drag&Drop Operations
...
Align Edit Properties...
Domain Object Components
Property Sheets
Generate Code...
Code Generators
Figure 1: Basic components of Combo The diagram in Figure 1 is not complete. We describe further important components together with component management in the next section. The components depicted in Figure 1 are: • • • • • •
the domain model that is to be manipulated the components representing the objects of the domain model visualizers to display the domain objects editors to directly manipulate visualized objects drag and drop operations operations on visualized objects that are activated by means of menus, like displaying properties and generating code • operation-specific components like property sheets (for a “display properties” operation) and code generators (for a “generate code” operation)
The domain model manages the objects of the problem domain, maintains semantic dependencies between these objects, and ensures data consistency. A domain model may be simple: for example, a collection of graphic objects in a drawing editor. An editor for visually manipulating the architecture of an application requires a more complex model that ensures the validity of operations on this architecture. Another set of components represents the objects of a problem domain. For a file manager these are folders, aliases and files; for a user interface builder these are buttons, sliders, checkboxes, etc.; for an application builder the domain objects are the parts of the application. Visualizers are used to display domain objects in a drawing view. The relation between an object and its visualizer(s) is not defined statically in source code. Instead, the environment checks at run time whether an appropriate visualizer component exists. The availability of such a component is checked using the component manager that is described in the next section. Visualized objects may be edited by means of direct manipulation (dm). If a displayed object is selected using a special key combination, a dm-editor component is searched for that allows editing the selected object. If an appropriate dm-editor is found, it is installed invisibly for the user upon selection of the object and de-installed after editing is finished. There may exist dmeditor components that are more general and that are able to edit a number of different visualized objects and more specialized ones for specific objects. The framework uses a best-match strategy to select the most appropriate one. If it is not able to decide which component matches best, either one is taken randomly or the task is delegated to the user by means of pop-up menus and dialogs. Visualized objects can be dragged and dropped within a view or from one view to another. If a dragged object is dropped onto a view or onto another object (e.g., a file onto a folder), a drag&drop-operation component is searched for that is able to perform the associated operation on the model. Another set of components that are handled by the core framework are operations that are initiated by means of menus. Such operations include displaying the properties of a selected object, generating code for a selected object, etc. The framework collects all available operations of this kind and displays them as menu items. Some of the supplied operation components are (small) component frameworks themselves. An example is a plugable “Properties...” operation, which provides the functionality for editing the properties of an object. This component collects all property sheets that are able to edit the properties of the selected visualized object and displays them in a tabbed dialog. Evolution support System evolution is supported implicitly through the trading mechanism, which tolerates certain changes without a need for rebuilding the system. The system will simply not find components with a new interface, unless intended clients know the new interface. For example, all components implementing property sheets offer a property-sheet interface1 that is addressed by the plugable “Properties...” operation. If newer property sheets with a new interface are provided, the framework will not be affected since the sheets are collected using the trading mechanism. However, all property-sheet components offering the new interface will not be found and thus cannot be used (since the “Properties...” operation searches for property sheets offering the old interface). 1 An interface describes a set of semantically related operations defined by a component, but reveals nothing of their implementation. In the remainder of this paper, we mean such a description consisting of operation signatures (names and parameters) when using the term interface.
Thus evolution is also supported explicitly through the architecture of the framework. Operation-specific components like property sheets are decoupled from the basic framework and only addressed by the operation component itself, which leads to a hierarchical (tree-like) architecture of interface dependencies among components. The interfaces of components that are nearer to the root are kept simpler than the interfaces of components that are nearer to the leaves of this structure and thus are less likely to change (see Figure 2).
Property Sheet Properties ... Operation
Figure 2: Hierarchical component dependencies. A design guideline is to keep the interfaces of components nearer to the root of this structure simpler, i.e., fewer operations, than those of components that are nearer to the leaves of the structure.
Again, we take the implementation of the property sheet mechanism in our framework as an example. In order to use components that implement property sheets but offer a new interface, existing client components like the “Properties...” operation can be replaced by a new implementation that is able to use the new interface (or both the old and the new interface). The “Properties...” operation component supports a more general and simpler interface (in this case an interface for managing operations in menus) that is less likely to change in our framework. 4.2: Component representation A component in Combo is usually implemented as a set of C++ classes that are packed to one binary unit. This corresponds to the notion of a subsystem as described by Wirfs-Brock et. al. [24]. One way to implement the interface to a subsystem is to use a class or an abstract class, as described by the Facade pattern [22]. For reasons of flexibility and support of system evolution, we have used a mechanism similar to COM. A Combo component may offer not only one interface, but several interfaces that may in addition be implemented as separate components representing role-specific, exchangeable behavior (see [25] for a discussion of roles in object-oriented systems). In addition to client interfaces, a Combo component may provide one or more outgoing interfaces. A general event notification interface is used as a generic outgoing interface. Both client interfaces and outgoing interfaces as well as component properties can be queried at run time as described in the next section. To support composition environments (including component frameworks), it makes sense to classify component interfaces on a meta-level. For example, it is useful to distinguish between interfaces that are used for finding components, for adapting components, for creating objects, etc. We provide dedicated client interfaces for these tasks as described in the next section.
4.3: Component management The selection of appropriate components for certain tasks at run time is performed by component managers. A component manager uses meta-information obtained from manager-specific configuration files and from the components themselves to find components and create component instances. Component selection The framework provides a standard component manager, which is always the one that is accessed by clients using the Component Manager Interface (see Figure 3). The component manager searches for components that • support a specific client interface, • have certain properties, or • are able to deal with an object or a set of objects. The query for a specific client interface is independent of a specific class or type hierarchy and thus independent of specific language characteristics. Instead of testing whether a component “is a” certain abstraction (the is-a query is used in many object-oriented languages), we ask a component whether it is able to act as a certain abstraction at a specific time. Properties that can be queried are not values of the instance variables of objects—since objects are not components—but characteristics of components and thus have nothing to do with the “Properties...” operation and the property sheets that were described in the previous section. Examples of component properties are mapping decisions [26], quality of service specifications [27] (like performance, e.g., in terms of time complexity, and reliability) and communication protocols that are not expressed in the component interface. Currently component properties are simply specified using ASCII strings for property names and values. A component manager may also search for a component that is able to deal with a specific object or a set of objects. In this case, the system checks whether the outgoing interfaces of the component match the client interfaces of the supplied parameters. In addition, properties of the parameter objects (which can be seen as an extended specification) may influence the selection of an appropriate component. Component Manager Interface
Binding Interfac e Std. Component Manager Specialized Managers
Client
Component
Creation Interface
Client Interface 1
Client Interface n
Figure 3: Component managers and interfaces The interface of the component manager offers three main methods that can be used to search for a component based on the above criteria: FindProvider, FindBestProvider and FindAllProviders. The
parameters of these methods are query objects, which may consist of objects specifying required interfaces, properties and abilities. Currently the framework supports only simple compound queries. In addition, the manager supports component categories, which can be used as an additional search criterion. For example, a call to FindAllProviders(&Interface (“MenuOperation”))) returns all components that support the MenuOperation interface. A call to FindAllProviders(&CompoundQuery(&Interface(“PropertySheet”), &Ability(anObject))) returns all property sheets that are able to display the properties of the object anObject. (In fact, components are returned that are able to create or supply instances of components that match the specified criteria). The component manager uses a Binding Interface to query components about their properties and capabilities (see Figure 3). The Binding Interface may also be used to obtain a suitability rate that is used by the manager to select the most appropriate component for a specific task. The Binding Interface may either be implemented by the component itself or by an additional binding component. How it is implemented is completely transparent (invisible) to the component manager, which queries all components that offer a Binding Interface (whether this is the component itself or an extra binding component). The implementation of this interface as an extra (role) component bears the advantage of separating the binding decision from a component and thus allows exchanging the componentspecific binding strategy. The implementation of such a role roughly corresponds to the Extension Object pattern described by Helm and Gamma [28]. Object creation The result of the query process is a component that can create instances of the queried component by means of a Creation Interface. Again, this interface may be implemented by the queried component itself or by a separate factory component. Decoupling object creation and initialization from component implementation by means of factories allows changing the creation strategy or supplying new default values for initialization. Combo supports several ways to supply data needed for instance initialization: • Data can be supplied as an additional parameter to a Create method that is part of the Creation Interface. This corresponds to an extensible factory as described in [22]. • Data can be embedded in a factory component. This allows separating object initialization code from component composition (i.e., framework) code. There may exist multiple factory components that are able to create instances of one specific component and that contain different initialization and creation code. A factory component may contain initialization data hard-wired in its code, or it may load these data from an external medium (e.g., a file). Factory components that are used this way are similar to the concept of a moniker used in COM/OLE/ActiveX [13]. How object creation is performed—by means of the component itself or by means of a factory component—is a matter of flexibility but does not affect the Creation Interface and thus not the clients of the component manager. A client always first calls one of the Find*Provider methods and then uses the Creation Interface for object creation. Sometimes it suffices or must be ensured that only one instance of a component is created (in [22] the singleton pattern is used for this purpose). This is also supported transparently by the components implementing the Creation Interface. A singleton is only created the first time Create is called. Each subsequent call to Create returns the same unique instance.
Changing the component management Component managers are (plugable) components themselves. For different types of components different component managers can be used that employ different strategies for selecting components and creating instances. When a client accesses the component management interface, the standard component manager first looks for a dedicated component manager for the requested component. A specialized manager may load components from another network location, implement another strategy for selecting components, or even rely on interfaces other than the standard binding and creation interfaces. 4.4: Application examples The Combo framework was first used for the implementation of a user interface builder [29] and afterwards for implementing a prototype of the adaptable development environment [30] mentioned in the introduction to Section 4. Both applications were used to redesign and extend the framework considerably.
Figure 4: A Combo-based user interface builder. The largest window serves as the tool palette, which was generated by a special operation plug-in. The menus and the property dialogs are built at run time based on the available components. The bottom window shows that the user interface elements are fully functional in edit mode also.
The user interface editor is depicted in Figure 4. The component set of this tool includes visualizers and direct-manipulation editors for user interface elements. It offers no standard tool palette. Instead it contains an operation plug-in that creates a tool palette from the set of user interface elements added to the configuration in the current view. In addition, the editor includes a number of property sheets and code generators for user interface elements. The editor can be customized at run time using a “Load Package” operation plug-in. Figure 5 gives an impression of the first version of the tool for visualizing and manipulating framework architectures. The tool uses the desktop metaphor for visualizing the structure of an application framework. The idea is to let a framework supplier predefine templates for various
kinds of applications based on the framework and supply editing tools for dedicated framework parts. Such a predefined structure is modified and extended by application developers, who use the architecture editor in addition to other source-code based browsing and editing tools.
Figure 5: Visualization of an architecture using the desktop metaphor. The examined application (left window) consists of a number of different documents (bottom window). The structure and responsibilities of a document are displayed in the foremost window. Each of the icons in this window represents a part of the application or a responsibility that can be edited with dynamically selected plug-in editors.
The visualizers that are used in the architecture assistent are simple and only draw iconic representations of the various parts of a framework. Currently only one dedicated direct-manipulation editor is used; it allows editing names of the displayed elements. The domain model that the tool uses is more complex since it has to check the validity of operations on a specific framework architecture. The main plug-in components that are provided are special editors for the visualized parts of a framework and components maintaining links to other development tools (e.g., SNiFF+ [31]). These editors range from simple dialogs to highly graphical editors. For example, opening the “Layout of ...” item may either open a user interface builder (if available), or simply display the source code for defining the layout of the window. Parts of the component management mechanism of Combo are also integrated in a framework for distributed applications [32], where it is used for finding appropriate communication services and application proxies at run time. 4.5: Related work The idea of component selection by means of properties and capability to deliver a service is also supported in distributed infrastructures like ODP [33] and CORBA [18]. The ODP trading function [34] and the CORBA trading service [35] are specified in technical alignment and provide similar functionality. In both approaches a trader stores exported service offers, which contain the characteristics of a service in terms of capabilities (called service properties) and the location of an interface at which the service is available. A client (called importer) may issue a service request to the trader and search the database of service offers. Instead of storing service offers, we manage references to the components providing services. The components are able to answer requests for the support of a particular service at a given time themselves. This is similar to an alternative approach to the CORBA trading service as described in [36]. In addition to queries for properties and incoming interfaces, queries for capabilities or outgoing interfaces are important in our approach.
Both ODP and OMG traders allow a client to specify search policies, which is especially important if interworking traders are used. In addition, preferences for the return order of matching services (best matching first, last or random) can be specified for each search. In our approach, different search strategies can be realized by using special managers that can be plugged in transparently to the client. The standard component manager also optimizes searching by organizing components internally by interface. (Components with multiple interfaces are present in different sets at the same time.) Selection strategies (all, best, random) can be specified by using different methods for issuing search requests as described in Section 4.3. In object-oriented environments object creation based on abstract interfaces and specifications can also be found (e.g., [37], [38], [39]). Most of the approaches in this area are relying on metainformation extracted from class hierarchies. We used a simple trader of this kind for dynamically selecting proper communication services in a framework for distributed process control and called it abstraction-based object creation in [37]. A more sophisticated implementation is presented in [40], where trading is used for associating materials to be worked on with tools to be used in a framework that is based on the tools and materials metaphor [41]. The use of trading in object-oriented systems is exemplified as a design pattern in [38]. The trading mechanism described in this paper differs from these approaches in several aspects. First, the design of our trader is component-oriented, which means that it is based on the support of interfaces and not on class hierarchies. While inheritance, especially from a pure abstract class, also means the support of a specific interface, this is only the case in objectoriented systems. In a component-based system it is important which interfaces are supported, no matter how this is implemented. Therefore the design of our system is not based on the availability of a mechanism for traversing class hierarchies but on the ability of each component to answer requests for specific incoming and outgoing interfaces as well as properties. Another difference is that the component manager presented in this paper is not only used for finding components and creating objects but also (transparently to clients) for managing the created objects. On each create request, a component (or the corresponding factory) decides whether to create a new object or whether to (re)use an already existing object. This especially makes sense for components defining objects with no state or extrinsic state. Examples are components objectifying behavior, like code generators in our framework. Instances of such components can be shared by a number of clients. The component manager also supports reference counting, which is important for determining whether components can be unloaded or not. In addition, our environment provides configuration support. As described in Section 4.3, optimizations and change of search strategies are possible by supplying specialized manager components as plug-ins. The standard manager also supports configuration-specific attributes for components. These are not properties of a component, but attributes that are attached by a person configuring the system. For example, the attributes “advanced” or “standard” may be attached to individual components implementing property sheets, thus allowing control of the degree of functionality offered to a specific user. A final important point is the clear distinction of properties and incoming and outgoing interfaces that is present in our approach. Apart from the trading mechanism, the component framework used for displaying property dialogs and property sheets for specific objects can be compared to similar mechanisms in JavaBeans [9] and ActiveX [13]. Like JavaBeans, we provide simple editors for basic data types (numbers, strings, etc.). Unlike JavaBeans, property dialogs are not created automatically using reflection and conventions for property access operations. Instead, a property sheet has to be programmed using a small framework that makes creating property sheets easy. We do not think that this is a drawback. The layout and naming of dialog fields that is created by the reflectionbased mechanism in JavaBeans is inelegant and clumsy and thus only makes sense for testing
purposes or quick prototypes. More serious approaches will rely on customizers in JavaBeans, which also have to be created manually or by means of dedicated application building tools. However, what distinguishes our framework from these commercial approaches is the use of the trading mechanism to collect and display available property sheets in a kind of tabbed dialog. In addition, we support easy configuration of the system by means of adding and removing specific components and through the possibility of attaching attributes to components. The latter allows creating component subsets.
5: Conclusion We have described the basic characteristics and requirements of component technology and component composition. In addition, we have presented a component framework for directmanipulation editors. The framework provides a component-ready design and allows the composition of binary software components by means of a trading mechanism. In the traditional object-oriented view, the concepts of component selection, object creation, component interfaces and component implementation are usually defined by or tightly connected with the class construct. Since this is a source of inflexibility, these concepts are provided by exchangeable (i.e., plugable) binders, factories and other components implementing rolespecific behavior in our system. We abstained from using implementation inheritance for component composition. Component coupling and object creation are performed at run time by means of component managers and may be based on properties, interfaces and capabilities of components.
6: Acknowledgments The author wishes to thank Wolfgang Hartl and Gabriel Kowalik for their contributions to the construction of the described framework.
7: References [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15] [16] [17] [18] [19]
Graham I. (1994). Object-Oriented Methods, Addison-Wesley. Lewis T. (ed.) (1995). Object Oriented Application Frameworks, Manning Publications. Cox B. (1986). Object-Oriented Programming: An Evolutionary Approach, Addison-Wesley. Udell J. (1994). “Componentware”, Cover Story of BYTE May 1994. Webster (1997). Merriam-Webster WWW Dictionary and Webster’s Revised Unabridged Dictionary, http://www.m-w.com/dictionary.htm, Merriam-Webster, Inc., 1997. Firesmith D., Eykholt E. (1995). Dictionary of Object Technology, SIGS Reference Library. Nierstrasz O., Dami L. (1995). “Component-Oriented Software Technology”, Object-Oriented Software Composition (edited by Nierstrasz O. and Tsichritzis D.), Prentice Hall. Sametinger J. (1997). Software Engineering with Reusable Components, Springer. SUN Microsystems (1996). JavaBeans 1.0-A Specification, available at http://www.javasoft.com, Dec. 1996. Williams S., Kindel C. (1995). “The Component Object Model”, Dr. Dobb’s Special Report, Winter 1994/95. Gruntz D. (1996). “The Fragile Base Class Problem”, addendum to ECOOP’96 tutorial notes. Szyperski C. (1997). Component Software, draft, to be published by Addison Wesley in autumn 1997. Chappell D. (1996). Understanding ActiveX and OLE, Microsoft Press. Hamilton J., Klarer R., Mendell M., Thomson B. (1995). “Using SOM with C++”, The C++ Report, SIGS Publications, July/August 1995. Microsoft Corporation (1995). The Component Object Model Specification, Draft 0.9, Oct. 1995. Wegner P. (1997). “Frameworks for Compound Active Documents”, http://www.cs.brown.edu/people/pw, as of May 1997. Brockschmidt K. (1995). Inside OLE (2nd ed.), ISBN 1-55615-843-2, Microsoft Press. Siegel J., et. al. (1996). CORBA Fundamentals and Programming, Wiley Computer Publishing, John Wiley & Sons. Ousterhout J. (1997). “Scripting: Higher Level Programming for the 21st Century”, white paper, Sun Microsystem Laboratories, http://www.sunlabs.com/~ouster/scripting.html, as of March 28, 1997.
[20] IBM Corp. (1995). VisualAge for Smalltalk, User’s Guide, Version 3.0, International Business Machines Corporation. [21] Schiffer S. (1997). Visuelle Programmierung - Grundlagen, Potentiale und Grenzen (in German), PhD thesis, Institut für Wirtschaftsinformatik, Johannes Kepler Universität Linz, to be published by Addison Wesley Germany in autumn 1997. [22] Gamma E., Helm R., Johnson R., Vlissides J. (1995). Design Patterns, Elements of Reusable Object-Oriented Software, Addison-Wesley. [23] Weinand A., Gamma E. (1995). “ET++ A Portable Homogenous Class Library and Application Framework”, Object Oriented Application Frameworks (edited by Lewis T.), Manning Publications. [24] Wirfs-Brock R., Wilkerson B., Wiener L. (1990). Designing Object-Oriented Software, Prentice-Hall. [25] Gottlob G., Schrefl M., Röck B. (1996). “Extending Object-Oriented Systems with Roles”, ACM Transactions on Information Systems, July 1996. [26] Kiczales G. (1994). “Why are Black Boxes so Hard to Reuse”, Invited Talk at OOPSLA ’94, Open Implementation Project, Xerox Palo Alto Research Center, transcript available from UVC at http://www.uvc.com/kiczales/transcript.html. [27] Coulouris G., Dollimore J., Kindberg T. (1994). Distributed Systems – Concepts and Design (2nd ed.), p. 52, Addison Wesley. [28] Helm R., Gamma E. (1995). “Designing Objects for Extension”, Dr. Dobb’s Sourcebook, May/June 1995. [29] Kowalik G. (1997). A User Interface Editor for ET++ Applications (in German), master thesis, Institut für Wirtschaftsinformatik, Johannes Kepler Universität Linz, Oct. 1997. [30] Hartl W. (1997). A Tool for the Visualization of Framework-Based Software Architectures (in German), master thesis, C. Doppler Laboratory for Software Engineering, Universität Linz. [31] Takefive Inc. (1997). SNiFF+ web site: http://www.takefive.co.at or http://www.takefive.com. [32] Weinreich R., Altmann J. (1997). “An Object-oriented Infrastructure for a Cooperative Software Development Environment”, Proceedings of the International Symposium on Applied Corporate Computing (ISACC), Monterrey, Mexico. [33] ISO/IEC, ITU. (1997). Information Technology–Open Distributed Processing–Reference Model: Foundations, ISO/IEC 10746-2, ITU-T Rec. X.902. [34] ISO/IEC. (1997). Open Distributed Processing–Trading Function–Part 1: Specification, International Standard ISO/IEC DIS 13235-1. [35] OMG (1997). “Trading Object Service Specification”, CORBAservices: Common Object Services Specification, available from http://www.omg.org, July 1997. [36] Bearman M., Duddy K., Raymond K., Vogel A. (1997). “Trader Down Under: Upside Down and Inside Out”, Theory and Practice of Object Systems, Vol. 3(1), John Wiley & Sons. [37] Weinreich R. (1993). Concepts and Techniques for Object-Oriented Software Development, Trauner Universitätsverlag Linz/Wien, March 1993. [38] Bäumer D., Riehle D. (1997). “Product Trader”, Pattern Languages of Program Design 3 (edited by Martin R., Riehle D., Buschmann F.), Addison Wesley, 1997. [39] Wallingford E. (1997). “Sponsor Selector”, Pattern Languages of Program Design 3 (edited by Martin R., Riehle D., Buschmann F.), Addison Wesley, 1997. [40] Riehle D. (1996). “Patterns for Encapsulating Class Trees”, Pattern Languages of Program Design 2 (edited by Vlissides J., Coplien J., Kerth N.), Addison Wesley, 1996. [41] Riehle D., Züllighoven H. (1995). “A Pattern Language for Tool Construction and Integration Based on the Tools and Materials Metaphor”, Pattern Languages of Program Design (edited by Coplien J., Schmidt D.), Addison Wesley, 1995