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