CLIENT_PROPAGATED
priority model).
valuetype containing the stock name to the corresponding
event sink of one or more StockBroker objects at a priority
designated by the StockBroker when it subscribed with the
StockDistributor. The StockBroker objects that consume this
event will 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
object to obtain more information about the stock. This object
reference will indicate the appropriate priority at which to run the
request in the stock distributor, which will contains a thread
pool with lanes corresponding to the priorities at which
StockBrokers subscribe.
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 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. Note that this thread
will need to set its priority (via
RTCurrent::the_priority()) to the appropriate value
before making calls to StockBrokers.
Step 2: Defining the Stock Quoter Interfaces Using IDL 2.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 2.x interfaces. We start with the valuetype data
type that objects can use to communicate using CCM's
publisher/subscriber event mechanism. Whenever a stock value changes,
the stock distributor will publish the following
valuetype containing the name of the stock:
valuetype StockName {
// Name of the stock.
public string name;
};
Unlike CORBA Objects (which are passed by reference),
instances of CORBA valuetype 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. You will next write an interface implemented by the stock broker to handle callbacks from the stock distributor.
interface StockNameConsumer
{
// Push an event to the consumer.
void push_StockName (in StockName the_stockname);
};
Now that we've defined our StockName
valuetype, we can combine it with the
StockQuoter interface defined earlier to create a factory
interface called StockBroker:
interface StockBroker
{
// Factory operation to return StockNameConsumer object reference.
StockNameConsumer get_consumer_notifier ();
// Event sink operations to perform connectivity.
void connect_quoter_info (in StockQuoter c);
StockQuoter disconnect_quoter_info ();
StockQuoter get_connection_quoter_info ();
};
The get_consumer_notifier() operation returns an object
reference to the StockNameConsumer IDL 2.x interface
shown earlier. When the stock quoter system is initialized, this
factory operation will be used to connect the stock distributor
publisher with the StockNameConsumer subscriber.
These connect_quoter_info(),
disconnect_quoter_info(), and
get_connection_quoter_info() operations are also used
connect the StockBroker with the StockQuoter
object that's provided by the StockDistributor interface
describe next.
The StockDistributor object has the following IDL 2.x
interface description:
interface StockDistributor : Trigger
{
// Event source operations to establish connectivity.
Cookie subscribe_notifier (in Stock::StockNameConsumer c,
in RTCORBA::Priority priority);
Stock::StockNameConsumer unsubscribe_notifier (in Cookie ck);
// Factory operation to return StockQuoter object reference.
StockQuoter provide_quoter_info ();
attribute long notification_rate;
};
The subscribe_notifier() and
unsubscribe_notifier() operations are to
subscribe/unsubscribe StockBroker objects that consume
the StockName events published by the
StockDistributor in accordance with a designated
priority. For example, assuming there were stockBroker
and stockDistributor object references to the respective
StockBroker and StockDistributor objects,
these object references could be automatically connected using the
following steps:
Stock::StockNameConsumer_var consumer = stockBroker->get_consumer_notifier ();
stockDistributor->subscribe_notifier (consumer.in (), HIGH_PRIORITY);
The provide_quoter_info() factory operation returns
object references that StockBroker consumers can use to
obtain more information about a particular stock. As before, this
factory operation can be used in conjunction with the
StockBroker's connect_quoter_info()
operation to perform connection plumbing, as follows:
Stock::StockQuoter_var quoter = stockDistributor->provide_quoter_info ();
stockBroker->connect_quoter_info (quoter.in ());
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 2.x Features to Manage the Creation of Objects.
Instances of the StockBroker and
StockDistributor objects can be created at startup time
via factories.
interface StockBrokerHome
{
StockBroker create ();
};
interface StockDistributorHome
{
StockDistributor create ();
};
These 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
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: Implement the Main Program.
You'll need to implement a main() functions for stock
distributors and stock brokers that will dynamically create the
appropriate instances of the factories and bootstrap objects, obtains
and activates the appropriate POA (you'll need to use
RTPortableServer::POA for both the StockDistributed and
StockBroker), and then calls CORBA::ORB::run() method to
run the application event loops. To make your life easy, applications
should write their IORs to a file before it calls the ORB's
run() method (if you'd like to use a Naming Service
please feel free to do so).
Client applications should read the name of the file that contains the
IOR discussed above. When the client starts up, it will read the
contents of this file into a string and use the
CORBA::string_to_object() method to convert the string
into an object reference. This object reference will then be downcast
via _narrow() to an object reference for the various
factories operations.
For the purposes of the assignment, you can make the driver programs very simple, i.e., you can read commands from standard input and write replies to standard output. For example, you could type the following commands to the stock distributor
% ./distributor
> rate 1 second
to tell it to generate events at a rate of 1 second. Likewise, you
could type the following commands to the stock broker:
% ./broker tango.dre.vanderbilt.edu
> subscribe "MSFT" 10
Current value of MSFT is $100
Current value of MSFT is $101
...
which will subscribe for MSFT stock at priority 10 and then print out
its value when it receives it from the publisher. If anything fails to work properly the programs should simply print out the appropriate exception and exit with a return status of 1. If everything works correctly, the programs should exit with a return status of 0.
Back to CS 396 home page.