Composing Software Systems from Adaptable Software Components
George T. Heineman
Worcester Polytechnic Institute
Worcester, MA 01609
http://www.cs.wpi.edu/~heineman
Abstract
The construction of software systems from pre-existing, independently
developed software components will only occur when application builders
can adapt software components to suit their needs. Our ADAPT framework [Hein97] supports both component designers in creating
components that can easily be adapted, and application builders in
adapting software components. We propose that software components
provide two interfaces -- one for behavior and one for adapting that
behavior as needed. In this position paper, we outline some requirements
for composing software systems from components and suggest that
adaptation be recognized as a significant factor.
1 Introduction
The goal of constructing software applications from reusable software
components is proving to be very challenging. We believe that adapting
software components for use by a particular application is a key enabling
technology towards realizing this goal. Using a software component in a
different manner than for which it was designed, however, is challenging
because the new context may be inconsistent with implicit assumptions
made by the component. Techniques such as component adaptors [Yell97] that overcome syntactic incompatibilities
between components do not address the need to adapt software components.
Our focus is on supporting both component designers and application
builders: the designers will be aided in creating components that can
easily be adapted (thus increasing reuse), and for the first time,
application builders will have mechanisms for adapting software
components. By design, black box components often only allow minimal
customization and are reusable if they exactly match a particular need in
an application. However, the use of the component is also heavily
dependent on the ability for application builders to adapt the component
for use in different applications.
We make a distinction between software evolution, where the software
component is modified by the component designer, and adaptation,
where an application builder adapts the component for a different use.
We also differentiate adaption from customization; an end-user
customizes a software component by choosing from a fixed set of options
(such as OIA/D [Kicz97]). An end-user adapts a
software component by writing new code to alter existing functionality.
1.1 ADAPT
The goal of the ADAPT framework is to increase the feasibility of
component-based software development by showing how to design adaptable
software components. The main idea is that component designers must
provide mechanisms that allow application builders to incorporate and
adapt these components into their application. Two research directions
for the ADAPT project that are relevant to the discussion of
compositional software architecture are:
- A Component specification language for specifying the interface of a
component and how it is adapted.
- Active interfaces
1.1.1 Component Specification Language
component Spreadsheet {
implements Serializable,
SpreadsheetListener;
// one-dimensional property.
indexedProperty Function function(String)
// one-dimensional property.
indexedProperty String Value(String);
// Basic state properties of this component
property boolean debug;
// Methods
float getNumericValue(String);
void installFunctions();
float evaluateConstant(String);
void evaluate(Node);
float calculateFunction(Expression);
// expects add/remove
void addSpreadsheetListener(SpreadsheetListener);
void removeSpreadsheetListener(SpreadsheetListener);
// SpreadsheetListener Interface
void handleSpreadsheetEvent(SpreadsheetEventObject);
}
|
The ADAPT (Architectural Description of adAPTable components) language is
used to describe the interface for a component and its adaptations. If
the component is written in a reflective language, such as Java, then the
specification for a component can initially be generated directly from
the component. The above figure describes one such
specification generated for a Spreadsheet
Bean. This Bean supports a set of spreadsheet services, allowing
clients to set individual cell values (through the Value property), and
allows external client Beans to become listeners for refresh requests as
new values are added and computed. An ADAPT description provides a
convenient place to specify adaptations to the component, as we now
describe.
1.1.2 Active Interfaces
The interface must play a greater role in helping application builders
adapt the component. The component interface is more than a syntactic
description of the method invocations accepted by the component. As
defined in [Abow95], components are active
computational entities whose interfaces defines methods to invoke, events
to receives and/or send, or complex access protocols. An active
interface decides whether to take action when a method is called, an
event is announced, or a protocol executes. There are two phases to all
interface requests: the "before-phase" occurs before the component
performs any steps towards executing the request; the "after-phase"
occurs when the component has completed all execution steps for the
request. These phases are similar to the Lisp advice facility described
in [Rama97]. A standard way to alter the behavior
of a component is to interpose an entity to intercept messages and/or
events. Because such adaptation is likely to occur, the component should
provide an interface for this purpose.
Suppose that the application builder wishes to modify the Spreadsheet Bean
in Figure 1 so that it generates an event whenever
the particular value of a cell changes (for example, because the cell
contains a calculated formula), not just when the contents change; for
example, changing a cell from "(+ 2 3)" to "(* 5 1)"
changes the contents, but not the value. The application builder could
modify the component directly (which we are trying to avoid) or filter
out messages from the Spreadsheet (but this would require the client to
store duplicate values to detect differences, and is space/time
inefficient). We use an active interface to insert a
before-evaluate function that has the Spreadsheet component record
the value of the cell before its update and an after-evaluate
function that compares the new value against the old; if the values are
different, the after-evaluate function generates the appropriate
notification. These functions would then be incorporated into the object
ss, the instantiation of the Spreadsheet component. With this
scheme, different component objects from the same class can be adapted in
different ways, offering even more flexibility to the application
builder.
component ss adapts Spreadsheet {
code code.jar;
action storeValue (in Node);
action compareValue (in Node);
void evaluate (Node node) {
before storeValue(node);
after compareValue(node);
};
};
|
Active interfaces are different from the pre-packaged implementation
strategies of OIA/D [Kicz97]. OIA/D sketches a
solution showing how the client can provide their own implementation
strategy, but typically an entire method for a component is replaced.
Our approach is more fine-grained, allowing adaptation to occur when
needed. We do not violate the encapsulation of the component, since the
methods invoked within the active interface do not directly access
private information in the component. Thus the component designer has
great flexibility, and can place the responsibility for correctness on
the application builders that adapt the component.
1.2 Context
Our ADAPT framework [Hein97] is independent of the
particular programming language and architectural style, and is thus
widely applicable. For our initial prototype, we have chosen to use the
JavaBeans [SUN97] software component model. A Java
Bean is a reusable software component written in Java that can be
manipulated visually in a design environment, such as the sample Bean
Developers Kit (BDK) shipped with the initial release of JavaBeans. BDK
allows application builders to instantiate a collection of Beans that
communicate with each other using events. The JavaBeans event
model provides a convenient mechanism for components to propagate state
change notifications to one or more listeners. Each Bean contains a set
of state properties (i.e., named attributes) and BDK allows application
builders to customize a Bean by modifying its properties.
We are interested in extending the JavaBean component model to distributed
applications. In particular, we are designing a message framework called
SOWER on which a distributed application composed of beans can be built.
SOWER is based on the Event-Based Software Integration (EBI) described in
[Barr96]. The key features of SOWER are:
- It is integrated with the BDK.
- JavaBean components can be used as is without modification.
- Connector code is automatically generated as needed to deliver
JavaBean events between remote components.
- The registration of the communication between Beans is separate from
the actual delivery of Bean events.
In this way, we can experiment with constructing distributed applications
from components and investigate the evolvability of such software
systems.
2 Requirements
For this position paper, we identify the following requirements for
compositional software architectures. We discuss these requirements in
the context of JavaBeans, but they apply equally regardless of programming
language.
2.1 Core Requirements
- Separation of physical composition from logical
composition. JavaBeans provides a convenient abstraction for
communication between two components, and the distribution mechanism must
maintain this separation.
- Using JavaBeans without design modification. The JavaBeans
standard is gathering support in industry, so any approach to building
distributed applications must be compatible with the basic Bean model.
- Support for dynamic configuration. The framework enabling
communication between distributed Beans must allow the application builder
to deploy and move Beans between each site. The virtual
communication between Beans should be flexible enough to be reconfigured
when Beans move.
2.2 Advanced Requirements
As part of our efforts towards building adaptable software components, we
feel the following requirements are essential for realizing the goal of
building distributed applications from software components.
- In Situ Adaptation. When adapting the behavior of a class
C, object-oriented design methodologies suggest that a new subclass
SC be created that extends C to create the new, desired
functionality. This approach does not work when we wish to adapt the
behavior of a component. First, even though a component may syntactically
be equivalent to a class (as in JavaBeans), inheritance is ill-suited for
such adaptation. Consider a component constructed using the Facade design
pattern [Gamm95]; creating a subclass of the
Facade class complicates the design. Second, once a component is
deployed, the application builder should be able to adapt the component by
supplying new code to be integrated into the component; inheritance is
strictly a compile-time mechanism.
3. Conclusions
In this paper, we outlined some requirements for compositional software
architectures. We are focused on creating design methods and
implementation mechanisms that allow application builders to adapt software
components in their applications. We showed that component models must
provide some mechanism for adaptation, and we introduced active interfaces
for this purposes. We sketched the ADAPT and SOWER frameworks, and
described their usefulness in constructing distributed applications from
software components.
References
- [Abow95]
Formalizing Style to Understand Descriptions of Software
Architecture. ACM Transactions on Software Engineering and
Methodology, 4(4):319-364, October 1995.
- [Barr96]
A Framework for Event-Based Software Integration. Daniel Barrett,
Lori Clarke, Peri Tarr, Alexander Wise. ACM Transactions on Software
Engineering and Methodology, 5(4):378-421, October 1996.
- [Gamm95]
Design Patterns: Elements of Reusable Object-Oriented Software.
Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides. Addison-Wesley,
1995.
- [Hein97]
A Model for Designing Adaptable Software Components. George
Heineman. Submitted for Publication.
- [Kicz97]
Open Implementation Design Guidelines. Gregor Kiczales, et al.
19th International Conference on Software Engineering, pages 481-490, May
1997.
- [Rama97]
A Emacspeak: A Speech-Enabling Interface. Dr. Dobb's Journal,
22(1):18-23, September 1997.
- [SUN97]
JavaBeans 1.0 API Specification. Sun Microsystems, Inc. December
4, 1996.
- [Yell97]
Protocol Specification and Component Adaptors. Daniel Yellin and
Robert Strom. ACM Transactions on Programming Languages and Systems,
19(2):292-333, March 1997.