Embedded OO-Programming Language
A component language embeds a programming
language and uses its constructs to implement
components. ArchJava which embeds Java has ports
with both provided and required interfaces. It
defines the interfaces of a port either by listing, after
the keyword provides or requires, operation
specifications, or by listing method
implementations. But you cannot define the
interfaces of a port using Java interfaces. Thus, the
identical concept “interface” is described by
different constructs in the component language and
the OO-language, which is certainly a drawback.
On the other hand, ArchJava allows to derive
components from classes, like the worker
component from the class Thread (Aldrich, May
2002). But how can a component, which is not a
class, but a first-class citizen of its own, inherit
implementation from a class?
Therefore, requirement 1 is: a component
language should not reinvent constructs for concepts
it shares with its programming language. On the
other hand, it should not intermingle differing
concepts in the component language and
programming language.
Component Inheritance
ArchJava transfers the type concept of class-based
languages directly to components. It defines a
component type implicitly as the type that is
generated by a component class, and it defines
inheritance in such a way that a derived component
inherits from a base component both the component
type and its implementation.
This has two drawbacks. A definition of a
component type that is independent from the
implementation is required to define e.g. a product
line architecture or a component framework. A
product line architecture defines product component
types which are implemented by different product
components. Similarly, a component framework
defines a set of collaborating component types
which are implemented by different components.
Second, a component should not inherit the
implementation from another component, but should
be composed with the other component in order to
reuse its functionality. Therefore, requirement 2 is
that the definition of component types and
inheritance among them should be provided, but
implementation inheritance among components
should be disallowed.
Component Encapsulation
ArchJava allows that a parent component invokes
directly internal methods of a subcomponent which
are not defined by a provided port. This breaks the
encapsulation of the subcomponent. Further, a
graceful evolution is inhibited since it is not possible
that a sibling subcomponent invokes these methods
instead of the parent component at a later point of
the evolution. On the other hand, ACOEL allows
that a parent component exposes a reference to a
subcomponent in a port. When it passes that
component reference to a sibling component, ports
of the sibling component may be connected to ports
of the subcomponent. That means a component may
be at the same time a subcomponent of two different
components. This breaks a sound architectural
structure.
Requirement 3 is that a component should be
completely encapsulated, i.e. it should collaborate
only via its ports with external code. As a
consequence, a subcomponent of a component must
not collaborate with other components outside of its
parent component. Therefore, the passing of
component or port references should be restricted or
prohibited.
Interface Symmetry
ArchJava has a complete symmetry among provided
and required interfaces with regard to their
definition and their use, since a port may comprise
both of them. ACOEL (Sreedhar, 2002) has a
symmetry with regard to their definition, but not
with regard to their use. A mix-in allows to put a
filter between a provided port and the implementing
class. But it does not allow to put a filter between
the implementing class and a required port.
Requirement 4 is that the definition and the
handling of provided and required ports should be
symmetrical.
Ports and Connectors
An ArchJava port may combine a provided and a
required interface, like:
port port1 provides m1, m2 requires m3, m4;
As usual, a port with a required interface I
1
may
be connected to a port with a provided interface I
2
when I
2
is a subtype of I
1
. But an ArchJava
connector may fork the calls from a required
interface I
1
to several provided interfaces like I
2
and
I
3
if each is a supertype of I
1
, and their union is a
subtype of I
1
, and their intersection with regard to I
1
is empty. For example, with port2 and port3:
port port2 provides m3, m6 requires m1, m5;
port port3 provides m4, m5, m6 requires m2, m3;
ArchJava allows to connect port1, port2, and
port3 by a connect statement. If port1 would require
additionally m6 the connection would not be correct
and rejected. This is not easy to check and
ENGINEERING A COMPONENT LANGUAGE: COMPJAVA
99