In the SCA 0.9 schemas, the relationship between a Component
and its Component Type is determined by the
<sca:implementation /> element which is contained by the
<sca:component /> element. There is some indirection in the
transformed version of the schema used to generate the EMF model API
for various reasons, so the relationships are more easily discerned
looking through the Java API. Here you will find that org.eclipse.stp.core.sca.Component
has the method getImplementation() that returns an Implementation
(base interface type, not that fancy).
For this to be useful, you would really need to know what
type the implementation is; so to avoid alot of casting down, most
of the work with an Implementation is facilitated
through the Component Type Introspection Framework. Keep in mind
that the ComponentType is mostly (if not completely)
derived from the Implementation ; ComponentType
is the "standard way" of talking about the configuration points in
any arbitrary Implementation .
A ComponentType is an abstraction that is
derived (as in extracted or computed and _not_ subclassed)
from the Implementation . An Implementation
may use the ComponentType schema to describe its services,
references, and properties (like AbstractImplementation
does, which will be discussed later), but in general we will want to
derive these completely from the actual Implementation For
instance, there are annotations that describe the Java ComponentType
which are embedded in a Java *.java source file, which are defined
as part of the Java Client and Implementation specification. So for
a Java component, we would have something like:
<sca:component>
<sca:implementation.java ... />
... configuration ...
</sca:component>
So we can get to the actual implementation element (e.g.
<sca:implementation.java />) through:
Component.getImplementation();
However, it would be more useful to get the ComponentType
through:
Component.resolveComponentType();
There is a 1:1 relationship between ComponentType
and Implementation . Remember that Component s
can share Implementation s and therefore share the same
ComponentType . But each Component is its
own configured instance of the Implementation . (So a
Java Implementation that requires a reference R of
type T may have that reference resolved differently in two
Components CA, CB that configure the Implementation,
but the ComponentType that describes reference R
of type T will be the same in-memory model).
That is, the infrastructure is smart enough to share the ComponentType
for re-useable implementations (like two Components CA and CB
that reference the same Java implementation JI; they will
have the same, shared ComponentType instance -- the
same in-memory model of the ComponentType derived from
the JI implementation).
The following diagram shows the "Composite
contains Component s" relationship.
However, to allow Composite to be the common
super class for Module and Subsystem , the
type called Component cannot have an direct
relationship to Implementation in the schema, because ModuleComponent
uses a attribute that indicates a URI instead of an
<sca:implementation /> element).
So the abstraction here has:
- a type named
ImplementComponent (which is the
<sca:component /> element).
- a type named
ModuleComponent (which is the
<sca:moduleComponent /> element).
- a type named Component (which is the
<sca:abstractComponent/> element which is never
serialized, non-spec, only for the purposes of the API)
The ImplementationComponent is broken out to
allow Component to be extended by ModuleComponent ;
We can then share a common abstract type between Module
and Subsystem (Module and Subsystem
both extend Composite -- a common abstraction used only
by the API and not part of the spec, and not persisted).
When we made these changes, we choose to leave the base type
name as "Component" instead of something like
"AbstractComponent". We layer in the getImplementation()
API by hand since the calculation for a "simple"
implementation (like Java or BPEL) is different than the calculation
for a "deployable" implementation (like Module). However,
these differences are somewhat incidental, and should not affect how
clients work with Component that represents a ImplementationComponent
or a ModuleComponent .
In addition to this machinery, the API supports three
important subclasses of Implementation out of the box.
Remember that each of these are the Java API types which represent
the XML types defined by the schema; furthermore, each of these
types are substitution groups from standard elements defined by the
SCA 0.9 specification. The naming convention followed requires that
a substitution for the spec-element <sca:implementation /> be
named <sca:implementation.xxx />, and have a generated type of XXXImplementation .
While other namespaces could be supported, the STP Core API only
defines implementations which are either useful abstractions for the
tooling or defined by the SCA 0.9 specification, which are all
defined in the "sca" namespace.
AbstractImplementation : A simple substitution
group for <implementation /> that contains an
<sca:componentType /> element. This element can be used for
top-down development, before a real implementation is specified. An
AbstractImplementation can be:
- "untyped" (no intended implementation
expressed),
- "typed" (the user has indicated they eventually
want this to be a xxx implementation, but no real implementation
has been associated yet), or
- "implemented" (e.g. no more
AbstractImpelmentation)
ModuleImplementation : An abstraction that
carries along the URI from the ModuleComponent . While
the XML element is a substitution for <sca:implementation />;
it is never serialized.
JavaImplementation : The type for
<sca:implementation.java /> element.
There's also UnknownImplementation and PropertiesImplementation
which are used when the Implementation cannot be determined
and for testing; respectively.
The AbstractImplementation described above can
be used for top-down design through Component.setAbstractImplementation(ComponentType) ,
which will create an <sca:implementation.abstract /> element
as a child of the <sca:component /> element in the Module file
(sca.module).
So to recap:
A Component has an Implementation, and the
relationship is best expressed through the API. To allow for
commonality in tooling that works with Component and ModuleComponent
alike, Module and Subsystem alike, there is
indirection the generated form of the schema to provide a more
usable API. The Component type does not correspond to
any spec-level type (remember this is the <sca:abstractComponent
/> in the generated schemas), but instead the ImplementationComponent
is the <sca:component /> element, and ModuleComponent
is the <sca:moduleComponent /> element. An Implementation
derives its ComponentType ; the API is exposed on the Component
which configures the Implementation ( via Component.resolveComponentType() ).
|