CCM-based Publish/Subscribe CORBA Stock Quoter Service (Assignment 4)

Overview

This assignment will complete the previous CORBA 3.0 publish/subscribe-based implementation of the stock quoter service by using CORBA Component Model (CCM) features and new OMG's Deployment and Configuration specification based tools called DAnCE.

In this design, publishers generate events that are transmitted to one or more subscribers, who can then take further action depending on the events they receive and their internal state. The overall flow of information in our latest incarnation of the stock quoter system thus works as follows:

  1. Stock broker clients subscribe with a stock distributor server to receive notification events whenever a stock value of interest to them changes.

  2. The stock distributor server monitors a real-time stock feed database.

  3. Whenever the value of a stock changes, the distributor publishes an event to interested stock brokers.

  4. If stock brokers are interested in learning more details about a stock whose value has changed, they can invoke an operation on the stock distributor to receive more information.
By employing the Publisher/Subscriber pattern in our stock quoter example, we can alleviate the key drawbacks with polling-based request/response designs, i.e., stock brokers only contact the stock distributor server via request/response operations when the value of a stock changes, rather than polling them repeatedly to see if the value has changed.

The CORBA Stock Quoter service is designed using the Publisher/Subscriber pattern. In previous assignments, you defined a StockDistributor component that publishes events to indicate that a particular stock's value has changed. This component monitors the real-time stock database and, when the values of particular stocks change, pushes an eventtype containing the stock name to the corresponding event sink of one or more StockBroker components. The StockBroker objects that consume this event then examine the stock name stored in the event. If they are interested in the stock, they can invoke a request/response operation via an object reference exported by the StockDistributor component to obtain more information about the stock.

For completeness, this document describes the first four steps from the previous assignment and then describes the new step 5, which involves assembling and deploying the components developed in the other steps.

Step 1: Defining the Stock Quoter Interfaces using IDL 2.x Types. You will start by defining some interfaces and other types using IDL 2.x features. All of these types will be defined in a module called Stock, i.e.:


// IDL schema definition for Stock Quoter publisher/subscriber service.
module Stock
{
  exception Invalid_Stock {};
  // Feel free to add other exceptions as you see fit.

  // ...
When stock brokers want to learn more information about a particular stock whose value has changed recently, they can invoke the get_stock_info() operation on the following StockQuoter interface within the Stock module:

	interface StockQuoter {
          StockInfo get_stock_info (in string stock_name) raises Invalid_Stock;
	};
This interface returns the following StockInfo struct:

       struct StockInfo {
         string name;
         long high;
         long low;
         long last;
         // ...
       };
As shown above, StockInfo contains information about the high and low trading values of the stock during the trading thus far today, along with the most recent value. It also includes the stock name so that each StockInfo instance is self-identifying and is thus easily trackable and usable in collections.

The stock distributor itself runs as a daemon that can be started and stopped by a system administrator. The following Trigger interface instructs the stock distributor to perform these control operations:


	interface Trigger { 
          void start ();
          void stop ();
	}
When an administrator calls start() the stock distributor begins to monitor the real-time stock database until the stop() operation is called. In your application, you can simply spawn a thread that reads from a simple STL std::map that maps stock names (i.e., "BEAS," "IBM," and "MSFT") to "real-time" stock quotes.

Step 2: Defining the Stock Quoter Components Using IDL 3.x Types. Now that we've illustrated the core IDL 2.x types in our stock quoter system, we'll show how they are combined together using IDL 3.x component types. We start with the eventtype data type that components can use to communicate using CCM's publisher/subscriber event mechanism. Whenever a stock value changes, the stock distributor will publish the following eventtype containing the name of the stock:


        eventtype StockName { 
          // Name of the stock.
          public string name; 
        };
Unlike CORBA Objects (which are passed by reference), instances of CORBA eventtype are always passed by value. Like CORBA structs, they can contain state in the form of fields. Unlike structs, however, they can have user-defined operations and support inheritance.

Now that we've defined our StockName eventtype, we can combine it with the StockQuoter interface defined earlier to create a CCM component called StockBroker:


        component StockBroker
        {
          consumes StockName notifier_in;
          uses StockQuoter quoter_info_in;
        };
The StockBroker component contains two ports that correspond to the two roles it plays. First, it is a subscriber that consumes a StockNameL eventtype called notifier_in that's published by the StockDistributor when the value of a stock changes. Second, it is a user of the StockQuoter interface we defined earlier to provide additional information about a stock. This dependency is indicated explicitly in IDL 3.x via a CCM receptacle called quoter_info_in that indicates the uses relationship on the StockQuoter interface. The StockDistributor object has the following IDL 2.x interface description:

        component StockDistributor supports Trigger 
        {
          publishes StockName notifier_out;
          provides StockQuoter quoter_info_out;
          attribute long notification_rate;
        };
This CCM component supports (i.e., inherits from) the Trigger interface defined earlier, which enables a system administrator application to start() and stop() instances of StockDistributor.

The supports keyword is useful for components like StockDistributor that have a "primary" interface, which alleviates application developers from having to go through extra steps just to access the operations of that interface. If the interface were specified as a facet via the provides keyword instead, applications would have to call an operation to get a reference to the facet, and then invoke the desired operation. Instead, the supports keyword allows administrator applications to invoke the start() and stop() operation directly on the component reference since the Trigger interface is a parent of StockDistributor. StockDistributor also publishes a StockName eventtype called notifier_out that is pushed to the StockBroker subscriber components when a stock value changes. StockDistributor also defines a StockQuoter facet called quoter_info_out.

Finally, in addition to the inherited Trigger operations, system administrators can use the notification_rate attribute to control the rate at which the StockDistributor object checks the stock quote database and pushes changes to StockBroker subscribers. Attributes in are primarily used for configuration, e.g., to define optional behaviors, modality, resource hints, etc. They are represented as a pair of accessor/mutator methods in C++.

Step 3: Use IDL 3.x Features to Manage the Creation of Objects. Instances of the StockBroker and StockDistributor objects can be created at startup time via home factories. In CCM, home is a new IDL keyword that's used to define a factory that manages one type of component. A component instance is managed by one home instance. Since a home has an interface, it's identified via an object reference. By default, a home has standard lifecycle operations, e.g., create(), though which users can define operations with arbitrary parameter lists if the defaults don't suffice. For our stock quoter example we can use the defaults, so our homes are defined as follows:


        home StockBrokerHome manages StockBroker {};
        home StockDistributorHome manages StockDistributor {};
These home factories reduce the bookkeeping that CORBA applications must do to create and manage their objects.

You will use the TAO CORBA IDL compiler to translate these IDL 2.x and 3.x interfaces into stubs and skeletons. The stock distributor application (which you must write) will use the stubs as a proxy to publish StockNames the stock broker application(s). As discussed above, the brokers can call back to the distributor to get more info on the stocks. In addition, you must also write the factory interfaces that set everything in motion.

Step 4: Use CIDL Features to Map Components to Executors. Component developers need to define the structure and state of their components. The CCM approach is to use the composition declaration in the Component Implementation Definition Language CIDL that describes how to connect component definitions (which perform business logic) with home definitions (which are the factories that create components). Since a component can be instantiated by more than one home, a composition designates which home will manage which component.

CCM allows developers to define a single component and have multiple home definitions that manage the same component using IDL 3.x keywords. By defining the composition, the component developer designates the relationship between a home and the component it manages. It is important to note, however, that the composition does not specify component types explicitly, but rather implicitly from the home type within the composition since each home can manage only one type of component. The CIDL for our stock quoter example is placed in a file called stock.cdl, as shown below:


composition session StockDistributor_Impl {
  home executor StockDistributorHome_Exec  {
    implements StockDistributorHome;      
    manages StockDistributor_Exec;  
  }
};

composition session StockBroker_Impl {
  home executor StockBrokerHome_Exec  {
    implements StockBrokerHome;      
    manages StockBroker_Exec;  
  }
};
You'll then need to implement the executors corresponding to the code generated by the CIDL compiler. The best way to learn how to implement the executor code is to learn through a hello example, which you can find in the $CIAO_ROOT/DAnCE/examples/Hello directory.

Step 5: Assemble and Deploy Your Components. You'll need multiple XML files to create a assembly and deploy your components into a target environment.

StockDistributor Monolithic Component:

StockBroker Monolithic Component:

For Quoter Assembly:

There are a number of dependencies among these descriptor files, in particular:

package.tpd -> Quoter.pcd -> Quoter.cpd -> Quoter.cid --> (StockDistribut.cpd, StockBroker.cpd)

The easiest way to create these XML files is to use visual tools, such as CoSMIC. For this particular assignment, however, most of the XML descriptor files are given to you and they are ready to download and use. The one file you need to write is Quoter.cid, which specifies how many instances of components you plan to deploy, as well as the connections among these instances of components. This file should define two component instances: a_StockDistributor and a_StockBroker, with the name of StockDistributor_Instance and StockBroker_Instance, respectively. A planner could also specify that a deployment plan contains a number of component instances, with two or more instances having the same component type. Note that each component instance must have a unique name within a single deployment plan.

Finally, you'll need to use the DAnCE daemons and tools to deploy your assembly.


Learning and Using CORBA Component Model

We will again use the TAO (Common Object Request Broker Architecture) and CIAO (CORBA Component Model) implementation. Please see the online help for information on how to setup your TAO and CIAO development environment on EECS's computing system. If you'd prefer to use TAO and CIAO on your laptop or home PC you can download it from deuce.doc.wustl.edu/Download.html.

This documentation page shows you how to install and build CIAO on your computing system. Likewise, this small tutorial show you how to write a simple "hello" example by using CIAO.


Concluding Remarks

This third CORBA assignment requires more knowledge of CCM and distributed software design than the first two assignments, which just exercised basic skills required to become adept at using CORBA component middleware to developed distributed applications. Subsequent assignments will build on the third assignment, so make sure you get it working correctly.


Back to CS 396 home page.