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