1 /*------------------------------------------------------------------------------
  2 Name:      Global.cpp
  3 Project:   xmlBlaster.org
  4 Copyright: xmlBlaster.org, see xmlBlaster-LICENSE file
  5 Comment:   Create unique timestamp
  6 Version:   $Id: Global.cpp 18007 2011-10-12 21:37:44Z ruff $
  7 ------------------------------------------------------------------------------*/
  8 #include <client/protocol/CbServerPluginManager.h>
  9 #include <util/dispatch/DispatchManager.h>
 10 #include <util/Timeout.hpp>
 11 #include <algorithm>
 12 #include <util/lexical_cast.h>
 13 #include <util/Global.h>
 14 
 15 // For usage():
 16 #include <util/qos/address/Address.h>
 17 #include <util/qos/address/CallbackAddress.h>
 18 #include <util/qos/storage/MsgUnitStoreProperty.h>
 19 #include <util/qos/storage/ClientQueueProperty.h>
 20 #include <util/qos/storage/CbQueueProperty.h>
 21 #if defined(XMLBLASTER_MSXML_PLUGIN)
 22 #  error Implement Microsoft XML parser for /DXMLBLASTER_MSXML_PLUGIN
 23 #else  // XMLBLASTER_XERCES_PLUGIN
 24 #  include <util/parser/Sax2XercesParser.h>
 25 #endif
 26 #ifdef COMPILE_SOCKET_PLUGIN
 27 #  include <client/protocol/socket/SocketDriver.h>
 28 #endif
 29 #ifdef COMPILE_CORBA_PLUGIN
 30 #  include <client/protocol/corba/CorbaDriver.h>
 31 #endif
 32 #ifdef XMLBLASTER_COMPILE_LOG4CPLUS_PLUGIN
 33 #  include<util/Log4cplus.h>
 34 #endif
 35 
 36 #if !defined(XMLBLASTER_NO_RCSID)
 37    /*
 38    Add the exact version of the C++ client library, this is for examination
 39    with for example the UNIX 'strings' command only.
 40    If it makes problem just set -DXMLBLASTER_NO_RCSID
 41    */
 42 #  if defined(__GNUC__) || defined(__ICC)
 43       // To support query state with 'ident libxmlBlasterClient.so' or 'what libxmlBlasterClient.so'
 44       // or 'strings libxmlBlasterClient.so  | grep Global.cpp'
 45       static const char *rcsid_GlobalCpp  __attribute__ ((unused)) =  "@(#) $Id: Global.cpp 18007 2011-10-12 21:37:44Z ruff $ xmlBlaster @version@ #@revision.number@";
 46 #  elif defined(__SUNPRO_CC)
 47       static const char *rcsid_GlobalCpp  =  "@(#) $Id: Global.cpp 18007 2011-10-12 21:37:44Z ruff $ xmlBlaster @version@ #@revision.number@";
 48 #  endif
 49 #endif
 50 
 51 namespace org { namespace xmlBlaster { namespace util {
 52 //#if __GNUC__ == 2 || defined(__sun)
 53 #if __GNUC__ == 2 || defined(__SUNPRO_CC)
 54 //#if __GNUC__ == 2
 55   // Problems with g++ 2.95.3 and template<>
 56 #else
 57 /** Specialization for bool to return "true" instead of "1", see lexical_cast.h */
 58 template<> std::string lexical_cast(bool arg)
 59 {
 60    return (arg) ? XMLBLASTER_TRUE : XMLBLASTER_FALSE; // "true", "false"
 61 }
 62 /** Specialization for bool to return "true" instead of "1", see lexical_cast.h */
 63 template<> const char * lexical_cast(bool arg)
 64 {
 65    return (arg) ? XMLBLASTER_TRUE.c_str() : XMLBLASTER_FALSE.c_str();
 66 }
 67 
 68 template<> bool lexical_cast(std::string arg)
 69 {
 70    return arg == "1" || arg == XMLBLASTER_TRUE || arg == "TRUE"; // "true"
 71 }
 72 
 73 template<> bool lexical_cast(const char* arg)
 74 {
 75    return lexical_cast<bool>(std::string(arg));
 76 }
 77 
 78 
 79 /** Specialization for std::string to return std::string as default impl. crashes on sun with gcc 
 80     Don't use template<> std::string lexical_cast(const std::string& arg) since it won't be 
 81     invoked (instead the default template will be invoked)
 82 */
 83 template<> std::string lexical_cast(std::string arg)
 84 {
 85    return arg;
 86 }
 87 
 88 #endif
 89 using namespace std;
 90 using namespace org::xmlBlaster::util::dispatch;
 91 using namespace org::xmlBlaster::client::protocol;
 92 
 93 Global::Global() : ME("Global"), pingerMutex_(), sessionName_(0)
 94 {
 95    cbServerPluginManager_ = 0;
 96    pingTimer_             = 0;
 97    dispatchManager_       = 0;
 98    copy();
 99    property_              = new Property();
100    isInitialized_ = false;
101 
102    if(global_ == NULL)
103      global_ = this;
104 }
105 
106 void Global::copy()
107 {
108    args_        = 0 ;
109    argv_        = NULL;
110    property_    = NULL;
111    pingTimer_   = NULL;
112    dispatchManager_ = NULL;
113    cbServerPluginManager_ = NULL;
114    id_          = "";
115 }
116 
117 /*
118 Global::Global(const Global& global) : ME("Global")
119 {
120    args_ = global.args_;
121    argv_ = global.argv_;
122 }
123 */
124 
125 Global& Global::operator =(const Global &)
126 {
127    copy();
128    return *this;
129 }
130 
131 
132 Global::~Global()
133 {
134    try {
135       delete property_;
136       delete cbServerPluginManager_;
137       delete pingTimer_;
138       delete dispatchManager_;
139    }
140    catch (...) {
141    }
142    try {
143       if (this != global_) {
144          global_->destroyInstance(this->getInstanceName());
145       }
146       else {
147          globalRefMap_.clear();
148          globalMap_.clear();
149       }
150    }
151    catch (...) {
152    }
153 }
154 
155 Global *Global::global_ = NULL;
156 Global::GlobalRefMap Global::globalRefMap_;
157 Global::GlobalMap Global::globalMap_;
158 thread::Mutex Global::globalMutex_;
159 
160 //-----------------
161 // Global.cpp modification
162 Global& Global::getInstance(string name)
163 {
164    if (name == "" || name == "default") {
165       if (global_ == NULL) {
166          global_ = new Global();
167          Object_Lifetime_Manager::instance()->manage_object(Constants::XB_GLOBAL_KEY, global_);  // if not pre-allocated.
168       }
169       return *global_;
170    }
171 
172    GlobalMap::iterator iter = globalMap_.find(name);
173    if (iter != globalMap_.end()) {
174       Global* glP = (*iter).second;
175       return *glP;
176    }
177 
178    throw XmlBlasterException(USER_ILLEGALARGUMENT,
179          "UNKNOWN NODE",
180          string("Global::getInstance"),
181             "The Global instance '" + name + "' is not known");
182 }
183 
184 GlobalRef Global::createInstance(const string& name, const Property::MapType *propertyMapP, bool holdReferenceCount)
185 {
186    if (name == "") {
187      throw XmlBlasterException(USER_ILLEGALARGUMENT,
188                   "UNKNOWN NODE",
189                   string("Global::createInstance"),
190                    "Please call createInstance with none empty name argument");
191    }
192    if (name == "default") {
193      throw XmlBlasterException(USER_ILLEGALARGUMENT,
194                   "UNKNOWN NODE",
195                   string("Global::createInstance"),
196                    "Please call getInstance to access the 'default' Global instance");
197    }
198 
199    thread::Lock lock(globalMutex_);
200 
201    {
202       GlobalRefMap::iterator iter = globalRefMap_.find(name);
203       if (iter != globalRefMap_.end()) {
204          GlobalRef gr = (*iter).second;
205          return gr;
206       }
207    }
208    {
209       GlobalMap::iterator iter = globalMap_.find(name);
210       if (iter != globalMap_.end()) {
211          //Global* glP = (*iter).second;
212          throw XmlBlasterException(USER_ILLEGALARGUMENT,
213                      "UNKNOWN NODE",
214                      string("Global::createInstance"),
215                       "Please call getInstance to access the '" + name + "' Global instance");
216       }
217    }
218 
219    if (holdReferenceCount) {
220       GlobalRef globRef = GlobalRef(new Global());
221       globRef->instanceName_ = name;
222       if (propertyMapP != NULL) {
223          globRef->initialize(*propertyMapP);
224       }
225       GlobalRefMap::value_type el(name, globRef);
226       globalRefMap_.insert(el);
227       return globRef;
228    }
229    else {
230       Global* glP = new Global();
231       glP->instanceName_ = name;
232       if (propertyMapP != NULL) {
233          glP->initialize(*propertyMapP);
234       }
235       GlobalMap::value_type el(name, glP);
236       globalMap_.insert(el);
237       return GlobalRef(glP);
238    }
239 }
240 
241 const string& Global::getInstanceName()
242 {
243    if (this->instanceName_ == "" && this == global_) {
244       this->instanceName_ = "default";
245    }
246    return this->instanceName_;
247 }
248 
249 bool Global::containsInstance(const std::string &name)
250 {
251    bool ret = globalRefMap_.count(name) != 0;
252    if (ret) {
253       return true;
254    }
255    return globalMap_.count(name) != 0;
256 }
257 
258 bool Global::destroyInstance(const std::string &name)
259 {
260    if (name == "") {
261       return false;
262    }
263    if (name == "default") {
264      throw XmlBlasterException(USER_ILLEGALARGUMENT,
265                   "UNKNOWN NODE",
266                   string("Global::destroyInstance"),
267                    "The 'default' Global instance is handled by the life time manager and can't be destroyed manually");
268    }
269    thread::Lock lock(globalMutex_);
270    {
271       bool ret = globalRefMap_.count(name) != 0;
272       if (ret) {
273          globalRefMap_.erase(name);
274          //cout << "DEBUG ONLY: " << name << " RefSize=" + lexical_cast<std::string>(globalRefMap_.size()) <<
275          //     " Size=" + lexical_cast<std::string>(globalMap_.size()) << endl;
276          return ret;
277       }
278    }
279    {
280       bool ret = globalMap_.count(name) != 0;
281       if (ret) {
282          globalMap_.erase(name);
283          //cout << "DEBUG ONLY: " << name << " Size=" + lexical_cast<std::string>(globalMap_.size()) <<
284          //     " RefSize=" + lexical_cast<std::string>(globalRefMap_.size()) << endl;
285          return ret;
286       }
287    }
288    return false;
289 }
290 
291 Global& Global::initialize(int args, const char * const argv[])
292 {
293    if (isInitialized_) {
294       getLog("org.xmlBlaster.util").warn(ME, "::initialize: the global is already initialized. Ignoring this initialization");
295       return *this;
296    }
297    args_     = args;
298    argv_     = argv;
299    if (property_ != NULL) delete property_;
300    property_ = NULL;
301    property_ = new Property(args, argv);
302    property_->loadPropertyFile(); // load xmlBlaster.properties
303    isInitialized_ = true;
304    return *this;
305 }
306 
307 Global& Global::initialize(const Property::MapType &propertyMap)
308 {
309    if (isInitialized_) {
310       getLog("org.xmlBlaster.util").warn(ME, "::initialize: the global is already initialized. Ignoring this initialization");
311       return *this;
312    }
313    args_     = 0;
314    argv_     = 0;
315    if (property_ != NULL) delete property_;
316    property_ = NULL;
317    property_ = new Property(propertyMap);
318    property_->loadPropertyFile(); // load xmlBlaster.properties
319    isInitialized_ = true;
320    return *this;
321 }
322 
323 void Global::fillArgs(ArgsStruct_T &args)
324 {
325    if (property_ == 0) {
326       args.argc = 0;
327       args.argv = 0;
328       return;
329    }
330    const Property::MapType &prmap = property_->getPropertyMap();
331    args.argc = 2*prmap.size()+1;
332    args.argv = new char *[args.argc];
333 
334    string execName = (argv_ != 0 && args_ > 0) ? argv_[0] : "xmlBlasterClient";
335    args.argv[0] = new char[execName.length()+1];
336    strcpy(args.argv[0],execName.c_str());
337    int i = 1;
338    Property::MapType::const_iterator ipm;
339    for (ipm = prmap.begin(); ipm != prmap.end(); ++ipm) {
340       args.argv[i] = new char[(*ipm).first.size()+2];
341       *(args.argv[i]) = '-';
342       strcpy(args.argv[i]+1, (*ipm).first.c_str()); i++;
343       args.argv[i] = new char[(*ipm).second.size()+1];
344       strcpy(args.argv[i], (*ipm).second.c_str()); i++;
345    }
346 }
347 
348 void Global::freeArgs(ArgsStruct_T &args)
349 {
350    for (size_t i=0; i<args.argc; i++)
351       delete [] args.argv[i];
352    delete [] args.argv;
353    args.argc = 0;
354 }
355 
356 bool Global::wantsHelp()
357 {
358    return getProperty().getBoolProperty("help", false, false) ||
359           getProperty().getBoolProperty("-help", false, false) ||
360           getProperty().getBoolProperty("h", false, false) ||
361           getProperty().getBoolProperty("?", false, false); 
362 }
363 
364 string &Global::getVersion()
365 {
366    static string version = "@version@";  // is replaced by ant / build.xml to e.g. "0.901"
367    return version;
368 }
369 
370 string &Global::getRevisionNumber()
371 {
372    static string revisionNumber = "@revision.number@";  // is replaced by ant / build.xml to subversions revision number, e.g. "1207"
373    if (revisionNumber.find("@",0) != 0 && revisionNumber!=string("${revision.number}"))
374       return revisionNumber;
375    return getVersion();
376 }
377 
378 string &Global::getReleaseId()
379 {
380    if (Global::getVersion() == Global::getRevisionNumber())
381       return Global::getVersion();
382    static string releaseId = Global::getVersion() + " #" + Global::getRevisionNumber();
383         return releaseId;
384 }
385 
386 string &Global::getBuildTimestamp()
387 {
388    static string timestamp = "@build.timestamp@"; // is replaced by ant / build.xml to e.g. "03/20/2003 10:22 PM";
389    return timestamp;
390 }
391 
392 string& Global::getCompiler()
393 {
394    static string cppCompiler = "@cpp.compiler@"; // is replaced by ant / build.xml to e.g. "g++";
395    return cppCompiler;
396 }
397 
398 
399 /**
400  * Is overwritten be environment, for example  "-protocol IOR"
401  */
402 string& Global::getDefaultProtocol()
403 {
404 #  if COMPILE_SOCKET_PLUGIN
405    static string defaultProtocol = Constants::SOCKET;
406 #  elif COMPILE_CORBA_PLUGIN
407    static string defaultProtocol = Constants::IOR;
408 #  else
409    log_.error(ME, "Missing protocol in getDefaultProtocol(), please set COMPILE_CORBA_PLUGIN or COMPILE_SOCKET_PLUGIN on compilation");
410 #  endif
411    return defaultProtocol;
412 }
413 
414 Property& Global::getProperty() const
415 {
416    if (property_ == NULL)
417      throw XmlBlasterException(USER_CONFIGURATION,
418                                "UNKNOWN NODE",
419                                ME + string("::getProperty"), "Please call initialize to init Property");
420    return *property_;
421 }
422 
423 string Global::usage()
424 {
425    string sb;
426    sb += "\n";
427    sb += "\nXmlBlaster C++ client " + Global::getReleaseId() + " compiled at " + Global::getBuildTimestamp() + " with " + Global::getCompiler();
428    sb += "\n";
429 //#  if COMPILE_SOCKET_PLUGIN && COMPILE_CORBA_PLUGIN
430    sb += "\n   -protocol SOCKET | IOR";
431    sb += "\n                       IOR for CORBA, SOCKET for our native protocol.";
432    sb += "\n";
433 //#  endif
434 #  ifdef COMPILE_SOCKET_PLUGIN
435       sb += org::xmlBlaster::client::protocol::socket::SocketDriver::usage();
436       sb += "\n   -logLevel           ERROR | WARN | INFO | TRACE | DUMP [WARN]";
437       sb += "\n                       NOTE: Switch on C++ logging simultaneously to see the traces";
438       sb += "\n                             as the C logging is redirected to the C++ logging library\n";
439       sb += "\n";
440 #  endif
441 #  ifdef COMPILE_CORBA_PLUGIN
442       sb += org::xmlBlaster::client::protocol::corba::CorbaDriver::usage();
443       sb += "\n";
444 #  endif
445 #  if defined(XMLBLASTER_MSXML_PLUGIN)
446 #     error Implement Microsoft XML parser for /DXMLBLASTER_MSXML_PLUGIN
447 #  else  // XMLBLASTER_XERCES_PLUGIN
448    sb += org::xmlBlaster::util::parser::Sax2Parser::usage();
449    sb += "\n";
450 #  endif
451    sb += org::xmlBlaster::util::qos::SessionQos::usage();
452    sb += "\n";
453    sb += org::xmlBlaster::util::qos::address::Address(Global::getInstance()).usage();
454    sb += "\n";
455    sb += org::xmlBlaster::util::qos::storage::ClientQueueProperty::usage();
456    sb += "\n";
457    //sb += org::xmlBlaster::util::qos::storage::MsgUnitStoreProperty::usage();
458    //sb += "\n";
459    sb += org::xmlBlaster::util::qos::address::CallbackAddress(Global::getInstance()).usage();
460    sb += "\n";
461    sb += org::xmlBlaster::util::qos::storage::CbQueueProperty::usage();
462    sb += "\n";
463    const I_Log& ll = getInstance().getLog();
464    sb += ll.usage();
465    return sb;
466    /*
467       StringBuffer sb = new StringBuffer(4028);
468       sb.append(org.xmlBlaster.client.XmlBlasterAccess.usage(this));
469       sb.append(logUsage());
470       return sb.toString();
471    */
472 }
473 
474 LogManager& Global::getLogManager()
475 {
476    return logManager_;
477 }
478 
479 I_Log& Global::getLog(const string &logName)
480 {
481    try {
482 #     if XMLBLASTER_COMPILE_LOG4CPLUS_PLUGIN==1
483          static bool first = true;
484          if (first) {
485             logManager_.setLogFactory("log4cplus", new Log4cplusFactory());
486             logManager_.initialize(getProperty().getPropertyMap());
487             first = false;
488          }
489          return logManager_.getLogFactory().getLog(logName);
490 #     else
491          return logManager_.getLogFactory().getLog(logName); // Use our default Log.cpp
492 #     endif
493    }
494    catch(...) {
495       throw XmlBlasterException(INTERNAL_UNKNOWN, "UNKNOWN NODE", ME + string("::getLog() failed to setup logging configuration"));
496    }
497 }
498 
499 int Global::getArgs()
500 {
501    return args_;
502 }
503 
504 const char * const* Global::getArgc()
505 {
506    return argv_;
507 }
508 
509 string Global::getLocalIP() const
510 {
511    // change this to a better way later ...
512    return string("127.0.0.1");
513 }
514 
515 string Global::getBootstrapHostname() const
516 {
517    return getProperty().getStringProperty(string("bootstrapHostname"), getLocalIP());
518    /* URL:
519    string bootstrapHostname = getProperty().getStringProperty(string("bootstrapHostname"), getLocalIP());
520    int bootstrapPort = getProperty().getIntProperty(string("bootstrapPort"), Constants::XMLBLASTER_PORT);
521    return "http://" + bootstrapHostname + ":" + lexical_cast<std::string>(bootstrapPort);
522    */
523 }
524 
525 string Global::getCbHostname() const
526 {
527 //   std::cout << "Global::getCbHostname implementation is not finished" << std::endl;
528    return getProperty().getStringProperty(string("bootstrapHostname"), getLocalIP());
529 }
530 
531 CbServerPluginManager& Global::getCbServerPluginManager()
532 {
533    if (cbServerPluginManager_ == NULL) {
534       cbServerPluginManager_ = new CbServerPluginManager(*this);
535    }
536    return *cbServerPluginManager_;
537 }
538 
539 DispatchManager& Global::getDispatchManager()
540 {
541    if (dispatchManager_ == NULL) {
542       dispatchManager_ = new DispatchManager(*this);
543    }
544    return *dispatchManager_;
545 }
546 
547 Timeout& Global::getPingTimer()
548 {
549    if (pingTimer_) return *pingTimer_;
550    thread::Lock lock(pingerMutex_);
551    { // this is synchronized. Test again if meanwhile it has been set ...
552       getLog("org.xmlBlaster.util").trace(ME, "::getPingTimer: creating the singleton 'ping timer'");
553       if (pingTimer_) return *pingTimer_;
554       pingTimer_ = new Timeout(*this, string("ping timer"));
555       return *pingTimer_;
556    }
557 }
558 
559 const string& Global::getBoolAsString(bool val)
560 {
561    return (val) ? XMLBLASTER_TRUE : XMLBLASTER_FALSE;
562    // return lexical_cast<std::string>(val); 
563    // gcc complains: warning: returning reference to temporary
564 }
565 
566 void Global::setSessionName(SessionNameRef sessionName)
567 {
568    sessionName_ = sessionName;
569 }
570 
571 SessionNameRef Global::getSessionName() const
572 {
573    return sessionName_;
574 }
575 
576 
577 /**
578  * The absolute session name. 
579  * Before connection it is temporay the relative session name
580  * and changed to the absolute session name after connection (when we know the cluster id)
581  * @return For example "/node/heron/client/joe/2"
582  */
583 string Global::getId() const
584 {
585    return id_;
586 }
587 
588 string Global::getImmutableId() const
589 {
590    return immutableId_;
591 }
592 
593 string Global::getStrippedId() const
594 {
595    return getStrippedString(id_);
596 }
597 
598 string Global::getStrippedImmutableId() const
599 {
600    return getStrippedString(immutableId_);
601 }
602 
603 string Global::getStrippedString(const string& text) const
604 {
605    string ret = text;
606    string::iterator
607      ref = remove(ret.begin(), ret.end(), '/'); // StringHelper.replaceAll(text, "/", "");
608    replace(ret.begin(), ref, '.', '_');         // StringHelper.replaceAll(strippedId, ".", "_");
609    replace(ret.begin(), ref, ':', '_');         // StringHelper.replaceAll(strippedId, ":", "_");
610    ref = remove(ret.begin(), ref, '\\');        // StringHelper.replaceAll(strippedId, "\\", "");
611    ret.erase(ref, ret.end());
612    return ret;
613 }       
614 
615 void Global::setId(const string& id) 
616 {
617    id_ = id;
618    resetInstanceId();
619 }
620 
621 void Global::setImmutableId(const string& id) 
622 {
623    immutableId_ = id;
624 }
625 
626 void Global::resetInstanceId() {
627    thread::Lock lock(globalMutex_);
628    instanceId_ = "";
629 }
630 
631 std::string Global::getInstanceId() const {
632    if (instanceId_ == "") {
633       thread::Lock lock(globalMutex_);
634       if (instanceId_ == "") {
635          Timestamp timestamp = TimestampFactory::getInstance().getTimestamp();
636          //ContextNode node(this, "instanceId",
637          //                 lexical_cast<std::string>(timestamp), getContextNode());
638          instanceId_ = getId() + "/instanceId/" + lexical_cast<std::string>(timestamp);
639       }
640    }
641    return instanceId_;
642 }
643 
644 std::string waitOnKeyboardHit(const std::string &str)
645 {
646    char ptr[256];
647    std::string retStr;
648 
649    // Flush input stream
650    while (true) {
651       cout.flush();
652       size_t ret = std::cin.rdbuf()->in_avail();
653       if (ret == 0) break;
654       std::cin.getline(ptr,255,'\n');
655    }
656 
657    // Request input
658    if (str != "")
659       std::cout << str;
660 
661    // Read input, ignore newlines
662    *ptr = 0;
663    bool first=true;
664    while (true) {
665       std::cin.getline(ptr,255,'\n');
666       if (strlen(ptr))
667          retStr = ptr;
668       else {
669          if (str != "" && !first)
670             std::cout << str;
671       }
672       first = false;
673 
674       size_t ret = std::cin.rdbuf()->in_avail();
675       if (ret == 0 && retStr != "") {
676          return retStr;
677       }
678    }
679 }
680 
681 }}} // namespace


syntax highlighted by Code2HTML, v. 0.9.1