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:
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.
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.
Back to CS 396 home page.