\begin{center}\vbox{\input{titlepage}
}\end{center}

A Hands-On Guide to the Common Component Architecture
Common Component Architecture Forum Tutorial Working Group
Version: 0.7.0

Copyright ©  Common Component Architecture Forum

Licensing Information

This document is distributed under the Creative Commons Attribution 2.5 License. See http://creativecommons.org/licenses/by/2.5/legalcodefor the complete license agreement.

In summary, you are free:

Under the following conditions:

Your fair use and other rights are in no way affected by the above.

Requested Attribution

Common Component Architecture Forum Tutorial Working Group, A Hands-On Guide to the Common Component Architecture, version 0.7.0, http://www.cca-forum.org/tutorials/.

Or in format:

@Manual{cca-tutorial:0.7.0,
  title = {A Hands-On Guide to the Common Component Architecture},
  author = {Common Component Architecture Forum Tutorial Working Group},
  edition = {0.7.0},
  year = ,
  URL = {http://www.cca-forum.org/tutorials/}
}


Contents


Preface

The Common Component Architecture (CCA) is an environment for component-based software engineering (CBSE) specifically designed to meet the needs of high-performance scientific computing. It has been developed by members of the Common Component Architecture Forum .

This document is intended to guide the reader through a series of increasingly complex tasks starting from composing and running a simple scientific application using pre-installed CCA components and tools, to writing (simple) components of your own. It was originally designed and used to guide the `hands-on' portion of the CCA tutorial, but we hope that it will be useful for self-study as well.

We assume that you've had an introduction to the terminology and concepts of CBSE and the CCA in particular. If not, we recommend you peruse a recent version of the CCA tutorial presentations before undertaking to complete the tasks in this Guide.

Help us Improve this Guide

If you find errors in this document, or have trouble understanding any portion of it, please let us know so that we can improve the next release. Email us at cca-tutorial@cca-forum.org with your comments and questions.

Finding the Latest Version of the CCA Hands-On Exercises

The hands-on exercises and this Guide are evolving and improving. We will maintain links to the current releases of this Guide, the tutorial code, and accompanying tools at http://www.cca-forum.org/tutorials/#sources . If you want older versions or intermediate "release candidates", follow the links there to the parent download directories to see the full list of available files.


Typographic Conventions

File and Directory Naming Conventions

Throughout this Guide, we refer to various files and directories, the precise location of which depends on how and where things were built and installed. All such references will be based on a few key directory locations, which will be determined when you build and install the software (Appendix E and Appendix F). Wherever appropriate, we will write these as environment variables, so that the text in the Guide can simply be pasted into your shell session (assuming your login environment is setup as suggested in Section E.4).

Image warningWarning

Note that tools such as the Ccaffeine framework do not expand environment variables. In these cases, you'll need to type in the complete path, substituting the placeholder (i.e., ``TUTORIAL_SRC'') with the actual path.

If you're participating in an organized tutorial, you will be given information separately about the particular paths corresponding to these locations.

CCA_TOOLS_ROOT ($CCA_TOOLS_ROOT)
The installation location of the CCA tools. (See Section E.1.)

0 [TAU_ROOT ($TAU_ROOT)] The installation location of the TAU Portable Profiling package. (See Section E.3.)

[TAU_CMPT_ROOT ($TAU_CMPT_ROOT)] The installation location of the TAU performance component. (See Section E.3.)

TUTORIAL_SRC ($TUTORIAL_SRC)
The top of the tree where the ``ODE'' part of the tutorial code has been built. (See Appendix F.) In an organized tutorial, this is likely to a central location shared by all students, which may not be modified.

STUDENT_SRC ($STUDENT_SRC)
The top of the student's private copy of the ODE code tree. If you're doing this tutorial on your own, STUDENT_SRC can be the same as TUTORIAL_SRC, but if you part of an organized tutorial, the STUDENT_SRC tree is the one you can modify and rebuild.

PDE_SRC ($PDE_SRC)
The location containing the PDE example code tree. (See Appendix F.) In an organized tutorial, this is likely to a central location shared by all students, which may not be modified.

PDE_STUDENT_SRC ($PDE_STUDENT_SRC)
The student's private copy of the PDE code tree, analagous to STUDENT_SRC.

WORKDIR ($WORKDIR)
This is the location of a working directory, in which you can carry out all of the exercises in this Guide. The basic requirements are that you have write access and sufficient disk space for the work (perhaps 100 MB), and if you're working through the tutorial independently, you can usually choose the WORKDIR based on your knowledge of the system you're using. If you're part of an organized tutorial, you will be assigned a WORKDIR.

Image warningWarning

If you're part of an organized tutorial please be careful to use the WORKDIR you are assigned! Often there are special considerations in such an environment, which might not be obvious to you as a participant. For example, it is fairly common for all cluster nodes to mount user home directories from a single NFS file server. An entire class of students working on I/O-intensive activities (like building the tutorial code) at the same time has been known to kill servers from time to time. So frequently, you will be asked to use directories local to your assigned cluster node.

Acknowledgments

There are quite a few people active in the Tutorial Working Group who have contributed to the general development of the CCA tutorial and this Guide in particular:

People
Benjamin A. Allan, Rob Armstrong, David E. Bernholdt (chair), Randy Bramley, Tamara L. Dahlgren, Lori Freitag Diachin, Wael Elwasif, Tom Epperly, Madhusudhan Govindaraju, Ragib Hasan, Dan Katz, Jim Kohl, Gary Kumfert, Lois Curfman McInnes, Alan Morris, Boyana Norris, Craig Rasmussen, Jaideep Ray, Sameer Shende, Torsten Wilde, Shujia Zhou
Institutions
Argonne National Laboratory, Binghamton University - State University of New York, Indiana University, Jet Propulsion Laboratory, Los Alamos National Laboratory, Lawrence Livermore National Laboratory, NASA/Goddard, University of Illinois, Oak Ridge National Laboratory, Sandia National Laboratories, University of Oregon

Finally, we must acknowledge the efforts of the numerous additional people who have worked very hard to make the Common Component Architecture what it is today. Without them, we wouldn't have anything to present tutorials about!


1. Introduction

In this Guide, we will take you step by step through a series of hands-on tasks with CCA components in the CCA software environment. The initial set of exercises are based on an example that's intentionally chosen to be very simple from a scientific viewpoint, numerical integration in one dimension, so that we can focus on the issues of the component environment. It may look like overkill to have broken down such a simple task into multiple components, but once you have a basic understanding of how to use and create components, you should be able to extend the concepts to components that are scientifically interesting to you and far more complex.

The exercises are laid out as follows:

You are strongly advised to at least read and understand Chapter 2 before going on to later exercises. You'll need to use the techniques of Chapter 2 to test the components you write later.

In Chapter 2, you'll be working with a complete version, pre-built of the tutorial code tree. Then in Chapter 3 you'll start from scratch to create components on your own, replicating those in Chapter 2. In this way, the separate complete tutorial code tree can always serve as a reference if you run into problems. Of course if you're working through this Guide as part of an organized tutorial, there should be instructors around who can help you. And if you're working on your own, you can email us for help at cca-tutorial@cca-forum.org .

Image tipTip

Some of these exercises can involve a fair amount of typing. You may find it convenient to use the online HTML version of this Guide (at http://www.cca-forum.org/tutorials/#sources ) to cut and paste the necessary inputs. Note, however, that not everything can be cut-and-pasted directly. Take particular care with lines that had to be broken for purposes of documentation, and for placeholder values such as ``TUTORIAL_SRC''.

1.1 The CCA Software Environment

The CCA is, at its heart, just a specification. There are several realizations of the CCA as a software environment. In this Guide, we use the following tools to provide that software environment, which are currently the most widely used for high-performance (as opposed to distributed) computing using the CCA:

Babel
A tool for language interoperability. It allows components written in different languages to be connected together. The Scientific Interface Definition Language (SIDL) is defined by Babel. For more information, see the Babel page . Babel uses Chasm for Fortran 90 array support. For more information, see the Chasm repository .

Bocca
A tool for generating and manipulating projects using CCA components or other SIDL based code. Bocca is designed to simplify the tedious and mechanical aspects of CCA and Babel. Before bocca, this Guide was a lot longer because we had to take you step by step through writing all of this "boilerplate" code for yourself.

Ccaffeine
A CCA framework which emphasizes local and parallel high-performance computing, and the most common CCA framework in real applications. For more information, see the Ccaffeine page .

Many of the commands you will type are specific to the fact that you're using these tools as your CCA software environment. But the components you will use and create are independent of the particular tools being used.

1.2 Where to Go from Here

Before starting the exercises, you'll need to do a little bit of work to set things up. Depending on whether you're working through the Guide on your own (see Section 1.2.1) or participating in an organized tutorial (see Section 1.2.2), this may include getting logged in to a remote system, preparing the CCA environment, and building the tutorial code. Once you've setup everything as outlined below, you should be ready to proceed to Chapter 2.


1.2.1 For Self-Study Users

Getting Connected:
If you're working through the Guide on your own, you may choose to work locally or remotely, depending on the resources you have available. If you're working remotely, you may want to refer to the notes on using the CCA tools remotely in Appendix D.

Preparing the CCA Environment:
In this case, you will need to download and install the CCA tools (Ccaffeine , Babel , and Bocca ) and configure your login environment to use them, following the instructions in Appendix E.

Building the Tutorial Code:
You'll also need to download and build the tutorial code tree following the instructions in Appendix F.


1.2.2 For Organized Tutorial Participants

If you're participating in an organized tutorial, most of the preparatory work will have been done in advance by the tutorial instructors. Usually, they will provide you with a separate set of instructions tailored to the arrangements for the particular tutorial you're attending.

Getting Connected:
Look to the separate handout or the tutorial instructors for details of your account, your machine assignment, etc. Appendix D should give you sufficient information to get logged in to the remote machine. If you have any problems, ask the tutorial instructors.

Preparing the CCA Environment:
In this case, the CCA tools (Ccaffeine , Babel , and Bocca ) will already have been built in a common area. The handout or tutorial instructors will provide you with the procedures you might need to follow to setup your environment (the PATH and other environment variables). Some general notes can be found in Section E.4.

Building the Tutorial Code:
Once again, the tutorial code will already have been built in a central location, and the details will be noted on the handout.

Image tipTip

In some of the later exercises (starting with Section 4), you will need to build your own copy of (parts of) the tutorial code tree so that you can modify them. Depending on your hardware environment, this may be pretty time consuming. If you're pressed for time you may want to go ahead and start building your own copy of the PDE and then ODE portions of the tutorial code tree before starting the first exercise. Follow the instructions in Appendix F, and you probably want to launch the build in a separate window. The tutorial instructors should be able to tell you whether this ``pre-build'' step is necessary.


2. Assembling and Running a CCA Application

In this exercise, you will work with pre-built components from the integrator example to compose several CCA-based applications and execute them. The integrator application is a simple example, designed to illustrate the basics of creating, building, and running component-based applications without scientific complexities a more realistic application would also present. The purpose of this application is to numerically integrate a one-dimensional function. Several different integrators and functions are available, in the form of components. A ``driver'' component controls the calculation, and for the Monte Carlo integrator, a random number generator is also required. The specific components available are shown in Table 2.1.


Table 2.1: Integrator Application Components (details may vary depending on the languages your CCA tools installation is configured for).
Components Notes
Drivers <#10212#>
  drivers.CXXDriver
  drivers.F90Driver
  drivers.PYDriver
Integrators Various integration algorithms
  integrators.Boole  
  integrators.MonteCarlo  
  integrators.Midpoint  
  integrators.Simpson  
  integrators.Simpson38  
  integrators.Trapezoid  
Functions  
  functions.CosFunction cos(x) ; integrates to sin(1) $ \approx$ 0.841
  functions.CubeFunction x3 ; integrates to 0.25
  functions.LinearFunction x ; integrates to 0.5
  functions.PiFunction $ {\frac{{4}}{{1+x^2}}}$ ; integrates to $ \pi$
  functions.QuinticFunction x5 -4x4 ; integrates to $ {\frac{{1}}{{6}}}$ - $ {\frac{{4}}{{5}}}$ $ \approx$ - 0.633
  functions.SquareFunction x2 ; integrates to $ {\frac{{1}}{{3}}}$
Random Number Generators  
  randomgens.RandNumGenerator Required for Monte Carlo integration

The Ccaffeine framework provide three different ways for users to interact with it in order to assemble and run CCA applications. You can type commands in yourself at the framework's prompt, execute a script containing those same commands, or use a graphical user interface.2.1The graphical approach is the easiest for most people to get a feel for how components work, so we will start with that (Section 2.1) and later discuss how actions in the GUI map onto instructions in a script (see Section 2.2).

In practice, most users set the GUI interface aside after they become more comfortable with the CCA environment in favor of the scripting approach. That's especially true once they've developed a bunch of components and want to run simulations with them in batch jobs, where GUIs tend not to be so convenient. Of course it is entirely up to you which approach you use in the long run.


2.1 Using the GUI Front-End to Ccaffeine

Image noteNote

At this point, you will start using the tutorial-src code tree. If you're doing this tutorial as a self-study exercise, you'll need to make sure it has been built according to the instructions in Appendix F. For organized tutorials, this is generally done in advance by the tutorial instructors.

There is a graphical front-end for Ccaffeine (known as Ccaffeine GUI , or ``the GUI'' which provides a fairly simple visual programming metaphor for the assembly of applications using CCA components. In this exercise, we'll use the Ccaffeine GUI to assemble and run several different ``applications'' using the components already available in the tutorial-src tree.

Ccaffeine and its GUI are run as two separate processes, possibly on two different machines. Depending on the specific circumstances, there are a variety of ways to invoke the GUI and the Ccaffeine framework. Bocca generates two helper scripts in the project's utils subdirectory, which will serve most purposes. Which to use depends on whether the graphical display you're using (the ``GUI host '') is directly attached to the machine on which you're running the framework (the ``Ccaffeine host ''), or whether they're separated by a network link.


2.1.1 Running the GUI Locally (GUI host and Ccaffeine host are Identical)

When you're working on a display that is directly attached to the Ccaffeine host , the Bocca -generated  utils/run-gui.sh script is the simplest one to use. It requires no arguments, launches both Ccaffeine and the GUI, and automatically initializes the framework with a palette consisting of all of the components in the Bocca project.

Image tipTip

Always make sure you're using the run-gui.sh script generated for the particular project you're working on because they'll be initialized with different sets of components. In this chapter, the command is  $TUTORIAL_SRC/utils/run-gui.sh, but in later exercises it will be different!


2.1.2 Running the GUI Remotely (GUI host and Ccaffeine host are Distinct)

There are two different mechanisms to run the GUI remotely:

Using X11 on GUI host :
If you have an X11 server on GUI host , you can use the  run-gui.sh command on Ccaffeine host and let X11 take care of the graphics. However many users find the performance unacceptable using this approach, especially over slower network connections. In that case, try the method below.

Using a socket connection:
In this case, you run the GUI locally on GUI host (it is a Java application, and works on Linux/unix, Mac, and Windows platforms) and connect to the remote framework on Ccaffeine host over a TCP/IP socket.

Image tipTip

Connections between the GUI and the framework can be tunneled through an ssh connection. This may help in cases where firewalls or other network setups that prevent direct point to point connections (i.e. cluster compute nodes accessible only through the head node). See Appendix D and in particular Section D.3.

Image noteNote

This procedure requires that you have GUI on your GUI host . This includes the simple-gui.sh (on Windows, simple-gui.bat) script and the ccafe-gui.jar file. In a normal build of the CCA tools, you can find these files in the $CCA_TOOLS_ROOT/lib directory. If you're participating ain an organized tutorial, they also have been made available on a web site or other more convenient location. No special installation procedure is required, but the script and the jar file do need to be in the same directory.

On Ccaffeine host :
First, launch the framework, using the Bocca -generated utility script for your project, telling it what port to listen on for the connection from the GUI:  utils/bocca-gui-backend.sh --port port_num. The script automatically initializes the framework with a palette consisting of all of the components in the Bocca project.

The port number must be in the range 1025-65535, and cannot be in use by another application on the host (if it is, you will get an error message; simply try another port). You must use the same port number for the framework and the GUI. In organized tutorials, you may be assigned a port to help reduce the chances of collisions. If so, please use it!

Image tipTip

Always make sure you're using the bocca-gui-backend.sh script generated for the particular project you're working on because they'll be initialized with different sets of components. In this chapter, the command is  $TUTORIAL_SRC/utils/bocca-gui-backend.sh, but in later exercises it will be different!

On GUI host :
Start the GUI locally by executing the simple-gui.sh (on Windows, simple-gui.bat) script, specify both the host and port the framework is listening on:  simple-gui.sh --port port_num --host Ccaffeine _host.

Image tipTip

If you invoke the simple-gui.sh (simple-gui.bat) script without arguments, the GUI will pop up a dialog box asking you to specify the hostname and port number to connect to. Filling in these dialogs quickly gets tedious, so you're better off using the command line. (In Windows, launch a Command Prompt window, and change directories to wherever you put simple-gui.bat and the GUI jar file.) In both Windows and most Linux/unix shells, you can simply use the $ \uparrow$ (up-arrow) key to recall the previous command to be executed again.

Image tipTip

We have on occasion observed problems with the Ccaffeine GUI interface hanging (most often while populating the palette as the GUI starts up). We think this is due to a subtle race condition in the GUI, which we haven't yet been able to isolate. The best advice seems to be to kill both the framework and GUI and try launching them again.

Other Ways to Launch the GUI and Ccaffeine (OPTIONAL READING)

As your usage of the CCA becomes more sophisticated, you're likely to encounter situations where the Bocca -generated helper scripts don't do exactly what you want. For example, you may need to use a different rc file to initialize the framework. Is is therefore worth mentioning a couple of the underlying tools, which are part of the CCA tools distribution:

gui-backend.sh
This command underlies utils/bocca-gui-backend.sh. The difference is that gui-backend.sh requires an additional argument to specify the rc file to initialize the framework, --ccafe-rc rc_file.

gui.sh
This command is equivalent to simple-gui.sh, but can be used on a machine with the CCA tools installed without needing to worry about where the GUI's jar file is.


2.1.3 Assembling and Running an Application Using the GUI

For the purposes of this exercise, we will assume that you are working in and environment in which GUI host and Ccaffeine host are separate machines. If they are the same, you can use $TUTORIAL_SRC/utils/run-gui.sh as described in Section 2.1.1 instead of the first two steps, below.

  1. Run  $TUTORIAL_SRC/utils/bocca-gui-backend.sh --port port_num on the Ccaffeine host using the appropriate port.

    In the Ccaffeine host terminal window, you will see something like:

    my rank: -1, my pid: 9625
    Type: Server
    

  2. Run  simple-gui.sh --port port_num --host backend_host (on Windows,  simple-gui.bat) on the GUI host .

    Once the GUI connects to Ccaffeine , Ccaffeine begins running the rc file it was invoked with. In the GUI host terminal window, you first see some startup messages from the GUI itself, followed by a series of messages as Ccaffeine processes the rc file and the GUI displays the results. These are debugging messages and can largely be ignored.

    In the Ccaffeine host terminal, you should see some additional messages as Ccaffeine processes the rc file, like:

    CCAFFEINE configured with spec (0.8.2) and babel (1.0.4).
    
    CCAFFEINE configured with classic (0.5.7).
    
    CCAFFEINE configured without neo and neo components.
    CmdLineClient parsing ...
    
    CmdContextCCA::initRC: Found components/tests/test_gui_rc.
    # There are allegedly 11 classes in the component path
    

    Finally, in the GUI host window, you should see some output associated with the GUI's initialization process, and the GUI itself should have appeared on your display, looking something Figure 2.1.

    Figure 2.1: GUI with components in palette and empty arena (Step 2).
    Image gui-step02

    Image tipTip

    The default layout has the palette area fairly narrow. You can click-and-drag on the bar separating the palette and the arena to adjust the width.

    Image noteNote

    You may see additional components in your palette , as we try to expand the variety of examples we provide in the tutorial-src .

    As mentioned above, the test_gui_rc sets up the path and loads the framework's palette with a set of available components. rc files are explained in detail in Section 2.2.

  3. We will begin by instantiating a drivers.CXXDriver component. Click-and-drag the component you want from the palette to the arena . When you release the mouse button in the arena , a dialog box will pop up prompting you to name this instance of the component. The default will be the last part of the component's class name (i.e. CXXDriver for drivers.CXXDriver ) with a numerical suffix to insure the name is unique. The suffix starts at 0 and simply counts up according to the number of instances of that component you've created in that session. You can, of course, enter any instance name you like, as long as it is unique across all components in the arena , but for simplicity, we will always accept the default value in this Guide.

  4. For the first application, follow the same procedure to instantiate: (you may notice some debugging messages in the GUI host terminal window as you do this), and your GUI should look something like Figure 2.2.

    Figure 2.2: GUI with several components instantiated in arena (Step 4).
    Image gui-step04

    Image tipTip

    You can drag components around the arena to arrange them as suits you - just click on the black area of the component and drag it to the new location. The positions have no bearing on the operation of the GUI or your application.

  5. The next step is to begin making connections between the ports of your components. Click-and-release CXXDriver0 's integrate uses port, then click-and-release MonteCarlo0 's integrate provides port and a red line should be drawn between the two (Figure 2.3).

    Figure 2.3: Driver's integrator port connected to integrator's integrator port (Step 5).
    Image gui-step05

    Image tipTip

    If you hover the cursor over a particular port on a component, a ``tool tip'' box will pop up with the port's name and type based on the arguments to the addProvidesPort or registerUsesPort calls in the component's setServices method. This can be useful for double checking to make sure you're connecting matching ports.

    Also notice that when you hover over a particular port (either uses or provides ), matching ports of the opposite type (either provides or uses ) will be highlighted.

    Image noteNote

    You can move components around even after their ports are connected - the connections will automatically rearrange. There is no harm in connections crossing each other, nor in connections passing behind other components (though of course they may make it harder to interpret the ``wiring diagram'' correctly).

  6. Complete the first application by making the following connections:

    At this point, your GUI should look something like Figure 2.4.

    Figure 2.4: Fully connected application (Step 6).
    Image gui-step05b

  7. The application is now fully assembled and is ready to run. If you click-and-release the go button on the CXXDriver0 component, you should see the result appear in the Ccaffeine host terminal, ``Value = 3.139160''2.2 and the message

    ``IN: ##specific go command successful'' in the GUI host terminal.

    Image tipTip

    Remember that your application is running within the framework. Unless the application itself does something special, the output from the application will appear in the window in which the framework is running.

  8. Next, we're going to use some of the other components to assemble a different application using the components. Since they're already in the palette , you can instantiate them in the same way as Step 3. Your GUI should look like Figure 2.5.

    Figure 2.5: Additional components instantiated (Step 8).
    Image gui-step07

    Image tipTip

    As we've mentioned, wiring diagrams can become hard to interpret when they become cluttered, as is the case with the screen shot above. To help interpret the diagram, remember the following:

    • ``Wires'' only connect to the sides of ports - on the left side of provides ports (on the left side of the component), or on the right side of uses ports. Connections are never made to the top or bottom of a component.

    • The GUI's wire-drawing algorithm is aware only of the two components that are being connected. It will make no attempt to avoid other components or other wires. So wires can pass behind components without connecting to any of their ports, and wires may overlap.

    • If you're still uncertain how to interpret the connections try rearranging the components slightly. Connections attached to the component will follow as you drag it around, but others not associated with that component will remain unchanged.

  9. Next, we break the port connections we don't need so we can reconnect to the new components. Right-click on the integrate (either the user or the provider ) and a dialog box will pop up asking you to confirm that you want to break the connection.2.3 You will need to break the following connections:

    There is no need to remove unused components from the arena - as long as they are not connected to active components, they will not interfere.2.4 In fact in this case, neither MonteCarlo0 nor RandNumGenerator0 are used, so it is safe to leave them connected to each other.

    Image noteNote

    Steps 8 and 9 could have been done in either order.

  10. Assemble the new application (Figure 2.6) by making the following connections:

    Figure 2.6: Another application, with additional unused components still in arena (Step 10).
    Image gui-step09

    Click-and-release the go button on the CXXDriver0 component, you should see the result appear in the Ccaffeine host terminal, ``Value = 3.141593'' and the message ``IN: ##specific go command successful'' in the GUI host terminal.

  11. Finally, create a third application by replacing PiFunction0 with CubeFunction0 (Figure 2.7). When you click on the go you should get ``Value = 0.250000''2.5 in the Ccaffeine host terminal.

    Figure 2.7: A third application, with extraneous components still in arena (Step 11).
    Image gui-step10

  12. At this point, you should understand how to instantiate components, how to connect and disconnect their ports, and how to execute the application with the go port. Feel free to use any and all of the components available in the palette to experiment with other integration applications.

    Image noteNote

    Observe that as a user of CCA components, you have no idea what language each component is implemented in. (Admittedly, the names of the drivers are suggestive of the implementation language, but those names were chosen at the convenience of the component developer, and they provide no guarantees regarding the components' implementations.) The language interoperability features of Babel allow components to be hooked together regardless of implementation language with complete transparency.

  13. To politely exit the GUI, select File $ \Rightarrow$ Quit. This will terminate both the GUI and the backend ccafe-client sessions.

    Image tipTip

    If you've used the GUI to setup and start a long-running simulation, and you don't want to leave the GUI running continuously, you can use the File $ \Rightarrow$ Detach option to close the GUI but leave the backend running. However it is currently impossible to reattach to a running session.

    Image tipTip

    If the backend crashes while the GUI is running, exit the GUI by using Detach. Trying to Quit without a running backend will cause the GUI to hang.


2.2 Running Ccaffeine Using an rc File

In practice, most people don't use the GUI all the time. And even die-hard GUI users will sometimes need to modify the rc file that does the initialization. Ccaffeine will also accept commands interactively or in the form of a script (the rc file). This capability is very useful when you simply want to run CCA-based applications that you already know how to assemble. In this section, we will examine in detail an rc file that does everything you did in the GUI in the previous section.

When we're not using the GUI, the Ccaffeine invocation is much simpler, and there is no need for the helper scripts we used before (utils/bocca-gui-backend.sh or gui-backend.sh). For direct use, Ccaffeine can be invoked as  ccafe-single or  ccafe-batch, depending on whether you're using it in a single-process (i.e. sequential) interactive situation, or in non-interactive situations, including parallel jobs. These commands are part of the CCA tools installation, and should be in your path if you've followed the procedures in Appendix E.4.

  1. Change directories to your WORKDIR so that we can capture the output of running the $TUTORIAL_SRC/components/tests/task0.rc rc file.

    Execute the command

    $ ccafe-single \
    --ccafe-rc $TUTORIAL_SRC/components/tests/task0.rc \
    > task0.out 2>&1

    (if you're using the csh or tcsh shell, the output redirection should be `` >& task0.out'' instead of `` > task0.out 2>&1'').

    View the task0.out file satisfy yourself that the script ran. (Of course you can view the script itself too, if you want.) Below we'll work our way through each section of the script and the corresponding output, but it may help you to see the input and output in their entirety. The step numbers appearing in the script comments should correspond to the steps in the preceding GUI procedure.

  2. The beginning of the task0.rc script looks like this:
    #!ccaffeine bootstrap file. 
    # ------- don't change anything ABOVE this line.-------------
    
    # Step 2
    
    path
    path set /home/csm/bernhold/proj/cca/tutorial/tutorial/src-acts07/components/lib
    path
    
    palette
    repository get-global drivers.CXXDriver
    repository get-global drivers.F90Driver
    repository get-global functions.CubeFunction
    repository get-global functions.LinearFunction
    repository get-global functions.QuinticFunction
    repository get-global functions.SquareFunction
    repository get-global integrators.MonteCarlo
    repository get-global integrators.Simpson
    repository get-global integrators.Trapezoid
    repository get-global randomgens.RandNumGenerator
    palette
    

    The rc file begins with a ``magic'' line (a structured comment) indicating that the script is meant to be processed by Ccaffeine . Ccaffeine expect to find such a line at the beginning of all rc files.

    Ccaffeine uses a ``path'' to determine where it should look for CCA components (specifically the .cca files, which internally point to the actual libraries that comprise the component). The rc file prints the path before and after setting the path for pedagogical reasons. In ``real'' scripts, you might want to print the path out for debugging or documentation purposes.

    Path-related commands in Ccaffeine include:

    path
    Prints the current path.

    path append
    Adds a directory to the end of the current path.

    path init
    Sets the path from the value of the $CCA_COMPONENT_PATH environment variable.

    path prepend
    Adds a directory to the beginning of the current path.

    path set
    Sets the path to the value provided.

    As you saw in the GUI, Ccaffeine has the concept of a palette of components from which applications can be assembled. Unlike a typical unix shell, where putting an executable into your path means you can use it directly, Ccaffeine has a two step process. Components in the path can be added to the palette using the command repository get-global class_name, where class_name is the component's class name. This two step approach gives you a little more control when there are large numbers of components in your path. However in this case, we've simply loaded all of the components in the tutorial-src tree.

    The palette commands before and after the block of repository commands is simply meant to illustrate that the framework's palette starts empty, and ends up with the components you requested. They aren't needed in a ``real'' script.

    The output from these commands should look something like this:

    CCAFFEINE configured with spec (0.8.2) and babel (1.0.4).
    
    CCAFFEINE configured with classic (0.5.7).
    
    CCAFFEINE configured without neo and neo components.
    my rank: -1, my pid: 27566
    Type: One Processor Interactive
    
    
    CmdContextCCA::initRC: Found task0_rc.
    
    
    
    
    pathBegin
    pathEnd! empty path.
    
    # There are allegedly 11 classes in the component path
    
    pathBegin
    pathElement /home/csm/bernhold/proj/cca/tutorial/tutorial/src-acts07/components/lib
    pathEnd
    
    Components available:
    
    Loaded drivers.CXXDriver NOW  GLOBAL .
    
    Loaded drivers.F90Driver NOW  GLOBAL .
    
    Loaded functions.CubeFunction NOW  GLOBAL .
    
    Loaded functions.LinearFunction NOW  GLOBAL .
    
    Loaded functions.QuinticFunction NOW  GLOBAL .
    
    Loaded functions.SquareFunction NOW  GLOBAL .
    
    Loaded integrators.MonteCarlo NOW  GLOBAL .
    
    Loaded integrators.Simpson NOW  GLOBAL .
    
    Loaded integrators.Trapezoid NOW  GLOBAL .
    
    Loaded randomgens.RandNumGenerator NOW  GLOBAL .
    
    Components available:
    drivers.CXXDriver
    drivers.F90Driver
    functions.CubeFunction
    functions.LinearFunction
    functions.QuinticFunction
    functions.SquareFunction
    integrators.MonteCarlo
    integrators.Simpson
    integrators.Trapezoid
    randomgens.RandNumGenerator
    

    Image noteNote

    rc files used to initialize the GUI should contain only the magic line, path and repository get-global commands. You can view $TUTORIAL_SRC/components/tests/guitest.gen.rc as an example.

  3. Next we instantiate the components we're going to use to assemble our first application, to place them in the arena :
    # Steps 3-4
    
    instances
    instantiate drivers.CXXDriver CXXDriver0
    instantiate functions.PiFunction PiFunction0
    instantiate integrators.MonteCarlo MonteCarlo0
    instantiate randomgens.RandNumGenerator RandNumGenerator0
    instances
    

    The command syntax is instantiate class_name instance_name. (The plain instantiate commands before and after are, once again, for pedagogical purposes, to list the contents of the arena .) The component's class_name is set in the SIDL file where it is defined, and is also used in the repository get-global command. The instance_name is chosen by the user, and must simply be unique within the arena . You may remember that the GUI suggests a default instance_name when prompting you for it, but that's a feature of the GUI, not the framework. Here you have to enter it yourself. It happens that we've used the same thing that the GUI would suggest.

    The output from these commands should look something like this:

    FRAMEWORK of type Ccaffeine-Support
    
    CXXDriver0 of type drivers.CXXDriver 
    successfully instantiated
    
    PiFunction0 of type functions.PiFunction 
    successfully instantiated
    
    MonteCarlo0 of type integrators.MonteCarlo 
    successfully instantiated
    
    RandNumGenerator0 of type randomgens.RandNumGenerator 
    successfully instantiated
    
    CXXDriver0 of type drivers.CXXDriver
    FRAMEWORK of type Ccaffeine-Support
    MonteCarlo0 of type integrators.MonteCarlo
    PiFunction0 of type functions.PiFunction
    RandNumGenerator0 of type randomgens.RandNumGenerator
    

  4. Now we need to connect up the ports on the components we've instantiated in order to assemble the application:
    # Steps 5-6
    
    display chain
    display component MonteCarlo0
    connect CXXDriver0 integrate MonteCarlo0 integrate
    connect MonteCarlo0 function PiFunction0 function
    connect MonteCarlo0 RandomGeneratorPort RandNumGenerator0 RandomGeneratorPort
    display chain
    

    The command syntax is connect user_component user_port provider_component provider_port.

    The display command provides various kinds of information about the arena and components therein. display chain details the connections between components. display component component_instance lists the uses and provides ports the component has registered.

    The output from these commands should look something like this:

    Component CXXDriver0 of type drivers.CXXDriver
    Component FRAMEWORK of type Ccaffeine-Support
    Component MonteCarlo0 of type integrators.MonteCarlo
    Component PiFunction0 of type functions.PiFunction
    Component RandNumGenerator0 of type randomgens.RandNumGenerator
    
    ------------------------------------
    Instance name: MonteCarlo0
    Class name: integrators.MonteCarlo
    ------------------------------------
    UsesPorts registered for MonteCarlo0
    
    0. Instance Name: function Class Name: function.FunctionPort
    1. Instance Name: RandomGeneratorPort Class Name: randomgen.RandomGeneratorPort
    ------------------------------------
    ProvidesPorts registered for MonteCarlo0
    
    Instance Name: integrate Class Name: integrator.IntegratorPort
    ------------------------------------
    
    CXXDriver0))))integrate---->integrate((((MonteCarlo0
    connection made successfully
    
    MonteCarlo0))))function---->function((((PiFunction0
    connection made successfully
    
    MonteCarlo0))))RandomGeneratorPort---->RandomGeneratorPort((((RandNumGenerator0
    connection made successfully
    
    Component CXXDriver0 of type drivers.CXXDriver
     is using integrate connected to Port: integrate provided by component MonteCarlo0
    Component FRAMEWORK of type Ccaffeine-Support
    Component MonteCarlo0 of type integrators.MonteCarlo
     is using function connected to Port: function provided by component PiFunction0
     is using RandomGeneratorPort connected to Port: RandomGeneratorPort provided by component RandNumGenerator0
    Component PiFunction0 of type functions.PiFunction
    Component RandNumGenerator0 of type randomgens.RandNumGenerator
    

  5. Now that we have a complete application, we can start it by invoking the driver's go :
    # Step 7
    
    go CXXDriver0 go
    

    The command syntax is go component_instance port_name.

    The output from these commands should look something like this:

    Value = 3.140205
    ##specific go command successful
    

  6. Now we use commands we already know to complete the rest of the operations that we previously performed using the GUI:
    # Step 8
    
    instantiate integrators.Simpson Simpson0
    instantiate functions.CubeFunction CubeFunction0
    
    # Step 9
    
    disconnect CXXDriver0 integrate MonteCarlo0 integrate
    disconnect MonteCarlo0 function PiFunction0 function
    
    # Step 10
    
    connect CXXDriver0 integrate Simpson0 integrate
    connect Simpson0 function PiFunction0 function
    display chain
    go CXXDriver0 go
    
    # Step 11
    
    disconnect Simpson0 function PiFunction0 function
    connect Simpson0 function CubeFunction0 function
    display chain
    go CXXDriver0 go
    

    The output from these commands should look something like this:

    Simpson0 of type integrators.Simpson 
    successfully instantiated
    
    CubeFunction0 of type functions.CubeFunction 
    successfully instantiated
    
    
    
    
    CXXDriver0))))integrate-\ \-integrate((((MonteCarlo0
    connection broken successfully
    
    MonteCarlo0))))function-\ \-function((((PiFunction0
    connection broken successfully
    
    
    
    
    CXXDriver0))))integrate---->integrate((((Simpson0
    connection made successfully
    
    Simpson0))))function---->function((((PiFunction0
    connection made successfully
    
    Component CXXDriver0 of type drivers.CXXDriver
     is using integrate connected to Port: integrate provided by component Simpson0
    Component CubeFunction0 of type functions.CubeFunction
    Component FRAMEWORK of type Ccaffeine-Support
    Component MonteCarlo0 of type integrators.MonteCarlo
     is using RandomGeneratorPort connected to Port: RandomGeneratorPort provided by component RandNumGenerator0
    Component PiFunction0 of type functions.PiFunction
    Component RandNumGenerator0 of type randomgens.RandNumGenerator
    Component Simpson0 of type integrators.Simpson
     is using function connected to Port: function provided by component PiFunction0
    
    Value = 3.141593
    ##specific go command successful
    
    
    
    
    Simpson0))))function-\ \-function((((PiFunction0
    connection broken successfully
    
    Simpson0))))function---->function((((CubeFunction0
    connection made successfully
    
    Component CXXDriver0 of type drivers.CXXDriver
     is using integrate connected to Port: integrate provided by component Simpson0
    Component CubeFunction0 of type functions.CubeFunction
    Component FRAMEWORK of type Ccaffeine-Support
    Component MonteCarlo0 of type integrators.MonteCarlo
     is using RandomGeneratorPort connected to Port: RandomGeneratorPort provided by component RandNumGenerator0
    Component PiFunction0 of type functions.PiFunction
    Component RandNumGenerator0 of type randomgens.RandNumGenerator
    Component Simpson0 of type integrators.Simpson
     is using function connected to Port: function provided by component CubeFunction0
    
    Value = 0.250000
    ##specific go command successful
    

  7. At the end of the rc files, it is important to remember to terminate the framework:
    # Step 13
    
    quit
    

    The output from these commands should look something like this:

    bye!
    exit
    

    Image warningWarning

    If your rc file ends without a quit command, Ccaffeine will leave you in interactive mode rather than terminating and returning you to the shell prompt. If you make this mistake a Control-c will interrupt Ccaffeine and return you to the shell prompt.

Feel free to copy $TUTORIAL_SRC/components/tests/task0.rc to your workspace, modify it, and run it yourself.


2.3 Notes on More Advanced Usage of the GUI

There are a couple of other features of the GUI and its interaction with the Ccaffeine backend that are worth mentioning.


3. Using Bocca : A Project Manager for SIDL or CCA

While the CCA specification allows you to create components ``by hand'', it is much quicker to use an application generator that provides templated code for components and a build system. Naturally Bocca cannot create your implementation for you, but all of the glue code for multi-language interoperability and component interfaces in a CCA application is created and maintained with a few commands. The advantage of this approach is that a lot of build and component defaults have been chosen for you. The downside is that, while some customization is possible, the project directory and file structures are largely predetermined.


3.1 Creating a Bocca Project

If your CCA environment is configured properly (Section E) then the bocca command is already in your command path and you are ready to go. Find a safe place to begin your Bocca project, such as your WORKDIR:

$ cd $WORKDIR

The first thing to do is to create a project directory within which all of your components and ports will reside. Normally you would choose a relevant project name but for now we will just call it demo. Create the project directory now:

$ bocca create project demo --language=LANG

The project was created successfully in /home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/cxx/demo

Here LANG specifies the default implementation language for components in this project, if you don't specifically indicate a language when creating the component (a project can contain components in any mixture of Babel -supported languages). For this exercise, choose the one of  c,  cxx,  f90,  java, or  python with which you are most comfortable (some of these choices may not be available if your Babel installation is not configured for them, but these are the languages for which this Guide has detailed instructions). If you don't specify a default language when creating the project, Bocca will use C++.

Now that the project is created, we see that Bocca has created a lot of build scaffolding to support the componentized application we will write. The first thing you notice is that Bocca has created a directory:

$ ls -F

demo/

Feel free to poke around a bit:

$ ls -F demo

BOCCA/
buildutils/
components/
config/
configure*
configure.ac*
configure.ac1
depl/
external/
install/
Makefile
make.project
make.project.in
make.rules.user
make.vars.user
ports/
README
utils/

Before using a new Bocca project or working with an existing project just checked out from a source code repository, you will need to configure it for the details of your local environment. For a new project this is easy: ./configure from within your new project directory.

$ cd demo && ./configure

checking for bash... /bin/sh
checking for GNU make... make
checking for gcc... /usr/bin/cc
checking for C compiler default output file name... a.out
checking whether the C compiler works... yes
checking whether we are cross compiling... no
checking for suffix of executables... 
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether /usr/bin/cc accepts -g... yes
checking for /usr/bin/cc option to accept ISO C89... none needed
checking for openpty in -lutil... yes
checking for bocca... /project/projectdirs/cca/install-new/bin/bocca
c cxx f90 f77 python
configure: Configuring with languages: c cxx f90 f77 python
configure: Project source dir apparently /home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/cxx/demo
configure: Using 4 processe(s) in calls to make.
checking whether make sets $(MAKE)... yes
configure: creating ./config.status
config.status: creating make.project
config.status: creating buildutils/make.vars.common
config.status: creating utils/run-gui.sh
config.status: creating utils/bocca-gui-backend.sh
config.status: creating utils/demo-config
config.status: creating utils/config-data
config.status: creating utils/demo-config.h
config.status: executing outmsg commands


3.2 Creating Ports and Components

Let's create a component. First make sure that your current working directory is inside the project directory:

$ pwd

/home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/cxx/demo

It is important to be in the project directory (or its subdirectories) when you invoke bocca because it picks up all of the context for your project from there (similar to CVS or Subversion). Go ahead and create the component now:

$ bocca create component emptyComponent

Babel updating the cxx implementation of component demo.emptyComponent ...

Notice that Bocca selected demo as the default package name for emptyComponent since no package name was specified when creating the component. Normally, Bocca uses the project name as the package name for both ports and components unless a different default package name was specified when the project was created. We have named our component emptyComponent because it has no uses nor provides ports and thus is rather uninteresting. Nonetheless, Bocca has generated all of the necessary make system scaffolding and code for the component, including the setServicescall. Listing the directory shows the files Bocca has generated (shown here for LANGcxx):

$ ls components/demo.emptyComponent

BOCCA
demo_emptyComponent_Impl.cxx
demo_emptyComponent_Impl.hxx
demo_emptyComponent_Impl.hxx.rej
glue
Makefile
make.rules.user
make.vars.user

Components created in Fortran, C, and Python will contain a similar set files appropriate to the language. In the components directory a new directory, demo.emptyComponent, has been created to hold your component. And inside there is the code already generated for the component (again continuing with LANG =  cxx) in the files: demo_emptyComponent_Impl.cxx, demo_emptyComponent_Impl.hxx with some Babel glue code in the glue subdirectory. Note the file ending in .rej named demo_emptyComponent_Impl.hxx.rej. This file is produced by the Bocca splicing process. It records code fragments that Bocca discarded while generating demo_emptyComponent_Impl.hxx and can usually be ignored and even deleted.


An Empty Component in Ccaffeine (OPTIONAL READING)

Although the component you've created can't actually do anything useful at this point, it is a valid component. You can build it and instantiate it in Ccaffeine if you like:

$ make

make[1]: Entering directory `/home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/cxx/demo'
# =======================================================================
# No SIDL files in external/sidl, skipping build for external
# =======================================================================
# =======================================================================
# No SIDL files in ports/sidl, skipping build for ports
# =======================================================================
# =======================================================================
# Building in components/clients/, languages: cxx
# =======================================================================
 ## Building clients... 
# =======================================================================
# Building in components/, languages: cxx
# =======================================================================
   [s] Building class/component demo.emptyComponent: 
   [s] using Babel to generate cxx implementation code from demo.emptyComponent.sidl... 
   [s] compiling sources... 
   [s] creating class/component library: libdemo.emptyComponent.la ... 
   [s] finished libtooling: components/demo.emptyComponent/libdemo.emptyComponent.la ... 
   [s] building /home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/cxx/demo/install/share/cca/demo/demo.emptyComponent_depl.xml ... 
   [s] creating Ccaffeine test script (components/tests/instantiation.gen.rc)... 
Build summary:
SUCCESS building demo.emptyComponent
### To test instantiation of successfully built components, run 'make check' ###
################ Finished building everything #################
####### You can run some simple tests with 'make check' #######
make[1]: Leaving directory `/home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/cxx/demo'

(Your output should be substantially similar, but will at least have different paths.)

Now, you can run Ccaffeine and the GUI following the same procedure you used in Section 2.1. If you instantiate the emptyComponent , you should see something similar to Figure 3.1. Of course it lacks any uses or provides ports and thus cannot be used for anything, but it is a full-fledged CCA component.

Figure 3.1: GUI showing the emptyComponent generated in Section 3.2 instantiated in the arena .
Image hog-bocca-screen-shot0


3.2.1 Creating the Integrator and Function Components

In order to have some exportable or importable functionality in a component we must have some uses and provides ports. Bocca will also create the scaffolding and code for ports. Following the model of the integrator application of Chapter 2, we will create a Function , an Integrator , and a Driver . However before we can do that we will have to create some ports for these components to use and provide .

Let's begin by creating a FunctionPort and an Integration :

$ bocca create port Integration

Updating makefiles (for demo.Integration)...

$ bocca create port FunctionPort

Updating makefiles (for demo.FunctionPort)...

Notice that we are continuing to use the default package demo, though we could specify something different.

Now, create a set of components similar to those that you used in Chapter 2, specifying that they will provide or use the appropriate ports:

$ bocca create component Function --provides=FunctionPort@fun

Babel updating the cxx implementation of component demo.Function ...

$ bocca create component Integrator \
--provides=Integration@integrate \
--uses=FunctionPort@odeRHS

Babel updating the cxx implementation of component demo.Integrator ...

$ bocca create component Driver --go=run \
--uses=Integration@integrate

Babel updating the cxx implementation of component demo.Driver ...

This last bocca create decorates our Driver component with a CCA standard go port, which is not specified as part of this project. Since gov.cca.ports.GoPort is a part of the CCA specification, Bocca takes care of knowing where to find the SIDL definition of this port. The special --go option allows Bocca to generate a default go implementation which prefetches the uses ports so that all the user needs to do for our example is add numerical code. In languages which are not object-oriented, this substantially reduces the errors in handling ports, exceptions, and memory deallocation.

Image noteNote

It is not necessary to know at component creation time all ports that will be used or provided or other implementation details. Bocca provides various commands for changing project entities, e.g. adding or removing uses and provides ports.

As we have defined a number of new things, this would be a good time to rebuild the project:

$ make

make[1]: Entering directory `/home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/cxx/demo'
# =======================================================================
# No SIDL files in external/sidl, skipping build for external
# =======================================================================
# =======================================================================
# Building in ports/, languages: cxx
# =======================================================================
 ## Building ports... 
   [c] using Babel to generate cxx client code for demo.FunctionPort... 
   [c] creating library: libdemo.FunctionPort-cxx.la... 
   [c] installing demo.FunctionPort.sidl 
   [c] building /home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/cxx/demo/install/share/cca/demo/demo.FunctionPort_depl.xml ... 11071 
   [c] using Babel to generate cxx client code for demo.Integration... 
   [c] creating library: libdemo.Integration-cxx.la... 
   [c] installing demo.Integration.sidl 
   [c] building /home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/cxx/demo/install/share/cca/demo/demo.Integration_depl.xml ... 11404 
# =======================================================================
# Building in components/clients/, languages: cxx
# =======================================================================
 ## Building clients... 
# =======================================================================
# Building in components/, languages: cxx
# =======================================================================
   [s] Building class/component demo.Driver: 
   [s] using Babel to generate cxx implementation code from demo.Driver.sidl... 
   [s] compiling sources... 
   [s] creating class/component library: libdemo.Driver.la ... 
   [s] finished libtooling: components/demo.Driver/libdemo.Driver.la ... 
   [s] building /home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/cxx/demo/install/share/cca/demo/demo.Driver_depl.xml ... 
   [s] creating Ccaffeine test script (components/tests/instantiation.gen.rc)... 
   [s] Building class/component demo.Function: 
   [s] using Babel to generate cxx implementation code from demo.Function.sidl... 
   [s] compiling sources... 
   [s] creating class/component library: libdemo.Function.la ... 
   [s] finished libtooling: components/demo.Function/libdemo.Function.la ... 
   [s] building /home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/cxx/demo/install/share/cca/demo/demo.Function_depl.xml ... 
   [s] creating Ccaffeine test script (components/tests/instantiation.gen.rc)... 
   [s] Building class/component demo.Integrator: 
   [s] using Babel to generate cxx implementation code from demo.Integrator.sidl... 
   [s] compiling sources... 
   [s] creating class/component library: libdemo.Integrator.la ... 
   [s] finished libtooling: components/demo.Integrator/libdemo.Integrator.la ... 
   [s] building /home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/cxx/demo/install/share/cca/demo/demo.Integrator_depl.xml ... 
   [s] creating Ccaffeine test script (components/tests/instantiation.gen.rc)... 
   [s] Building class/component demo.emptyComponent: 
doing nothing -- library is up-to-date.
Build summary:
SUCCESS building demo.Driver
SUCCESS building demo.Function
SUCCESS building demo.Integrator
### To test instantiation of successfully built components, run 'make check' ###
################ Finished building everything #################
####### You can run some simple tests with 'make check' #######
make[1]: Leaving directory `/home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/cxx/demo'

Note that this operation can be very time-consuming when your project is managing many ports and components with the fully supported set of Babel language bindings.

Running make check will test whether the components you've created can be instantiated successfully in the Ccaffeine framework:

$ make check

make[1]: Entering directory `/home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/cxx/demo'
make --no-print-directory --no-builtin-rules -C components check
### Test library load and instantiation for the following languages: cxx
Running instantiation tests only
Test script: /home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/cxx/demo/components/tests/instantiation.gen.rc
Log file: /home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/cxx/demo/components/tests/instantiation.gen.rc.log
SUCCESS:
==> Instantiation tests passed for all built components (see /home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/cxx/demo/components/tests/instantiation.gen.rc.log).
make --no-print-directory --no-builtin-rules check-user
make[1]: Leaving directory `/home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/cxx/demo'

So far, with very little work, we have generated what appears to be an application but is really just the componentized shell of an application. If you were to run the GUI (Section 2.1) or do the command-line equivalent in Ccaffeine (Section 2.2), you would find that the components are decorated with the ports you expect, and they can even be connected (an operation of the framework, not of the components or ports). But if you attempted to run an application using these components, nothing would happen because they're only skeletons, providing the component-ness, but not the functionality.

Image noteNote

Along with everyting else it does, Bocca generates a set of utility scripts which are tailored to the specific Bocca project (i.e. having the right paths, the right sets of components, etc.). In Section 2 you ran Bocca-generated utility scripts in the pre-built tutorial tree (i.e.  $TUTORIAL_SRC/utils/run-gui.sh). When you're working in your own Bocca projects, make sure you use the utility scripts associated with that project, or things won't work properly.


3.3 How to Edit and Find Files in Bocca Projects

The next step in developing components requires you implement the component's intended functionality within the Bocca -generated skeleton. There are two places that we have to change things to make that happen: add methods to the interface definitions (.sidl file) and then put the implementation code into the components in the language chosen in Section 3.1.

Because Bocca generates all the files in the project, it knows where to find the code associated with each SIDL symbol. Using the bocca edit command, you can specify the SIDL symbol you're interested in and Bocca will bring up the appropriate file in your editor of choice. Additionally, after you exit the editor, Bocca regenerates all other source files that depend on the source file edited.

The last invocation requires that your editor support the +N option, which is used for specifying the initial position in the file. All emacs and vi versions support this feature. If your favorite editor does not support +N, omit the method name and search for it in the opened file using the editor's search capability.

If you replace edit in any of the above, with whereis, Bocca prints out the path of the file that would be edited without starting up an editor.

The environment variable BOCCA_EDITOR (and if that is not set, then EDITOR) controls what editor gets invoked by bocca edit.

Image tipTip

If you need to set BOCCA_EDITOR to get the editor you want, you might want to add the appropriate setting to your login files.

Image tipTip

Users of emacs may want to set BOCCA_EDITOR to ``emacs -nw'' when editing on a remote cluster with slow or no X11 connections.

There is also a way for you to tell Bocca that you've edited a file by some means other than bocca edit.

If you do not tell Bocca about files you've modified, you might find that the project's files are not in a consistent state. For example, if you add a method to a .sidl file it will not appear it in the implementation file until Bocca updates it.


3.4 Adding Methods to Ports

In Section 3.2.1, we had Bocca create skeleton .sidl files for the Integration and FunctionPort . Now we need to flesh out the ports by actually specifying the methods they contain.

$ bocca edit Integration

The SIDL code for Integration looks like this:

// DO-NOT-DELETE bocca.splicer.begin(demo.comment)

// Insert-UserCode-Here {demo.comment} (Insert your package comments here)
// DO-NOT-DELETE bocca.splicer.end(demo.comment)
package demo version 0.0 {

    // DO-NOT-DELETE bocca.splicer.begin(demo.Integration.comment)
    
// Insert-UserCode-Here {demo.Integration.comment} (Insert your port comments here)
    // DO-NOT-DELETE bocca.splicer.end(demo.Integration.comment)
    interface Integration extends gov.cca.Port
    {
        // DO-NOT-DELETE bocca.splicer.begin(demo.Integration.methods)
        
// Insert-UserCode-Here {demo.Integration.methods} (Insert your port methods here)
        // DO-NOT-DELETE bocca.splicer.end(demo.Integration.methods)
    }
}

Insert the march method:

// DO-NOT-DELETE bocca.splicer.begin(demo.comment)

// Insert-UserCode-Here {demo.comment} (Insert your package comments here)
// DO-NOT-DELETE bocca.splicer.end(demo.comment)
package demo version 0.0 {

    // DO-NOT-DELETE bocca.splicer.begin(demo.Integration.comment)
    
// Insert-UserCode-Here {demo.Integration.comment} (Insert your port comments here)
    // DO-NOT-DELETE bocca.splicer.end(demo.Integration.comment)
    interface Integration extends gov.cca.Port
    {
        // DO-NOT-DELETE bocca.splicer.begin(demo.Integration.methods)
        double march(in double lowBound, in double upBound, in int count);
        // DO-NOT-DELETE bocca.splicer.end(demo.Integration.methods)
    }
}

After you quit the editor, bocca edit then automatically updates the components that depend on the port edited:

Updating makefiles (for demo.Integration, demo.Integrator, demo.Driver)...
Using Babel to validate the SIDL for port demo.Integration ...
Babel updating the cxx implementation of component demo.Integrator ...
Babel updating the cxx implementation of component demo.Driver ...

Next edit the file FunctionPort.sidl:

$ bocca edit FunctionPort

Add two methods, init and evaluate so that function looks like this:

// DO-NOT-DELETE bocca.splicer.begin(demo.comment)

// Insert-UserCode-Here {demo.comment} (Insert your package comments here)
// DO-NOT-DELETE bocca.splicer.end(demo.comment)
package demo version 0.0 {

    // DO-NOT-DELETE bocca.splicer.begin(demo.FunctionPort.comment)
    
// Insert-UserCode-Here {demo.FunctionPort.comment} (Insert your port comments here)
    // DO-NOT-DELETE bocca.splicer.end(demo.FunctionPort.comment)
    interface FunctionPort extends gov.cca.Port
    {
        // DO-NOT-DELETE bocca.splicer.begin(demo.FunctionPort.methods)
        void   init(in array<double,1> params);
        double evaluate(in double x);
        // DO-NOT-DELETE bocca.splicer.end(demo.FunctionPort.methods)
    }
}

Again quit the editor and the dependent components are updated as indicated by this output from bocca edit:

Updating makefiles (for demo.FunctionPort, demo.Function, demo.Integrator)...
Using Babel to validate the SIDL for port demo.FunctionPort ...
Babel updating the cxx implementation of component demo.Function ...
Babel updating the cxx implementation of component demo.Integrator ...

These files contain the language-independent specification of the ports and their methods, expressed using SIDL. When you type make all of the the new method information is propagated to the language-dependent implementation files using Babel . Of course the methods will be unimplemented but the components will build anyway. So let's do that now:

$ make && make check

make[1]: Entering directory `/home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/cxx/demo'
# =======================================================================
# No SIDL files in external/sidl, skipping build for external
# =======================================================================
# =======================================================================
# Building in ports/, languages: cxx
# =======================================================================
 ## Building ports... 
   [c] using Babel to generate cxx client code for demo.FunctionPort... 
   [c] creating library: libdemo.FunctionPort-cxx.la... 
15,16c15,16
<         
< // Insert-UserCode-Here {demo.FunctionPort.methods} (Insert your port methods here)
---
>         void   init(in array<double,1> params);
>         double evaluate(in double x);
   [c] installing modified demo.FunctionPort.sidl in /home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/cxx/demo/install/share/cca.
   [c] building /home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/cxx/demo/install/share/cca/demo/demo.FunctionPort_depl.xml ... 24528 
   [c] using Babel to generate cxx client code for demo.Integration... 
   [c] creating library: libdemo.Integration-cxx.la... 
15,16c15
<         
< // Insert-UserCode-Here {demo.Integration.methods} (Insert your port methods here)
---
>         double march(in double lowBound, in double upBound, in int count);
   [c] installing modified demo.Integration.sidl in /home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/cxx/demo/install/share/cca.
   [c] building /home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/cxx/demo/install/share/cca/demo/demo.Integration_depl.xml ... 24834 
# =======================================================================
# Building in components/clients/, languages: cxx
# =======================================================================
 ## Building clients... 
# =======================================================================
# Building in components/, languages: cxx
# =======================================================================
   [s] Building class/component demo.Driver: 
   [s] using Babel to generate cxx implementation code from demo.Driver.sidl... 
   [s] compiling sources... 
   [s] creating class/component library: libdemo.Driver.la ... 
   [s] finished libtooling: components/demo.Driver/libdemo.Driver.la ... 
   [s] building /home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/cxx/demo/install/share/cca/demo/demo.Driver_depl.xml ... 
   [s] creating Ccaffeine test script (components/tests/instantiation.gen.rc)... 
   [s] Building class/component demo.Function: 
   [s] using Babel to generate cxx implementation code from demo.Function.sidl... 
   [s] compiling sources... 
   [s] creating class/component library: libdemo.Function.la ... 
   [s] finished libtooling: components/demo.Function/libdemo.Function.la ... 
   [s] building /home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/cxx/demo/install/share/cca/demo/demo.Function_depl.xml ... 
   [s] creating Ccaffeine test script (components/tests/instantiation.gen.rc)... 
   [s] Building class/component demo.Integrator: 
   [s] using Babel to generate cxx implementation code from demo.Integrator.sidl... 
   [s] compiling sources... 
   [s] creating class/component library: libdemo.Integrator.la ... 
   [s] finished libtooling: components/demo.Integrator/libdemo.Integrator.la ... 
   [s] building /home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/cxx/demo/install/share/cca/demo/demo.Integrator_depl.xml ... 
   [s] creating Ccaffeine test script (components/tests/instantiation.gen.rc)... 
   [s] Building class/component demo.emptyComponent: 
doing nothing -- library is up-to-date.
Build summary:
SUCCESS building demo.Driver
SUCCESS building demo.Function
SUCCESS building demo.Integrator
### To test instantiation of successfully built components, run 'make check' ###
################ Finished building everything #################
####### You can run some simple tests with 'make check' #######
make[1]: Leaving directory `/home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/cxx/demo'
make[1]: Entering directory `/home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/cxx/demo'
make --no-print-directory --no-builtin-rules -C components check
### Test library load and instantiation for the following languages: cxx
Running instantiation tests only
Test script: /home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/cxx/demo/components/tests/instantiation.gen.rc
Log file: /home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/cxx/demo/components/tests/instantiation.gen.rc.log
SUCCESS:
==> Instantiation tests passed for all built components (see /home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/cxx/demo/components/tests/instantiation.gen.rc.log).
make --no-print-directory --no-builtin-rules check-user
make[1]: Leaving directory `/home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/cxx/demo'

The methods you inserted into the SIDL port specifications have now been inserted into your already generated components. At this point we are ready to insert the actual implementation into the bodies of these methods. Notice that up to this point, you created the skeleton for an entire application without having to write any code at all, except for the SIDL for the ports. Finally, it is time to implement the components' functionality in the programming language of your choice.

3.5 Language-Specific Function, Integrator, and Driver Code

Please jump to the appropriate section for the implementation language you chose in Section 3.1 and then continue with Section 3.6 (p. [*]).

Language Section Page
C++ 3.5.1 [*]
F90 3.5.2 [*]
C 3.5.3 [*]
Python 3.5.4 [*]
Java 3.5.5 [*]


3.5.1 C++ Implementation

Image noteNote

Assumes you created the project with  bocca create project demo --language=cxx or did not specify a language (cxx is the default).

Edit the evaluate method in the implementation file (also known as ``the impl'') that Bocca has generated for you (by invoking Babel ). Use the bocca edit -i to go directly to each method.

$ bocca edit -i Function evaluate

The editor opens up in the place where the implementation code for evaluate  must be put. You see a default implementation generated by Babel for all user methods: the throwing of an exception which says the method is not yet implemented.

double
demo::Function_impl::evaluate_impl (
  /* in */double x ) 
{
  // DO-NOT-DELETE splicer.begin(demo.Function.evaluate)
  // Insert-Code-Here {demo.Function.evaluate} (evaluate method)
  // 
  // This method has not been implemented
  // 
  // DO-DELETE-WHEN-IMPLEMENTING exception.begin(demo.Function.evaluate)
  ::sidl::NotImplementedException ex = ::sidl::NotImplementedException::_create();
  ex.setNote("This method has not been implemented");
  ex.add(__FILE__, __LINE__, "evaluate");
  throw ex;
  // DO-DELETE-WHEN-IMPLEMENTING exception.end(demo.Function.evaluate)
  // DO-NOT-DELETE splicer.end(demo.Function.evaluate)
}

As the comment suggests, this method is ``not implemented'', but some code has been inserted by Babel to make sure an exception is thrown to inform the user if this method is called by mistake. Delete this exception code and substitute an implementation for the PiFunction (i.e., the integral from 0 to 1 of 4/(1 + x2) is an approximation of \bgroup\color{Green}$ \pi$\egroup ).

  // DO-NOT-DELETE splicer.begin(demo.Function.evaluate)
    return 4.0 / (1.0 + x * x);
  // DO-NOT-DELETE splicer.end(demo.Function.evaluate)

Now in the same file just above the evaluate method, find the second method for the FunctionPort init method:

  // DO-NOT-DELETE splicer.begin(demo.Function.init)
    // Do nothing.
  // DO-NOT-DELETE splicer.end(demo.Function.init)

We don't have any initialization in this simple example, so we just eliminate the code that throws the exception when the method is executed.

After quitting the editor the state of the source code tree is updated if there are any dependencies on the edited implementation. Usually there are no dependencies on the implementation file, so Bocca does very little after you exit the editor and all you see is the information from the edit command about what file was edited:

/home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/cxx/demo/components/demo.Function/demo_Function_Impl.cxx

Similarly edit the march method in the Integrator with

$ bocca edit -i Integrator march

double
demo::Integrator_impl::march_impl (
  /* in */double lowBound,
  /* in */double upBound,
  /* in */int32_t count ) 
{
  // DO-NOT-DELETE splicer.begin(demo.Integrator.march)
  // Insert-Code-Here {demo.Integrator.march} (march method)
  // 
  // This method has not been implemented
  // 
  // DO-DELETE-WHEN-IMPLEMENTING exception.begin(demo.Integrator.march)
  ::sidl::NotImplementedException ex = ::sidl::NotImplementedException::_create();
  ex.setNote("This method has not been implemented");
  ex.add(__FILE__, __LINE__, "march");
  throw ex;
  // DO-DELETE-WHEN-IMPLEMENTING exception.end(demo.Integrator.march)
  // DO-NOT-DELETE splicer.end(demo.Integrator.march)
}

Again remove this boilerplate exception code and insert an implementation of the Trapezoid rule for integration that uses the FunctionPort :

  // DO-NOT-DELETE splicer.begin(demo.Integrator.march)
  demo::FunctionPort  odeRHS;
  gov::cca::Port          generalPort;

  try {
    generalPort = d_services.getPort("odeRHS");
  } catch ( ::gov::cca::CCAException ex) {
    // we cannot go on. add to the error report.
    ex.add( __FILE__, __LINE__,
           "odeRHS port not available in Integrator.march");
    throw;
  }

  odeRHS = ::babel_cast< demo::FunctionPort >(generalPort);
  if (odeRHS._is_nil()){
    // we cannot go on. toss an exception after cleaning up.
    try {
      d_services.releasePort("odeRHS");
    } catch (...) {
      // suppress framework complaints; we're already handling an exception.
    }
    ::sidl::SIDLException ex = ::sidl::SIDLException::_create();
    ex.setNote("Error: odeRHS port is nil. Weird.");
    ex.add(__FILE__, __LINE__, "demo::Integrator::integrate_impl");
    throw ex;
  }

  double h = (upBound - lowBound) / count;
  double retval = 0.0;
  double sum = 0.0;
  for (int i = 1; i <= count; i++){
    sum += odeRHS.evaluate(lowBound + (i - 1) * h) +
           odeRHS.evaluate(lowBound + i * h);
  }
  retval = h/2.0 * sum;
  d_services.releasePort("odeRHS");
  return retval;
  // DO-NOT-DELETE splicer.end(demo.Integrator.march)

After quitting the editor the state of the source code tree is updated if there are any dependencies on the edited implementation. Usually there are no dependencies on the implementation file, so Bocca does very little after you exit the editor and all you see is the information from the edit command about what file was edited:

/home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/cxx/demo/components/demo.Integrator/demo_Integrator_Impl.cxx

Finally for the Driver component we have to implement the GoPort details to get things going. Bocca will take you to the generated method, which looks like this:

$ bocca edit -i Driver go

int32_t
demo::Driver_impl::go_impl () 

{
  // DO-NOT-DELETE splicer.begin(demo.Driver.go)
// User editable portion is in the middle at the next Insert-UserCode-Here line.


// Bocca generated code. bocca.protected.begin(demo.Driver.go:boccaGoProlog)
  int bocca_status = 0;
  // The user's code should set bocca_status 0 if computation proceeded ok.
  // The user's code should set bocca_status -1 if computation failed but might
  // succeed on another call to go(), e.g. when a required port is not yet 
  // connected.
  // The user's code should set bocca_status -2 if the computation failed and 
  // can never succeed in a future call.
  // The user's code should NOT use return in this function.
  // Exceptions that are not caught in user code will be converted to 
  // status -2.

  gov::cca::Port port;

  // nil if not fetched and cast successfully:
  demo::Integration integrate; 
  // True when releasePort is needed (even if cast fails):
  bool integrate_fetched = false; 
  // Use a demo.Integration port with port name integrate 
  try{
    port = this->d_services.getPort("integrate");
  } catch ( ::gov::cca::CCAException ex )  {
    // we will continue with port nil (never successfully assigned) and 
    // set a flag.

#ifdef _BOCCA_STDERR
    std::cerr << "demo.Driver: Error calling getPort(\"integrate\") "
              " at " << __FILE__ << ":" << __LINE__ -5 << ": " << ex.getNote() 
              << std::endl;
#endif // _BOCCA_STDERR

  }
  if ( port._not_nil() ) {
    // even if the next cast fails, must release.
    integrate_fetched = true; 
    integrate = ::babel_cast< demo::Integration >(port);
    if (integrate._is_nil()) {

#ifdef _BOCCA_STDERR
      std::cerr << "demo.Driver: Error casting gov::cca::Port "
                << "integrate to type "
                << "demo::Integration" << std::endl;
#endif //_BOCCA_STDERR

      goto BOCCAEXIT; // we cannot correctly continue. clean up and leave.
    } 
  } 


// Bocca generated code. bocca.protected.end(demo.Driver.go:boccaGoProlog)



  // When this try/catch block is rewritten by the user, we will not change it.
  try {

    // All port instances should be rechecked for ._not_nil before calling in 
    // user code. Not all ports need be connected in arbitrary use.
    // The uses ports appear as local variables here named exactly as on the 
    // bocca commandline.

    // Insert-UserCode-Here {demo.Driver.go} 

    // REMOVE ME BLOCK.begin(demo.Driver.go)

#ifdef _BOCCA_STDERR
    std::cerr << "USER FORGOT TO FILL IN THEIR GO FUNCTION HERE." << std::endl;
#endif

    // REMOVE ME BLOCK.end(demo.Driver.go)

  } 
  // If unknown exceptions in the user code are tolerable and restart is ok, 
  // return -1 instead. -2 means the component is so confused that it and 
  // probably the application should be destroyed.
  // babel requires exact exception catching due to c++ binding of interfaces.
  catch (gov::cca::CCAException ex) {
    bocca_status = -2;
    std::string enote = ex.getNote();

#ifdef _BOCCA_STDERR
    std::cerr << "CCAException in user go code: " << enote << std::endl;
    std::cerr << "Returning -2 from go()" << std::endl;;
#endif

  }
  catch (sidl::RuntimeException ex) {
    bocca_status = -2;
    std::string enote = ex.getNote();

#ifdef _BOCCA_STDERR
    std::cerr << "RuntimeException in user go code: " << enote << std::endl;
    std::cerr << "Returning -2 from go()" << std::endl;;
#endif

  }
  catch (sidl::SIDLException ex) {
    bocca_status = -2;
    std::string enote = ex.getNote();

#ifdef _BOCCA_STDERR
    std::cerr << "SIDLException in user go code: " << enote << std::endl;
    std::cerr << "Returning -2 from go()" << std::endl;;
#endif

  }
  catch (sidl::BaseException ex) {
    bocca_status = -2;
    std::string enote = ex.getNote();

#ifdef _BOCCA_STDERR
    std::cerr << "BaseException in user go code: " << enote << std::endl;
    std::cerr << "Returning -2 from go()" << std::endl;;
#endif

  }
  catch (std::exception ex) {
    bocca_status = -2;

#ifdef _BOCCA_STDERR
    std::cerr << "C++ exception in user go code: " << ex.what() << std::endl;
    std::cerr << "Returning -2 from go()"  << std::endl;
#endif

  }
  catch (...) {
    bocca_status = -2;

#ifdef _BOCCA_STDERR
    std::cerr << "Odd exception in user go code " << std::endl;
    std::cerr << "Returning -2 from go()" << std::endl;
#endif

  }


  BOCCAEXIT:; // target point for error and regular cleanup. do not delete.
// Bocca generated code. bocca.protected.begin(demo.Driver.go:boccaGoEpilog)

  // release integrate 
  if (integrate_fetched) {
    integrate_fetched = false;
    try{
      this->d_services.releasePort("integrate");
    } catch ( ::gov::cca::CCAException ex )  {

#ifdef _BOCCA_STDERR
      std::cerr << "demo.Driver: Error calling releasePort("
                << "\"integrate\") at " 
                << __FILE__ << ":" << __LINE__ -4 << ": " << ex.getNote() 
                << std::endl;
#endif // _BOCCA_STDERR

    }
    // c++ port reference will be dropped when function exits, but we 
    // must tell framework.
  }


  return bocca_status;
// Bocca generated code. bocca.protected.end(demo.Driver.go:boccaGoEpilog)

  // 
  // This method has not been implemented
  // 
  // DO-NOT-DELETE splicer.end(demo.Driver.go)
}

Find the REMOVE block within the go method implementation, delete it, and insert the numerical logic needed to use the integrator.IntegratorPort port. Any required local variables should be inserted just before the boccaGoProlog protected block.

The go subroutine will be called by the framework when the component's run button (the name of this particular GoPort instance) is pushed in the GUI. Bocca generates the code to the Integration that the Driver is connected to. We just have to use it to compute the integral and return the proper value for bocca_status.

  // DO-NOT-DELETE splicer.begin(demo.Driver.go)
// User editable portion is in the middle at the next Insert-UserCode-Here line.


// Bocca generated code. bocca.protected.begin(demo.Driver.go:boccaGoProlog)
  int bocca_status = 0;
  // The user's code should set bocca_status 0 if computation proceeded ok.
  // The user's code should set bocca_status -1 if computation failed but might
  // succeed on another call to go(), e.g. when a required port is not yet 
  // connected.
  // The user's code should set bocca_status -2 if the computation failed and 
  // can never succeed in a future call.
  // The user's code should NOT use return in this function.
  // Exceptions that are not caught in user code will be converted to 
  // status -2.

  gov::cca::Port port;

  // nil if not fetched and cast successfully:
  demo::Integration integrate; 
  // True when releasePort is needed (even if cast fails):
  bool integrate_fetched = false; 
  // Use a demo.Integration port with port name integrate 
  try{
    port = this->d_services.getPort("integrate");
  } catch ( ::gov::cca::CCAException ex )  {
    // we will continue with port nil (never successfully assigned) and 
    // set a flag.

#ifdef _BOCCA_STDERR
    std::cerr << "demo.Driver: Error calling getPort(\"integrate\") "
              " at " << __FILE__ << ":" << __LINE__ -5 << ": " << ex.getNote() 
              << std::endl;
#endif // _BOCCA_STDERR

  }
  if ( port._not_nil() ) {
    // even if the next cast fails, must release.
    integrate_fetched = true; 
    integrate = ::babel_cast< demo::Integration >(port);
    if (integrate._is_nil()) {

#ifdef _BOCCA_STDERR
      std::cerr << "demo.Driver: Error casting gov::cca::Port "
                << "integrate to type "
                << "demo::Integration" << std::endl;
#endif //_BOCCA_STDERR

      goto BOCCAEXIT; // we cannot correctly continue. clean up and leave.
    } 
  } 


// Bocca generated code. bocca.protected.end(demo.Driver.go:boccaGoProlog)

  // When this try/catch block is rewritten by the user, we will not change it.
  try {

    // All port instances should be rechecked for ._not_nil before calling in
    // user code. Not all ports need be connected in arbitrary use.
    // The uses ports appear as local variables here named exactly as on the
    // bocca commandline.

    // Insert-UserCode-Here {demo.Driver.go}
    double value;
    int count = 100000;
    double lowerBound = 0.0, upperBound = 1.0;

    // operate on the port
    value = integrate.march(lowerBound, upperBound, count);
    std::cout << "Value = " << value << std::endl;
  }
  // If unknown exceptions in the user code are tolerable and restart is ok,
  // return -1 instead. -2 means the component is so confused that it and
  // probably the application should be destroyed.
  catch (sidl::BaseException ex) {
    bocca_status = -2;
    std::string enote = ex.getNote();

#ifdef _BOCCA_STDERR
    std::cerr << "Exception in user go code: " << enote << std::endl;
    std::cerr << "Returning -2 from go()" << std::endl;;
#endif

  }
  catch (std::exception ex) {
    bocca_status = -2;

#ifdef _BOCCA_STDERR
    std::cerr << "C++ exception in user go code: " << ex.what() << std::endl;
    std::cerr << "Returning -2 from go()"  << std::endl;
#endif

  }
  catch (...) {
    bocca_status = -2;

#ifdef _BOCCA_STDERR
    std::cerr << "Odd exception in user go code " << std::endl;
    std::cerr << "Returning -2 from go()" << std::endl;
#endif

  }


  BOCCAEXIT:; // target point for error and regular cleanup. do not delete.
// Bocca generated code. bocca.protected.begin(demo.Driver.go:boccaGoEpilog)

  // release integrate 
  if (integrate_fetched) {
    integrate_fetched = false;
    try{
      this->d_services.releasePort("integrate");
    } catch ( ::gov::cca::CCAException ex )  {

#ifdef _BOCCA_STDERR
      std::cerr << "demo.Driver: Error calling releasePort("
                << "\"integrate\") at " 
                << __FILE__ << ":" << __LINE__ -4 << ": " << ex.getNote() 
                << std::endl;
#endif // _BOCCA_STDERR

    }
    // c++ port reference will be dropped when function exits, but we 
    // must tell framework.
  }


  return bocca_status;
// Bocca generated code. bocca.protected.end(demo.Driver.go:boccaGoEpilog)

  // DO-NOT-DELETE splicer.end(demo.Driver.go)

After quitting the editor the state of the source code tree is updated if there are any dependencies on the edited implementation. Usually there are no dependencies on the implementation file, so Bocca does very little after you exit the editor and all you see is the information from the edit command about what file was edited.

/home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/cxx/demo/components/demo.Driver/demo_Driver_Impl.cxx

Now remake your project tree to finish the components:

$ make

make[1]: Entering directory `/home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/cxx/demo'
# =======================================================================
# No SIDL files in external/sidl, skipping build for external
# =======================================================================
# =======================================================================
# Building in ports/, languages: cxx
# =======================================================================
 ## Building ports... 
# =======================================================================
# Building in components/clients/, languages: cxx
# =======================================================================
 ## Building clients... 
# =======================================================================
# Building in components/, languages: cxx
# =======================================================================
   [s] Building class/component demo.Driver: 
   [s] creating class/component library: libdemo.Driver.la ... 
   [s] finished libtooling: components/demo.Driver/libdemo.Driver.la ... 
   [s] building /home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/cxx/demo/install/share/cca/demo/demo.Driver_depl.xml ... 
   [s] creating Ccaffeine test script (components/tests/instantiation.gen.rc)... 
   [s] Building class/component demo.Function: 
   [s] creating class/component library: libdemo.Function.la ... 
   [s] finished libtooling: components/demo.Function/libdemo.Function.la ... 
   [s] building /home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/cxx/demo/install/share/cca/demo/demo.Function_depl.xml ... 
   [s] creating Ccaffeine test script (components/tests/instantiation.gen.rc)... 
   [s] Building class/component demo.Integrator: 
   [s] creating class/component library: libdemo.Integrator.la ... 
   [s] finished libtooling: components/demo.Integrator/libdemo.Integrator.la ... 
   [s] building /home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/cxx/demo/install/share/cca/demo/demo.Integrator_depl.xml ... 
   [s] creating Ccaffeine test script (components/tests/instantiation.gen.rc)... 
   [s] Building class/component demo.emptyComponent: 
doing nothing -- library is up-to-date.
Build summary:
SUCCESS building demo.Driver
SUCCESS building demo.Function
SUCCESS building demo.Integrator
### To test instantiation of successfully built components, run 'make check' ###
################ Finished building everything #################
####### You can run some simple tests with 'make check' #######
make[1]: Leaving directory `/home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/cxx/demo'

It is good practice to do a make check at this point:

$ make check

make[1]: Entering directory `/home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/cxx/demo'
make --no-print-directory --no-builtin-rules -C components check
### Test library load and instantiation for the following languages: cxx
Running instantiation tests only
Test script: /home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/cxx/demo/components/tests/instantiation.gen.rc
Log file: /home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/cxx/demo/components/tests/instantiation.gen.rc.log
SUCCESS:
==> Instantiation tests passed for all built components (see /home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/cxx/demo/components/tests/instantiation.gen.rc.log).
make --no-print-directory --no-builtin-rules check-user
make[1]: Leaving directory `/home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/cxx/demo'

You should now be able to instantiate these components, assemble them into an application, and run the application, following the same procedures as in Section 2, and get a result that's reasonably close to pi .


3.5.2 Fortran9X Implementation

Image noteNote

Assumes you created the project with  bocca create project demo --language=f90.

Edit the evaluate method in the implementation file (also known as ``the impl'') that Bocca has generated for you (by invoking Babel ). Use the bocca edit -i to go directly to each method.

$ bocca edit -i Function evaluate

The editor opens up in the place where the implementation code for evaluate  must be put. You see a default implementation generated by Babel for all user methods: the throwing of an exception which says the method is not yet implemented.

recursive subroutine demo_Function_evaluate_mi(self, x, retval, exception)
  use sidl
  use sidl_NotImplementedException
  use sidl_BaseInterface
  use sidl_RuntimeException
  use demo_Function
  use demo_Function_impl
  ! DO-NOT-DELETE splicer.begin(demo.Function.evaluate.use)
  ! Insert-Code-Here {demo.Function.evaluate.use} (use statements)
  ! DO-NOT-DELETE splicer.end(demo.Function.evaluate.use)
  implicit none
  type(demo_Function_t) :: self
  ! in
  real (kind=sidl_double) :: x
  ! in
  real (kind=sidl_double) :: retval
  ! out
  type(sidl_BaseInterface_t) :: exception
  ! out



! DO-NOT-DELETE splicer.begin(demo.Function.evaluate)
! Insert-Code-Here {demo.Function.evaluate} (evaluate method)
! 
! This method has not been implemented
! 

  ! DO-DELETE-WHEN-IMPLEMENTING exception.begin(demo.Function.evaluate)
  type(sidl_BaseInterface_t) :: throwaway
  type(sidl_NotImplementedException_t) :: notImpl
  call new(notImpl, exception)
  call setNote(notImpl, 'Not Implemented', exception)
  call cast(notImpl, exception,throwaway)
  call deleteRef(notImpl,throwaway)
  return
  ! DO-DELETE-WHEN-IMPLEMENTING exception.end(demo.Function.evaluate)
! DO-NOT-DELETE splicer.end(demo.Function.evaluate)
end subroutine demo_Function_evaluate_mi

As the comment suggests, this method is ``not implemented'', but some code has been inserted by Babel to make sure an exception is thrown to inform the user if this method is called by mistake. Delete this exception code and substitute an implementation for the PiFunction (i.e., the integral from 0 to 1 of 4/(1 + x2) is an approximation of \bgroup\color{Green}$ \pi$\egroup ).

! DO-NOT-DELETE splicer.begin(demo.Function.evaluate)
  retval = 4.0 / (1.0 + x * x)
! DO-NOT-DELETE splicer.end(demo.Function.evaluate)

Now in the same file just above the evaluate method, find the second method for the FunctionPort init method:

! DO-NOT-DELETE splicer.begin(demo.Function.init)
  ! Do nothing
! DO-NOT-DELETE splicer.end(demo.Function.init)

We don't have any initialization in this simple example, so we just eliminate the code that throws the exception when the method is executed.

After quitting the editor the state of the source code tree is updated if there are any dependencies on the edited implementation. Usually there are no dependencies on the implementation file, so Bocca does very little after you exit the editor and all you see is the information from the edit command about what file was edited:

/home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/f90/demo/components/demo.Function/demo_Function_Impl.F90

Similarly edit the march method in the Integrator with

$ bocca edit -i Integrator march

recursive subroutine demo_Integrator_march_mi(self, lowBound, upBound, count,  &
  retval, exception)
  use sidl
  use sidl_NotImplementedException
  use sidl_BaseInterface
  use sidl_RuntimeException
  use demo_Integrator
  use demo_Integrator_impl
  ! DO-NOT-DELETE splicer.begin(demo.Integrator.march.use)
  ! Insert-Code-Here {demo.Integrator.march.use} (use statements)
  ! DO-NOT-DELETE splicer.end(demo.Integrator.march.use)
  implicit none
  type(demo_Integrator_t) :: self
  ! in
  real (kind=sidl_double) :: lowBound
  ! in
  real (kind=sidl_double) :: upBound
  ! in
  integer (kind=sidl_int) :: count
  ! in
  real (kind=sidl_double) :: retval
  ! out
  type(sidl_BaseInterface_t) :: exception
  ! out



! DO-NOT-DELETE splicer.begin(demo.Integrator.march)
! Insert-Code-Here {demo.Integrator.march} (march method)
! 
! This method has not been implemented
! 

  ! DO-DELETE-WHEN-IMPLEMENTING exception.begin(demo.Integrator.march)
  type(sidl_BaseInterface_t) :: throwaway
  type(sidl_NotImplementedException_t) :: notImpl
  call new(notImpl, exception)
  call setNote(notImpl, 'Not Implemented', exception)
  call cast(notImpl, exception,throwaway)
  call deleteRef(notImpl,throwaway)
  return
  ! DO-DELETE-WHEN-IMPLEMENTING exception.end(demo.Integrator.march)
! DO-NOT-DELETE splicer.end(demo.Integrator.march)
end subroutine demo_Integrator_march_mi

Again remove this boilerplate exception code and insert an implementation of the Trapezoid rule for integration that uses the FunctionPort :

! DO-NOT-DELETE splicer.begin(demo.Integrator.march.use)
  ! the port types we need go here.
  use gov_cca_Port
  use demo_FunctionPort
! DO-NOT-DELETE splicer.end(demo.Integrator.march.use)

! DO-NOT-DELETE splicer.begin(demo.Integrator.march)
  ! User's local declarations. We follow the pattern generated for us in Driver.go()
  type(gov_cca_Port_t) :: port
  type(gov_cca_Services_t) :: services
  type(SIDL_BaseInterface_t) :: throwaway
  type(SIDL_BaseInterface_t) :: dumex
  type(demo_Integrator_wrap) :: dp
  logical dr_port ! if dr_X true, the deleteRef(X) is needed before return.

  type(demo_FunctionPort_t) :: odeRHS__p
  ! odeRHS__p is non-null if specific uses port obtained.

  logical odeRHS_fetched
  ! odeRHS_fetched true if releaseport is needed for this port.

! a small message catalog for exception reporting
  character (LEN=*) errMsg00
  character (LEN=*) errMsg0
  character (LEN=*) errMsg1
  character (LEN=*) errMsg2
  character (LEN=*) errMsg3
  character (LEN=*) errMsg4
  parameter(errMsg00= &
     'NULL d_services pointer in demo.Integrator.march()')
  parameter(errMsg0= &
    'demo.Integrator: Error go() getPort(odeRHS) failed.')
  parameter(errMsg1= &
    'demo.Integrator: Error casting odeRHS to FunctionPort')
  parameter(errMsg2= &
     'demo.Integrator: Error in deleteRef(port) while getting odeRHS')
  parameter(errMsg3= &
     'demo.Integrator: Error calling releasePort(odeRHS).')
  parameter(errMsg4= &
     'demo.Integrator: Error in deleteRef for port odeRHS.')

! numerical method variable, other than the call arguments:
  real (kind=sidl_double) :: h, fvalueleft, fvalueright, sum, left, right
  integer i

  BOCCA_EXTERNAL
  ! not crashing if something fails .eq. good bookkeeping and exception handling.
  ! start with initialization
  call set_null( odeRHS__p)
  odeRHS_fetched = .false.
  call set_null(services)
  call set_null(port)
  call set_null(throwaway)
  call set_null(dumex)
  dr_port = .false.
  call demo_Integrator__get_data_m(self,dp);
  services =  dp%d_private_data%d_services
  retval = -4.0

  if (is_null(services) ) then
    call BOCCA_SIDL_THROW_F90(exception, errMsg00)
  endif

  ! Use a demo.FunctionPort port with port name odeRHS
  call getPort(services,"odeRHS", port, exception)
  BOCCA_SIDL_CHECK_F90(exception, errMsg0)

  odeRHS_fetched = .true.
  ! even if the next cast fails, must releasePort per odeRHS_fetched.
  call cast(port, odeRHS__p, exception)
  BOCCA_SIDL_CHECK_F90(exception, errMsg1)

  ! done with the generic port pointer. drop it.
  call deleteRef(port, exception)
  call set_null(port)
  BOCCA_SIDL_CHECK_F90(exception, errMsg2)

  !! here's the numerical work

  ! the trapezoidal rule
  h = (upBound - lowBound) / count
  sum = 0.0
  fvalueleft = 0.0
  fvalueright = 0.0
  do i =  1,count
    left = lowBound + (i - 1) * h
    call evaluate(odeRHS__p, left, fvalueleft, exception)
    BOCCA_SIDL_CHECK_F90(exception, 'error calculating fvalueleft')

    right = lowBound + i * h
    call evaluate(odeRHS__p, right, fvalueright, exception)
    BOCCA_SIDL_CHECK_F90(exception, 'error calculating fvalueright')

    sum = sum + fvalueleft + fvalueright
  enddo
  retval = h/2.0 * sum;

  !! the numerical work is done.

BOCCAEXIT continue ! target point for normal and error cleanup.

  if (not_null(port)) then
    call deleteRef(port,throwaway)
    call checkException(self, throwaway, 'cleanup port error', .false., dumex)
    call set_null(port)
  endif

  ! release odeRHS
  if (odeRHS_fetched) then
    odeRHS_fetched = .false.
    call releasePort(services, 'odeRHS', throwaway)
    call checkException(self, throwaway, errMsg3, .false., dumex)

    if ( not_null(odeRHS__p) ) then
      call deleteRef(odeRHS__p, throwaway)
      call checkException(self, throwaway, errMsg4, .false., dumex)
      call set_null(odeRHS__p)
    endif

  endif
! DO-NOT-DELETE splicer.end(demo.Integrator.march)

After quitting the editor the state of the source code tree is updated if there are any dependencies on the edited implementation. Usually there are no dependencies on the implementation file, so Bocca does very little after you exit the editor and all you see is the information from the edit command about what file was edited:

/home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/f90/demo/components/demo.Integrator/demo_Integrator_Impl.F90

Finally for the Driver component we have to implement the GoPort details to get things going. Bocca will take you to the generated method, which looks like this:

$ bocca edit -i Driver go

recursive subroutine demo_Driver_go_mi(self, retval, exception)
  use sidl
  use sidl_NotImplementedException
  use sidl_BaseInterface
  use sidl_RuntimeException
  use demo_Driver
  use demo_Driver_impl
  ! DO-NOT-DELETE splicer.begin(demo.Driver.go.use)

! Bocca generated code. bocca.protected.begin(demo.Driver.go.use) 
  use gov_cca_Port
  use demo_Integration

! Bocca generated code. bocca.protected.end(demo.Driver.go.use) 

  ! DO-NOT-DELETE splicer.end(demo.Driver.go.use)
  implicit none
  type(demo_Driver_t) :: self
  ! in
  integer (kind=sidl_int) :: retval
  ! out
  type(sidl_BaseInterface_t) :: exception
  ! out



! DO-NOT-DELETE splicer.begin(demo.Driver.go)



! Insert-User-Declarations-Here

! Bocca generated code. bocca.protected.begin(demo.Driver.go:boccaGoProlog)

  integer bocca_status
!  The user's code should set bocca_status 0 if computation proceeded ok.
!  The user's code should set bocca_status -1 if computation failed but might
!  succeed on another call to go(), e.g. wheh a required port is not yet connected.
!  The user's code should set bocca_status -2 if the computation failed and can
!  never succeed in a future call.
!  The users's code should NOT use return in this function;
!  Exceptions that are not caught in user code will be converted to status -2.
! 


  type(gov_cca_Port_t) :: port
  type(gov_cca_Services_t) :: services 
  type(SIDL_BaseInterface_t) :: throwaway
  type(SIDL_BaseInterface_t) :: dumex
  type(demo_Driver_wrap) :: dp
  logical dr_port ! if dr_X true, the deleteRef(X) is needed before return.

  type(demo_Integration_t) ::  integrate__p	! non-null if specific uses port obtained. 
  logical integrate_fetched            ! true if releaseport is needed for this port.
  character (LEN=*) errMsg0_integrate
  character (LEN=*) errMsg1_integrate
  character (LEN=*) errMsg2_integrate
  character (LEN=*) errMsg3_integrate
  character (LEN=*) errMsg4_integrate
  parameter(errMsg0_integrate= &
    'demo.Driver: Error go() getPort(integrate) failed.')
  parameter(errMsg1_integrate= &
    'demo.Driver: Error casting gov.cca.Port integrate to type demo.Integration')
  parameter(errMsg2_integrate= &
     'demo.Driver: Error in deleteRef(port) while getting integrate')
  parameter(errMsg3_integrate= &
     'demo.Driver: Error calling releasePort(integrate). Continuing.')
  parameter(errMsg4_integrate = &
     'demo.Driver: Error in deleteRef for port integrate. Continuing.')


  BOCCA_EXTERNAL
  ! not crashing if something fails requires good bookkeeping and exception handling.
  call set_null(services)
  call set_null(port)
  call set_null(throwaway)
  call set_null(dumex)
  dr_port = .false.
  bocca_status = 0
  call demo_Driver__get_data_m(self,dp);
  services =  dp%d_private_data%d_services

  if (is_null(services) ) then
    call BOCCA_SIDL_THROW_F90(exception, 'NULL d_services pointer in demo.Driver.go()')
  endif

  ! Use a demo.Integration port with port name integrate 
  call getPort(services,"integrate", port, throwaway)
  if ( not_null(throwaway) ) then
    call set_null(port)
    call checkException(self, throwaway, errMsg0_integrate, .false., dumex)
    ! we will continue with port null (never successfully assigned) and set a flag.
  endif

  call set_null( integrate__p)
  integrate_fetched = .false.
  if ( not_null(port)) then
    integrate_fetched = .true. ! even if the next cast fails, must releasePort.
    call cast(port, integrate__p, exception) 
    BOCCA_SIDL_CHECK_F90(exception, errMsg1_integrate)
    call deleteRef(port, exception)
    call set_null(port) 
    BOCCA_SIDL_CHECK_F90(exception, errMsg2_integrate)
  endif


! Bocca generated code. bocca.protected.end(demo.Driver.go:boccaGoProlog) 




! When this block is rewritten by the user, we will not change it.
! All port instances should be rechecked for NULL before calling in user code.
! Not all ports need be connected in arbitrary use.
! The port instance names used in registerUsesPort appear as local variable
! names here with the suffix __p added.


! BEGIN REMOVE ME BLOCK
#ifdef _BOCCA_STDERR
  write(*,*) 'USER FORGOT TO FILL IN THEIR FUNCTION demo.Driver.go.'
#endif
! END REMOVE ME BLOCK


!    If unknown exceptions in the user code are tolerable and restart is ok, 
!    set bocca_status -1 instead.
!    -2 means the component is so confused that it and probably the application 
!    should be destroyed.
! 


BOCCAEXIT continue ! target point for normal and error cleanup. do not delete.
! Bocca generated code. bocca.protected.begin(demo.Driver.go:boccaGoEpilog) 

  if (not_null(port)) then
    call deleteRef(port,throwaway)
    call checkException(self, throwaway, 'cleanup port error', .false., dumex)
    call set_null(port)
  endif

  ! release integrate
  if (integrate_fetched) then
    integrate_fetched = .false.
    call releasePort(services, 'integrate', throwaway)
    call checkException(self, throwaway, errMsg3_integrate, .false., dumex)
    
    if ( not_null(integrate__p) ) then
      call deleteRef(integrate__p, throwaway)
      call checkException(self, throwaway, errMsg4_integrate, .false., dumex)
      call set_null(integrate__p)
    endif

  endif


! Bocca generated code. bocca.protected.end(demo.Driver.go:boccaGoEpilog) 


! Insert-User-Exception-Cleanup-Here 

  retval = bocca_status
! 
! This method has not been implemented
! 

! DO-NOT-DELETE splicer.end(demo.Driver.go)
end subroutine demo_Driver_go_mi

Find the REMOVE block within the go method implementation, delete it, and insert the numerical logic needed to use the integrator.IntegratorPort port. Any required local variables should be inserted just before the boccaGoProlog protected block.

The go subroutine will be called by the framework when the component's run button (the name of this particular GoPort instance) is pushed in the GUI. Bocca generates the code to the Integration that the Driver is connected to. We just have to use it to compute the integral and return the proper value for bocca_status.

! DO-NOT-DELETE splicer.begin(demo.Driver.go)
! Insert-User-Declarations-Here
  ! local variables for integration
  real (kind=sidl_double) :: lowBound
  real (kind=sidl_double) :: upBound
  integer (kind=sidl_int) :: count
  real (kind=sidl_double) :: value
! Bocca generated code. bocca.protected.begin(demo.Driver.go:boccaGoProlog)

  integer bocca_status
!  The user's code should set bocca_status 0 if computation proceeded ok.
!  The user's code should set bocca_status -1 if computation failed but might
!  succeed on another call to go(), e.g. wheh a required port is not yet connected.
!  The user's code should set bocca_status -2 if the computation failed and can
!  never succeed in a future call.
!  The users's code should NOT use return in this function;
!  Exceptions that are not caught in user code will be converted to status -2.
! 


  type(gov_cca_Port_t) :: port
  type(gov_cca_Services_t) :: services 
  type(SIDL_BaseInterface_t) :: throwaway
  type(SIDL_BaseInterface_t) :: dumex
  type(demo_Driver_wrap) :: dp
  logical dr_port ! if dr_X true, the deleteRef(X) is needed before return.

  type(demo_Integration_t) ::  integrate__p	! non-null if specific uses port obtained. 
  logical integrate_fetched            ! true if releaseport is needed for this port.
  character (LEN=*) errMsg0_integrate
  character (LEN=*) errMsg1_integrate
  character (LEN=*) errMsg2_integrate
  character (LEN=*) errMsg3_integrate
  character (LEN=*) errMsg4_integrate
  parameter(errMsg0_integrate= &
    'demo.Driver: Error go() getPort(integrate) failed.')
  parameter(errMsg1_integrate= &
    'demo.Driver: Error casting gov.cca.Port integrate to type demo.Integration')
  parameter(errMsg2_integrate= &
     'demo.Driver: Error in deleteRef(port) while getting integrate')
  parameter(errMsg3_integrate= &
     'demo.Driver: Error calling releasePort(integrate). Continuing.')
  parameter(errMsg4_integrate = &
     'demo.Driver: Error in deleteRef for port integrate. Continuing.')


  BOCCA_EXTERNAL
  ! not crashing if something fails requires good bookkeeping and exception handling.
  call set_null(services)
  call set_null(port)
  call set_null(throwaway)
  call set_null(dumex)
  dr_port = .false.
  bocca_status = 0
  call demo_Driver__get_data_m(self,dp);
  services =  dp%d_private_data%d_services

  if (is_null(services) ) then
    call BOCCA_SIDL_THROW_F90(exception, 'NULL d_services pointer in demo.Driver.go()')
  endif

  ! Use a demo.Integration port with port name integrate 
  call getPort(services,"integrate", port, throwaway)
  if ( not_null(throwaway) ) then
    call set_null(port)
    call checkException(self, throwaway, errMsg0_integrate, .false., dumex)
    ! we will continue with port null (never successfully assigned) and set a flag.
  endif

  call set_null( integrate__p)
  integrate_fetched = .false.
  if ( not_null(port)) then
    integrate_fetched = .true. ! even if the next cast fails, must releasePort.
    call cast(port, integrate__p, exception) 
    BOCCA_SIDL_CHECK_F90(exception, errMsg1_integrate)
    call deleteRef(port, exception)
    call set_null(port) 
    BOCCA_SIDL_CHECK_F90(exception, errMsg2_integrate)
  endif


! Bocca generated code. bocca.protected.end(demo.Driver.go:boccaGoProlog) 




! When this block is rewritten by the user, we will not change it.
! All port instances should be rechecked for NULL before calling in user code.
! Not all ports need be connected in arbitrary use.
! The port instance names used in registerUsesPort appear as local variable
! names here with the suffix __p added.
  ! Initialize local variables
  count = 100000
  lowBound = 0.0
  upBound = 1.0

  if (not_null(integrate__p)) then
     value = -1.0 ! nonsense number to confirm it is set

     ! operate on the port. if successful, set the status to 0 for ok.
     bocca_status = -2
     call march(integrate__p, lowBound, upBound, count, value, exception)
     ! jump to BOCCAEXIT if an error.
     BOCCA_SIDL_CHECK_F90(exception,'Driver:go: problem calling integrate')
     write(*,*) 'Value = ', value
     bocca_status = 0
  else
     bocca_status = -1 ; ! integratorPort is not connected.
     write(*,*) 'Driver: integrate port not connected. connect and try again'
  endif
!    If unknown exceptions in the user code are tolerable and restart is ok,
!    set bocca_status -1 instead.
!    -2 means the component is so confused that it and probably the application
!    should be destroyed.
!


BOCCAEXIT continue ! target point for normal and error cleanup. do not delete.
! Bocca generated code. bocca.protected.begin(demo.Driver.go:boccaGoEpilog) 

  if (not_null(port)) then
    call deleteRef(port,throwaway)
    call checkException(self, throwaway, 'cleanup port error', .false., dumex)
    call set_null(port)
  endif

  ! release integrate
  if (integrate_fetched) then
    integrate_fetched = .false.
    call releasePort(services, 'integrate', throwaway)
    call checkException(self, throwaway, errMsg3_integrate, .false., dumex)
    
    if ( not_null(integrate__p) ) then
      call deleteRef(integrate__p, throwaway)
      call checkException(self, throwaway, errMsg4_integrate, .false., dumex)
      call set_null(integrate__p)
    endif

  endif


! Bocca generated code. bocca.protected.end(demo.Driver.go:boccaGoEpilog) 


! Insert-User-Exception-Cleanup-Here

  retval = bocca_status
! DO-NOT-DELETE splicer.end(demo.Driver.go)

After quitting the editor the state of the source code tree is updated if there are any dependencies on the edited implementation. Usually there are no dependencies on the implementation file, so Bocca does very little after you exit the editor and all you see is the information from the edit command about what file was edited.

/home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/f90/demo/components/demo.Driver/demo_Driver_Impl.F90

Now remake your project tree to finish the components:

$ make

make[1]: Entering directory `/home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/f90/demo'
# =======================================================================
# No SIDL files in external/sidl, skipping build for external
# =======================================================================
# =======================================================================
# Building in ports/, languages: f90
# =======================================================================
 ## Building ports... 
# =======================================================================
# Building in components/clients/, languages: f90
# =======================================================================
 ## Building clients... 
# =======================================================================
# Building in components/, languages: f90
# =======================================================================
   [s] Building class/component demo.Driver: 
   [s] creating class/component library: libdemo.Driver.la ... 
   [s] finished libtooling: components/demo.Driver/libdemo.Driver.la ... 
   [s] building /home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/f90/demo/install/share/cca/demo/demo.Driver_depl.xml ... 
   [s] creating Ccaffeine test script (components/tests/instantiation.gen.rc)... 
   [s] Building class/component demo.Function: 
   [s] creating class/component library: libdemo.Function.la ... 
   [s] finished libtooling: components/demo.Function/libdemo.Function.la ... 
   [s] building /home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/f90/demo/install/share/cca/demo/demo.Function_depl.xml ... 
   [s] creating Ccaffeine test script (components/tests/instantiation.gen.rc)... 
   [s] Building class/component demo.Integrator: 
   [s] creating class/component library: libdemo.Integrator.la ... 
   [s] finished libtooling: components/demo.Integrator/libdemo.Integrator.la ... 
   [s] building /home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/f90/demo/install/share/cca/demo/demo.Integrator_depl.xml ... 
   [s] creating Ccaffeine test script (components/tests/instantiation.gen.rc)... 
   [s] Building class/component demo.emptyComponent: 
doing nothing -- library is up-to-date.
Build summary:
SUCCESS building demo.Driver
SUCCESS building demo.Function
SUCCESS building demo.Integrator
### To test instantiation of successfully built components, run 'make check' ###
################ Finished building everything #################
####### You can run some simple tests with 'make check' #######
make[1]: Leaving directory `/home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/f90/demo'

It is good practice to do a make check at this point:

$ make check

make[1]: Entering directory `/home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/f90/demo'
make --no-print-directory --no-builtin-rules -C components check
### Test library load and instantiation for the following languages: f90
Running instantiation tests only
Test script: /home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/f90/demo/components/tests/instantiation.gen.rc
Log file: /home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/f90/demo/components/tests/instantiation.gen.rc.log
SUCCESS:
==> Instantiation tests passed for all built components (see /home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/f90/demo/components/tests/instantiation.gen.rc.log).
make --no-print-directory --no-builtin-rules check-user
make[1]: Leaving directory `/home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/f90/demo'

You should now be able to instantiate these components, assemble them into an application, and run the application, following the same procedures as in Section 2, and get a result that's reasonably close to pi .


3.5.3 C Implementation

Image noteNote

Assumes you created the project with  bocca create project demo --language=c.

Edit the evaluate method in the implementation file (also known as ``the impl'') that Bocca has generated for you (by invoking Babel ). Use the bocca edit -i to go directly to each method.

$ bocca edit -i Function evaluate

The editor opens up in the place where the implementation code for evaluate  must be put. You see a default implementation generated by Babel for all user methods: the throwing of an exception which says the method is not yet implemented.

double
impl_demo_Function_evaluate(
  /* in */ demo_Function self,
  /* in */ double x,
  /* out */ sidl_BaseInterface *_ex)
{
  *_ex = 0;
  {
    /* DO-NOT-DELETE splicer.begin(demo.Function.evaluate) */
    /* Insert-Code-Here {demo.Function.evaluate} (evaluate method) */
    /*
     * This method has not been implemented
     */

    /* DO-DELETE-WHEN-IMPLEMENTING exception.begin(demo.Function.evaluate) */
    SIDL_THROW(*_ex, sidl_NotImplementedException,     "This method has not been implemented");
  EXIT:;
    /* DO-DELETE-WHEN-IMPLEMENTING exception.end(demo.Function.evaluate) */
    /* DO-NOT-DELETE splicer.end(demo.Function.evaluate) */
  }
}

As the comment suggests, this method is ``not implemented'', but some code has been inserted by Babel to make sure an exception is thrown to inform the user if this method is called by mistake. Delete this exception code and substitute an implementation for the PiFunction (i.e., the integral from 0 to 1 of 4/(1 + x2) is an approximation of \bgroup\color{Green}$ \pi$\egroup ).

  /* DO-NOT-DELETE splicer.begin(demo.Function.evaluate) */
  return 4.0 / (1.0 + x * x);
  /* DO-NOT-DELETE splicer.end(demo.Function.evaluate) */

Now in the same file just above the evaluate method, find the second method for the FunctionPort init method:

  /* DO-NOT-DELETE splicer.begin(demo.Function.init) */
  /* Do nothing.*/
  /* DO-NOT-DELETE splicer.end(demo.Function.init) */

We don't have any initialization in this simple example, so we just eliminate the code that throws the exception when the method is executed.

After quitting the editor the state of the source code tree is updated if there are any dependencies on the edited implementation. Usually there are no dependencies on the implementation file, so Bocca does very little after you exit the editor and all you see is the information from the edit command about what file was edited:

/home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/c/demo/components/demo.Function/demo_Function_Impl.c

Similarly edit the march method in the Integrator with

$ bocca edit -i Integrator march

double
impl_demo_Integrator_march(
  /* in */ demo_Integrator self,
  /* in */ double lowBound,
  /* in */ double upBound,
  /* in */ int32_t count,
  /* out */ sidl_BaseInterface *_ex)
{
  *_ex = 0;
  {
    /* DO-NOT-DELETE splicer.begin(demo.Integrator.march) */
    /* Insert-Code-Here {demo.Integrator.march} (march method) */
    /*
     * This method has not been implemented
     */

    /* DO-DELETE-WHEN-IMPLEMENTING exception.begin(demo.Integrator.march) */
    SIDL_THROW(*_ex, sidl_NotImplementedException,     "This method has not been implemented");
  EXIT:;
    /* DO-DELETE-WHEN-IMPLEMENTING exception.end(demo.Integrator.march) */
    /* DO-NOT-DELETE splicer.end(demo.Integrator.march) */
  }
}

Again remove this boilerplate exception code and insert an implementation of the Trapezoid rule for integration that uses the FunctionPort :

  /* DO-NOT-DELETE splicer.begin(demo.Integrator.march) */
  gov_cca_Port port = NULL;
  gov_cca_Services services = NULL;
  sidl_BaseInterface throwaway_excpt = NULL;
  sidl_BaseInterface dummy_excpt = NULL;
  struct demo_Integrator__data *pd = NULL;
  const char *errMsg = NULL;
  double retval = 0.0;

  demo_FunctionPort odeRHS = NULL;
  /* odeRHS non-null if specific uses port obtained. */

  int odeRHS_fetched = FALSE;
  /* odeRHS_fetched true if releaseport is needed for this port. */

  pd = demo_Integrator__get_data(self);
  if (pd == NULL) {
    SIDL_THROW(*_ex, sidl_SIDLException,
     "NULL object data pointer in demo.Integrator.march()");
  }
  services = pd->d_services;
  if (services == NULL) {
    SIDL_THROW(*_ex, sidl_SIDLException,
      "NULL pd->d_services pointer in demo.Integrator.march()");
  }

  /* Use a demo.Integration port with port name odeRHS */
  port =
    gov_cca_Services_getPort(services,"odeRHS", _ex); SIDL_CHECK(*_ex);
  odeRHS_fetched = TRUE;
  /* even if the next cast fails, must releasePort. */

  errMsg="demo.Integrator: Error casting odeRHS to FunctionPort";
  odeRHS = gov_cca_Services__cast2(port,
                                          "demo.FunctionPort",
                                           _ex); SIDL_CHECK(*_ex);
  gov_cca_Port_deleteRef(port, _ex); port = NULL; SIDL_CHECK(*_ex);

  {
    double h;
    double sum = 0.0;
    double left, right, fvalueleft, fvalueright;
    int i;

    h = (upBound - lowBound) / (1.0*count);
    printf("Evaluating from %g to %g by %d\n",lowBound ,upBound, count);
    for (i = 1; i <= count; i++){

      left = lowBound + (i - 1) * h;
      fvalueleft = demo_FunctionPort_evaluate(odeRHS,
                     left,_ex); SIDL_CHECK(*_ex);

      right = lowBound + i * h;
      fvalueright = demo_FunctionPort_evaluate(odeRHS,
                      right,_ex); SIDL_CHECK(*_ex);

      sum += (fvalueleft + fvalueright);
    }
    retval = h * sum/2.0;
    printf("IP returning %g\n",retval);
  }
EXIT:; /* target point for normal and error cleanup. do not delete. */

  /* release integrate */
  if (odeRHS_fetched) {
    odeRHS_fetched = FALSE;
    gov_cca_Services_releasePort(services,"odeRHS",&throwaway_excpt);
    if ( throwaway_excpt != NULL) {
      errMsg= "demo.Integrator: Error calling"
              " releasePort(\"integrate\"). Continuing.";
      demo_Integrator_checkException(self, throwaway_excpt, errMsg,
                                          FALSE, &dummy_excpt);
    }
    if (odeRHS != NULL) {
      demo_FunctionPort_deleteRef(odeRHS, &throwaway_excpt);
      errMsg =  "Error in demo_FunctionPort_deleteRef"
                " for demo.Function port odeRHS";
      demo_Integrator_checkException(self, throwaway_excpt, errMsg,
                                          FALSE, &dummy_excpt);
      odeRHS = NULL;
    }
  }

  return retval;
  /* DO-NOT-DELETE splicer.end(demo.Integrator.march) */

After quitting the editor the state of the source code tree is updated if there are any dependencies on the edited implementation. Usually there are no dependencies on the implementation file, so Bocca does very little after you exit the editor and all you see is the information from the edit command about what file was edited:

/home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/c/demo/components/demo.Integrator/demo_Integrator_Impl.c

Finally for the Driver component we have to implement the GoPort details to get things going. Bocca will take you to the generated method, which looks like this:

$ bocca edit -i Driver go

int32_t
impl_demo_Driver_go(
  /* in */ demo_Driver self,
  /* out */ sidl_BaseInterface *_ex)
{
  *_ex = 0;
  {
    /* DO-NOT-DELETE splicer.begin(demo.Driver.go) */

  /* User action portion is in the middle at the next Insert-UserCode-Here line. */


  /* Insert-User-Declarations-Here */

/* Bocca generated code. bocca.protected.begin(demo.Driver.go:boccaGoProlog) */

  int bocca_status = 0;
  /* The user's code should set bocca_status 0 if computation proceeded ok.
  // The user's code should set bocca_status -1 if computation failed but might
  // succeed on another call to go(), e.g. wheh a required port is not yet connected.
  // The user's code should set bocca_status -2 if the computation failed and can
  // never succeed in a future call.
  // The users's code should NOT use return in this function;
  // Exceptions that are not caught in user code will be converted to status -2.
  */


  gov_cca_Port port = NULL;
  gov_cca_Services services = NULL;
  sidl_BaseInterface throwaway_excpt = NULL;
  sidl_BaseInterface dummy_excpt = NULL;
  struct demo_Driver__data *pd = NULL;
  const char *errMsg = NULL;

  demo_Integration integrate = NULL;	/* non-null if specific uses port obtained. */
  int integrate_fetched = FALSE;		/* true if releaseport is needed for this port. */


  pd = demo_Driver__get_data(self);
  if (pd == NULL) {
    SIDL_THROW(*_ex, sidl_SIDLException, 
       "NULL object data pointer in demo.Driver.go()");
  }
  services = pd->d_services;
  if (services == NULL) {
    SIDL_THROW(*_ex, sidl_SIDLException, 
        "NULL pd->d_services pointer in demo.Driver.go()");
  }

  /* Use a demo.Integration port with port name integrate */
  port = gov_cca_Services_getPort(services,"integrate", &throwaway_excpt);
  if (throwaway_excpt != NULL) {
    port = NULL;
    errMsg="go() getPort(integrate) failed.";
    demo_Driver_checkException(self, throwaway_excpt, errMsg, 
                                    FALSE, &dummy_excpt);
    /* we will continue with port NULL (never successfully assigned) and set a flag. */
    BOCCA_FPRINTF(stderr, 
         "demo.Driver: Error calling getPort(\"integrate\") at %s:%d. Continuing.\n",
         __FILE__ , __LINE__ -8 );
  }

  if ( port != NULL ) {
    integrate_fetched = TRUE; /* even if the next cast fails, must releasePort. */
    errMsg="demo.Driver: Error casting gov.cca.Port integrate to type demo.Integration";
    integrate = demo_Integration__cast(port, _ex); SIDL_CHECK(*_ex);
    gov_cca_Port_deleteRef(port,_ex); port = NULL; SIDL_CHECK(*_ex);
  }


/* Bocca generated code. bocca.protected.end(demo.Driver.go:boccaGoProlog) */




  /* When this block is rewritten by the user, we will not change it.
     All port instances should be rechecked for NULL before calling in user code.
     Not all ports need be connected in arbitrary use.
     The port instance names used in registerUsesPort appear as local variable
     names here.
     'return' should not be used here; set bocca_status instead.
   */

  /* Insert-UserCode-Here {demo.Driver.go} */

  /* BEGIN REMOVE ME BLOCK */
  BOCCA_FPRINTF(stderr, 
        "USER FORGOT TO FILL IN THEIR GO FUNCTION %s:%d.\n",
        __FILE__,__LINE__);
  /* END REMOVE ME BLOCK */

  /* If unknown exceptions in the user code are tolerable and restart is ok, 
     set bocca_status -1 instead.
     -2 means the component is so confused that it and probably the component 
     or application should be destroyed.
   */


EXIT:; /* target point for normal and error cleanup. do not delete. */
/* Bocca generated code. bocca.protected.begin(demo.Driver.go:boccaGoEpilog) */

  /* release integrate */
  if (integrate_fetched) {
    integrate_fetched = FALSE;
    gov_cca_Services_releasePort(services,"integrate",&throwaway_excpt);
    if ( throwaway_excpt != NULL) {
      errMsg= "demo.Driver: Error calling releasePort(\"integrate\"). Continuing.";
      demo_Driver_checkException(self, throwaway_excpt, errMsg, FALSE, &dummy_excpt);
    }
    if (integrate != NULL) {
      demo_Integration_deleteRef(integrate, &throwaway_excpt);
      errMsg = "Error in demo_Integration_deleteRef for demo.Driver port integrate";
      demo_Driver_checkException(self, throwaway_excpt, errMsg, FALSE, &dummy_excpt);
      integrate = NULL;
    }
  }


/* Bocca generated code. bocca.protected.end(demo.Driver.go:boccaGoEpilog) */


/* Insert-User-Exception-Cleanup-Here */

  return bocca_status;
    /*
     * This method has not been implemented
     */

    /* DO-NOT-DELETE splicer.end(demo.Driver.go) */
  }
}

Find the REMOVE block within the go method implementation, delete it, and insert the numerical logic needed to use the integrator.IntegratorPort port. Any required local variables should be inserted just before the boccaGoProlog protected block.

The go subroutine will be called by the framework when the component's run button (the name of this particular GoPort instance) is pushed in the GUI. Bocca generates the code to the Integration that the Driver is connected to. We just have to use it to compute the integral and return the proper value for bocca_status.

  /* DO-NOT-DELETE splicer.begin(demo.Driver.go) */


  /* User action portion is in the middle at the next Insert-UserCode-Here line. */


  /* Insert-User-Declarations-Here */

/* Bocca generated code. bocca.protected.begin(demo.Driver.go:boccaGoProlog) */

  int bocca_status = 0;
  /* The user's code should set bocca_status 0 if computation proceeded ok.
  // The user's code should set bocca_status -1 if computation failed but might
  // succeed on another call to go(), e.g. wheh a required port is not yet connected.
  // The user's code should set bocca_status -2 if the computation failed and can
  // never succeed in a future call.
  // The users's code should NOT use return in this function;
  // Exceptions that are not caught in user code will be converted to status -2.
  */


  gov_cca_Port port = NULL;
  gov_cca_Services services = NULL;
  sidl_BaseInterface throwaway_excpt = NULL;
  sidl_BaseInterface dummy_excpt = NULL;
  struct demo_Driver__data *pd = NULL;
  const char *errMsg = NULL;

  demo_Integration integrate = NULL;	/* non-null if specific uses port obtained. */
  int integrate_fetched = FALSE;		/* true if releaseport is needed for this port. */


  pd = demo_Driver__get_data(self);
  if (pd == NULL) {
    SIDL_THROW(*_ex, sidl_SIDLException, 
       "NULL object data pointer in demo.Driver.go()");
  }
  services = pd->d_services;
  if (services == NULL) {
    SIDL_THROW(*_ex, sidl_SIDLException, 
        "NULL pd->d_services pointer in demo.Driver.go()");
  }

  /* Use a demo.Integration port with port name integrate */
  port = gov_cca_Services_getPort(services,"integrate", &throwaway_excpt);
  if (throwaway_excpt != NULL) {
    port = NULL;
    errMsg="go() getPort(integrate) failed.";
    demo_Driver_checkException(self, throwaway_excpt, errMsg, 
                                    FALSE, &dummy_excpt);
    /* we will continue with port NULL (never successfully assigned) and set a flag. */
    BOCCA_FPRINTF(stderr, 
         "demo.Driver: Error calling getPort(\"integrate\") at %s:%d. Continuing.\n",
         __FILE__ , __LINE__ -8 );
  }

  if ( port != NULL ) {
    integrate_fetched = TRUE; /* even if the next cast fails, must releasePort. */
    errMsg="demo.Driver: Error casting gov.cca.Port integrate to type demo.Integration";
    integrate = demo_Integration__cast(port, _ex); SIDL_CHECK(*_ex);
    gov_cca_Port_deleteRef(port,_ex); port = NULL; SIDL_CHECK(*_ex);
  }


/* Bocca generated code. bocca.protected.end(demo.Driver.go:boccaGoProlog) */




  /* When this block is rewritten by the user, we will not change it.
     All port instances should be rechecked for NULL before calling in user code.
     Not all ports need be connected in arbitrary use.
     The port instance names used in registerUsesPort appear as local variable
     names here.
     'return' should not be used here; set bocca_status instead.
   */

  /* Insert-UserCode-Here {demo.Driver.go} */
  if (integrate == NULL) {
    bocca_status = -1; /* not connected. skip computation. */
  } else {
    int count = 100000;
    double value = -4;
    double lowerBound = 0.0;
    double upperBound = 1.0;
    fprintf(stdout, "Initvalue = %g\n", value);
    value = demo_Integration_march(integrate, lowerBound, upperBound,
                                               count, _ex); SIDL_CHECK(*_ex);
    fprintf(stdout, "Value = %g\n", value);
    fflush(stdout);
  }
  /* If unknown exceptions in the user code are tolerable and restart is ok,
     set bocca_status -1 instead.
     -2 means the component is so confused that it and probably the component or application
     should be destroyed.
   */


EXIT:; /* target point for normal and error cleanup. do not delete. */
/* Bocca generated code. bocca.protected.begin(demo.Driver.go:boccaGoEpilog) */

  /* release integrate */
  if (integrate_fetched) {
    integrate_fetched = FALSE;
    gov_cca_Services_releasePort(services,"integrate",&throwaway_excpt);
    if ( throwaway_excpt != NULL) {
      errMsg= "demo.Driver: Error calling releasePort(\"integrate\"). Continuing.";
      demo_Driver_checkException(self, throwaway_excpt, errMsg, FALSE, &dummy_excpt);
    }
    if (integrate != NULL) {
      demo_Integration_deleteRef(integrate, &throwaway_excpt);
      errMsg = "Error in demo_Integration_deleteRef for demo.Driver port integrate";
      demo_Driver_checkException(self, throwaway_excpt, errMsg, FALSE, &dummy_excpt);
      integrate = NULL;
    }
  }


/* Bocca generated code. bocca.protected.end(demo.Driver.go:boccaGoEpilog) */


/* Insert-User-Exception-Cleanup-Here */

  return bocca_status;
  /* DO-NOT-DELETE splicer.end(demo.Driver.go) */

After quitting the editor the state of the source code tree is updated if there are any dependencies on the edited implementation. Usually there are no dependencies on the implementation file, so Bocca does very little after you exit the editor and all you see is the information from the edit command about what file was edited.

/home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/c/demo/components/demo.Driver/demo_Driver_Impl.c

Now remake your project tree to finish the components:

$ make

make[1]: Entering directory `/home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/c/demo'
# =======================================================================
# No SIDL files in external/sidl, skipping build for external
# =======================================================================
# =======================================================================
# Building in ports/, languages: c
# =======================================================================
 ## Building ports... 
# =======================================================================
# Building in components/clients/, languages: c
# =======================================================================
 ## Building clients... 
# =======================================================================
# Building in components/, languages: c
# =======================================================================
   [s] Building class/component demo.Driver: 
   [s] creating class/component library: libdemo.Driver.la ... 
   [s] finished libtooling: components/demo.Driver/libdemo.Driver.la ... 
   [s] building /home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/c/demo/install/share/cca/demo/demo.Driver_depl.xml ... 
   [s] creating Ccaffeine test script (components/tests/instantiation.gen.rc)... 
   [s] Building class/component demo.Function: 
   [s] creating class/component library: libdemo.Function.la ... 
   [s] finished libtooling: components/demo.Function/libdemo.Function.la ... 
   [s] building /home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/c/demo/install/share/cca/demo/demo.Function_depl.xml ... 
   [s] creating Ccaffeine test script (components/tests/instantiation.gen.rc)... 
   [s] Building class/component demo.Integrator: 
   [s] creating class/component library: libdemo.Integrator.la ... 
   [s] finished libtooling: components/demo.Integrator/libdemo.Integrator.la ... 
   [s] building /home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/c/demo/install/share/cca/demo/demo.Integrator_depl.xml ... 
   [s] creating Ccaffeine test script (components/tests/instantiation.gen.rc)... 
   [s] Building class/component demo.emptyComponent: 
doing nothing -- library is up-to-date.
Build summary:
SUCCESS building demo.Driver
SUCCESS building demo.Function
SUCCESS building demo.Integrator
### To test instantiation of successfully built components, run 'make check' ###
################ Finished building everything #################
####### You can run some simple tests with 'make check' #######
make[1]: Leaving directory `/home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/c/demo'

It is good practice to do a make check at this point:

$ make check

make[1]: Entering directory `/home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/c/demo'
make --no-print-directory --no-builtin-rules -C components check
### Test library load and instantiation for the following languages: c
Running instantiation tests only
Test script: /home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/c/demo/components/tests/instantiation.gen.rc
Log file: /home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/c/demo/components/tests/instantiation.gen.rc.log
SUCCESS:
==> Instantiation tests passed for all built components (see /home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/c/demo/components/tests/instantiation.gen.rc.log).
make --no-print-directory --no-builtin-rules check-user
make[1]: Leaving directory `/home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/c/demo'

You should now be able to instantiate these components, assemble them into an application, and run the application, following the same procedures as in Section 2, and get a result that's reasonably close to pi .


3.5.4 Python Implementation

Image noteNote

Assumes you created the project with  bocca create project demo --language=python.

Edit the evaluate method in the implementation file (also known as ``the impl'') that Bocca has generated for you (by invoking Babel ). Use the bocca edit -i to go directly to each method.

$ bocca edit -i Function evaluate

The editor opens up in the place where the implementation code for evaluate  must be put. You see a default implementation generated by Babel for all user methods: the throwing of an exception which says the method is not yet implemented.

  def evaluate(self, x):
    #
    # sidl EXPECTED INCOMING TYPES
    # ============================
    # double x
    #

    #
    # sidl EXPECTED RETURN VALUE(s)
    # =============================
    # double _return
    #

# DO-NOT-DELETE splicer.begin(evaluate)
    #
    # This method has not been implemented
    #

    # DO-DELETE-WHEN-IMPLEMENTING exception.begin(evaluate)
    noImpl = sidl.NotImplementedException.NotImplementedException()
    noImpl.setNote("This method has not been implemented.")
    raise  sidl.NotImplementedException._Exception, noImpl
    # DO-DELETE-WHEN-IMPLEMENTING exception.end(evaluate)
# DO-NOT-DELETE splicer.end(evaluate)

As the comment suggests, this method is ``not implemented'', but some code has been inserted by Babel to make sure an exception is thrown to inform the user if this method is called by mistake. Delete this exception code and substitute an implementation for the PiFunction (i.e., the integral from 0 to 1 of 4/(1 + x2) is an approximation of \bgroup\color{Green}$ \pi$\egroup ).

# DO-NOT-DELETE splicer.begin(evaluate)
    return 4.0 / (1.0 + x * x)
# DO-NOT-DELETE splicer.end(evaluate)

Now in the same file just above the evaluate method, find the second method for the FunctionPort init method:

# DO-NOT-DELETE splicer.begin(init)
    # Do nothing.
    pass
# DO-NOT-DELETE splicer.end(init)

We don't have any initialization in this simple example, so we just eliminate the code that throws the exception when the method is executed.

After quitting the editor the state of the source code tree is updated if there are any dependencies on the edited implementation. Usually there are no dependencies on the implementation file, so Bocca does very little after you exit the editor and all you see is the information from the edit command about what file was edited:

/home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/python/demo/components/demo.Function/demo/Function_Impl.py

Similarly edit the march method in the Integrator with

$ bocca edit -i Integrator march

  def march(self, lowBound, upBound, count):
    #
    # sidl EXPECTED INCOMING TYPES
    # ============================
    # double lowBound
    # double upBound
    # int count
    #

    #
    # sidl EXPECTED RETURN VALUE(s)
    # =============================
    # double _return
    #

# DO-NOT-DELETE splicer.begin(march)
    #
    # This method has not been implemented
    #

    # DO-DELETE-WHEN-IMPLEMENTING exception.begin(march)
    noImpl = sidl.NotImplementedException.NotImplementedException()
    noImpl.setNote("This method has not been implemented.")
    raise  sidl.NotImplementedException._Exception, noImpl
    # DO-DELETE-WHEN-IMPLEMENTING exception.end(march)
# DO-NOT-DELETE splicer.end(march)

Again remove this boilerplate exception code and insert an implementation of the Trapezoid rule for integration that uses the FunctionPort :

# DO-NOT-DELETE splicer.begin(march)
    # Use a demo.FunctionPort port with port name odeRHS
    try:
        port = self.d_services.getPort("odeRHS")
    except Exception,e:
        if self.bocca_print_errs:
            print "demo.Integrator: port odeRHS not connected."
        e.args = "demo.Integrator: port odeRHS not connected:\n%s" \
                 % e.args
        raise
    odeRHS = demo.FunctionPort.FunctionPort(port);
    if not odeRHS:
        if self.bocca_print_errs:
            print "demo.Integrator: Error casting port gov.cca.Port " \
                + "to odeRHS type demo.FunctionPort"
        ex = sidl.SIDLException.SIDLException()
        ex.setNote(__name__,0,
                   'Error casting self Port to demo.FunctionPort')
        raise sidl.SIDLException._Exception, ex

    # do the math
    h = (upBound - lowBound) / count
    retval = 0.0
    sum = 0.0
    for i in range(1,count+1):
        sum += odeRHS.evaluate(lowBound + (i - 1) * h)
        sum += odeRHS.evaluate(lowBound + i * h)

    retval = h/2.0 * sum
    self.d_services.releasePort("odeRHS")
    return retval
# DO-NOT-DELETE splicer.end(march)

After quitting the editor the state of the source code tree is updated if there are any dependencies on the edited implementation. Usually there are no dependencies on the implementation file, so Bocca does very little after you exit the editor and all you see is the information from the edit command about what file was edited:

/home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/python/demo/components/demo.Integrator/demo/Integrator_Impl.py

Finally for the Driver component we have to implement the GoPort details to get things going. Bocca will take you to the generated method, which looks like this:

$ bocca edit -i Driver go

  def go(self):
    #
    # sidl EXPECTED RETURN VALUE(s)
    # =============================
    # int _return
    #

    """\
 
Execute some encapsulated functionality on the component. 
Return 0 if ok, -1 if internal error but component may be 
used further, and -2 if error so severe that component cannot
be further used safely.
"""
# DO-NOT-DELETE splicer.begin(go)


# Bocca generated code. bocca.protected.begin(go:boccaGoProlog)
    bocca_status = 0
    # The user's code should set bocca_status 0 if computation proceeded ok.
    # The user's code should set bocca_status -1 if computation failed but might
    # succeed on another call to go(), e.g. when a required port is not yet connected.
    # The user's code should set bocca_status -2 if the computation failed and can
    # never succeed in a future call.
    # The users's code should NOT use return in this function;
    # Exceptions that are not caught in user code will be converted to status 2.

    if bocca_status == 0: # skip this getport if a problem already occured.
        # Use a demo.Integration port with port name integrate 
        try:
            port = self.d_services.getPort("integrate")
        except sidl.BaseException._Exception, e:
            port = None
            if self.bocca_print_errs:
                (etype, eobj, etb) = sys.exc_info()
                msg="demo.Driver: Error calling getPort('integrate'): "                    + eobj.exception.getNote()
                print >>sys.stderr,'Exception:', msg
   
        integrate_fetched = False;
        if not port:
            if self.bocca_print_errs:
                print 'demo.Driver: getPort("integrate") returned nil.'
        else:
            integrate_fetched = True # even if the next cast fails, must release.
            integrate = demo.Integration.Integration(port);
            if not integrate:
                bocca_status = -1
                if self.bocca_print_errs:
                    print "demo.Driver: Error casting port gov.cca.Port to "                        + "integrate type demo.Integration"


    if bocca_status == 0: # all is ok so far and we do the user code, else cleanup and return.
        # user code indents to match this.
# Bocca generated code. bocca.protected.end(go:boccaGoProlog)


        # If this try/catch block is rewritten by the user, we will not change it.
        try:
            try:
                # The user might not require all ports to be connected in all configurations.
                # Each uses port is available as the local variable with the same name.
                # Those that are properly connected will be a value other than None.
                # the proper test for an unavailable port is "if not portinstancename:"


                # BEGIN REMOVE ME BLOCK
                ex = sidl.SIDLException.SIDLException()
                ex.setNote("USER FORGOT TO FILL IN THEIR FUNCTION demo.Driver.go()")
                raise sidl.SIDLException._Exception, ex
                # END REMOVE ME BLOCK

            except sidl.BaseException._Exception, e:
                bocca_status = -2
                if self.bocca_print_errs:
                    (etype, eobj, etb) = sys.exc_info()
                    msg="demo.Driver: Error in go() execution: "+eobj.exception.getNote()
                    print >>sys.stderr,'Exception:', msg
                # if specific exceptions in the user code are tolerable 
                # and restart is ok, bocca_status -1 instead.
                # 2 means the component is so confused that it and probably 
	        # the application should be destroyed.
            except Exception,e:
                bocca_status = -2
                if self.bocca_print_errs:
                    print >> sys.stderr, 'Exception in demo.Driver go():'+str(e)
            except:
                bocca_status = -2
                print >> sys.stderr, 'Unclassified Exception in demo.Driver go()'
        finally:
            # always executed.
            pass
        # This version of TryExceptFinally for compatibility with python 2.3 and up


# Bocca generated code. bocca.protected.begin(go:boccaGoEpilog)
        # end user code.
    # end if bocca_status == 0.

    # release integrate 
    if integrate_fetched:
        integrate_fetched = False
        try:
            self.d_services.releasePort("integrate")
        except sidl.BaseException._Exception, e:
            port = None
            if self.bocca_print_errs:
                (etype, eobj, etb) = sys.exc_info()
                msg="demo.Driver: Error calling releasePort('integrate'): "                    + eobj.exception.getNote()
                print >>sys.stderr,'Exception:', msg


    return bocca_status
# Bocca generated code. bocca.protected.end(go:boccaGoEpilog)


    #
    # This method has not been implemented
    #

# DO-NOT-DELETE splicer.end(go)

Find the REMOVE block within the go method implementation, delete it, and insert the numerical logic needed to use the integrator.IntegratorPort port. Any required local variables should be inserted just before the boccaGoProlog protected block.

The go subroutine will be called by the framework when the component's run button (the name of this particular GoPort instance) is pushed in the GUI. Bocca generates the code to the Integration that the Driver is connected to. We just have to use it to compute the integral and return the proper value for bocca_status.

# DO-NOT-DELETE splicer.begin(go)
# Bocca generated code. bocca.protected.begin(go:boccaGoProlog)
    bocca_status = 0
    # The user's code should set bocca_status 0 if computation proceeded ok.
    # The user's code should set bocca_status -1 if computation failed but might
    # succeed on another call to go(), e.g. when a required port is not yet connected.
    # The user's code should set bocca_status -2 if the computation failed and can
    # never succeed in a future call.
    # The users's code should NOT use return in this function;
    # Exceptions that are not caught in user code will be converted to status 2.

    if bocca_status == 0: # skip this getport if a problem already occured.
        # Use a demo.Integration port with port name integrate 
        try:
            port = self.d_services.getPort("integrate")
        except sidl.BaseException._Exception, e:
            port = None
            if self.bocca_print_errs:
                (etype, eobj, etb) = sys.exc_info()
                msg="demo.Driver: Error calling getPort('integrate'): "                    + eobj.exception.getNote()
                print >>sys.stderr,'Exception:', msg
   
        integrate_fetched = False;
        if not port:
            if self.bocca_print_errs:
                print 'demo.Driver: getPort("integrate") returned nil.'
        else:
            integrate_fetched = True # even if the next cast fails, must release.
            integrate = demo.Integration.Integration(port);
            if not integrate:
                bocca_status = -1
                if self.bocca_print_errs:
                    print "demo.Driver: Error casting port gov.cca.Port to "                        + "integrate type demo.Integration"


    if bocca_status == 0: # all is ok so far and we do the user code, else cleanup and return.
        # user code indents to match this.
# Bocca generated code. bocca.protected.end(go:boccaGoProlog)


        # If this try/catch block is rewritten by the user, we will not change it.
        try:
            try:
                # The user might not require all ports to be connected in all configurations.
                # Each uses port is available as the local variable with the same name.
                # Those that are properly connected will be a value other than None.
                # the proper test for an unavailable port is "if not portinstancename:"
                count = 100000
                lowerBound = 0.0
                upperBound = 1.0

                # operate on the port
                value = integrate.march(lowerBound, upperBound, count)
                print 'Value =', value
            except sidl.BaseException._Exception, e:
                bocca_status = -2
                if self.bocca_print_errs:
                    (etype, eobj, etb) = sys.exc_info()
                    msg="demo.Driver: Error in go() execution: " \
                        + eobj.exception.getNote()
                    print >>sys.stderr,'Exception:', msg
                # if specific exceptions in the user code are tolerable
                # and restart is ok, bocca_status -1 instead.
                # 2 means the component is so confused that it and probably
        # the application should be destroyed.
            except Exception,e:
                bocca_status = -2
                if self.bocca_print_errs:
                    print >> sys.stderr, 'Exception in demo.Driver go():'+str(e)
            except:
                bocca_status = -2
                print >> sys.stderr, 'Unclassified Exception in demo.Driver go()'
        finally:
            # always executed.
            pass
        # This version of TryExceptFinally for compatibility with python 2.3 and up

# Bocca generated code. bocca.protected.begin(go:boccaGoEpilog)
        # end user code.
    # end if bocca_status == 0.

    # release integrate 
    if integrate_fetched:
        integrate_fetched = False
        try:
            self.d_services.releasePort("integrate")
        except sidl.BaseException._Exception, e:
            port = None
            if self.bocca_print_errs:
                (etype, eobj, etb) = sys.exc_info()
                msg="demo.Driver: Error calling releasePort('integrate'): "                    + eobj.exception.getNote()
                print >>sys.stderr,'Exception:', msg


    return bocca_status
# Bocca generated code. bocca.protected.end(go:boccaGoEpilog)
# DO-NOT-DELETE splicer.end(go)

After quitting the editor the state of the source code tree is updated if there are any dependencies on the edited implementation. Usually there are no dependencies on the implementation file, so Bocca does very little after you exit the editor and all you see is the information from the edit command about what file was edited.

/home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/python/demo/components/demo.Driver/demo/Driver_Impl.py

Now remake your project tree to finish the components:

$ make

make[1]: Entering directory `/home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/python/demo'
# =======================================================================
# No SIDL files in external/sidl, skipping build for external
# =======================================================================
# =======================================================================
# Building in ports/, languages: python
# =======================================================================
 ## Building ports... 
# =======================================================================
# Building in components/clients/, languages: python
# =======================================================================
 ## Building clients... 
# =======================================================================
# Building in components/, languages: python
# =======================================================================

   [s] Building class/component demo.Driver: 
make[3]: `.gencode' is up to date.
   [s] creating class/component library: libdemo.Driver.la ... 
   [s] finished libtooling: components/demo.Driver/libdemo.Driver.la ... 
   [s] building /home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/python/demo/install/share/cca/demo/demo.Driver_depl.xml ... 
   [s] creating Ccaffeine test script (components/tests/instantiation.gen.rc)... 

   [s] Building class/component demo.Function: 
make[3]: `.gencode' is up to date.
   [s] creating class/component library: libdemo.Function.la ... 
   [s] finished libtooling: components/demo.Function/libdemo.Function.la ... 
   [s] building /home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/python/demo/install/share/cca/demo/demo.Function_depl.xml ... 
   [s] creating Ccaffeine test script (components/tests/instantiation.gen.rc)... 

   [s] Building class/component demo.Integrator: 
make[3]: `.gencode' is up to date.
   [s] creating class/component library: libdemo.Integrator.la ... 
   [s] finished libtooling: components/demo.Integrator/libdemo.Integrator.la ... 
   [s] building /home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/python/demo/install/share/cca/demo/demo.Integrator_depl.xml ... 
   [s] creating Ccaffeine test script (components/tests/instantiation.gen.rc)... 

   [s] Building class/component demo.emptyComponent: 
make[3]: `.gencode' is up to date.
doing nothing -- library is up-to-date.
Build summary:
SUCCESS building demo.Driver
SUCCESS building demo.Function
SUCCESS building demo.Integrator
### To test instantiation of successfully built components, run 'make check' ###
################ Finished building everything #################
####### You can run some simple tests with 'make check' #######
make[1]: Leaving directory `/home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/python/demo'

It is good practice to do a make check at this point:

$ make check

make[1]: Entering directory `/home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/python/demo'
make --no-print-directory --no-builtin-rules -C components check
### Test library load and instantiation for the following languages: python
Running instantiation tests only
Test script: /home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/python/demo/components/tests/instantiation.gen.rc
Log file: /home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/python/demo/components/tests/instantiation.gen.rc.log
SUCCESS:
==> Instantiation tests passed for all built components (see /home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/python/demo/components/tests/instantiation.gen.rc.log).
make --no-print-directory --no-builtin-rules check-user
make[1]: Leaving directory `/home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/python/demo'

You should now be able to instantiate these components, assemble them into an application, and run the application, following the same procedures as in Section 2, and get a result that's reasonably close to pi .


3.5.5 Java Implementation

Image noteNote

Assumes you created the project with  bocca create project demo --language=java.

Edit the evaluate method in the implementation file (also known as ``the impl'') that Bocca has generated for you (by invoking Babel ). Use the bocca edit -i to go directly to each method.

$ bocca edit -i Function evaluate

The editor opens up in the place where the implementation code for evaluate  must be put. You see a default implementation generated by Babel for all user methods: the throwing of an exception which says the method is not yet implemented.

  public double evaluate_Impl (
    /*in*/ double x ) 
    throws sidl.RuntimeException.Wrapper
  {
    // DO-NOT-DELETE splicer.begin(demo.Function.evaluate)
    // Insert-Code-Here {demo.Function.evaluate} (evaluate)
    /*
     * This method has not been implemented
     */

    // DO-DELETE-WHEN-IMPLEMENTING exception.begin(demo.Function.evaluate)
    sidl.NotImplementedException noImpl = new sidl.NotImplementedException();
    noImpl.setNote("This method has not been implmented.");
    sidl.RuntimeException.Wrapper rex = (sidl.RuntimeException.Wrapper) sidl.RuntimeException.Wrapper._cast(noImpl);
    throw rex;
    // DO-DELETE-WHEN-IMPLEMENTING exception.end(demo.Function.evaluate)
    // DO-NOT-DELETE splicer.end(demo.Function.evaluate)

As the comment suggests, this method is ``not implemented'', but some code has been inserted by Babel to make sure an exception is thrown to inform the user if this method is called by mistake. Delete this exception code and substitute an implementation for the PiFunction (i.e., the integral from 0 to 1 of 4/(1 + x2) is an approximation of \bgroup\color{Green}$ \pi$\egroup ).

    // DO-NOT-DELETE splicer.begin(demo.Function.evaluate)
    return 4.0 / (1.0 + x * x);
    // DO-NOT-DELETE splicer.end(demo.Function.evaluate)

Now in the same file just above the evaluate method, find the second method for the FunctionPort init method:

    // DO-NOT-DELETE splicer.begin(demo.Function.init)
    // Do nothing.
    // DO-NOT-DELETE splicer.end(demo.Function.init)

We don't have any initialization in this simple example, so we just eliminate the code that throws the exception when the method is executed.

After quitting the editor the state of the source code tree is updated if there are any dependencies on the edited implementation. Usually there are no dependencies on the implementation file, so Bocca does very little after you exit the editor and all you see is the information from the edit command about what file was edited:

/home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/java/demo/components/demo.Function/demo/Function_Impl.java

Similarly edit the march method in the Integrator with

$ bocca edit -i Integrator march

  public double march_Impl (
    /*in*/ double lowBound,
    /*in*/ double upBound,
    /*in*/ int count ) 
    throws sidl.RuntimeException.Wrapper
  {
    // DO-NOT-DELETE splicer.begin(demo.Integrator.march)
    // Insert-Code-Here {demo.Integrator.march} (march)
    /*
     * This method has not been implemented
     */

    // DO-DELETE-WHEN-IMPLEMENTING exception.begin(demo.Integrator.march)
    sidl.NotImplementedException noImpl = new sidl.NotImplementedException();
    noImpl.setNote("This method has not been implmented.");
    sidl.RuntimeException.Wrapper rex = (sidl.RuntimeException.Wrapper) sidl.RuntimeException.Wrapper._cast(noImpl);
    throw rex;
    // DO-DELETE-WHEN-IMPLEMENTING exception.end(demo.Integrator.march)
    // DO-NOT-DELETE splicer.end(demo.Integrator.march)

Again remove this boilerplate exception code and insert an implementation of the Trapezoid rule for integration that uses the FunctionPort :

    // DO-NOT-DELETE splicer.begin(demo.Integrator.march)
  gov.cca.Port port = null;
  port = this.d_services.getPort("odeRHS");
  demo.FunctionPort odeRHS;
  odeRHS = ( demo.FunctionPort.Wrapper )
                  demo.FunctionPort.Wrapper._cast((gov.cca.Port.Wrapper)port);
  if (odeRHS == null) {
    if (bocca_print_errs) {
        System.err.println("demo.Integrator: Error casting gov.cca.Port"
                         + " odeRHS to type demo.FunctionPort");
    }
    sidl.SIDLException ex = new sidl.SIDLException();
    sidl.SIDLException.Wrapper msg = (sidl.SIDLException.Wrapper)
        sidl.SIDLException.Wrapper._cast(ex);
    throw msg;
  }

  double h = (upBound - lowBound) / count;
  double retval = 0.0;
  double sum = 0.0;
  for (int i = 1; i <= count; i++){
    sum += odeRHS.evaluate(lowBound + (i - 1) * h) +
           odeRHS.evaluate(lowBound + i * h);
  }
  retval = h/2.0 * sum;

  this.d_services.releasePort("odeRHS");
  return retval;
    // DO-NOT-DELETE splicer.end(demo.Integrator.march)

After quitting the editor the state of the source code tree is updated if there are any dependencies on the edited implementation. Usually there are no dependencies on the implementation file, so Bocca does very little after you exit the editor and all you see is the information from the edit command about what file was edited:

/home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/java/demo/components/demo.Integrator/demo/Integrator_Impl.java

Finally for the Driver component we have to implement the GoPort details to get things going. Bocca will take you to the generated method, which looks like this:

$ bocca edit -i Driver go

  public int go_Impl () 
    throws sidl.RuntimeException.Wrapper
  {
    // DO-NOT-DELETE splicer.begin(demo.Driver.go)


// Bocca generated code. bocca.protected.begin(demo.Driver.go:boccaGoProlog)
  int bocca_status = 0;
  // The user's code should set bocca_status 0 if computation proceeded ok.
  // The user's code should set bocca_status -1 if computation failed but might
  // succeed on another call to go(), e.g. wheh a required port is not yet connected.
  // The user's code should set bocca_status -2 if the computation failed and can
  // never succeed in a future call.
  // The users's code should NOT use return in this function;
  // Exceptions that are not caught in user code will be converted to status 2.

  gov.cca.Port port = null;

  boolean integrate_fetched = false;
  if (bocca_status == 0) { // skip further getports if problem occurs.
    // Use a demo.Integration port with port name integrate, unless we've hit 
    // a problem already.
    try{
      port = this.d_services.getPort("integrate");
    } catch ( gov.cca.CCAException.Wrapper ex )  {
      // we will continue with port nil (never successfully assigned) and set a flag.
      if (bocca_print_errs) {
        System.err.println("Error calling getPort(\"integrate\")" 
                          + ex.getNote());
        System.err.println("Continuing without integrate");
      }
    }
    demo.Integration integrate;
    if ( port != null  ) {
      integrate_fetched = true; // even if the next cast fails, must release.
      integrate = ( demo.Integration.Wrapper ) 
                  demo.Integration.Wrapper._cast((gov.cca.Port.Wrapper)port);
      if (integrate == null) {
        if (bocca_print_errs) {
          System.err.println("demo.Driver: Error casting gov.cca.Port "
                  + "integrate to type demo.Integration");
        }
        bocca_status = -1;
      } 
    } 
  } 


  if (bocca_status == 0) { 
// skip user code if we already have an unexpected error. go to cleanup.
// Bocca generated code. bocca.protected.end(demo.Driver.go:boccaGoProlog)



  // If this try/catch block is rewritten by the user, we will not change it.
  try {
    // All port instances may be rechecked for null before calling in user code.
    // Java will throw a null object exception when using the port if it's null.
    // The port instance names used in registerUsesPort appear as local variable
    // names here.

    // Insert-UserCode-Here {demo.Driver.go} 

    // BEGIN REMOVE ME BLOCK
    sidl.SIDLException ex = new sidl.SIDLException();
    ex.setNote("USER FORGOT TO FILL IN THEIR FUNCTION demo.Driver.go()");
    sidl.BaseException.Wrapper bex =
      (sidl.BaseException.Wrapper)sidl.BaseException.Wrapper._cast(ex);
    throw bex;
    // END REMOVE ME BLOCK


  } catch (sidl.BaseException.Wrapper ex) {
    bocca_status = -2;
    if (bocca_print_errs) {
      System.err.println("SIDL Exception in user go code: "+ ex.getNote() );
      System.err.println("Returning 2 from go()");
    }
  } catch (java.lang.Exception jex) {
    bocca_status = -2;
    if (bocca_print_errs) {
      if (((sidl.BaseInterface)jex).isType("sidl.BaseException")) {
        System.err.println("sidl Exception in user go code: " 
                           + ((sidl.BaseException)jex).getNote() );
      } else {
        System.err.println("java Exception in user go code: "+ jex.getMessage());
      }
      System.err.println("Returning 2 from go()");
    }
    // If unknown exceptions in the user code are tolerable and restart is ok, 
    // use bocca_status -1 instead.
    // 2 means the component is so confused that it and probably the application
    // should be destroyed.
  }


// Bocca generated code. bocca.protected.begin(demo.Driver.go:boccaGoEpilog)
  } // cleanup

  // release integrate 
  if (integrate_fetched) {
    integrate_fetched = false;
    try{
      this.d_services.releasePort("integrate");
    } catch ( gov.cca.CCAException.Wrapper ex )  {
      if (bocca_print_errs) {
        System.err.println("demo.Driver: Error calling "
            + "releasePort(\"integrate\"): " + ex.getNote()); 
      }
    }
    // java port reference will be dropped when function exits, 
    // but we must tell framework.
  }


  return bocca_status;
// Bocca generated code. bocca.protected.end(demo.Driver.go:boccaGoEpilog)

    /*
     * This method has not been implemented
     */

    // DO-NOT-DELETE splicer.end(demo.Driver.go)

Find the REMOVE block within the go method implementation, delete it, and insert the numerical logic needed to use the integrator.IntegratorPort port. Any required local variables should be inserted just before the boccaGoProlog protected block.

The go subroutine will be called by the framework when the component's run button (the name of this particular GoPort instance) is pushed in the GUI. Bocca generates the code to the Integration that the Driver is connected to. We just have to use it to compute the integral and return the proper value for bocca_status.