Write a local test client for two components

To show the use of both components in an application, we write a test client in the following file structure:

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

The client starts with a lot of include and using namespace statements. Note that the included header files reflect the used components.

#include <localComponents/CCM.h>
#include <CCM_Local/HomeFinder.h>
#include <CCM_Utils/Debug.h>

#include <CCM_Local/CCM_Session_Display/Display_gen.h>
#include <CCM_Local/CCM_Session_Hello/Hello_gen.h>
#include <CCM_Local/CCM_Session_Display/DisplayHome_gen.h>
#include <CCM_Local/CCM_Session_Hello/HelloHome_gen.h>

using namespace std;
using namespace CCM_Utils;
using namespace CCM_Local;
using namespace CCM_Session_Display;
using namespace CCM_Session_Hello;

In the main function, after setting the debugging mode, both component homes are registered at the home finder.

int main ( int argc, char *argv[] )
{
  // Set debugging mode
  Debug::set_global(true);

  // Get in instance of the local HomeFinder and register component homes
  localComponents::HomeFinder* homeFinder = HomeFinder::Instance (  );
  try {                       
    homeFinder->register_home( create_DisplayHomeAdapter(), "DisplayHome" );
    homeFinder->register_home( create_HelloHomeAdapter(), "HelloHome" );
  } catch ( ... )  {
    cout << "Aut'sch: when register homes!" << endl;
    return -1;
  }

Now, we can use the home finder to find the homes by name. We create an instance of each component, get references the the component's facets and connect the facet of Display with the receptacle of Hello. Note that both ports are defined by the same LCD interface.

  try {
    // Find component home
    SmartPtr<DisplayHome> myDisplayHome (dynamic_cast<DisplayHome*>
      ( homeFinder->find_home_by_name ( "DisplayHome").ptr ()));
    SmartPtr<HelloHome> myHelloHome (dynamic_cast<HelloHome*>
      ( homeFinder->find_home_by_name ( "HelloHome").ptr ()));

    // Create component instance
    SmartPtr<Hello> myHello = myHelloHome.ptr()->create();
    SmartPtr<Display> myDisplay = myDisplayHome.ptr()->create();
 
    // Get facet references and connect facets to receptacles
    SmartPtr<CCM_Console> console = myHello.ptr()->provide_console();	
    SmartPtr<CCM_LCD> lcd = myDisplay.ptr()->provide_lcd();
    myHello.ptr()->connect_lcd(lcd);

    // Configure the component's attribute
    myDisplay.ptr()->prompt("-=> ");

    // Component configuration finished	
    myHello.ptr()->configuration_complete();
    myDisplay.ptr()->configuration_complete();

The test client has build an component assembly of two components in memory and can use its functionality.

  
    // Call operations on the component assembly
    cout << "Display Version = " 
         << myDisplay.ptr()->getComponentVersion()  << endl;
    cout << "Hello Version = "  
         << myHello.ptr()->getComponentVersion() << endl;

    console.ptr()->println("Hello from the client");

To tear the component assembly town, we disconnect the ports and remove the component instances from memory. We also unregister the component's homes from the home finder.

    
    // Disconnect component ports
    myHello.ptr()->disconnect_lcd();    

    // Destroy component instances
    myDisplay.ptr()->remove();
    myHello.ptr()->remove();

    // Unregister component homes
    homeFinder->unregister_home("DisplayHome");
    homeFinder->unregister_home("HelloHome");
  }
  catch ( localComponents::HomeNotFound ) {
    cout << "Aut'sch: can't find a home!" << endl;
    return -1;
  }
  catch ( ... )  {
    cout << "Aut'sch: there is something wrong!" << endl;
    return -1;
  }
  return 0;
}

We build the test client with Confix and run the binary:

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

Isn't it cool?
We have run a test client that uses two components which are connected via facet and receptacle to build a component assembly. In the same way, we can create more complex assemblies that form a real component based application as well.

Look at the printed debugging information to trace the execution thread of the test client. We can also switch off the messages by setting the debugging mode in the main function to false.

2003-11-09