Subsections

The developer's job

Remember, the component developer implements the behavior of the component with respect to the defined interfaces. This section shows how the CCM Tools make this job easier.

Set up component environment

Before we can develop components, we have to create the component's environment. First, we create or extend the Confix configuration file /.confix (see the Confix manual for more details). An example Confix configuration file is included in the CCM Tools source distribution, and Example 3.3.1 shows a basic template.
\begin{Example}
% latex2html id marker 299\begin{lrbox}{\fmbox}\begin{minipage...
...box{\usebox{\fmbox}}\caption{A skeletal Confix configuration file.}\end{Example}

Next, we install the local C++ component runtime libraries:

~/hello> ccmtools-c++-environment
The libraries will be installed into the PREFIX directory specified in your Confix configuration. Note that the CCM Tools always use the ``ccmtools'' Confix profile.

That's it, now we are ready to implement components. Note that the component's environment is installed only once for all the components we implement.

Create an empty component

To get the component logic and the skeletons of the business logic from the IDL file, we start the local C++ code generator:

~/hello> ccmtools-c++-generate -c 1.0 -d -p hello1.0 Hello.idl

The ccmtools-c++-generate call accepts a bunch of command line parameters. In the example we only use a few to demonstrate the possibilities. An in depth description of the CCM Tools is out of the scope this tutorial (see the CCM Tools User's Guide instead), but here is a short description of the options we used:

After calling ccmtools-c++-generate, we have a new subdirectory (hello1.0) that contains the generated component logic. Also, the skeletons for the business logic have been copied into the current directory:

  hello/
  |-- HelloHome_app.cc
  |-- HelloHome_app.h
  |-- HelloHome_mirror_app.cc
  |-- HelloHome_mirror_app.h
  |-- Hello_app.cc
  |-- Hello_app.h
  |-- Hello_mirror_app.cc
  |-- Hello_mirror_app.h
  |-- Hello.idl
  |-- Hello_user_types.h
  |-- _check_CCM_Session_Hello.cc
  |-- hello1.0/

The component developer really ought not to care about the generated component logic in the subdirectory (if you don't believe us, though, feel free to read through it; just don't edit anything). The interesting files are in the current directory. These files are as follows:

The generated business logic skeletons contains enough code to be compilable. Each method includes a debug statement that prints out the file name and the method name of the executed function. Thus, we have an empty but compilable component. Let's compile it!

~/hello> ccmtools-c++-configure -p hello1.0
~/hello> ccmtools-c++-make -p hello1.0

The ccmtools-c++-configure and ccmtools-c++-make scripts also accept command line parameters as described below:

After compiling the source code, the test client calls some operations of the generated component logic. The running test prints out a lot of debugging messages; these messages document the execution flow of the program. The first component is running!

Test driven development

Software development is an iterative process. Kent Beck [1] proposed a Test Driven Development (TDD) methodology that starts by implementing the test - before implementing the application!

Figure 3.2: Test driven development process
\includegraphics[width=6cm,angle=0]{TestDrivenDevelopment}

As shown in Fig. 3.2, the CCM Tools make use of the TDD idea in the context of components. For every component $C$, the CCM Tools generate a mirror component $\overline{C}$. Each input port (receptacle) of $C$ corresponds to an output port (facet) of $\overline{C}$, and vice versa. A test client coordinates creating and connecting the components, as well as the test calls to the facets of $C$.

The current component directory contains the skeletons of the mirror component business logic and the test client:

Note that the mirror component $\overline{C}$ and the test client are always generated at the same time as the component itself, without additional development effort. Both of these pieces of generated code can be suppressed by leaving out the debug (-d or -debug) parameter when generating the component code with ccmtools-c++-generate.

As explained above, the component's unit test client creates $C$ and $\overline{C}$ instances and connects these components together as shown in Fig. 3.2. This process begins automatically after compiling. Later on, if you want to rerun the test to impress colleagues and pets, you can type:

~/hello> /tmp/hello1.0/CCM_Test/hello1.0_CCM_Test__check_CCM_Session_Hello

Write the test first

Now is a good time to start the development of business code. First, we have to define the behavior of the business code in an executable semantic. Thus we write a test case in the mirror component (Hello_mirror_app.cc), as shown in Example 3.3.2.


\begin{Example}
% latex2html id marker 382\begin{lrbox}{\fmbox}\begin{minipage...
...tion{Business logic implementation in a mirror component function.}\end{Example}

The test case is implemented in the ccm_activate() callback method of the mirror component because this method is called after creating and connecting $C$ and $\overline{C}$. We use the context object (ctx) to get a smart pointer to the facet of $C$ before we call the println() operation. To compile and run the unit test again, we just use the CCM Tools C++ component make tool:

~/hello> ccmtools-c++-make -p hello1.0

From the output of the test client, we can see that the println() method of $C$ is called from the mirror component $\overline{C}$, but println() in the test fails. Remember, there is no business code implemented in println(); it is an empty function skeleton! Note that functions with a void return type will not fail the test, because the test client has no way of receiving notification that such function calls succeeded.

Write the business logic

Finally, we can implement the business logic that satisfies the written test case. We open the Hello_app.cc file and add a single line, as shown in Example 3.3.3.


\begin{Example}
% latex2html id marker 408\begin{lrbox}{\fmbox}\begin{minipage...
...x}}\caption{Business logic implementation in a component function.}\end{Example}

As discussed above, the println() method simply prints out the given string and returns the number of characters of the string - that's it! We'll run the test again to see if it's working:

~/hello> ccmtools-c++-make -p hello1.0

Yay, the unit test passed!

Note that all the hand crafted code is in the current directory. There is no need to touch the generated code in hello1.0. To protect the business code from overwriting, the ccmtools-c++-generate tool creates the *_app.[h,cc] files only if they do not exist. If you really want to overwrite these business logic files, however, you can use the force (-f or -force) option to the ccmtools-c++-generate tool.

Deploy the component

Deploying a component means that the component's source code will be compiled into a component library file. This library file will then be stored in the component repository, which is simply a directory on the computer that will serve as a component server. The CCM Tools provide this functionality in a single call:

~/hello> ccmtools-c++-install -p hello1.0

The ccmtools-c++-install script accepts the following command line parameters:

After being installed, the component is part of the component repository and can be used in a component assembly or a local client.

Write a local test client

A component based application builds up component assemblies using deployed components. In this section we'll show this task using a simple test client that instantiates the Hello component and calls the component's operations.

First, we'll add a test directory to our project and implement the client code in the subdirectory client:

    hello/
    |-- hello1.0/
    |-- test/
    |   |-- client/
    |   |   |-- client.cc

The test client needs a bunch of included header files that are generated by the CCM Tools. There are different namespaces defined in the header files that we are using in the client code. The header lines from the test client are shown in Example 3.3.4.

The main function contains all the necessary code to use a local component. At the local home finder, the client needs to register the HelloHome instance, as shown in Example 3.3.5. After home registration, we can find the home by its name and create a component instance. From the component instance we get a reference to the Console facet. Finally, to indicate the component the end of create and configuration, we call configuration_complete method. See Example 3.3.6 for the code needed here.

Now that we have a component, we are ready to use the operations provided by the component and its facet. Example 3.3.7 shows how to call component methods. After calling component methods to test the component, the client needs to tear down the components to free up allocated memory. To tear the application town, we remove the component instance from memory and unregister the component's home, as shown in Example 3.3.8.


\begin{Example}
% latex2html id marker 455\begin{lrbox}{\fmbox}\begin{minipage...
...caption{Test client header lines for the single component example.}\end{Example}


\begin{Example}
% latex2html id marker 465\begin{lrbox}{\fmbox}\begin{minipage...
...caption{Registering the component home with the local home finder.}\end{Example}


\begin{Example}
% latex2html id marker 475\begin{lrbox}{\fmbox}\begin{minipage...
...ption{Creating the component and facet in the hello world example.}\end{Example}


\begin{Example}
% latex2html id marker 485\begin{lrbox}{\fmbox}\begin{minipage...
...ox}}\caption{Calling component methods in the hello world example.}\end{Example}


\begin{Example}
% latex2html id marker 495\begin{lrbox}{\fmbox}\begin{minipage...
...aring down the client in the single component hello world example.}\end{Example}

To compile and install the local test client we use the Confix tool, which is also used by the component build process. Note that we use the same confix profile the CCM Tools, to ensure that the client can access the component libraries.

~/hello/test> confix.py --bootstrap --configure  \
                        --make --targets=install --profile=ccmtools

Finally, we can run the test client:

~/hello/test> confix.py --bootstrap --configure  \
                        --make --targets=install --profile=ccmtools
~/hello> test_client_client

The advantage here is that the development of the local component is separated from the development of the test client. Thus, a deployed component can be used in different applications at the same time.

Integrate existing business logic

The component's business code, in the example above, is very simple and therefore directly implemented in the Hello_app.[h,cc] files. Usually, however, business code has been already developed in a separated business directory. Even more likely is that the business logic is contained in some sort of legacy code library:

    hello/
    |-- hello1.0/
    |-- test/
    |   |-- client/
    |   |-- business/
    |   |   |-- legacy.h
    |   |   |-- legacy.cc

For this example, we'll use some implemented business logic from legacy code. This legacy code provides a print_string method, so all the component developer needs to do is call up the legacy function, as shown in Example 3.3.10.


\begin{Example}
% latex2html id marker 523\begin{lrbox}{\fmbox}\begin{minipage...
...fbox{\usebox{\fmbox}}\caption{A short legacy code library wrapper.}\end{Example}

We suggest building the business logic in the same way as the test client, using the Confix tool. Always remember to use the Confix ``ccmtools'' profile when using the CCM Tools.

test> confix.py --bootstrap --configure \
                --make --targets=install --profile=ccmtools

After installing the component test, the Hello_app.cc file can be modified as shown in Example 3.3.11 to integrate the separately compiled business code.

Integrate existing business logic

The component's business code, in the example above, is very simple and therefore directly implemented in the Hello_app.[h,cc] files. Usually, however, business code has been already developed in a separated business directory. Even more likely is that the business logic is contained in some sort of legacy code library:

    hello/
    |-- hello1.0/
    |-- test/
    |   |-- client/
    |   |-- business/
    |   |   |-- legacy.h
    |   |   |-- legacy.cc

For this example, we'll use some implemented business logic from legacy code. This legacy code provides a print_string method, so all the component developer needs to do is call up the legacy function, as shown in Example 3.3.10.


\begin{Example}
% latex2html id marker 549\begin{lrbox}{\fmbox}\begin{minipage...
...fbox{\usebox{\fmbox}}\caption{A short legacy code library wrapper.}\end{Example}

We suggest building the business logic in the same way as the test client, using the Confix tool. Always remember to use the Confix ``ccmtools'' profile when using the CCM Tools.

test> confix.py --bootstrap --configure \
                --make --targets=install --profile=ccmtools

After installing the component test, the Hello_app.cc file can be modified as shown in Example 3.3.11 to integrate the separately compiled business code.


\begin{Example}
% latex2html id marker 566\begin{lrbox}{\fmbox}\begin{minipage...
...luding legacy code in a component's business logic implementation.}\end{Example}

In conclusion, to build the final component and the test client, we type:

~/hello> ccmtools-c++-make -p hello1.0
~/hello/test> confix.py --bootstrap --configure \
                        --make --targets=install --profile=ccmtools
~/hello/test> test_client_client

In summary, we have included legacy code in the component's business logic and used the existing client to integrate the component in an application. This is the beginning of the process of componentizing an existing legacy library. By fully compartmentalizing legacy code (if that is possible), the respective components can be individually tested to provide for more stable component based software systems in the future.

Undeploy the component

To remove the component from the component repository, type:

~/hello> ccmtools-c++-uninstall -p hello1.0

The command line parameters are the same as those for the ccmtools-c++-install tool. Note that the source code is not affected by the undeployment process; the uninstallation simply removes the component library and cleans up the build directory tree.

2003-11-09