summaryrefslogtreecommitdiff
path: root/TAO/docs/tutorials/Quoter/RT_Event_Service/index.html
diff options
context:
space:
mode:
Diffstat (limited to 'TAO/docs/tutorials/Quoter/RT_Event_Service/index.html')
-rw-r--r--TAO/docs/tutorials/Quoter/RT_Event_Service/index.html385
1 files changed, 385 insertions, 0 deletions
diff --git a/TAO/docs/tutorials/Quoter/RT_Event_Service/index.html b/TAO/docs/tutorials/Quoter/RT_Event_Service/index.html
new file mode 100644
index 00000000000..d664c603331
--- /dev/null
+++ b/TAO/docs/tutorials/Quoter/RT_Event_Service/index.html
@@ -0,0 +1,385 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+ <head>
+ <title>TAO's RT Event Service</title>
+ <!-- $Id$ -->
+ </head>
+
+ <BODY text = "#000000"
+ link="#000fff"
+ vlink="#ff0f0f"
+ bgcolor="#ffffff">
+
+ <h3>TAO's RT Event Service</h3>
+
+ <P>We have already explored how to use
+ <A HREF="../Event_Service/index.html">
+ TAO's COS Event Service
+ </A>
+ to receive updated stock prices,
+ but what if we are not interested in all the stocks?
+ One approach is to use multiple event channels, each one
+ carrying different traffic.
+ For example,
+ each event channel could carry only a subset of the stocks.
+ In this section we will explore another solution,
+ using TAO's real-time Event Service to perform filtering for us.
+ TAO's real-time Event Service can do many other things,
+ like preserving priority end-to-end,
+ using multicast to conserve network resources,
+ generating timeout and interval events,
+ and it can collaborate with TAO's Scheduling Service to
+ analyze the schedulability of your system.
+ </P>
+
+ <H3>Getting the Price Changes</H3>
+
+ <P>For this example we will use the same data structures that we
+ used in the previous example,
+ i.e., the events will be identical.
+ TAO's RT Event Service can be configured to carry your events in
+ a type-safe manner,
+ or you can use custom marshaling to send non-IDL structures in
+ the event,
+ but it is easier to use it like the COS Event Service first.
+ </P>
+
+ <H3>Connecting as a consumer</H3>
+
+ <P>Connecting as a consumer is very similar. Some of the base
+ classes and signatures change, but it is basically the same
+ idea:
+ First let us define the consumer object:
+ </P>
+<PRE>
+class Stock_Consumer : public POA_RtecEventComm::PushConsumer {
+public:
+ Stock_Consumer ();
+
+ void push (const RtecEventComm::EventSet& data TAO_ENV_ARG_DECL_NOT_USED);
+ void disconnect_push_consumer (TAO_ENV_SINGLE_ARG_DECL_NOT_USED);
+
+ // details omitted
+};
+</PRE>
+ <P>Notice that we receive an event set instead of a single event.
+ The event channel can use this feature to queue multiple events
+ and push them in a single operation.
+ First we need to extract the event data from the any:
+ </P>
+<PRE>
+void
+Stock_Consumer::push (const RtecEventComm::EventSet &data
+ TAO_ENV_ARG_DECL_NOT_USED)
+{
+ for (CORBA::ULong i = 0; i != data.length (); ++i) {
+ RtecEventComm::Event &e = data[i];
+
+ Quoter::Event *event;
+ if ((e.data.any_value >>= event) == 0)
+ continue; // Invalid event
+</PRE>
+ <P>Notice that the events have more structure,
+ they have a clearly separated header and data,
+ and the data has more than just an any.
+ The header is used to provide filtering, and
+ the event data field can be configured at compile time to carry
+ whatever IDL structures you want.
+ Now we can print out the new stock price:
+ </P>
+<PRE>
+ std::cout << "The new price for one stock in \""
+ << event->full_name.in ()
+ << "\" (" << event->symbol.in ()
+ << ") is " << event->price << std::endl;
+}
+</PRE>
+
+ <P>We also need to implement the disconnect callback:
+ </P>
+<PRE>
+void
+Stock_Consumer::disconnect_push_consumer (TAO_ENV_SINGLE_ARG_DECL_NOT_USED)
+{
+ this->supplier_proxy_ = CosEventChannelAdmin::ProxyPushSupplier::_nil ();
+}
+</PRE>
+ <P>As with the COS Event Channel we can voluntarily disconnect,
+ too:
+ </P>
+<PRE>
+void
+Stock_Consumer::disconnect ()
+{
+ // Do not receive any more events...
+ this->supplier_proxy_->disconnect_push_supplier ();
+}
+</PRE>
+
+ <H4>How to connect to the RT event channel</H4>
+
+ <P>Connecting to the RT event channel is very similar to
+ connecting to the regular event channel.
+ The only difference is that we must specify the events that we
+ want to receive. This is described using a fairly complex IDL
+ structure, but TAO provides a helper class to generate it.
+ We will assume that we are using the naming service or
+ something similar to obtain a reference to the event service:
+ </P>
+<PRE>
+ CORBA::Object_var tmp = naming_context->resolve (name);
+ RtecEventChannelAdmin::EventChannel_var event_channel =
+ RtecEventChannelAdmin::EventChannel::_narrow (tmp);
+</PRE>
+ <P>Now we use the event channel to obtain the factory used for
+ consumer connections:
+ </P>
+<PRE>
+ RtecEventChannelAdmin::ConsumerAdmin_var consumer_admin =
+ event_channel->for_consumers ();
+</PRE>
+ <P>And use the factory to obtain a proxy:
+ </P>
+<PRE>
+void
+Stock_Consumer::connect (RtecEventChannelAdmin::ConsumerAdmin_ptr consumer_admin)
+{
+ this->supplier_proxy_ =
+ consumer_admin->obtain_push_supplier ();
+</PRE>
+ <P>Now we list the events that we want to receive.
+ We use a simple algorithm to assign an event type to each stock
+ symbol:
+ </P>
+<PRE>
+ CORBA::ULong rhat_event_type =
+ (int('R') << 24) | (int('H') << 16) | (int('A') << 8) | int('T');
+ CORBA::ULong aaaa_event_type =
+ (int('A') << 24) | (int('A') << 16) | (int('A') << 8) | int('A');
+</PRE>
+ <P>Now we create the subscription:
+ </P>
+<PRE>
+ ACE_ConsumerQOS_Factory subscriptions;
+ subscriptions.insert_type (rhat_event_type, 0);
+ subscriptions.insert_type (aaaa_event_type, 0);
+</PRE>
+ <P>And connect to the proxy:
+ </P>
+<PRE>
+ RtecEventComm::PushConsumer_var myself = this->_this ();
+ this->supplier_proxy_->connect_push_consumer (
+ myself.in (),
+ subscriptions.get_ConsumerQOS ());
+}
+</PRE>
+
+ <H3>Notifying the Price Changes</H3>
+
+ <P>As with the COS Event Channel example we will make our
+ implementation of the <CODE>Modify_Stock</CODE> interface
+ generate events whenever the price changes:
+ </P>
+<PRE>
+class Quoter_Modify_Stock_i : public POA_Quoter::Modify_Stock {
+public:
+ Quoter_Modify_Stock_i (const char *symbol,
+ const char *full_name,
+ CORBA::Double price);
+
+ void set_price (CORBA::Double new_price)
+ throw (CORBA::SystemException);
+
+ void disconnect_push_supplier (TAO_ENV_SINGLE_ARG_DECL_NOT_USED);
+
+private:
+ Quoter::Event data_;
+
+ RtecEventChannelAdmin::ProxyPushConsumer_var consumer_proxy_;
+
+ POA_RtecEventComm::PushSupplier_tie < Quoter_Stock_i > supplier_personality_;
+};
+</PRE>
+ <P>The implementation of the <CODE>set_price()</CODE> method is
+ very similar.
+ First we store the new price:
+ </P>
+<PRE>
+void
+Quoter_Stock_i::set_price (CORBA::Double new_price)
+ throw (CORBA::SystemException)
+{
+ this->data_.price = new_price;
+</PRE>
+ <P>Next we prepare the event.
+ This time we must create a sequence, but we just have one
+ element in it:
+ </P>
+<PRE>
+ RtecEventComm::EventSet event (1);
+ event.length (1);
+</PRE>
+ <P>We set the event type based on the stock symbol:
+ </P>
+<PRE>
+ RtecEventComm::Event &e = event[0];
+ const char *symbol = this->data_.symbol;
+ e.header.type =
+ ((int(symbol[0]) << 24)
+ | (int(symbol[1]) << 16)
+ | (int(symbol[2]) << 8)
+ | int(symbol[3]));
+ e.header.source = 1;
+</PRE>
+ <P>The event source is not used in this example, but it must be
+ non-zero. Now we can set the data:
+ </P>
+<PRE>
+ e.data.any_value <<= this->data_;
+</PRE>
+ <P>and send the event to the event channel:
+ </P>
+<PRE>
+ this->consumer_proxy_->push (event);
+}
+</PRE>
+
+ <H3>Connecting to the Event Service as a Supplier</H3>
+
+ <P>As in the COS Event Channel case we need a supplier personality
+ to connect to it.
+ We gain access to the Event Service, for example using the
+ naming service:
+ </P>
+<PRE>
+ CORBA::Object_var tmp = naming_context->resolve (name);
+ RtecEventChannelAdmin::EventChannel_var event_channel =
+ RtecEventChannelAdmin::EventChannel::_narrow (tmp);
+</PRE>
+ <P>Now we use the event channel to obtain the factory used for
+ supplier connections:
+ </P>
+<PRE>
+ RtecEventChannelAdmin::SupplierAdmin_var supplier_admin =
+ event_channel->for_suppliers ();
+</PRE>
+ <P>And use the factory to obtain a proxy:
+ </P>
+<PRE>
+ this->consumer_proxy_ =
+ supplier_admin->obtain_push_consumer ();
+</PRE>
+ <P>We build our publications so the event channel can match
+ consumers and suppliers based on their common events:
+ </P>
+<PRE>
+ const char *symbol = this->data_.symbol;
+ CORBA::ULong type =
+ ((int(symbol[0]) << 24)
+ | (int(symbol[1]) << 16)
+ | (int(symbol[2]) << 8)
+ | int(symbol[3]));
+ CORBA::ULong source = 1;
+ ACE_SupplierQOS_Factory publications;
+ publications.insert_type (type, source, 0, 1);
+</PRE>
+ <P>Finally we connect to the consumer proxy:
+ </P>
+<PRE>
+ RtecEventComm::PushSupplier_var supplier =
+ this->supplier_personality_._this ();
+ this->consumer_proxy_->connect_push_supplier (supplier);
+</PRE>
+
+ <P>The implementation of the disconnect callback is as before:
+ </P>
+<PRE>
+void
+Quoter_Stock_i::disconnect_push_supplier (TAO_ENV_SINGLE_ARG_DECL_NOT_USED)
+ throw (CORBA::SystemException)
+{
+ // Forget about the consumer it is not there anymore
+ this->consumer_proxy_ =
+ RtecEventChannelAdmin::ProxyPushConsumer::_nil ();
+}
+</PRE>
+
+ <H3>Exercise 1</H3>
+
+ <P>Implement a consumer that receives the price update events,
+ </P>
+ <P>The
+ <A HREF="Stock_Consumer.h">header file</A>
+ is already provided,
+ along with a sample
+ <A HREF="client.cpp">client.cpp</A>.
+ And other support files
+ <A HREF="../Event_Service/Quoter.idl">Quoter.idl</A>,
+ <A HREF="GNUMakefile">Makefile</A>,
+ <A HREF="Stock_i.h">Stock_i.h</A>,
+ <A HREF="Stock_i.cpp">Stock_i.cpp</A>,
+ <A HREF="Stock_Factory_i.h">Stock_Factory_i.h</A>,
+ <A HREF="Stock_Factory_i.cpp">Stock_Factory_i.cpp</A>,
+ and <A HREF="server.cpp">server.cpp</A>.
+ </P>
+
+ <H4>Solution</H4>
+
+ <P>Compare your solution with
+ <A HREF="Stock_Consumer.cpp">Stock_Consumer.cpp</A>.
+ </P>
+
+ <H4>Testing</H4>
+
+ <P>To test your changes you need to run three programs,
+ first TAO's Naming Service:
+<PRE>
+$ $TAO_ROOT/orbsvcs/Naming_Service/Naming_Service
+</PRE>
+ <P>then run TAO's Real-time Event Service
+ </P>
+<PRE>
+$ $TAO_ROOT/orbsvcs/Event_Service/Event_Service
+</PRE>
+
+ <P>Now you can run your client:
+<PRE>
+$ client AAAA CCCC
+</PRE>
+ <P>and finally the server:
+ </P>
+<PRE>
+$ server MSFT BBBB CCCC < stock_list.txt
+</PRE>
+ <P>Here is the
+ <A HREF="../Event_Service/stock_list.txt">stock_list.txt file</A>.
+ </P>
+
+ <H3>Exercise 2</H3>
+
+ <P>Run the same configuration as above,
+ but this time run multiple clients and servers:
+ </P>
+<PRE>
+$ client AAAA MSFT
+$ client PPPP
+$ server AAAA < stock_list1.txt
+$ server QQQQ < stock_list2.txt
+</PRE>
+ <P>Do the clients receive all the events from both servers?
+ </P>
+ <P>Here are the
+ <A HREF="../Event_Service/stock_list1.txt">stock_list1.txt</A>
+ and
+ <A HREF="../Event_Service/stock_list2.txt">stock_list2.txt</A>
+ files.
+ </P>
+
+ <hr>
+ <address><a href="mailto:coryan@cs.wustl.edu">Carlos O'Ryan</a></address>
+<!-- Created: Sat Nov 27 15:47:01 CST 1999 -->
+<!-- hhmts start -->
+Last modified: Wed May 16 10:13:34 PDT 2001
+<!-- hhmts end -->
+ </body>
+</html>