Fractal ADL Tutorial



AUTHOR :       
E. Bruneton          (France Telecom R&D)

Version   1.1
Released    September 12, 2003




This tutorial explains how the Fractal ADL and the Fractal ADL parser can be used to describe and instantiate Fractal applications. It is based on the example used in the Fractal tutorial, namely the HelloWorld example. The content of this tutorial is independent of any specific implementation of the Fractal API.

The ADL definitions described here can be found in the examples/helloworld directory of the Fractal distribution archive.

1 The Fractal ADL

The Fractal ADL is an XML based Architecture Description Language. It is based on three main constructs to specify component types, primitive templates and composite templates.

1.1 Specifying component types

1.1.1 Overview

Component types are specified with <component-type> elements. A component type element specifies the interfaces that are provided and required by components of this type. For example, the type of the HelloWorld root component, which provides a Main interface named m, and which does not require any interface, can be specified like this:
<component-type name="RootType">
  <provides>
    <interface-type name="m" signature="Main"/>
  </provides>
</component-type>

The type of the client component, which provides a similar interface, but which also has a client Service interface named s, can be specified like this:

<component-type name="ClientType">
  <provides>
    <interface-type name="m" signature="Main"/>
  </provides>
  <requires>
    <interface-type name="s" signature="Service"/>
  </requires>
</component-type>

It is also possible to define this type by extending the RootType definition:

<component-type name="ClientType" extends="RootType">
  <requires>
    <interface-type name="s" signature="Service"/>
  </requires>
</component-type>

This definition is equivalent to the previous one. In other words, ClientType inherits the m interface type from RootType. The type of the server component, which only provides a Service interface named s, can be specified like this:

<component-type name="ServerType">
  <provides>
    <interface-type name="s" signature="Service"/>
  </provides>
</component-type>

The server component also has an attribute controller interface, but this interface should not be specified in the type of this component: component types should only describe the functional interfaces of components, not their control interfaces.

1.1.2 Formal definition

The general form of <component-type> elements is the following:
<component-type name="..." extends="...">
  <provides>
    <interface-type name="..." signature="..." contingency="..." cardinality="..."/>
    ...
  </provides>
  <requires>
    <interface-type name="..." signature="..." contingency="..." cardinality="..."/>
    ...
  </requires>
</component-type>

The extends, signature, contingency and cardinality attributes are optional, as well as the <provides> and <requires> sub elements. The signature attribute can be omitted only when overriding an existing interface type definition. The contingency attribute must be equal to mandatory or optional. The default value is mandatory. The cardinality attribute must be equal to single or collection. The default value is single. The semantics of the inheritance mechanism is defined in Appendix A.

1.2 Specifying primitive templates

1.2.1 Overview

Primitive templates are specified with <primitive-template> elements. A primitive template element specifies the name of a Java class, and the component type that this class implements. For example, the template of the primitive client component of the HelloWorld application, which implements the ClientType type in the ClientImpl class, can be specified like this:
<primitive-template name="ClientImpl" implements="ClientType">
  <primitive-content class="ClientImpl"/>
</primitive-template>

The template of the primitive server component, which implements the ServerType type in the ServerImpl class, can be specified like this:

<primitive-template name="ServerImpl" implements="ServerType">
  <primitive-content class="ServerImpl"/>
  <controller>
    <attributes signature="ServiceAttributes">
      <attribute name="Header" value="-> "/>
      <attribute name="Count" value="1"/>
    </attributes>
  </controller>
</primitive-template>

This definition is slightly more complex than the previous one because the server component has two attributes, named Header and Count, which can be controlled with the ServiceAttributes attribute controller interface.

1.2.2 Formal definition

The general form of <primitive-template> elements is the following:
<primitive-template name="..." implements="..." extends="...">
  <primitive-content class="..."/>
  <controller>
    <attributes signature="...">
      <attribute name="..." value="..."/>
      ...
    </attributes>
    <template-controller desc="..."/>
    <component-controller desc="..."/>
  </controller>
</primitive-template>

The implements, extends, and signature attributes are optional, as well as the <primitive-content>, <controller>, <attributes>, <template-controller> and <component-controller> sub elements. The implements attribute can be omitted only when the extends attribute is defined. The <template-controller> and <component-controller> elements can be used to specify the controller descriptor of the template component, and of the components it instantiates. The semantics of the inheritance mechanism is defined in Appendix A.

1.3 Specifying composite templates

1.3.1 Overview

Composite templates are specified with <composite-template> elements. A composite template element specifies a set of sub components, a set of bindings between these sub components, and the component type that this assemblage implements. For example, the template of the root composite component of the HelloWorld application, which implements the RootType type, with two sub components named client and server, of type ClientType and ServerType, can be specified like this:
<composite-template name="ClientServer" implements="RootType">
  <composite-content>
    <components>
      <component name="client" type="ClientType"/>
      <component name="server" type="ServerType"/>
    </components>
    <bindings>
      <binding client="this.m"   server="client.m"/>
      <binding client="client.s" server="server.s"/>
    </bindings>
  </composite-content>
</composite-template>

Each <binding> element specifies a client interface and a server interface. Each interface is specified by the name of a sub component (or this to designate the composite template itself), followed by a dot, followed by the name of an interface of this component. The above definition just gives the type of the client and server sub components. In order to specify their implementation, one must extend the previous definition with a definition such as the following:

<composite-template name="ClientServerImpl" extends="ClientServer">
  <composite-content>
    <components>
      <component name="client" implementation="ClientImpl"/>
      <component name="server" implementation="ServerImpl"/>
    </components>
  </composite-content>
</composite-template>

This definition says that the client and server sub components are in fact the primitive components described by the ClientImpl and ServerImpl primitive templates. It is also possible to use composite components for the client and server sub components. For example, the following definitions describe a configuration where the client and server primitive components are wrapped inside intermediate composite components (as in section 2.2 of the Julia tutorial):

<composite-template name="WrappedClientImpl" implements="ClientType">
  <composite-content>
    <components>
      <component name="client" type="ClientType" implementation="ClientImpl"/>
    </components>
    <bindings>
      <binding client="this.m" server="client.m"/>
      <binding client="client.s" server="this.s"/>
    </bindings>
  </composite-content>
</composite-template>
<composite-template name="WrappedServerImpl" implements="ServerType">
  <composite-content>
    <components>
      <component name="server" type="ServerType" implementation="ServerImpl"/>
    </components>
    <bindings>
      <binding client="this.s" server="server.s"/>
    </bindings>
  </composite-content>
</composite-template>
<composite-template name="WrappedClientServerImpl" extends="ClientServer">
  <composite-content>
    <components>
      <component name="client" implementation="WrappedClientImpl"/>
      <component name="server" implementation="WrappedServerImpl"/>
    </components>
  </composite-content>
</composite-template>

It is possible to instantiate a template even if some sub component implementations are not defined, as long as all mandatory interfaces can be bound. For example, if the s interface in ClientType was optional, then it would be possible to instantiate the following composite template, where the implementation of the server component is not specified:

<composite-template name="ClientOptionalServerImpl" extends="ClientServer">
  <composite-content>
    <components>
      <component name="client" implementation="ClientImpl"/>
    </components>
  </composite-content>
</composite-template>

The result is a composite component that contains only one sub component.

1.3.2 Formal definition

The general form of <composite-template> elements is the following:
<composite-template name="..." implements="..." extends="...">
  <composite-content>
    <components>
      <component name="..." type="..." implementation="..."/>
      ...
    </components>
    <bindings>
      <binding client="..." server="..."/>
      ...
    </bindings>
    <sharing>
      <shared-component path="..." ref="..."/>
      ...
    </sharing>
  </composite-content>
  <controller>
    <attributes signature="...">
      <attribute name="..." value="..."/>
      ...
    </attributes>
    <template-controller desc="..."/>
    <component-controller desc="..."/>
  </controller>
</composite-template>

The implements, extends, type and signature attributes are optional, as well as the <composite-content>, <components>, <bindings>, <sharing> and <controller> sub elements. The implements attribute can be omitted only when the extends attribute is defined. The type attribute can be ommitted only when overriding a sub component definition. Bindings can only be defined if some sub components are defined in the current template, or in one of its super templates. Likewise for shared components, specified in the <sharing> element. In this element, a <shared-component> element means that the component designed by path (wich is a slash separated path relative to the current template) must be replaced by the component designed by ref (which is another path relative to the current template). The semantics of the inheritance mechanism is defined in Appendix A.

1.4 Specifying external templates

External templates are specified with <external-template> elements. An external template element specifies a name that can be used to retrieve an already instantiated component (the exact mechanism to retrieve the component is not specified. It can be JNDI, an RMI registry...). The general form of <external-template> elements is the following:
<external-template name="..." implements="...">
  <reference name="..."/>
</external-template>

All the attributes and sub elements are mandatory. The name attribute in the <reference> element is the name to be used to retrieve the already instantiated component. The org.objectweb.fractal.api.bootstrap name is reserved. It designates the fractal bootstrap component.

2 The Fractal ADL Parser

The Fractal ADL parser is a Fractal composite component that implements a parser for the Fractal ADL. This component, which is independent of any specific implementation of the Fractal API, loads type and template definitions and creates corresponding ComponentType objects and Template components. This section explains how the Fractal ADL parser can be used to instantiate Fractal applications.

2.1 Launching an application

In order to instantiate a Fractal application with the Fractal ADL parser, one must first construct the Fractal ADL parser component itself. This can be done with the following code:

Parser parser = Launcher.getBootstrapParser();

The getBootstrapParser method constructs a bootstrap parser component with the Fractal API. This parser can then be used to load the template of the application:

Component tmpl = parser.loadTemplate("ClientServerImpl", true);

The application itself is then created by instantiating and starting this template component:

Component comp = Fractal.getFactory(tmpl).newFcInstance();
Fractal.getLifeCycleController(comp).startFc();

And that's all! It is even not necessary to use an intermediate template component, by using false in the second argument of the loadTemplate method:

Component comp = parser.loadTemplate("ClientServerImpl", false);
Fractal.getLifeCycleController(comp).startFc();

It is also possible to launch an application without any Java code, directly from the command line, provided this application starts itself when constructed, or provides a run interface of type Runnable. In this case, the following command will directly start the application:

java ... org.objectweb.fractal.adl.Launcher template-name

If you want to use another parser component than the default bootstrap one, you can use the default parser to load the template of your own parser, instantiate this template, and use the resulting parser to load and instantiate your application as above:

Parser parser = Launcher.getBootstrapParser();
Component parserTmpl = parser.loadTemplate("MyParser");
Component parserComp = Fractal.getFactory(parserTmpl).newFcInstance();
parser = (Parser)parserComp.getFcInterface("parser");

Component tmpl = parser.loadTemplate("ClientServerImpl");
Component comp = Fractal.getFactory(tmpl).newFcInstance();
Fractal.getLifeCycleController(comp).startFc();

2.2 Specifying templates for the Fractal ADL parser

The Fractal ADL parser loads component type and template definitions from the classpath, like compiled Java classes. For example, if the classpath is build:externals/lib.jar, then a component type or template named foo.bar is loaded by looking for a file named foo/bar.fractal in the build directory, and then, if it is not found here, in the externals/lib.jar archive. This file is supposed to contain a single root XML element named foo.bar (like a class file, which contains only one compiled class).

The type and template name hierarchy can be arbitrary but it is convenient to reuse the class name hierarchy for component type names and template names. For example, if a class foo.bar.IImpl implementing an interface foo.bar.I can be used as a Fractal component, then it is convenient to define a component type named foo.bar.I or foo.bar.IType, and a primitive template named foo.bar.IImpl for this Fractal component. Indeed, this way, the compiled classes and the corresponding XML type and template descriptors will be in the same directories:

foo/
  bar/
    I.class
    I.fractal
    IImpl.class
    IImpl.fractal

In order to get the compiled classes and the corresponding XML descriptors in the same directory, named for example build, it is convenient to define the .fractal files in the Java source tree, along with the .java files, and to copy them automatically in the build directory:

build/
  foo/
    bar/
      I.class
      I.fractal      // copy of src/foo/bar/I.fractal
      IImpl.class
      IImpl.fractal  // copy of src/foo/bar/IImpl.fractal
src/
  foo/
    bar/
      I.java
      I.fractal
      IImpl.java
      IImpl.fractal

However it is not very practical to define each component type and each template in a separate file. The fractalc Ant task can be used to solve this problem: indeed it can split a file containing several component types and templates definitions, whose names and locations can be arbitrary, into several files containing only a single definition. This task takes as argument one or more files to be split, and the name of an output directory, and puts the splitted files, appropriately named, in appropriate sub directories of the given output directory. Thanks to this task it is possible to organize the source directory in the following way:

src/
  foo/
    bar/
      I.java
      IImpl.java
      Components.fractal // contains the foo.bar.I and foo.bar.IImpl definitions

The build directory can then be obtained by calling the javac task and then the fractalc task:

  <target name="compile">
    <mkdir dir="${build}"/>
    <javac srcdir="${src}" destdir="${build}">
      <include name="**/*.java"/>
    </javac>
    <fractalc srcdir="${src}" destdir="${build}">
      <include name="**/*.fractal"/>
    </fractalc>
  </target>

The fractalc task can also verify the definitions after they have been copied into the output directory (with the verify="true" option). This can be useful to detect errors as soon as possible. Finally the fractalc task can also generate in the output directory the .kilim files corresponding to the Fractal type and template definitions (with the kilim="true" option).

Appendix A Semantics of the inheritance mechanism

By definition, an XML element e that extends another XML element f is equivalent to the merging of e into f. The merging of an element e into an element f is an element g defined in the following way: For the Fractal ADL, the elements whose sub elements are merged with the first rule are the following: <provides>, <requires>, <attributes>, <components>, <bindings> and <sharing>. The attribute that gives the "name" of the sub elements is the client attribute for <bindings>, the path attribute for <sharing>, and the name attribute in all other cases.