diff options
Diffstat (limited to 'TAO/docs/tutorials/Quoter/RT_Event_Service/index.html')
-rw-r--r-- | TAO/docs/tutorials/Quoter/RT_Event_Service/index.html | 385 |
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> |