Articles Forum Examples Download Open Source
Oct 17, 2007
Copyright(c) 2007 by Pocomatic Software. All Rights Reserved.
As discussed in the article Why and What of Inversion of Control, the IoC technology shifts the plumbing complexities of object-oriented applications into dynamically reconfigurable component frameworks and declarative application descriptions. This allows application developers or even domain users to focus on implementing high level business logic and flexibly assemble up their applications without relying on contrived low level techniques, assuming application description schemas are reasonably expressive.
Nevertheless, application descriptions in core schemas of IoC frameworks are more or less plain C/C++ or java function invocations expressed in XML. For instance, assuming a GPS device consists of three software components wired up as in the following diagram:

As illustrated in the tutorial example, using the core IoC schema of PocoCapsule, the setup of this GPS device application can be described by the following XML stanza (examples/basic-ioc/gps/setup.xml):
|
<bean
id=”gps-locator” class=”GPSLocatorImpl”
<ioc
method=”subscribe”>
<method-arg ref=”nav-display”/>
</ioc>
</bean>
<bean
id=”nav-display” class=”NavDisplayImpl”>
<method-arg ref=”gps-locator”/>
</bean>
<bean
id=”tick-gen” class=”TickGenImpl” lazy-init=”false”>
<method-arg
type=”short” value=”10”/>
<method-arg type=”short” value=”1”/>
<ioc
method=”subscribe”>
<method-arg ref=”gps-locator”/>
</ioc>
<ioc method="start"/> </bean>
|
Intuitively, this XML stanza expresses the following imperative C++ code segment:
|
// instantiate the
position locator
GPSLocator* locator = new GPSLocatorImpl;
// instantiate a
position display,
// with ref of the
locator to retrieve position data.
NavDisplay* display = new NavDisplayImpl(locator);
// subscribe the
display to locator – to receive position
// change
notification.
locator->subscribe(display);
// instantiate the
tick generator, with appropriate
// configure setting:
the 1st arg is the count of ticks,
// the 2nd
arg the is interval (seconds) between ticks.
TickGen*
tick_gen = new TickGenImpl(10, 1);
// subscribe the
locator to the tick generator, to
// receive the
position pulling interval tick.
tick_gen->subscribe(locator);
// start the gps
device
tick_gen->start();
|
Such a low level schema has the advantages of being compact, straightforward, and generically applicable to virtually all practical problem domains. However, the compactness and generality come with the weaknesses of poor expressiveness and involving low level programming signatures (APIs). Therefore, IoC core schemas are error-prone and not desirable for domain users. For instance, the tick generator in the GPS example is to be instantiated using TickGenImpl class constructor with two arguments. From the IoC declaration and the equivalent C++ code, one would not able to tell the meaning and intention of these parameters. If the argument types were wrongly declared, the error could certainly be caught by the underlying reflection engine, however, with an error message hardly make sense for high level domain users. In a worse case, if their types of these two arguments were correctly declared but their values were accidentally swapped, it would hardly be noticed by users and not detectable by the container. Some attempts such as using property setters instead of multi-argument constructors/factories might address some of these pitfalls. However, these kludges would introduce additional verboseness and complexities that eventually defeat the meaning of using such a framework.
A better approach to address above issues is to raise the abstraction level of the framework by adding problem domain specific vocabularies and higher level syntactic constructs into the IoC core schema. For instance, with a higher level schema examples/basic-ioc/dsm-gps/gps-device.dtd, the same GPS device setup could be declared in the following XML stanza (examples/basic-ioc/dsm-gps/setup.xml):
|
<gps-device>
<tick-generator use=”TickGenImpl”
count=”10”
interval=”1”/>
<gps-locator use=”GPSLocatorImpl”/>
<navigation-display use=”NavDisplayImpl”/>
</gps-device>
|
Now, this GPS device setup description does not involve low level programming models and is much more readable by domain users. In additional, many low level syntactic errors can either be prevented in the first place or be detected by the XML parser with error messages easily comprehensible by domain users.
For other applications, such as Web Services and SOA, software define radios (SDR), robot technology component applications, video games, high performance computing (HPC), telecomm network management (TMN), intelligent networks (IN/AIN), CORBA POA servers, OMG Notification/DDS participants, one could keep adding vocabularies and syntactic constructs into the core IoC schema. Eventually, the accumulated schema could be expressive for pretty generic applications, however awfully bloated and complex. This is the dilemma of expressiveness and diversity vs. intuitiveness and simplicity.
As a solution to this dilemma, instead of enforcing a bloated one-size-fits-all generic god schema predefined by the framework, the framework could allow and encourage users or third parties to extend or even redefine the core schema into different customized variations for their specific problem domains. These user defined schema variations are referred to as domain specific modeling or domain specific language (DSM or DSL). As each of these schemas is only designed for one specific problem domain, they are able to be simple, intuitive while still highly expressive with a relative small set of problem specific vocabularies and high level syntactic constructs.
A widely used stone-age approach to enable user-defined DSMs/DSLs is to explicitly modify or recreate a new application description parser for each new schema. A seemingly clever new approach is to implicitly alter/enhance the parser using user implemented plug-in handlers to process XML DOM nodes of user defined schema elements. Both of these two approaches are imperative, proprietary, and involve low level XML DOM handling. Therefore, they are costly to develop/maintain, not meant for domain users, not able to be automated/tooled, and tightly tie to the particular IoC container.
Modeling application high level setups with user-defined schema elements is similar to modeling business entities (objects) with user-defined classes. A class in an OO programming language captures common characters of a category of business objects. Similarly, an user-defined schema element codifies recurring setup expression of applications. User-defined classes are supported by mainstream OO languages straightforwardly, intrinsically, and portably. Especially, to compile a source code containing user-defined classes, users neither have to modify the compiler nor need to implemented compiler plug-in handlers.
PocoCapsule IoC framework uses the model transformation approach to support user-defined DSM/DSL schemas. It simply leverages the declarative and component model neutral IoC infrastructure itself and the standardized, mature, and ubiquitous W3C Extended Stylesheet Language Transformations (XSLT) technology. Contrary to the stone-age and the clever solutions discussed previously, this model transformation approach does not involve any proprietary plug-in API or low level XML DOM. Therefore, it is straightforward even for domain users, easily portable across IoC containers (in different core schemas), open and friendly to third party tool vendors and existing tools as well.
Specifically, in this approach, for each user-defined DSM/DSL schema, the schema designer defines a set of source node to target nodes mapping templates that maps this DSM schema to a target schema, such as to the core schema. This set of templates is referred to as the stylesheet of the schema transformation. Typically, schema transformation stylesheets are also declared in XML documents (inline templates could also be supported).
Then, to use this user-defined DSM schema, a source application description (a XML file or string) should have the stylesheet file name (or URL) declared as its href attribute of the <?xml-transform> or <?xml-stylesheet> process instruction (PI). PocoCapsule framework will recursively perform schema transformations on the input and output application descriptions by their indicated stylesheets, until the final output result no longer has such a process instruction, presumably it has ended up with the core schema. Almost all practical DSM/DSL syntactic and semantic designs are able to be supported in this approach, because the underlying core schema is designed to support sufficiently generic C/C++ API invocation scenarios.
Lisp and C/C++ developers should be familiar with the scenario above. Schema transformation XSL templates in a stylesheet file are similar to Lisp defmacro S-expressions or C/C++ pre-process #define directives in a header file. The process instruction specifying the name or URL of a stylesheet in a given application description is similar to an #include directive specifying the header file in a C/C++ source code.
As said previously, model transformation stylesheets themselves are also XML documents typically. The default language of them is W3C XSLT. However, PocoCapsule also supports the so-called higher order transformation (HOT) that performs schema transformations on stylesheets (and even stylesheets of stylesheets, and so on) in the same way as on application descriptions. This allows users to design and use user-defined domain specific languages (DSL) to simplify their stylesheets instead of the verbose and error-prone XSLT.
The same GPS example is used to illustrate the design and use scenarios of user-defined DSM/DSL schemas in PocoCapsule. The full source code of this DSM'ized GPS example, including all C++ source code, XML/XSL documents, Makefile(s), and README document, can be found in the examples/basic-ioc/dsm-gps directory of a PocoCapsule installation.
In this example, the DSM/DSL schema for the GPS devices is defined as follows (see the examples/basic-ioc/dsm-gps/gps-device.dtd):
| <!ELEMENT gps-device (tick-generator, gps-locator, navigation-display*)
<!ELEMENT tick-generator EMPTY> <!ATTLIST tick-generator use CDATA #REQUIRED> <!ATTLIST tick-generator count CDATA #REQUIRED> <!ATTLIST tick-generator interval CDATA #REQUIRED>
<!ELEMENT gps-locator EMPTY> <!ATTLIST gps-locator use CDATA #REQUIRED>
<!ELEMENT navigation-display EMPTY> <!ATTLIST navigation-display use CDATA #REQUIRED>
|
In this DSM/DSL schema, a GPS device is declared as a composite consists of a tick-generator, a gps-locator, and arbitrary number of navigation-display components. The use attribute of these elements specifies the POCO implementation class to be used to instantiate the given component. The count and interval attributes of the <tick-generator> element specifies configuration parameters of the tick generator. All low level API signatures and component wirings are milted away. With this DSM/DSL schema, the same GPS device now can be described in the following application description (examples/basic-ioc/dsm-gps/setup.xml):
|
<gps-device>
<tick-generator use=”TickGenImpl”
count=”10”
interval=”1”/>
<gps-locator use=”GPSLocatorImpl”/>
<navigation-display use=”NavDisplayImpl”/>
</gps-device>
|
The designer of this schema should define the stylesheet of transformation templates that transforms this DSM/DSL schema to either an intermediate schema or directly to the final core IoC schema. Each individual template specifies the macro expansion of a given individual or a set of DSM/DSL node(s) (elements and attributes) into the target schema. For instance, the following template (see examples/basic-ioc/hot/gps-device2poco.dsl) defines the macro expansion of <tick-generator> element and its attributes into the core schema of PocoCapsule:
|
<!-- DSL transform template for
element
<tick-generator
use=”@use” count=”@count” interval=”@interval”> --> <dsl-template match=”tick-generator”> <bean class=”@use” destroy-method=”delte” lazy-init=”false”> <method-arg type=”short” value=”@count”/> <method-arg type=”short” value=”@interval”/>
<ioc method=”subscribe”> <method-arg ref=”gps-locator”/> </ioc>
<ioc method=”start”/> </bean>
</dsl-template>
|
For simplicity, this transformation template itself is also declared in a more expressive and less verbose DSL schema. Templates in this schema can be transformed to W3C XSLT templates using the higher order transformation (HOT) stylesheet http://www.pocomatic.com/poco-dsl2xsl.xsl. The corresponding W3C XSL template actually looks like the following <xsl:template> declaration in the following stylesheet (examples/basic-ioc/dsm-gps/gps-device2poco.xsl):
|
<!--
XSL transform template for element
<tick-generator
use=”@use” count=”@count” interval=”@interval”> --> <xsl:template match=”tick-generator”> <bean destroy-method=”delte” lazy-init=”false”>
<xsl:attribute
name=”class”>
<xsl:value-of select=”@use”/> </xsl:attribute> <method-arg type=”short”>
<xsl:attribute name=”value”>
<xsl:value-of select=”@count”/>
</xsl:attribute> </method-arg> <method-arg type=”short”>
<xsl:attribute name=”value”>
<xsl:value-of select=”@interval”/>
</xsl:attribute> </method-arg>
<ioc method=”subscribe”> <method-arg ref=”gps-locator”/> </ioc>
<ioc method=”start”/> </bean> </xsl:template>
|
This transformation template expressed either in DSL or in the equivalent XSL form is fairly intuitive. It implies that the <tick-generator> element in this example is to be transformed (macro expand) into the following declaration in core IoC schema:
|
<!-- transformed from the DSL expression
<tick-generator use=”TickGenImpl”
count=”10” interval=”1”/> --> <bean class=”TickGenImpl” destroy-method=”delte” lazy-init=”false”> <method-arg type=”short” value=”10”/> <method-arg type=”short” value=”1”/>
<ioc method=”subscribe”> <method-arg ref=”gps-locator”/> </ioc>
<ioc method=”start”/> </bean>
|
For an user of this schema, to enable the desired schema transformation, the stylesheet file name or its URL should be specified in the <?xml-transform> or <?xml-stylesheet> process instruction (PI) of the input application description, for instance, as in the following description (examples/basic-ioc/dsm-gps/setup.xml):
|
<!-- DTD of this descriptor -->
<!DOCTYPE
gps-devicce SYSTEM “file:gps-device.dtd”>
<!-- Process
instruction (PI) specifies the
stylesheet -->
<?xml-transform
type=”text/xsl”
href=”file:gps-device2poco.xsl”?>
<gps-device>
<tick-generator use=”TickGenImpl” count=”10”
interval=”1”/>
<gps-locator use=”GPSLocatorImpl”/>
<navigation-display use=”NavDisplayImpl”/>
</gps-device>
|
Then, this application description is able to be handled by the PocoCapsule/C++ core IoC container and all its utilities (such as pxgenproxy, pxencode) seamlessly as if this DSM/DSL schema was an intrinsic built-in feature of the framework.
To help users design their DSM/DSL schema, PocoCapsule comes with a handy utility, the pxtransform. This utility performs schema transformation recursively on the input document and writes the final result to another file or screen (when specified -E option). For instance, with the following command line:
|
% pxtransform setup.xml
|
The application description in the input file setup.xml will be transformed based on specified stylesheet in the <?xml-transform>/<?xml-stylesheet> process instruction. The output is to be written to setup_poco.xml by default.
By this model transformation approach, an IoC framework is able to support diverse DSMs/DSLs schemas easily. Combining with the inherent component model neutrality, an IoC and DSM/DSL integrated framework, such as PocoCapsule, turns out to be a effective framework for building other user-defined or committee-designed high level frameworks of various component models and description schemas.
Traditionally, these component frameworks are crafted from scratch manually with thousands or even tens of thousands lines of code and weeks or even months of efforts of a skillful framework developer. In a significant contrast, using an IoC+DSM/DSL framework, such as PocoCapsule, an average developer or even a domain user without much OO programming discipline is able to comfortably construct the same high level component framework in just a couple of days or even hours with less than a few hundreds lines of highly descriptive and self-documented code.
The following standardized or user-defined component frameworks, built from IoC and DSM technologies, are presented in PocoCapsule out-of-the-box.
The OpenSOA SCA assembly container: The Service Component Architecture (SCA, now becomes the OASIS Open-CSA) originally from Open-SOA group is a component-based framework for assembling and deploying WebServices applications.
JTRS-SCA core framework (CF) assembly container: The JTRS-SCA core framework (CF) for building component-based Software Defined Radio (SDR) applications.
PocoCapsule/CORBA: A CORBA server component framework for building POA server and OMG Event/Notification applications
PocoCapsule/DDS: A CORBA component framework for building OMG Data Distribution Service (OMG-DDS) applications.
PocoCapsule/RTC: A CORBA component framework for building OMG Robotic Technology Component (OMG-RTC) applications.
Other user-defined component frameworks for building WebServices, SDR, and robotic component applications.
These frameworks and their schema transformations to the PocoCapsule core schema are illustrated in the following diagram.

The PocoCapsule IoC&DSM framework encourages more user-defined DSM/DSL schemas than the primitive core schema. It either uses DSM/DSL as a mechanism to support high level frameworks for CORBA, OMG-DDS, Robotic Technology Component/OMG-RTC, Software Defined Radito (SDR)/JTRS-SCA, and WebServices/SCA applications, or leverages the DSM/DSL capability to enhance the core schema to support <map> and <property> in a type safe scenario. Within 25 examples of PocoCapsule, 19 of them use DSM/DSL schemas.
The inversion of control (IoC) technique was thought to be no more than a plain-old design pattern, a lousy way of wiring up objects via dependency injection, or a test driven development (TDD) methodology. Similarly, the concept of domain specific modeling (DSM) was seen merely as a response and alternative to the to-be-all-things-to-all-people UML based MDA and CASE tools. Like its predecessors, classic DSM solutions for C++ and Java applications were typically development phase tools and focused on application generation based on high level (and usually visual) designs.
The combination of the model transformation based DSM and the IoC based CBD framework prompts a new paradigm of software engineering. This change can better be understood by first looking at the following three eras in database evolving history:
Pre-database era: There was no database concept then. Data was intimately tied to the application programs that processed/used it (Richard G. Canning in 1973 Turing Award citation).
Pre-relational era: Database concept emerged that decoupled data from application programs. However, the burden of finding information from data stored in databases was placed heavily on users. Users had to write imperative and data store implementation dependent programs to navigate a data set step-by-step (therefore, these databases were also referred to as navigational database).
Relational era: a) Data are expressed in implementation independent and easily comprehensible model -- the relational model. b) High level declarative data manipulation languages (such as SQL) are provided for users to access data. These language are able to handle and return data sets in one single step (statement).
Now look at applications developed in classic OO languages (such as C++ and Java). From the component composition point of view, codes in such an application can be categorized as component implementations and component plumbings (e.g. instantiation, provisioning, lifecycle controling, and wiring). With this code classification, there are following three component plumbing scenarios:
Tightly coupled scenario: By this scenario, application component implementation and plumbing programs are tied and mixed together.
Decoupled scenario without an IoC framework: The application is designed following the dependency injection principle. Hence, application component plumbings are separated out and decoupled from component implementations. However, the burden of plumbings is still placed on users (programmers). They have to write imperative and component model dependent programs to wire components together into an application.
Decoupled scenario with an IoC + DSM framework: a) Facilitated by an IoC framework, plumbing logics are expressed in component programming model independent and easily comprehensible structured data models -- declarative application descriptions. b) With high level declarative query/view/transformation languages (such as XSL, XQuery), application plumbing descriptions are further able to be manipulated (as data models) conveniently and flexibly by domain users.
It is easy to see the paradigm shift along these three plumbing scenarios is similar to the paradigm shift along the database history. Especially, in the third scenario, code of component plumbings are expressed and manipulated as data. Therefore, manipulating a DSM in this scenario is more like performing data set query/view/transformation in databases rather than code generation in traditional DSM products.
Comparing to the other two scenarios, the IoC + DSM scenario is much more intuitive, expressive, and error-proof. DSM schemas can largely prevent low level programming signatures to be used in application descriptions. Furthermore, these schemas can easily impose more constrained and sophisticated schema validations (such as expression structures and attribute value enumerations or ranges). Consequently, application descriptions declared in these DSM schemas are more desirable for domain users and safer than the code or annotation based configurations that (by default) rely on very primitive validations provided by the low level language type system.
Application wired up in other two scenarios tend to miss the forest for the trees. The imperative and/or low level nature of code logic and descriptions made it very hard for one to figure out the high level architecture design of a complex application and vice versa. Application high level refactoring/reorganizing, evolution, and maintaining were largely based on highly un-effective and unsafe methods such as reverse engineering code pattern, low level code comments, and manually generated documents. On the contrary, the declarative and domain specific nature of DSM in IoC frameworks make application high level and large scope architectures manifest and self-documented by their declarative descriptions.
Back to the PocoCapsule articles page
This page has been visited:
| free hit counter html code |