Mail Archive Home | fractal-commits List | May 2008 Index
| <-- Date Index --> | <-- Thread Index --> |
Cecilia Comanche example: third and last chunk of the conversion from LyX to APT.
--- sandbox/debrouxl/comanche/src/site/apt/index.apt 2008-05-28 11:24:49 UTC (rev 7806)
+++ sandbox/debrouxl/comanche/src/site/apt/index.apt 2008-05-28 11:49:49 UTC (rev 7807)
@@ -300,12 +300,133 @@
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Implementation
+ This section explains how to program Fractal component based applications, by
+ using the Comanche example. It also introduces and motivates the concepts and
+ APIs of Fractal that are used.
+
* Choosing the components' granularity
+ As explained in section {{{#Design}Design}}, component oriented design is
+ quite independent from component oriented implementation. In particular, at
+ programming time, it is possible to merge several or even all the design
+ time components into a single, monolithic piece of code, if desired.\
+ For example, in the case of Comanche, one may choose to implement all the
+ design time components into a single class, as shown in section
+ {{{#Design}Design}}.\
+ One may also choose to implement each component in its own class, or to
+ implement some components in their own class, and to merge some other
+ components (such as the request dispatcher and its associated request
+ handlers) into a single class.
+
+ Using one runtime component per design time component gives maximum
+ flexibility and extensibility, but can be less efficient that merging several
+ design time components into a single runtime component. When in doubt, <the
+ first solution should be preferred>: optimizations can be done later on, if
+ needed.\
+ In the case of Comanche, we will therefore use one runtime component per
+ design time component.
+
* Implementing the component interfaces
+ Before implementing the component themselves, the first step is to implement
+ their <interfaces>. Indeed the Fractal component model requires a strict
+ separation between interfaces and implementation for all components (see
+ section {{{#Introduction}Introduction}}).\
+ This design pattern is indeed useful to easily replace one component
+ implementation with another. It also offers the possibility to add
+ interposition objects between a client and a component implementation, in
+ order to transparently manage some non functional concerns of the component
+ (as in the Enterprise Java Beans model).\
+ The only drawback of this design pattern is that it is a little less
+ efficient than a solution without interfaces. This is why it may sometimes
+ be needed to merge several design time components into a single Fractal
+ component.
+
+ The component interfaces can be implemented easily, since most, if not all,
+ of the work has been done during the definition of the component contracts.
+ In the case of Comanche, three interfaces must be implemented. They are
+ given below (see Appendix Comanche source code for the most importants bits
+ of the source code of Comanche):
+
++------------------------------------------------------------------------------+
+interface RequestHandler { int handleRequest (any r); }
+
+interface Scheduler { void schedule(any task); }
+
+interface Logger { void log(string msg); }
++------------------------------------------------------------------------------+
+
+ Here, anonymous type any was used, but non-component types (such as
+ <<<struct>>>s) can be used in interface method parameters. <This is not
+ recommended>. It is indeed better to use interfaces, even for data structures
+ that are not represented as components: these data structures can then be
+ implemented in various ways (including as components), without needing to
+ change the interfaces that refer to them.\
+ Note also that it would have been better to introduce a request factory
+ component (this was not done for simplification purposes; see the
+ {{{../cloneable/index.html}Cecilia Cloneable example}} for more information
+ on how to do that).
+
* Implementing the components
+ Now that the component interfaces have been implemented, we can implement the
+ components themselves. The components that do not have any dependencies to
+ other components can be programmed like ordinary C ``modules''.
+ For example, the logger component can be implemented as follows:
+
++------------------------------------------------------------------------------+
+#include <stdio.h>
+
+DECLARE_DATA { } ;
+#include <cecilia.h>
+
+void METHOD(l, log) (void *_this, char * msg) {
+ fprintf(stdout,"Basic logger: log \"%s\"\n",msg);
+}
++------------------------------------------------------------------------------+
+
+ In component oriented programming, and in Fractal in particular, the
+ components that have dependencies to other components must be programmed in a
+ specific way. In Cecilia, this is done using the thinkMC ``language'' (C
+ macros such as <<<METHOD>>>, <<<REQUIRED>>> and <<<CALL>>>).\
+ The Cecilia toolchain generates code to glue the components together. This
+ code glue is compiled and linked with your application, and it has support
+ for one of the goals of Fractal, dynamic reconfigurations.
+
+ In fact, in Fractal, a component with dependencies (or <bindings>) to other
+ components must implement the <<<BindingController>>> interface, defined in
+ the Fractal specification. This interface defines four generic methods
+ <<<listFc>>>, <<<lookupFc>>>, <<<bindFc>>> and <<<unbindFc>>> to manage
+ component bindings.
+
+ The <<<listFc>>> method returns the names of the dependencies of the
+ component, and the <<<lookupFc>>>, <<<bindFc>>> and <<<unbindFc>>> methods
+ are used to read, set and unset the corresponding bindings (the <<<s>>> and
+ <<<rh>>> strings do not have to be equal to the names of the corresponding
+ fields).\
+ This enables good distinction between the <controller> and <content> part of
+ Fractal components (see section {{{#Introduction}Introduction}}): the
+ controller part corresponds to the <<<BindingController>>> interface, and the
+ content part to the <<<boot.api.Main>>> interface (in the logger and scheduler
+ components, the controller part was empty).
+
+ The <<<listFc>>>, <<<lookupFc>>>, <<<bindFc>>> and <<<unbindFc>>> methods are
+ implicitely implemented by the code glue generated by the Cecilia toolchain,
+ if the <cardinality> of the bindings is <singleton> (a single server interface
+ is bound to a client interface). If the <cardinality> is <collection>, you
+ (currently) have to implement the <<<BindingController>>> methods in your
+ source code. The <<<RequestDispatcher>>> component does it.
+
+ In order to do that, you have to know that each binding must have a name of
+ the form <prefix><<postfix>> where <prefix> is common to all the bindings of
+ the collection, and where <<postfix>> is arbitrary, but distinct for each
+ binding.\
+ Have a look at the implementation of the <<<RequestDispatcher>>> component,
+ which contains a partial implementation of the collection binding.
+ Once again, this partial implementation was done for simplification purposes,
+ since <<<Map>>>s (Java) / <<<hashes>>> (Perl and most scripting languages) are
+ not part of the standard C language.
+
* Summary
Components must be implemented with an appropriate granularity, resulting from
@@ -318,10 +439,109 @@
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Configuration
+ This section presents the method to assemble and deploy Fractal components,
+ always by using the Comanche example. It also introduces and motivates the
+ Fractal tools that are used.
+
* ADL based configuration
+ Configuration and deployment <could> be done using a program that instantiates
+ components, but this method has several drawbacks:
+
+ * it's not that trivial to program;
+
+ * it's error prone: it's easy to forget a binding or to create a wrong
+ binding.
+
+ * the component architecture is not directly visible (the component's
+ hierarchy description, in particular, is completely lost);
+
+ * most importantly, <this method mixes two separate concerns, namely
+ architecture description and deployment>. It is impossible to deploy a
+ given component architecture in several ways, without rewriting the
+ configuration/deployment program).
+
+ []
+
+ In order to solve these problems, a solution is to use an Architecture
+ Description Language (ADL). As its name implies, an ADL definition describes a
+ component architecture, and only that, i.e. its does not describe the
+ instantiation method. This solves the most important drawback of the previous
+ configuration method.\
+ An ADL is also generally strongly typed, which allows the ADL parser to
+ perform verifications about the declared component architecture. Using an ADL
+ is therefore less error prone and more flexible than using the programmatic
+ approach.
+
+ Cecilia ADL is a possible, XML based ADL that can be used to describe Fractal
+ component configurations. Other ADLs can be created if needed (indeed these
+ ADLs are not part of the Fractal component model itself: they are just tools
+ based on this model).\
+ Cecilia ADL is strongly typed. The first step to define a component
+ architecture is therefore to define the types of the components. Each
+ component type must specify what components of this type provide to, and
+ require from other components. For example, the type of the file and error
+ handler components (but also of the request handler and backend components),
+ in Comanche, can be defined as follows (these components provide a
+ <<<RequestHandler>>> interface, and do not have dependencies):
+
+%{snippet|id=Content|url=""
+
+ Components with dependencies are declared in a similar way. For example, the
+ type of the request dispatcher component, in Comanche, can be defined as
+ follows:
+
+%{snippet|id=Content|url=""
+
+ Note that this type is declared to <extend> the previous handler type: this
+ means that the provided and required interface types declared in the handler
+ type are inherited by the dispatcher type. Note also the optional
+ <cardinality> attribute in the interface type definition: it means that
+ components of this type can have a variable number of bindings (as mentioned
+ above).
+
+ After the component types have been defined, the components themselves can be
+ defined. Here Cecilia ADL distinguishes between components that do not expose
+ their content, called <<primitive components>>, and components that do expose
+ it, called <<composite components>>.
+
+ A primitive component is defined by specifying its component type and the C
+ ``module'' that implements it. For example, the file handler component can
+ be defined as follows:
+
+%{snippet|id=Content|url=""
+
+ A composite component is defined by specifying its sub-components, and the
+ bindings between these sub-components. For example, the Comanche composite
+ component, which represents the whole application, and which contains the
+ Frontend and Backend components, can be defined as follows:
+
+%{snippet|id=Content|url=""
+
+ This definition says that the Comanche component provides a <<<Runnable>>>
+ interface (to start the application), that it contains two sub components
+ named <<<fe>>> and <<<be>>>, that the <<<Runnable>>> interface provided by
+ Comanche (<<<this.r>>>) is provided by the <<<Runnable>>> interface of its
+ frontend sub-component (<<<fe.r>>>), and that the request handler required
+ by the frontend sub-component (<<<fe.rh>>>) is provided by the backend
+ component (<<<be.rh>>>).
+
+ Once the application's architecture has been defined, it can be compiled,
+ which gives a C ``module'', in source code. The Cecilia ADL parser performs
+ preliminary verifications to check the architecture and, in particular,
+ to check that there is no missing or invalid binding.
+
+ If one wants to change the implementation of one or more of the components
+ used in the program (e.g. use a multi-threaded scheduler instead of a
+ sequential, synchronous one), modifying a few characters in an ADL file
+ is all that's necessary.
+
* Summary
+ Components can be configured and deployed in two different ways. The
+ programmatic approach mixes different concerns, and is not that trivial to
+ implement in C. The ADL-based approach correctly separates these concerns.
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Conclusion
@@ -377,7 +597,8 @@
implementation-specific files (semaphores, wrappers for several POSIX/*nix
functions).
- Notice the <<METHOD>>, <<CALL>> and <<DECLARE_DATA>> syntactic sugar.
+ Notice the <<METHOD>>, <<CALL>>, <<REQUIRED>> and <<DECLARE_DATA>> syntactic
+ sugar.
* Component interfaces
| <-- Date Index --> | <-- Thread Index --> |
Powered by MHonArc.
Copyright © 2006-2007, OW2 Consortium | contact | webmaster.