// Topic Interface file
struct Measurement {
string tower; // tower id
float windSpeed; // knots
short windDirection; // degrees
float temperature; // degrees Celsius
};
interface Monitor {
void report(Measurement m);
};
string tower; // tower id
float windSpeed; // knots
short windDirection; // degrees
float temperature; // degrees Celsius
};
interface Monitor {
void report(Measurement m);
};
// Implementing a Publisher
The implementation of our collector application can be summarized easily:
1. Obtain a proxy for the TopicManager. This is the primary IceStorm object,
used by both publishers and subscribers.
2. Obtain a proxy for the Weather topic, either by creating the topic if it does
not exist, or retrieving the proxy for the existing topic.
3. Obtain a proxy for the Weather topic’s “publisher object.” This proxy is
provided for the purpose of publishing messages, and therefore is narrowed to
the topic interface (Monitor).
4. Collect and report measurements.
1. Obtain a proxy for the TopicManager. This is the primary IceStorm object,
used by both publishers and subscribers.
2. Obtain a proxy for the Weather topic, either by creating the topic if it does
not exist, or retrieving the proxy for the existing topic.
3. Obtain a proxy for the Weather topic’s “publisher object.” This proxy is
provided for the purpose of publishing messages, and therefore is narrowed to
the topic interface (Monitor).
4. Collect and report measurements.
#include <Ice/Ice.h>
#include <IceStorm/IceStorm.h>
#include <Monitor.h>
int main(int argc, char* argv[])
{
...
#include <IceStorm/IceStorm.h>
#include <Monitor.h>
int main(int argc, char* argv[])
{
...
// Note that this example assumes that IceStorm uses the instance name IceStorm.
// The actual instance name may differ.
// The actual instance name may differ.
// instance name Specifies an alternate identity category for the IceStorm topic manager object. If
// defined, the identity of the object becomes name/TopicManager. If not specified,
// the default identity category is IceStorm.
Ice::ObjectPrx obj = communicator->stringToProxy(
"IceStorm/TopicManager:tcp -p 9999");
// defined, the identity of the object becomes name/TopicManager. If not specified,
// the default identity category is IceStorm.
Ice::ObjectPrx obj = communicator->stringToProxy(
"IceStorm/TopicManager:tcp -p 9999");
IceStorm::TopicManagerPrx topicManager =
IceStorm::TopicManagerPrx::checkedCast(obj);
IceStorm::TopicPrx topic;
try {
topic = topicManager->retrieve("Weather");
}
catch (const IceStorm::NoSuchTopic&) {
topic = topicManager->create("Weather");
}
Ice::ObjectPrx pub = topic->getPublisher()->ice_oneway();
MonitorPrx monitor = MonitorPrx::uncheckedCast(pub);
while (true) {
Measurement m = getMeasurement();
monitor->report(m);
}
...
}
}
...
}
// Using a Publisher Object
Type Safety
IceStorm places the burden on the developer to ensure that publishers and
subscribers are using it correctly.
subscribers are using it correctly.
Oneway or Twoway?
IceStorm messages have oneway semantics (see Section 41.3.3), but publishers
may use either oneway or twoway invocations when sending messages to the
publisher object.
may use either oneway or twoway invocations when sending messages to the
publisher object.
The differences between the invocation styles affect a publisher in four ways:
1) Efficiency
Oneway invocations have the advantage in efficiency
2) Ordering
If ordering is important, use twoway invocations with a reliability QoS of ordered, or use a single thread in the subscriber
3) Reliability
If the loss of messages is unacceptable, or you are unable to address the potential causes of
lost oneway messages, then twoway invocations are recommended.
lost oneway messages, then twoway invocations are recommended.
4) Delays
Twoway invocations are more susceptible to these delays than oneway invocations.
Transports
Each publisher can select its own transport for message delivery, therefore the
transport used by a publisher to communicate with IceStorm has no effect on how
IceStorm delivers messages to its subscribers.
Each publisher can select its own transport for message delivery, therefore the
transport used by a publisher to communicate with IceStorm has no effect on how
IceStorm delivers messages to its subscribers.
Request Contexts
A request context is an optional argument of all remote invocations (see Section 28.11). If a publisher supplies a request context when publishing a
message, IceStorm will forward it intact to subscribers.
message, IceStorm will forward it intact to subscribers.
Ice::ObjectPrx pub = topic->getPublisher();
Ice::Context ctx;
ctx["_fwd"] = "Oz";
MonitorPrx monitor =
MonitorPrx::uncheckedCast(pub->ice_context(ctx));
Ice::Context ctx;
ctx["_fwd"] = "Oz";
MonitorPrx monitor =
MonitorPrx::uncheckedCast(pub->ice_context(ctx));
// Implementing a Subscriber
Our subscriber implementation takes the following steps:
1. Obtain a proxy for the TopicManager. This is the primary IceStorm object,
used by both publishers and subscribers.
2. Create an object adapter to host our Monitor servant.
3. Instantiate the Monitor servant and activate it with the object adapter.
4. Subscribe to the Weather topic.
5. Process report messages until shutdown.
6. Unsubscribe from the Weather topic.
1. Obtain a proxy for the TopicManager. This is the primary IceStorm object,
used by both publishers and subscribers.
2. Create an object adapter to host our Monitor servant.
3. Instantiate the Monitor servant and activate it with the object adapter.
4. Subscribe to the Weather topic.
5. Process report messages until shutdown.
6. Unsubscribe from the Weather topic.
/
#include <Ice/Ice.h>
#include <IceStorm/IceStorm.h>
#include <Monitor.h>
using namespace std;
class MonitorI : virtual public Monitor {
public:
virtual void report(const Measurement& m,
const Ice::Current&) {
cout << "Measurement report:" << endl
<< " Tower: " << m.tower << endl
<< " W Spd: " << m.windSpeed << endl
<< " W Dir: " << m.windDirection << endl
<< " Temp: " << m.temperature << endl
<< endl;
}
};
#include <IceStorm/IceStorm.h>
#include <Monitor.h>
using namespace std;
class MonitorI : virtual public Monitor {
public:
virtual void report(const Measurement& m,
const Ice::Current&) {
cout << "Measurement report:" << endl
<< " Tower: " << m.tower << endl
<< " W Spd: " << m.windSpeed << endl
<< " W Dir: " << m.windDirection << endl
<< " Temp: " << m.temperature << endl
<< endl;
}
};
/
int main(int argc, char* argv[])
{
...
Ice::ObjectPrx obj = communicator->stringToProxy(
"IceStorm/TopicManager:tcp -p 9999");
IceStorm::TopicManagerPrx topicManager =
IceStorm::TopicManagerPrx::checkedCast(obj);
Ice::ObjectAdapterPtr adapter =
communicator->createObjectAdapter("MonitorAdapter");
MonitorPtr monitor = new MonitorI;
Ice::ObjectPrx proxy = adapter->
addWithUUID(monitor)->ice_oneway();
IceStorm::TopicPrx topic;
try {
topic = topicManager->retrieve("Weather");
IceStorm::QoS qos;
topic->subscribeAndGetPublisher(qos, proxy);
}
catch (const IceStorm::NoSuchTopic&) {
// Error! No topic found!
...
}
adapter->activate();
communicator->waitForShutdown();
topic->unsubscribe(proxy);
...
}
{
...
Ice::ObjectPrx obj = communicator->stringToProxy(
"IceStorm/TopicManager:tcp -p 9999");
IceStorm::TopicManagerPrx topicManager =
IceStorm::TopicManagerPrx::checkedCast(obj);
Ice::ObjectAdapterPtr adapter =
communicator->createObjectAdapter("MonitorAdapter");
MonitorPtr monitor = new MonitorI;
Ice::ObjectPrx proxy = adapter->
addWithUUID(monitor)->ice_oneway();
IceStorm::TopicPrx topic;
try {
topic = topicManager->retrieve("Weather");
IceStorm::QoS qos;
topic->subscribeAndGetPublisher(qos, proxy);
}
catch (const IceStorm::NoSuchTopic&) {
// Error! No topic found!
...
}
adapter->activate();
communicator->waitForShutdown();
topic->unsubscribe(proxy);
...
}