1 /*------------------------------------------------------------------------------
2 Name: xmlBlaster/demo/c++/HelloWorld2.cpp
3 Project: xmlBlaster.org
4 Comment: C++ client example
5 Author: Michele Laghi
6 ------------------------------------------------------------------------------*/
7 #include <client/XmlBlasterAccess.h>
8 #include <util/Global.h>
9 #include <util/queue/I_Queue.h>
10
11 using namespace std;
12 using namespace org::xmlBlaster::util;
13 using namespace org::xmlBlaster::util::qos;
14 using namespace org::xmlBlaster::util::dispatch;
15 using namespace org::xmlBlaster::client;
16 using namespace org::xmlBlaster::client::qos;
17 using namespace org::xmlBlaster::client::key;
18 using namespace org::xmlBlaster::util::queue;
19
20 /**
21 * This client connects to xmlBlaster and subscribes to a message.
22 * <p>
23 * We then publish the message and receive it asynchronous in the update() method.
24 * </p>
25 * <p>
26 * Note that the CORBA layer is transparently hidden,
27 * and all code conforms to STD C++ (with STL).
28 * </p>
29 * <pre>
30 * Invoke: HelloWorld2
31 * </pre>
32 * @see <a href="http://www.xmlBlaster.org/xmlBlaster/doc/requirements/interface.html"
33 * target="others">xmlBlaster interface</a>
34 */
35 class HelloWorld2 : public I_Callback, // for the asynchroneous updates
36 public I_ConnectionProblems // notification of connection problems when failsafe
37 {
38 private:
39 string ME; // the string identifying this class when logging
40 Global& global_;
41 I_Log& log_; // the reference to the log object for this instance
42
43 public:
44 HelloWorld2(Global& glob)
45 : ME("HelloWorld2"),
46 global_(glob),
47 log_(glob.getLog("HelloWorld2")) // all logs written in this class are written to the
48 { // log channel called 'HelloWorld2'. To see the traces of this
49 // channel invoke -trace[HelloWorld2] true on the command line,
50 // then it will only switch on the traces for the demo channel
51 log_.info(ME, "Trying to connect to xmlBlaster with C++ client lib " + Global::getReleaseId() +
52 " from " + Global::getBuildTimestamp());
53 }
54
55 virtual ~HelloWorld2() // the constructor does nothing for the moment
56 {
57 }
58
59
60 bool reachedAlive(StatesEnum /*oldState*/, I_ConnectionsHandler* connectionsHandler)
61 {
62 I_Queue* queue = connectionsHandler->getQueue();
63 if (queue && queue->getNumOfEntries() > 0) {
64 log_.info(ME, "Clearing " + lexical_cast<std::string>(queue->getNumOfEntries()) + " entries from queue");
65 queue->clear();
66 }
67 log_.info(ME, "reconnected");
68 return true;
69 }
70
71 void reachedDead(StatesEnum /*oldState*/, I_ConnectionsHandler* /*connectionsHandler*/)
72 {
73 log_.info(ME, "lost connection");
74 }
75
76 void reachedPolling(StatesEnum /*oldState*/, I_ConnectionsHandler* connectionsHandler)
77 {
78 I_Queue* queue = connectionsHandler->getQueue();
79 if (queue) {
80 log_.info(ME, "Found " + lexical_cast<std::string>(queue->getNumOfEntries()) + " entries in client side queue");
81 }
82 log_.info(ME, "going to poll modus");
83 }
84
85 void execute()
86 {
87 long sleepMillis = global_.getProperty().get("sleep", 1000L);
88 try {
89 XmlBlasterAccess con(global_);
90 con.initFailsafe(this);
91
92 // Creates a connect qos with the user 'joe' and the password 'secret'
93 ConnectQos qos(global_, "joe", "secret");
94 /*
95 string user = "joe";
96 string pwd = "secret";
97
98 // Creates a connect qos with the user and password
99 // <session name="client/joe/session/1" ...>
100 ConnectQos qos(global_, user+"/session/1", pwd);
101
102 // Configure htpasswd security plugin
103 // <securityService type="htpasswd" version="1.0">
104 // <![CDATA[
105 // <user>joe</user>
106 // <passwd>secret</passwd>
107 // ]]>
108 // </securityService>
109 org::xmlBlaster::authentication::SecurityQos sec(global_, user, pwd, "htpasswd,1.0");
110 qos.setSecurityQos(sec);
111 */
112 log_.info(ME, string("connecting to xmlBlaster. Connect qos: ") + qos.toXml());
113
114
115 // connects to xmlBlaster and gives a pointer to this class to tell
116 // which update method to invoke when callbacks come from the server.
117 ConnectReturnQos retQos = con.connect(qos, this); // Login and register for updates
118 log_.info(ME, "successfully connected to xmlBlaster. Return qos: " + retQos.toXml());
119
120
121 // subscribe key. By invoking setOid you implicitly choose the 'EXACT' mode.
122 // If you want to subscribe with XPATH use setQueryString instead.
123 SubscribeKey subKey(global_);
124 subKey.setOid("HelloWorld2");
125 SubscribeQos subQos(global_);
126 subQos.setMultiSubscribe(false);
127 log_.info(ME, string("subscribing to xmlBlaster with key: ") + subKey.toXml() +
128 " and qos: " + subQos.toXml());
129
130 I_Queue* queue = con.getQueue();
131 if (queue && queue->getNumOfEntries() > 0) {
132 log_.info(ME, "Found " + lexical_cast<std::string>(queue->getNumOfEntries()) + " entries in client side connection queue");
133 //queue->clear();
134 }
135
136 SubscribeReturnQos subRetQos = con.subscribe(subKey, subQos);
137 log_.info(ME, string("successfully subscribed to xmlBlaster. Return qos: ") +
138 subRetQos.toXml());
139
140 // publish a message with the oid 'HelloWorld2'
141 PublishQos publishQos(global_);
142 PublishKey publishKey(global_);
143 publishKey.setOid("HelloWorld2");
144 MessageUnit msgUnit(publishKey, string("Hi"), publishQos);
145 log_.info(ME, string("publishing to xmlBlaster with message: ") + msgUnit.toXml());
146 PublishReturnQos pubRetQos = con.publish(msgUnit);
147 log_.info(ME, "successfully published to xmlBlaster. Return qos: " + pubRetQos.toXml());
148 try {
149 log_.info(ME, "Sleeping now for " + lexical_cast<string>(sleepMillis) + " msec ...");
150 org::xmlBlaster::util::thread::Thread::sleep(sleepMillis);
151 }
152 catch(const XmlBlasterException &e) {
153 log_.error(ME, e.toXml());
154 }
155
156 // peek a history queue (could be any queue, see reveive() method
157 string oid("topic/HelloWorld2");
158 int maxEntries = 4;
159 long timeout = 0;
160 bool consumable = false;
161 vector<MessageUnit> msgVec = con.receive(oid, maxEntries, timeout, consumable);
162 log_.info(ME, "Success, got " + lexical_cast<string>(msgVec.size()) + " messages");
163 for (size_t i=0; i<msgVec.size(); i++) {
164 string str = msgVec[i].getContentStr();
165 log_.info(ME, "Peeked history messages '" + str + "'");
166 }
167
168
169 log_.info(ME, "Hit a key to finish ...");
170 char ptr[1];
171 std::cin.read(ptr,1);
172
173 // now an update should have come. Its time to erase the message,
174 // otherwise you would get directly an update the next time you connect
175 // to the same xmlBlaster server.
176 // Specify which messages you want to erase. Note that you will get an
177 // update with the status of the UpdateQos set to 'ERASED'.
178 EraseKey eraseKey(global_);
179 eraseKey.setOid("HelloWorld2");
180 EraseQos eraseQos(global_);
181 log_.info(ME, string("erasing the published message. Key: ") + eraseKey.toXml() +
182 " qos: " + eraseQos.toXml());
183 vector<EraseReturnQos> eraseRetQos = con.erase(eraseKey, eraseQos);
184 for (size_t i=0; i < eraseRetQos.size(); i++ ) {
185 log_.info(ME, string("successfully erased the message. return qos: ") +
186 eraseRetQos[i].toXml());
187 }
188 org::xmlBlaster::util::thread::Thread::sleep(500); // wait for erase notification
189
190 log_.info(ME, "Disconnect, bye.");
191 DisconnectQos disconnectQos(global_);
192 con.disconnect(disconnectQos);
193 }
194 catch (const XmlBlasterException &e) {
195 log_.error(ME, e.toXml());
196 }
197 }
198
199 /**
200 * Callbacks from xmlBlaster arrive here.
201 */
202 string update(const string& sessionId, UpdateKey& updateKey,
203 const unsigned char* content,
204 long contentSize, UpdateQos& updateQos)
205 {
206 string contentStr(reinterpret_cast<char *>(const_cast<unsigned char *>(content)), contentSize);
207 log_.info(ME, "Received update message with secret sessionId '" + sessionId + "':" +
208 updateKey.toXml() +
209 "\n content=" + contentStr +
210 updateQos.toXml());
211 // if (true) throw XmlBlasterException(USER_UPDATE_ERROR, "HelloWorld2", "TEST");
212 return "";
213 }
214
215 };
216
217 #include <iostream>
218
219 /**
220 * Try
221 * <pre>
222 * HelloWorld2 -help
223 * </pre>
224 * for usage help
225 */
226 int main(int args, char ** argv)
227 {
228 try {
229 org::xmlBlaster::util::Object_Lifetime_Manager::init();
230 Global& glob = Global::getInstance();
231 glob.initialize(args, argv);
232
233 string intro = "XmlBlaster C++ client " + glob.getReleaseId() +
234 ", try option '-help' if you need usage informations.";
235 glob.getLog().info("HelloWorld2", intro);
236
237 if (glob.wantsHelp()) {
238 cout << Global::usage() << endl;
239 cout << endl << "HelloWorld2";
240 cout << endl << " -sleep Sleep after publishing [1000 millisec]" << endl;
241 cout << endl << "Example:" << endl;
242 cout << endl << "HelloWorld2 -trace true -sleep 2000";
243 cout << endl << "HelloWorld2 -dispatch/connection/delay 10000 -sleep 2000000" << endl << endl;
244 org::xmlBlaster::util::Object_Lifetime_Manager::fini();
245 return 1;
246 }
247
248 HelloWorld2 hello(glob);
249 hello.execute();
250 }
251 catch (XmlBlasterException &e) {
252 std::cerr << "Caught exception: " << e.getMessage() << std::endl;
253 }
254 catch (...) {
255 std::cerr << "Caught exception, exit" << std::endl;
256 }
257 org::xmlBlaster::util::Object_Lifetime_Manager::fini();
258 return 0;
259 }
syntax highlighted by Code2HTML, v. 0.9.1