Chapter 3. Sewing CCA Components into an Application: the Driver Component

$Revision: 1.45 $

$Date: 2006/08/22 22:09:49 $

Table of Contents

3.1. The SIDL Definition of the Driver Component
3.2. Implementation of the CXXDriver in C++
3.2.1. The setServices Implementation
3.2.2. The go Implementation
3.3. Implementation of the F90Driver in Fortran 90
3.3.1. The setServices Implementation
3.3.2. Implementing the Constructor and Destructor
3.3.3. The go Implementation
3.4. SIDL and CCA Object Orientation in Fortran
3.5. Using Your New Component

In this exercise, you will create a new Driver component. This component is very simple, and basically only uses other components (it also provides a GoPort). If you're working in an environment in which components are already available that do most of what you need, it is often sufficient to create a component, which we refer to generically as a driver, that orchestrates these existing components to perform your computation.

Unlike other component models (e.g. Cactus or ESMF) CCA does not impose a built-in execution model. CCA allows the user to determine how the components are to be used. The driver component, in essence, takes the place of the main program in a normal application.

In this section we will walk through the construction of a driver component, either in Fortran (SIDL name drivers.F90Driver) or C++ (SIDL name drivers.CXXDriver) Regardless of language, our driver component will use an integrator.IntegratorPort (defined in $STUDENT_SRC/ports/sidl/integrator.sidl). It will also provide a gov.cca.ports.GoPort that allows an outside entity (a user or script) to start execution of the component. (These ports should be familiar from Chapter 2, Assembling and Running a CCA Application.)

[Important] Important

This and subsequent exercises use the student-src code tree instead of the tutorial-src code tree. The difference is that in the student-src we have deleted a bunch of components which you will recreate in these exercises. You can always refer to the completed versions in the tutorial-src to see what the final results should look like.

You'll need to build the student-src code tree in your own directory before you can proceed, by following the instructions in Appendix C, Building the Tutorial and Student Code Trees.

If you are participating in an organized tutorial your account information handout will tell you where you can obtain the tar file on the system you're using instead of having to download it.

3.1. The SIDL Definition of the Driver Component

The first step in creating a new component is to create its .sidl file. In SIDL, a component is a class that implements several SIDL interfaces. All CCA components must implement the gov.cca.Component interface, which is defined as part of the CCA specification (the CCA specification uses the gov.cca namespace). In addition, components must implement the interfaces corresponding to any CCA ports they wish to provide. The CCA specification defines a few ports, such as gov.cca.ports.GoPort, but mostly, ports are defined by the people who write components, or by communities that get together to agree on “standard” interfaces.

In order to better understand what is required to implement a given interface, you need to find the SIDL specification for it. First, we'll look in the SIDL file for the CCA specification to see what the gov.cca.Component interface looks like.

  1. View CCA_TOOLS_ROOT/share/cca-spec-babel-0_8_0-babel-1.0.0/cca.sidl. First, notice the package declarations at the beginning of the file:

    package gov {
    package cca version 0.8.0 {
    ...
    

    which declare the gov.cca namespace for everything in the file.

  2. Now, search for “interface Component”:

    ...
        /**
         * All components must implement this interface.
         */
        interface Component {
            ... Comments elided ...
            void setServices(in Services services) throws CCAException;
        }
    ...
    

    Which tells us that our driver will have to implement a setServices. This is the key method that allows a piece of code to become a CCA component. The component's setServices method is invoked by the CCA framework when the component is instantiated, and advertises to the framework the ports the component will provide and use.

  3. Since the port this component provides is also part of the CCA specification, this is the place to look for the definition of the GoPort. Search for “interface GoPort”:

    ...
        package ports {
    
            /**
             * Go, component, go!
             */
            interface GoPort extends Port {
                ... Comments elided ...
                int go();
            }
    ...
    

    First, notice that there is an additional package declaration here, making the full name of this interface gov.cca.ports.GoPort. This definition tells us that our driver component must also implement a go method.

  4. Now you have enough information to write the SIDL declaration for your driver component. At this point, you should choose whether you want to implement your driver component in C++ or Fortran 90. (Once you get one done, you can implement the other too, if you wish.)

    Edit the file $STUDENT_SRC/components/sidl/drivers.sidl and type in one of the two following SIDL declarations, according to your choice of language:

    1. package drivers version 1.0 {
        class F90Driver implements gov.cca.ports.GoPort,
                                       gov.cca.Component
        {
           int go();
           void setServices(in gov.cca.Services services) 
                            throws gov.cca.CCAException;
        }
      }
      
    2. package drivers version 1.0 {
        class CXXDriver implements gov.cca.ports.GoPort,
                                       gov.cca.Component
        {
           int go();
           void setServices(in gov.cca.Services services) 
                            throws gov.cca.CCAException;
        }
      }
      

    First, notice that the two declarations are identical except for the name, and in reality, you could choose anything you wanted for the name. The only reason we put an indication of the implementation language into the class name of this component was pedagogical: to avoid a name collision if you want to eventually implement both versions, and identify what distinguishes them. Normally, you might want different implementations of a component if they do things differently (i.e. use different algorithms), or in the case of a driver, solve different problems. Under normal circumstances, there is no reason to have more than one implementation of a component that does precisely the same thing (though it is common to have multiple implementations that do things in somewhat different ways, but with the same result).

    Second, notice that the class definition references both gov.cca.ports.GoPort and gov.cca.Component, and declares all of the methods that we saw in those interface definitions, with precisely the same signatures.

  5. Now you need to modify the Makefile system so that it is aware of the new component you're adding (the drivers.sidl is already listed there along with other .sidl files).

    Edit $STUDENT_SRC/component/MakeIncl.components and make the following additions:

    # SIDL files containing component declarations
    # For example:
    # SIDL_FILES = sidl/drivers.sidl
    SIDL_FILES = sidl/functions.sidl sidl/integrators.sidl sidl/randomgens.sidl \
    	sidl/drivers.sidl sidl/unitdrivers.sidl sidl/library.sidl
    
    # The COMPONENTS list contains the fully-qualified names of the component
    # classes, augmented with -LANGUAGE, where LANGUAGE is the language
    # in which the component is implemented, e.g., c, cxx, f90.
    # For example:
    # COMPONENTS = drivers.F90Driver-f90 drivers.CXXDriver-cxx
    COMPONENTS = drivers.PYDriver-python functions.PiFunction-cxx \
    library.CxxUnitsLibraryComp-cxx library.PyUnitsLibraryComp-python \
    undrivers.PyDriver-python \
    functions.LinearFunction-c integrators.MonteCarlo-f90 \
    randomgens.RandNumGenerator-cxx  integrators.Trapezoid-cxx \
            integrators.Simpson-f77\
            drivers.CXXDriver-cxx
    

    Of course if you've chose to create the Fortran 90 driver, you should add drivers.F90Driver-f90 to the definition of COMPONENTS instead. In both cases, notice the backslash (“\”) used to continue definition on to the next line. make will accept long lines, but the files are easier to read if they're nicely formatted.

    [Important] Important

    Before proceeding, you need to be sure that you have done the initial build of the student-src, following the directions in Appendix C, Building the Tutorial and Student Code Trees.

  6. When it is processing a .sidl file, Babel needs to be able to resolve external references contained within the file (for example, to gov.cca.Component, or to other ports, etc.). The simplest way to do this is to have Babel collect all of the information it needs in a repository. The build system for the tutorial is designed to do this, so at this point, we need to add the new drivers.sidl file to the repository.

    In the $STUDENT_SRC/components directory, type make .repository to make Babel process the .sidl files and update the XML repository. The output should look something like this:

    touch .sidl
    
    ### Generating XML for SIDL packages containing component declarations
    /san/cca/cca-tools_gcc_intelF90_PIC/bin/babel -t xml -R../xml_repository \
        -R/san/cca/cca-tools_gcc_intelF90_PIC/share/ \
         cca-spec-babel-0_8_0-babel-1.0.0/xml  \
         -o ../xml_repository sidl/functions.sidl sidl/integrators.sidl \
         sidl/randomgens.sidl sidl/drivers.sidl sidl/unitdrivers.sidl \
         sidl/library.sidl
    Babel: Parsing URL "file:/san/homedirs/bernhold/student-src/ \
    	components/sidl/functions.sidl".
    Babel: Parsing URL "file:/san/homedirs/bernhold/student-src/ \
    	components/sidl/integrators.sidl".
    Babel: Parsing URL "file:/san/homedirs/bernhold/student-src/ \
    	components/sidl/randomgens.sidl".
    Babel: Parsing URL "file:/san/homedirs/bernhold/student-src/ \
    	components/sidl/drivers.sidl".
    Babel: Parsing URL "file:/san/homedirs/bernhold/student-src/ \
    	components/sidl/unitdrivers.sidl".
    Babel: Parsing URL "file:/san/homedirs/bernhold/student-src/ \
    	components/sidl/library.sidl".
    touch .repository
    

The next step is to implement the internals of the component, which are obviously dependent on the implementation language you've chosen. For C++, continue directly on with Section 3.2, “Implementation of the CXXDriver in C++”. For Fortran 90, please jump to Section 3.3, “Implementation of the F90Driver in Fortran 90”.