| OOPS TRACK AT SAC 2004, NICOSIA/CYPRUS |
|
Integration of Independently Developed Components through Aliased Multi-Object Type Widening
Bo Nørregaard Jørgensen, University of Southern Denmark,
Denmark |
 |

PDF Version |
Abstract
The aim of component-based software development is to assemble applications
from existing components, writing as little extra code as possible.
For programmers, the assembling of applications from existing components
should increase reuse, thus allowing them to concentrate on value-added
tasks and to produce high-quality software within a shorter time. For
users, component-based software development promises tailor made functionality
from the customization of ready-made components, and that at a lower
cost than applications developed from scratch. However, this ideal
scenario has yet to become reality! Today, the majority of all applications
are still developed from scratch, and there are still relatively few
ready-made components that can be easily reused in the construction
of new applications. In this paper, we argue that the present situation
is primary caused by the conventional object-oriented programming languages
in which we try to assemble components. When Assembling independently
developed components in a conventional object-oriented programming
language, it leads to a number of complex integration problems. We
describe these problems in turn before we discuss how the new language
features of Lasagne/J, an extension of the Java programming language,
can be used to tackle them.
1 INTRODUCTION
The object-oriented programming languages and development environments
of today rely on components to be well integrated and do not handle
the integration of independently developed components well. Even slight
inconsistencies between components can lead to integration problems
that are difficult if not impossible to handle satisfactorily with
the reuse mechanisms available in current object-oriented languages.
Inconsistencies between components are to be expected in a world where
components and application frameworks are designed and developed by
independent organizations. The large number of development organizations
makes perfect coordination of components practically impossible. However,
the current state of affairs is unacceptable because it diminishes
the pervasiveness of component-based development due to the unnecessary
high cost of reuse caused by the various implementation techniques
required for fitting existing components for use in new contexts. It
is generally acknowledged that the effort necessary for reusing a component
should be smaller than the effort required for creating an equivalent
component from scratch. Components developed by a third party will
not become a serious alternative to in-house development before programming
languages and development environments can seamlessly support the integration
of such components. Rethinking and enhancing the programming constructs
of current object-oriented languages is therefore a necessity for enabling
the success of component-based development.
The present situation for
component-based development is characterized by the following dominating
factors:
- Components are written in a statically typed, class-based
object-oriented programming language.
- Components are developed and maintained by independent
organizations.
- Extending the behavior of a system is ideally done by adding
new components.
Each
of these factors has effect on the development of components. The
implications of these factors can be characterized as:
- The internal structure of a component is defined by a set
of related classes. Objects of these classes collaborate to implement
the services offered by the component.
- Most components have to be adapted before they can be reused
in settings different from those in which they were originally developed.
- The source code of existing components cannot or should
not be changed.
- The granularity of a component can vary from the size of
a simple GUI widget to a full-sized application.
Having identified the dominating
factors characterizing component-based development and clarified
their implications, we can now turn our attention
to the integration problems they cause. We will do so in section 2.
In section 3, we show how to tackle these problems using Lasagne/J,
an extension of Java™ that supports the extension of collaborating
objects through Aliased Multi-Object Type Widening. Related work is
discussed in section 4 and section 5 addresses challenges left for
future work. Finally, section 6 summarizes the main contributions of
this paper.
2 PROBLEMS, CAUSES AND SOLUTIONS
In this section we summarize problems
that component-based development must face today, due to the present
plane of development of languages
and tools. As part of discussing each problem, we briefly outline necessary
properties of a solution. We are not the first to recognize and acknowledge
the importance of these problems. Existing literature contains numerous
examples of the problems in various forms, along with different proposals
for solving them. However, the problems have largely been addressed
independently of each other, so none of the proposed solutions address
all of them in a unified fashion. New solutions which can address a
broader range of the problems, ideally all of them, are therefore needed.
We return to our proposal for such a solution in section 3.
Multiple
representations of real-world entities. When assembling an application
from independently developed components, it may occur that
different components contain individual representations for the same
real-world entities. As argued in [Ossher92] and [Mattsson99] this
is a problem because equivalent representations have to be coordinated
in the composed application. One practical problem is that objects
of equivalent classes must be interchangeable between components. Components
must be able to exchange objects that represent the same real-world
entity. However, the exchange of objects across component boundaries
is forbidden by the type system of the implementation language if the
exchanged objects belong to different class hierarchies, i.e. they
do not share a common supertype. A solution to the problem has to compensate
for the missing shared superclass and the possibility of slightly semantic
differences between the representations. Appropriate compensation could
be provided by mechanisms which support introduction of superclasses
into existing class hierarchies and adaptation of behavior in affected
classes.
Extending shared components. A shared component is
typically a component which controls a unique resource. In some situations
simultaneous
clients
may have different expectations to the behavior of a shared component.
One client could for instance require a newer version of the component
than the one required by another client. If the newer version of the
component is appropriate for the client requesting the older version,
we can simply replace the old version with the newer one. Often the
situation is more complex; simultaneous clients may have individual
conflicting requirements for the component’s behavior. For shared
stateless components the problem can be solved by maintaining different
versions of the component for each client. However, this approach does
not work for components which contain state. Here duplication will
result in inconsistencies for the part of the state that is common
to all versions of the component. As argued in [Meijer02] conventional
programming languages lack adequate support for expressing and managing
multiple versions of the same component, especially in the case where
different versions of the same component cannot co-exist. The absence
of adequate support leaves us in a situation where the requirements
of one client may exclude the presence of another. A solution to the
problem must allow developers to control the visibility of the modifications
made to a component, so that modifications are only visible to the
client who requested them.
Interface mismatch. Due to their independent
conception it is very unlikely that independently developed components
will have exactly
the same interface structure and behavior [Smith98]. In order to avoid
interface incompatibilities, different component vendors must agree
upon both structure and behavioral semantics of shared interfaces.
To some extend this may be achievable for domain specific components,
by complying with an external specification, but it is generally not
the case for general purpose components. Clients will therefore not
be able to substitute one component for another without compensating
for the differences between the two. Interface incompatibilities typically
manifest themselves as typing conflicts caused by the implementation
language, when trying to combine independently developed components,
as discussed by [Hölzle93] and [Mattsson99]. A solution should
allow developers to express how the behaviors of different abstractions
relate to each other. One example of this train of thought is a form
of polymorphism, called correspondence polymorphism [Rinat96]. In correspondence
polymorphism a correspondence relation declares how some methods and
attributes of one type correspond to other methods and attributes within
another type.
Architectural style mismatch. Components typically
use one of two architectural styles for interacting with other components.
The first style of interaction
is the explicit invocation style, which is naturally supported by the
call idiom used in the majority of all programming languages. The other
style of interaction is the implicit invocation style [Shaw96]. This
style of interaction is probably better known as event-based. Where
the explicit invocation style invokes methods directly on other components
by calling them, the implicit invocation style invokes methods indirectly
by announcing one or more events. Other components register their interest
in an event by associating a callback method with it. When the event
is announced, the source of the event invokes all of the callback methods
that have been associated with the event. The implicit invocation style
is more flexible than the explicit invocation style, because it supports
multiple receivers for an invocation instead of just one. Furthermore,
it supports loose coupling by allowing receivers to be dynamically
added and removed. However, the implicit invocation style is not supported
by conventional object-oriented programming languages, which means
that it has to be simulated by the normal call idiom. The general scheme
is that components which listen for events have to implement a listener
interface. It is the listener interfaces that associate events with
methods. Since the two interaction styles result in fundamentally different
code structures, the integration of components that use different styles
will either require major re-factoring of existing code or extensive
use of new glue code. In a world of independent development, it is
most likely that applications will be assembled from components supporting
one style or the other. As discussed in [Garlan95] care must be taken
when mixing the two styles. To bridge this mismatch in architectural
styles, we need language mechanisms which allow components to participate
in different styles of interaction simultaneously.
Modification of
inter and intra component collaborations. When development
takes place in a class-based object-oriented language, any well-formed
non-trivial component will consist of a set of related classes. From
this set of classes, the component instantiates the objects that form
the collaborations responsible for the functionality which the component
provides to its clients. Some of these objects also participate in
the collaborations that the component has with other components to
implement application-level functionality. Hence, any extension of
functionality either at the component-level or at the application-level
will require modifications of several classes. Likewise, adding a new
collaboration will require the modification of several classes in order
to adapt these classes to the appropriate collaboration roles. The
addition of a new collaboration is often a consequence of integrating
a new type of component. Changing the classes of a component to implement
an extension ties the original version of the component to its extended
version. Often an extension is used to bind a component to a specific
usage context, making the component less generic. The irreversible
nature of such bindings caused by invasive changes to classes is undesirable,
because in general it should be possible to continue the development
of a component independently of any extensions made to it. Furthermore,
the clarity of the relation between a component and its extensions
is damaged, because the code responsible for implementing the extensions
is not localized in one place, but instead spread across several classes.
This results in tangled code which is difficult to understand and maintain,
because it basically suffers from bad modularity. As pointed out in
[Mezini00] and [Kiczales97] there is a critical need for programming
constructs which can support the separation of base functionality from
extended functionality through capturing and encapsulation of distinct
and largely independent slides of program behavior into separate modules.
Iterated
extension of components. Similar to the creation of applications
by assembling independently developed components, one may argue that
it should also be possible to create higher-level applications by assembling
independently developed applications. Any application can be used as
a component in the construction of a higher-level application, if only
it complies with the component model of the applied component infrastructure.
Hence, at a latter point in its lifecycle an application can itself
become a component in the development of an even larger application.
Using a development approach that creates new applications from existing
applications will cause the classes constituting the components of
the applications involved in the assembling process to be iteratively
modified. The constituent classes of a component are potentially modified
each time the component is integrated into a new context. At the moment
wrapping is the most prominent non-invasive extension technique used
in component-based development to modify the behavior of existing components.
If we choose to ignore the many problems, such as efficiency and the
self-problem, which follows from using wrapping in conventional object-oriented
programming languages, it turns out that wrapping in general works
well as long as a component is only extended by a single client. However,
the situation becomes more problematic when subsequent integration
iterations extend a component with dependent extensions. Such iterated
extension of a component can cause consistency problems if not handled
appropriately. Let’s for a moment assume that we have two dependent
extensions. To ensure consistency all clients now have to access the
extended component through the second extension and the second extension
must access the component through the first extension. This implies
that all clients of the first extension must have their references
to the component replaced with references to the second extension.
Hence, as discussed in [Kniesel99] there is a need for the component
infrastructure to support dynamic re-wiring of component references.
Without support from the component infrastructure, re-wiring of object
references makes iterated extension of components very error phone
and difficult to manage in systems which continuously undergo evolution.
As argued in [Bosch99] an extended component should be just as extensible
with the extension as it was without the extension. In general the
presence of an extension should not preclude the applicability of another
extension, except in the situation where they are semantically incompatible.
A solution must allow us to dynamically extend the behavior of objects
without the need for changing existing object references.
3 INTEGRATING
COMPONENTS USING LASAGNE/J
We will use the development of a University
administration system to exemplify how Lasagne/J remedies the integration
problems discussed
above. But before we do so, we will give a brief introduction to the
main ideas behind Lasagne/J.
Lasagne/J in a nutshell
The Lasagne/J language extension facilitates
the integration of independently developed components through its ability
to dynamically extend the
behavior of a group of collaborating objects. Lasagne/J uses generic
wrappers to extend the behavior of objects. Generic means that a wrapper
can be applied in a type-safe manner to any type that is a subtype
of the type which the wrapper is intended to adapt. Each generic wrapper
can extend the behavior of exactly one object type. Thus the extension
of multiple objects happens through the coordinated use of several
wrappers. A generic wrapper extends an object by dynamically widen
the object’s type. Dynamic widening of object type is achieved
by changing the method dispatch process so that method lookup starts
at the method table of the outermost wrapper and ends with the object’s
own method table. In short, type widening supports overriding of existing
methods and the addition of new methods. The new method dispatch process
establishes a common-self between the object and its wrappers. This
implies that self within the object refers to the outermost wrapper.
All wrappers which participate in the coordinated extension
of a group of collaborating objects are organized in an extension package.
Extension
packages provide modularization of extensions. The starting points
for extending the collaborations of a group of objects are defined
by the wrappers in an extension package. More precisely, the types
of collaborating objects are dynamically widened by wrappers from an
extension package when their collaboration is initiated through an
alias of a wrapper type defined in the extension package. Due to the
central role of the alias in this process, we refer to this way of
widening the types of multiple objects as Aliased Multi-Object
Type Widening. Aliased Multi-Object Type Widening provides a way of controlling
the visibility of extensions to the clients of collaborating objects,
because the dynamic widening of object types is done specifically to
a particular alias. Hence, different extensions can be made available
to simultaneous clients simply by using different aliases. Extensions
activated through different aliases are kept isolated from each other
so that they only share the state of the extended objects. Any additional
state or behavior added by an extension is beyond the reach of other
extensions. The interested reader can find more details on the subject
in [Joergensen03]. We will discuss the issue of creating aliases of
wrapper types in a latter subsection.
Implementation wise Lasagne/J
is based on a mix of source code transformation and load-time byte
code rewriting, using the structural reflection
tool Javassist [Chiba00]. The use of load-time structural reflection
enables the extension of existing systems without requiring access
to the source code of their components. Source code transformation
is only needed to initiate Aliased Multi-Object Type Widening from
within new clients of existing components.
Integrating class hierarchies
with overlapping abstractions
Let’s assume that our University
administration system started out as a simple system only responsible
for registering students as
they enroll. The primary class in such a system will be that of a Student.
Clearly this system will turn out to be too limited, sooner or later
the system will have to be extended to meet the evolving expectations
of its users. A natural extension of the system would be to include
semester course management. Typical classes in a semester course management
system are Course, CourseOffering, Student, Schedule, etc. According
to our basic observations for component-based software development
listed in section 1, the administration system will be extended through
integration with a component that provides the additional functionality
of a semester course management system. Common to the class hierarchies
of the administration system and the semester course management system
is the abstraction of a Student (see figure 1.). Coincidently the abstractions
shared the same class name, but since they are the products of independent
development they will be defined in different class hierarchies. They
are therefore not interchangeable due to the typing conflict caused
by a statically typed, class-based programming language. One of the
classes has to be adapted before it can cross the typing barrier between
the two class hierarchies. If we assume that it is the administration
system that is responsible for creating Student objects we will have
to adapt these objects before they can be used by the semester course
management system. Hence, we have to extend the type of a Student object
without losing its identity.

Figure 1 Component dependent representations of the same real-world
entity
In Lasagne/J objects are adapted using generic wrappers. The
generic wrapper in figure 2 allows Student objects created by the
administration system to cross the typing barrier between the two class
hierarchies
and to be used as Student objects in the component providing the
semester course management functionality. 
Figure 2 Simple type adaptation wrapper
Here we introduce two
new keywords to the Java programming language for defining wrappers.
The keyword wrapper is introduced to
distinguish the definition of
a wrapper from a class definition and the keyword wraps is used to associate
a wrapper definition with a class definition (i.e., the static wrappee type).
To some extent the definition of wrappers are related to the definition of
classes, since they can define both state and behavior. Wrappers can be defined
for concrete and abstract classes, and applied to instances of those classes
as well as instances of their respective subclasses. The latter is a consequence
of fulfilling the genericity requirement [Büchi00], which states
that a wrapper must be applicable to any subtype of the static wrappee type
to be
generic. When used together the extends clause and
the wraps clause declare that the aggregate which results from applying a StudentTypeAdaptor wrapper
to an instance of org. lasagnej.examples.university.administration.Student is
a subtype of the class org.lasagnej.examples.university.semester.Student and
the static wrapper type StudentTypeAdaptor. Thus
the aggregate can now be used where an instance of the class org.lasagnej.examples.university.semester.Student is
expected. With respect to method lookup and dispatch the combination of the extends clause
with the wraps clause has type adaptor semantics.
That is, if the same method signature appears in both the extended class and
the static
wrappee type the method call is delegated to the wrappee, unless it is overridden
by the wrapper. Wrappers can only override public methods. This includes both
the public methods of the static wrappee type and the public methods of the
extended class. A public method that is not overridden by a wrapper is transparently
accessible through the wrapper. Hence, all the methods of the two Student classes
listed in figure 1 are accessible through the wrapper StudentTypeAdaptor.
If the extends clause is absent the wraps clause declares that the aggregate,
which results from combining a wrapper with an instance of the static wrappee
type, is a subtype not only of the static wrappee type but also the dynamic
wrappee type. However, since the dynamic wrappee type is not known until runtime,
it is only the methods of the static wrappee type that can be overridden by
the wrapper.
As mentioned earlier wrappers that belong to the same system
extension are
placed in the same package, a so-called extension package. This package cannot
be the same as the package in which the classes that they wrap are defined.
This separation of wrappers from the classes that they wrap is required in
order to encapsulate extensions into identifiable modules. Consequently,
a wrapper is always defined within another package than the package
of the class
that it wraps. At this point, in our running example, we have one extension
package containing a single wrapper, i.e., StudentTypeAdaptor,
since this is all that is required for performing the integration.
We can
now use the Façade design pattern [Gamma95a] to write a class
ServiceFacade that integrates the administration system with the semester
course management system. The class ServiceFacade implements the two use-cases
Sign
Up For Course and Commit Schedule. The source code of the class ServiceFacade is listed in figure 3.
Figure 3. The class ServiceFacade defines the point of integration
The integration of the two components happens through the cast statements
in line 11 and line 20. These are not normal cast statements; they
are constructive downcast statements. We have extended the
cast mechanism of the Java language to support constructive downcast.
Constructive downcast refers to the dynamic extension of an object
by casting the
object reference that refers to the object into the type of a wrapper
belonging to the desired extension. We call this cast constructive
because the referenced object dynamically becomes a type of the requested
wrapper type when it is accessed through the cast object reference.
A wrapper can only be used to change the type of a referenced object
if the wrapper wraps the static type of the object reference referring
to the object. The effect of a constructive downcast is not limited
to the referenced object; it also affects all objects with which the
referenced object collaborates. Hence, a constructive downcast designates
the point in an object collaboration where the Aliased Multi-Object
Type Widening process is initiated. Constructive downcast statements
inform the Lasagne/J runtime from which point on in the invocation
flow it must start to automatically apply wrappers to objects participating
in the object collaboration. The cast statements in line 11 and 20
widen an org.lasagnej.examples.university.admi nistration.Student into
an org.lasagnej.examples.university.semester.Student thereby
allowing Student objects from the administration system to be used
in the semester
course management system.
Iterated extension of shared base components
Returning to our University
scenario we will assume that the University’s
management has decided that the extended administration system
has proven so successful that it should be extended to also handle
the
management of tuition fees. Similar to the previous extension this
extension will also be based on integration with components developed
by third parties. For this purpose a sales management component
and an accounting component is purchased from two independent component
vendors. Before integration can take place, we have to inspect
the
class hierarchies of the four components involved, i.e., administration
system, semester course management, sales management, and accounting,
in order to identify potential overlapping classes. Figure 4 shows
two classes within the sales management and accounting components,
which may overlap with the class Student in the administration
system and the class Student in the semester course management system.

Figure 4 Roles applicable to Student objects
As part of the integration
effort, it is discovered that Student objects
within the context of sales management must take the
place of Customer objects. Now by comparing figure 1 with figure 4 it becomes
clear that the interfaces of org.lasagnej.examples.university.administration.Student and org.la sagnej.examples.university.sales.Customer must be
bridged before Student objects can be used in the place of Customer
objects.
The class org.lasagnej.exam ples.university.administration.Student deals with a student’s name and address as String objects
whereas the class org.lasagnej.examples.univer
sity.sales.Customer uses Name
and Address objects. Hence, we need to define a type adaptation
wrapper that allows Student objects to behave as Customer objects,
see figure
5.

Figure 5 Bridging Customer objects The wrapper StudentCustomerAdaptor overrides the necessary methods
in class Customer for bridging the class Student. Within the methods
of a wrapper, the keyword inner refers to the wrappee. It can be thought
of and treated as an implicitly declared and initialized final instance
field. Hence, the keyword inner defines a unique reference to the wrappee
within the scope of the wrapper. Similar to the way subclasses use
the keyword super to call overridden methods of their super class,
the keyword inner can be used by wrappers to call overridden methods
of the wrappee. A wrapper can choose to conceal the behavior of the
wrappee by not forwarding an invocation to inner. Optionally it can
redirect an invocation by invoking another method on the wrappee. Our
running example will also require a type adaptation wrapper for making
Student objects interchangeable with Account holder objects. However,
we choose to exclude the definition of this wrapper since it follows
the definition of the wrapper StudentCustomerAdaptor. Making objects
interchangeable using type adaptation wrappers is however not enough
to enhance the extended administration system with support for handling
tuition fees. We also have to extend the behavior of the use-case Commit
Schedule, and furthermore we have to add a new use-case Get
Tuition Fee. The implementations of these use-cases require a number of behavior
adapting and extending wrappers, one of which is a wrapper for the
class ServiceFacade. Figure 6 shows the wrapper for extending the class
ServiceFacade.

Figure 6 Tuition extension for the class ServiceFacade
To implement
the new use-case Get Tuition Fee, we need a number of wrappers
for extending the original behavior of the classes in the
semester course management system. These wrappers are shown in the
sequence diagram in figure 7. To better illustrate the Aliased Multi-Object
Type Widening process, we have changed the UML so that it allows us
to express wrapping of objects. The meaning of the compartment text
is changed from <object>:<class> to <wrapper>:<class>.
Iteration is shown by preceding a method call with a *.

Figure 7 Object
collaboration implementing the use-case Get Tuition Fee
As we can
see from figure 7 the introduction of a new use-case results in the
creation of a relatively large number of wrappers. In the
specific case, we had to create wrappers for all the classes in
the semester
course management system. The Aliased Multi-Object Type Widening
of the classes Student, Schedule,
and Course
Offering are initiated
by
the constructive downcast in line 20. Extending the system to handle
tuition fees implies that invoices have to be issued to students.
Figure 8 shows how Aliased Multi-Object Type Widening modifies
the objects
implementing the use-case Commit Schedule to call the
necessary methods in the sales management component and in the
accounting component.
The wrappers TuitionServiceFacade and TuitionOrder integrate
the sales management component and the accounting component.

Figure
8 Refinement of the collaboration implementing the use-case
Commit Schedule
Evolution of business logic through collaboration
refinement
Continuing our running example we will assume that the
University management has decided that no student will be allowed
to sign
up for a course
if she has a tuition balance from a previous semester. This
time no new components are needed. We can implement the decision
of
the University
management by changing the business rule for course enrollment.
This can be done through specializing the wrapper TuitionServiceFacade and the wrapper TuitionStudent from
before. Figure 9 shows the specialization of the wrapper TuitionServiceFacade.

Figure 9 Specializing
the wrapper for the tuition extension
When the wraps clause refers to
another wrapper it means that the new wrapper is a specialization of
the other wrapper. A specializing wrapper wraps the
same static wrappee type as the wrapper that it specializes. This means that
the specializing wrapper becomes a subtype of the original wrapper. The specializing
wrapper can add methods to and override methods of the original wrapper. Additional
methods are accessible through an object reference that is at least of the
same type as the specializing wrapper. When a wrapper specializes another wrapper,
the use of the keyword inner within the outermost wrapper refers to the next
inner wrapper. The outermost wrapper can conceal the behavior of the next inner
wrapper and the wrappee by not forwarding a call to inner. Activation of an
extension through constructive downcast of an object to the type of a specializing
wrapper will also activate all wrappers within the extension package of the
original wrapper. Thus the constructive downcast of a single object will affect
all objects participating in the object collaboration in which the constructive
downcast happens.

Figure 10 Extended object collaboration for changing the business
logic of the use-case Enroll In Course
The sequence diagram in figure
10 shows how a type adaptation wrapper is used to adapt Student objects
so that they can be used as AccountHolder
objects
in the context of the accounting component. A comparison of the class Student and the class AccountHolder in figure 11 shows that a simple type adaptation
wrapper will do since the interface of the class Student matches the interface
of the class AccountHolder - no adaptation of methods are required. Methods
invoked on an alias of type AccountHolder are automatically dispatched to the
corresponding methods on a Student object. All interactions with the system
that go through the new wrapper TuitionDebitServiceFacade will be subject to
the no tuition balance rule.

Figure 11 Incidentally structural and semantic
compatibility between independent developed classes
Bridging architectural
mismatch in interaction styles
To exemplify how Lasagne/J supports the
assembling of applications from components that use different architectural
styles of interaction,
we will extend our
running example with a web content management module for publishing semester
related information. One of the things that the university’s administration
wants to publish on the University’s home page is late cancellation of
courses. The development department purchased a new web content management
(WCM) component especially for this purpose. However, it soon turns out that
the WCM component is implemented using the Observer design pattern [Gamma95b],
whereas all other components in the system use the call idiom. The WCM component
uses an interface and two classes to implements event-based interaction. The
interface Observer declares the callback method update(Object
c) for content
change events. The class WebPublisher implements
the interface Observer and
provides the concrete implementation for the callback method update(Object
c). Finally, the abstract class Subject is
a utility class that provides methods for attaching and notifying observers.
In order to work with the WCM component,
components that cause content changes have to extend the class Subject.
In our case, such a component is the class SemesterCourseOffering in
the semester course management system. Hence, the class SemesterCourseOffering has
to notify the class WebPublisher when a course is
removed; that is, each time its method
removeCourseOffering() is invoked. Without Lasagne/J
this would clearly be a problem since we don’t want to change the source
code of the class SemesterCourseOffering to invoke the method
update(Object c) on the class
WebPublisher. However, with Lasagne/J the integration can simply be achieved
by defining a wrapper that extends the class Subject and wraps the class SemesterCourseOffering,
see figure 12.

Figure
12 Type widening of the class SemesterCourseOffering
Using the wrapper
CancellationSubject defined in figure 12
we can attach an instance of the class WebPublisher to
an instance of the class SemesterCourseOffering by
the combined constructive downcast and invocation statement ((CancellationSubject)sco).attach(new
WebPublisher()) where the variable sco refers to the semester that we
want to monitor. All invocations of the method removeCourseOffering() will
now cause the method update(Object c) to be invoked
as well. Thus, whenever a course is removed from a semester the WCM component
will be notified. The presence
of the method modifier adherent declares that the method removeCourseOffering() in
the wrapper Cancellation
Subject has to be executed for all subsequent invocations
of the method removeCourseOffering() on instances
of the class SemesterCourseOffering.
Hence, the presence of the method modifier adherent does
not only affect those invocations made through the alias sco but
also those made through other aliases. A wrapper method declared as adherent
sticks, so to speak, to the wrappee after
the first time the wrappee has been touched by an extension. Invoking the method
attach(WebPublisher wp) touched the SemesterCourseOffering object
with the web publishing extension.
4 RELATED WORK
In this section, we focus on work that possess properties
which we believe are essential for any solution which aims at eliminating
the integration problems
that developers face when assembling independently developed components. The
first property is the ability to support multiple simultaneous representations
for the same objects while preserving identity and state. Representation can
refer to both type and behavior. The second property is that of facilitating
coordinated extension of object collaborations.
Different approaches for supporting multiple representations
for the same object, by dynamically changing the class of the object,
have
been discussed in [Drossopoulou01],
[Serrano99] and [Malabarba00]. However, these approaches are limited to re-classifications
within the same class hierarchy in order to prevent run-time type errors. Furthermore,
the different representations cannot exist simultaneously, that is, an object
can only belong to one class at a time. Thus, none of these approaches meet
the need for re-classification across class hierarchies, nor do they meet the
need for supporting multiple simultaneous representations.
Support for multiple
simultaneous representations is discussed in [Bertino95]. Their approach
introduces the idea that an object can have multiple most specific
classes. Class selection is based on the static type of the object reference
through which the object is accessed. This allows for multiple simultaneous
representations of the same object. However, their approach cannot be used
as an integration tool for classes belonging to disjoint class hierarchies,
because it requires the set of most specific classes to have a common superclass.
Generic
wrappers as discussed in [Büchi00] support simultaneous representations
for the same object via the use of object composition at runtime. Different
clients of an object can extend the object’s type and behavior by applying
different wrapper objects to it. A notable feature of Generic wrappers is that
an existing wrapper object can be wrapped again. Because the wrapping process
is type transparent. Thus, it always remains possible to extend an already
extended object. However, the approach suffers from the object reference re-wiring
problem. A closely related approach is the work on type-safe delegation by
[Kniesel99]. Like Generic wrappers, type-safe delegation also suffers from
the object reference re-wiring problem.
Correspondence Polymorphism is proposed
in [Rinat96] as a means for establishing correspondences between types, none
of which is necessarily a subtype of the
other. As a result, methods may operate on objects and may receive arguments
of types different than the ones originally intended for. This allows programmers
to take advantage of similarities between existing types when such are identified
and recognized as beneficial.
Subject-oriented programming, as originally
introduced by [Harrison93], aims to support unanticipated integration
of independently developed applications.
The subject-oriented programming model claims that it can achieve this goal
by maintaining several class hierarchies, or so-called subjects, over the
same set of instantiated objects. The basic idea is that subjects can be
combined
into new applications using a number of composition rules. The programming
environment HyperJ, from IBM Research, adds subject-oriented programming
to Java. HyperJ is available, free of charge, from IBM’s alphaWorks.
Language
constructs for capturing the collaborations among objects have been discussed
in [Mezini98] and [Smaragdakis98]. The rationale for capturing
object collaborations is that the functionality of an application is not
confined
in the implementation of a single class but rather scattered across the
implementation of several classes. Making collaborations explicit at
the language level
provides us with a single place for changing the behavior of multiple objects.
A common
shortcoming of these two approaches is however that the behavior of a collaboration
is fixed when the collaboration is first instantiated in a component. Consequently,
different clients of a shared component cannot request different specializations
of the same collaboration. Approaches which can provide such support have
been proposed in [Ostermann02] and [Herrmann03]. These approaches allow
different clients to activate different specializations of the same
collaboration for
a shared component. However, the approach proposed in [Herrmann03] fails
short
when the extended collaboration has state that must be shared by the specialized
collaborations. The problem is the use of inheritance for specialization
of collaborations. Inheritance leads to replication of state maintained
in the
extended (i.e., super) collaboration. The proposal in [Ostermann02] does
not suffer from this problem, because it associates a specialized collaboration
with its super collaboration via a delegation link. Hence, state maintained
in the super collaboration is shared by the specialized collaborations.
A new relation between classes, called a context relation, is proposed
in [Seiter98]. Through a context relation a class (i.e., context class)
can
override the behavior
of several classes (i.e., base classes). A context class can either be
explicitly bound to a base class or it can be bound to a method invocation.
Binding
a context class to a method invocation will affect all nested invocations
as
well. Thus, clients can modify the object collaborations of a component
by attaching different context classes when invoking its services.
In Aspect-oriented
languages, like AspectJ [Kiczales01], modifications which affect several
classes are defined within a separate module called
an aspect.
At compile time, the compiler weaves these modifications into the sources
of the affected classes. Since aspects affect several classes they can
be used
to modify object collaborations. However, the weaving of aspect code
into classes limits the use of AspectJ to extensions that apply for
all clients
of a component.
We have deliberately excluded the discussion of using
object composition in conventional object-oriented languages, because
of its well-known
shortcomings. The interested reader may refer to [Hölzle93] for
a detailed discussion.
5 FUTURE WORK
Of particular interest for future work is the investigation
of mechanisms for identifying and handling of semantic incompatibilities
between independently
developed extensions. Extensions are said to be semantically incompatible
if
their combined use introduces undesirable application behavior. In most
cases we can determine whether two extensions will be semantically incompatible
by observing their behavior independently of each other. However, it
sometimes happens that semantic incompatibilities first appear after
the extensions
have
been integrated with the application. That is, the mutual presence of
the extensions causes the application to behave in ways that could not
be predicted
simply
by observing them independently. The common cause for semantic incompatibility
seems to be that the additional application logic introduced by one extension
interferes with the application logic introduced by another. The kind
of interference which is observed for independently developed extensions
can
be seen as a variant
of the feature interaction problem. The feature interaction
problem occurs
when the addition of a new feature to an application disrupts the existing
services offered by the application. Feature interaction has drawn a
lot of attention, especially in the telecommunication field where it
has been
a well
acknowledged problem for many years. An overview of the state of art
of feature
interaction research in telecommunication can be found in [Calder03].
The feature interaction problem can also be observed for plug-ins created
by
multiple vendors.
Plug-ins can interact in ways not envisioned by either vendor, and in
ways not predictable by users and system administrators. To facilitate
the development
of more advanced applications from independently developed extensions
it is crucial that we find ways of developing extensions in such a way
that
they
can be seamlessly integrated without too much additional effort for correcting
interference related problems.
6 SUMMARY
In this paper we have identified and described the programming
problems that we believe are most relevant to programmers in a world
where application
development becomes more dependent on the integration of independently
developed
components
with existing applications. Furthermore, we have discussed how the new
language features of Lasagne/J, an extension to the Java programming
language, remedy
many of those problems. Evidence for the feasibility of our approach
is given through a non-trivial integration example. The integration example
shows
that the proposed language features provide a unifying solution to the
identified problems. To summarize:
Multiple representations of real-world
entities: Objects belonging to different class hierarchies can be made
interchangeable by applying
wrappers
that
dynamically alternate their types to the types expected by the receiving
class hierarchy.
Extending shared objects: The visibility of wrappers
is alias specific. This means that clients independently of each other
can simultaneously
apply different
extensions to the same component.
Interface mismatch: Wrappers can adapt and extend the interface of an
object. This allows developers to deal with both structural and behavioral
integration
problems.
Architectural style mismatch: The use of wrappers which contain
so-called adherent methods allows developers to introduce a component
using event-based
interaction
into an architecture based on the call idiom.
Modification of intra and
inter object collaborations: Aliased Multi-Object Type Widening facilitates
coordinated modification of object collaborations.
Iterated extension
of components: Repeated constructive downcast of the alias through
which an object collaboration is initiated will extend
the objects
participating in the collaboration with wrappers from more extension
packages.
Through experimenting with Lasagne/J we have gained confidence
that language features like those proposed in this paper will help
to narrow
the current
gap between object-oriented programming languages and the needs of
component-based software development. However, in the balance of this
paper, we chose
to focus on how the proposed language features help to address those
problems,
instead
of their implementation. An implementation of Lasagne/J is available
and interested readers may download it from its project web site www.lasagnej.org.
REFERENCES
[Bertino95] Bertino E., Guerrini G.: Objects with Multiple
Most Specific Classes. In: proceedings of ECOOP’95. Lecture Notes
in Computer Science, Vol. 952. Springer-Verlag, (1995) pp. 102-126
[Bosch99]
Bosch J.: Superimposition: A Component Adaptation Technique. In: Information
and Software Technology. No 41. (1999) pp. 257-273
[Büchi00] Büchi
M., Weck W.: Generic Wrappers. In: proceedings of ECOOP 2000. Lecture
Notes in Computer Science, Vol. 1850. Springer-Verlag,
(2000) pp. 201-225
[Calder03] Calder M., Kolberg M., Magill E.H., Reiff-Marganiec
S.: Feature interaction: a critical review and considered forecast.
In:
Computer
Networks - The International Journal of Computer and Telecommunications
Networking,
Vol. 41 (1). Elsevier (2003) pp. 115-141
[Chiba00] Chiba S.: Load-time
Structural Reflection in Java. In: proceedings of ECOOP 2000. Lecture
Notes in Computer Science, Vol. 1850. Springer-Verlag,
(2000) pp. 313-336
[Drossopoulou01] Drossopoulou S., Damiani F., Dezani-Ciancaglini
M.: Fickle: Dynamic Object Re-classification. In: proceedings of ECOOP’01.
Lecture Notes in Computer Science, Vol. 2072. Springer-Verlag, (2001)
pp. 130-149
[Gamma95a] Gamma E., Helm R., Johnson R., Vlissides J.:
Design Patterns, Elements of Reusable Object-Oriented Software. Addison-Wesley
(1995)
pp. 185-194
[Gamma95b] Gamma E., Helm R., Johnson R., Vlissides J.:
Design Patterns, Elements of Reusable Object-Oriented Software. Addison-Wesley
(1995)
pp. 293-304
[Garlan95] Garlan D.,Allen R., Ockerbloom J.: Architectural
Mismatch or Why it’s hard to build systems out of existing parts.
In: proceedings of the 17th International Conference on Software Engineering.
ACM (1995)
pp. 179-185
[Herrmann03] Herrmann S.: Object Teams: Improving Modularity
for Crosscutting Collaborations. In: proceedings of NetObjectDays.
Lecture Notes in
Computer Science, Vol. 2591. Springer-Verlag, (2003) pp. 248-264
[Hölzle93]
Hölzle U.: Integrating Independently-Developed Components
in Object-Oriented Languages. In: proceedings of ECOOP '93. Lecture
Notes in Computer Science, Vol. 707. Springer-Verlag, (1993) pp. 36-56
[Harrison93]
Harrison W., Ossher H.: Subject-Oriented Programming (A Critique of
Pure Objects). In: proceedings of OOPSLA'93. SIGPLAN Notices,
Vol 28
(10). ACM (1993) pp. 411-428
[Joergensen03] Jørgensen B.N., Truyen
E.: Evolution of Collective Object Behavior in Presence of Simultaneous
Client-Specific Views. In:
proceedings
of OOIS03. Lecture Notes in Computer Science, Vol. 2817. Springer-Verlag,
(2003) pp. 18-32
[Kiczales97] Kiczales G., Lamping J., Mendhekar A.,
Maeda C., Lopes C.V., Loingtier J., Irwan J.: Aspect-Oriented Programming.
In: proceedings
of ECOOP’97.
Lecture Notes in Computer Science, Vol. 1241. Springer-Verlag, (1997)
pp. 220-242
[Kiczales01] Kiczales G., Hilsdale E., Hugunin J., Kersten
M., Palm J., Griswold G. W.: An Overview of AspectJ. In: proceedings
of ECOOP’01.
Lecture Notes in Computer Science, Vol. 2072. Springer-Verlag, (2001)
pp. 327-353
[Kniesel99] Kniesel G.: Type-Safe Delegation for Run-Time
Component Adaptation. In: proceedings of ECOOP'99. Lecture Notes in
Computer
Science, Vol.
1628. Springer-Verlag, (1999) pp. 351-366
[Malabarba00] Malabarba S.,
Pandey R., Gragg J., Barr E., and Barnes F.: Runtime Support for Type-Safe
Dynamic Java Classes. In: proceedings
of
ECOOP 2000.
Lecture Notes in Computer Science, Vol. 1850. Springer-Verlag, (2000)
pp. 337-361
[Mattsson99] Mattsson M., Bosch J.: Composition Problems,
Causes, & Solutions.:
In: M.E. Fayad, D.C. Schmidt, R.E. Johnson (Eds.): Building Application
Frameworks: Object Oriented Foundations of Framework Design. Wiley & Sons,
(1999) pp. 467-487
[Meijer02] Meijer E., Szyperski C.: Overcoming Independent
Extensibility Challenges. Erik Meijer and Clemens Szyperski. Communications
of the
ACM, Vol. 45, No.
10. ACM Press (2002) pp. 41–44
[Mezini98] Mezini M., Lieberherr
K.: Adaptive Plug and Play Components for Evolutionary Software Development.
In: proceedings of OOPSLA’98.
Sigplan Notices, Vol. 33, No. 10. ACM Press (1998) pp. 97-116
[Mezini00]
Mezini M., L. Seiter and K. Lieberherr.: Component Integration with
Pluggable Composite Adapters. In: M. Aksit (Eds.): Software Architectures
and
Component Technology: State of the Art in Research and Practice. Kluwer
Academic Publishers, (2000).
[Ossher92] Ossher H., Harrison W.: Combination
of inheritance hierarchies. In: proceedings of OOPSLA'92. ACM SIGPLAN
Notices, Vol 27 (10). ACM
(1992) pp. 25-40
[Ostermann02] Ostermann K.: Dynamically Composable
Collaborations with Delegation Layers. In: proceedings of ECOOP '02.
Lecture Notes in Computer
Science,
Vol. 2374. Springer-Verlag, (2002) pp. 89-110
[Rinat96] Rinat R., Magidor
M.: Metaphoric Polymorphisn: Taking Code Reuse One Step Further. In:
proceedings of ECOOP’96. Lecture
Notes in Computer Science, Vol. 1098. Springer-Verlag, (1996) pp. 449-471
[Seiter98]
Seiter L., Palsberg J., Lieberherr K.: Evolution of Object Behavior
using Context Relations. In: IEEE Transactions on Software
Engineering, Vol. 24(1) (1998) pp. 79-92
[Serrano99] Serrano M.: Wide
Classes. In: proceedings of ECOOP'99. Lecture Notes in Computer Science,
Vol. 1628. Springer-Verlag, (1999)
pp. 391-415
[Shaw96] Shaw M., Garlan D., Software Architecture: Perspectives
on an emerging discipline. Prentice Hall, 1996. ISBN 0-13-182957-2.
[Smaragdakis98]
Smaragdakis Y., Batory D.: Implementing Layered Designs with Mixin
Layers. In: proceedings of ECOOP’98. Lecture Notes
in Computer Science, Vol. 1445. Springer-Verlag, (1998) pp. 550-570
[Smith98]
Smith G., Gough J., and Szyperski C.: Conciliation: The Adaption of
Independently Developed Components. In: proceedings of PDCN'98.
(1998) pp. 31-38
About the author

|
 |
Bo Nørregaard Jørgensen is associate professor
in Software Engineering at the Maersk Mc-Kinney Moller Institute
for Production Technology, University of Southern Denmark. His
current research areas include reflective middleware systems,
component-based software development and the design of programming
language technologies for dynamic adaptation. Bo can be reached
at bnj@mip.sdu.dk. |
Cite this article as follows: Bo Nørregaard Jørgensen: “Integration
of Independently Developed Components through Aliased Multi-Object
Type Widening”, in Journal of Object Technology, vol. 3, no.
11, December 2004, Special issue: OOPS track at SAC 2004, Nicosia/Cyprus,
pp. 55-76. http://www.jot.fm/issues/issue_2004_12/article3
|