STP Core Overview Documentation

STP Core API [Index]

The STP Core API is an EMF-based model with several enhancements. The SCA standard is honored by the model, but there are some abstractions which are not directly dictated by the specification, but are useful in the context of developing a tool for the development of specification-compliant applications. These enhancements include a common base type, the abstraction of concepts such as Composite, WireSource and WireTarget, and cleaner method signatures for the manipulation of substitutable XML types (such as <sca:implementation />).

In this document, concepts are enclosed by italics (like this), references to types or methods in the Java API are enclosed by fixed-width fonts (like this), and references to elements in the schemas are enclosed in angle brackets(<likethis />).

org.eclipse.stp.core.sca.SCAObject [Top]

The base type for the SCA model, SCAObject provides capabilities that all SCA model objects can take advantage of. First, it provides standard facilities for associating org.eclipse.core.IStatus objects with a given model object. Thus, an invalid model element does not have to prevent the complete loading of the document. SCAObject also insulates the STP Core API from the standard EMF base interface (EObject), which is exposed only through SCAObject.getEObject(). This helps to keep the API on each SCA object clean and focused, but allows editors or advanced operations to take advantage of the many useful facilities of EObject when necessary. Finally, a bitmask of flags can be associated with each SCAObject, in order to keep track of characteristics of an object in a standard and extensible way.

In the diagram, SCAObject is shown as the common parent of the key model elements. Some model elements were filtered for clarity. The Composite type, which is not explicit in the SCA specification will be discussed below.

Useful Abstractions [Top]

There are several abstractions which were found useful when describing the SCA specification for a tooling-centric model.
Composite:

Provides a common base type for ModuleFragment and Subsystem. A Composite describes a collection of Components EntryPoints, and ExternalServices. It also provides a base where WireSource/WireTargets may be resolved.




AbstractService:

Exposes an Interface and provides a method to determine if it matches (or is compatible with) an AbstractReference.

AbstractReference:

Provides the same information as AbstractService but from the view point of a reference.




WireSource:

In SCA, either an EntryPoint or a Reference of a particular Component may be the source of an embedded wire. To make client code more reusable, each of these types provide a WireSource abstraction; EntryPoint extends WireSource directly, while Component provides an implementation which describes a particular Reference on the Component.

WireTarget:

Provides the opposite functionality of WireSource; ExternalService extends this type directly, while Component provides an implementation which describes a particular Service on the Component.




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 Components can share Implementations 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 Components" 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()).

EMF, XML Substitution Groups, and FeatureMaps, OH MY! [Top]

In EMF, XML Substitution Groups are managed by a special EMF data structure named FeatureMap. This type associates a particular EMF feature (e.g. the global document element from the XML Schema) with a particular instance which subclasses the substituable type indicate in the XML Schema declaration. With a few restrictions, the STP Core API was able to automatically manage the FeatureMap, and expose more friendly schemes for clients who wish to add substituted types (e.g. JavaInterface) to their respective fields (e.g. Service.set/getInterface).

Generating the STP Core API from the standard schemas [Top]

The STP Core API cannot be generated from scratch due to the modifications and enhancements. However, it can be regenerated to integrate updates from the specification. This process uses an extensible stylesheet transformation (XSLT) to convert the Standard SCA schemas to a form which will generate certain additive abstractions (like Composite), and also annotates the generated schemas with Ecore annotations to make the generation a little cleaner (by hiding some fields, renaming others, etc).

Repeating this process requires a client to load org.eclipse.stp.core, update the schema directory (schemas/sca) with the latest form of the schemas, and run the transform.xml Ant script. Next a client must reload the sca.genmodel file (right-click, select "Reload", follow the wizard. The resulting sca.ecore model file can then be used to generate new model and UI model elements (ItemProviders).

This documentation is maintained by Michael D. Elder (mdelder{at}us.ibm.com). Questions or requests for clarifications should be made to the STP Developer mailing list (stp-dev@eclipse.org). See http://www.eclipse.org/mail/index_all.php for details on how to sign up.

Copyright (c) 2006 IBM Corporation. All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at http://www.eclipse.org/legal/epl-v10.html

[Index] [Top]