initialisationhelper.h 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  1. /******************************************************************************
  2. *
  3. * package: Log4Qt
  4. * file: initialisationhelper.h
  5. * created: September 2007
  6. * author: Martin Heinrich
  7. *
  8. *
  9. * changes: Sep 2008, Martin Heinrich:
  10. * - Replaced usage of q_atomic_test_and_set_ptr with
  11. * QBasicAtomicPointer
  12. *
  13. *
  14. * Copyright 2007 - 2008 Martin Heinrich
  15. *
  16. * Licensed under the Apache License, Version 2.0 (the "License");
  17. * you may not use this file except in compliance with the License.
  18. * You may obtain a copy of the License at
  19. *
  20. * http://www.apache.org/licenses/LICENSE-2.0
  21. *
  22. * Unless required by applicable law or agreed to in writing, software
  23. * distributed under the License is distributed on an "AS IS" BASIS,
  24. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  25. * See the License for the specific language governing permissions and
  26. * limitations under the License.
  27. *
  28. ******************************************************************************/
  29. #ifndef LOG4QT_HELPERS_INITIALISATIONHELPER_H
  30. #define LOG4QT_HELPERS_INITIALISATIONHELPER_H
  31. /******************************************************************************
  32. * Dependencies
  33. ******************************************************************************/
  34. #include <QtCore/QAtomicPointer>
  35. #include <QtCore/QHash>
  36. #include <QtCore/QString>
  37. #if QT_VERSION >= QT_VERSION_CHECK(4, 4, 0)
  38. # ifndef Q_ATOMIC_POINTER_TEST_AND_SET_IS_ALWAYS_NATIVE
  39. # warning "QAtomicPointer test and set is not native. The macros Log4Qt::LOG4QT_GLOBAL_STATIC and Log4Qt::LOG4QT_IMPLEMENT_INSTANCE are not thread-safe."
  40. # endif
  41. #endif
  42. /******************************************************************************
  43. * Declarations
  44. ******************************************************************************/
  45. class QMutex;
  46. namespace Log4Qt
  47. {
  48. /*!
  49. * LOG4QT_GLOBAL_STATIC declares a static function \a FUNCTION that
  50. * returns a pointer to a singleton object of the type \a TYPE.
  51. *
  52. * The macro uses a static variable to store a pointer to the singleton
  53. * object. On the first invocation an object of the type \a TYPE is created
  54. * on the heap and the pointer is set. Any further invocations will return
  55. * the stored pointer. If multiple threads are accessing the function
  56. * without the pointer being set, each thread will create an object of the
  57. * type \a TYPE. The threads that find the pointer already been set will
  58. * delete their object. The singleton object will not be deleted during static
  59. * de-initialisation.
  60. *
  61. * The following example uses a global global mutex object to synchronise
  62. * access to a static member variable.
  63. *
  64. * \code
  65. * #file: myclass.h
  66. *
  67. * class MyClass
  68. * {
  69. * public:
  70. * MyClass();
  71. * ~MyClass();
  72. * private:
  73. * static qint64 msObjectCount;
  74. * }
  75. * \endcode
  76. * \code
  77. * #file: myclass.cpp
  78. *
  79. * #include myclass.h
  80. *
  81. * LOG4QT_GLOBAL_STATIC(QMutex, class_guard)
  82. *
  83. * MyClass::MyClass()
  84. * {
  85. * QMutexLocker(class_guard());
  86. * msObjectCount++;
  87. * }
  88. *
  89. * MyClass::~MyClass()
  90. * {
  91. * QMutexLocker(class_guard());
  92. * msObjectCount--;
  93. * }
  94. *
  95. * qint64 MyClass::msObjectCount = 0;
  96. * \endcode
  97. *
  98. * \note The function created by the macro is thread-safe.
  99. *
  100. * \sa \ref Log4Qt::LOG4QT_IMPLEMENT_INSTANCE "LOG4QT_IMPLEMENT_INSTANCE",
  101. * \ref Log4Qt::InitialisationHelper "InitialisationHelper"
  102. */
  103. #if QT_VERSION < QT_VERSION_CHECK(4, 4, 0)
  104. #define LOG4QT_GLOBAL_STATIC(TYPE, FUNCTION) \
  105. static volatile TYPE *sp_global_static_##FUNCTION = 0; \
  106. TYPE *FUNCTION() \
  107. { \
  108. if (!sp_global_static_##FUNCTION) \
  109. { \
  110. TYPE *p_temp = new TYPE; \
  111. if (!q_atomic_test_and_set_ptr(&sp_global_static_##FUNCTION, \
  112. 0, p_temp)) \
  113. delete p_temp; \
  114. } \
  115. return const_cast<TYPE *>(sp_global_static_##FUNCTION); \
  116. }
  117. #elif QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
  118. #define LOG4QT_GLOBAL_STATIC(TYPE, FUNCTION) \
  119. static QBasicAtomicPointer<TYPE > sp_global_static_##FUNCTION = \
  120. Q_BASIC_ATOMIC_INITIALIZER(0); \
  121. TYPE *FUNCTION() \
  122. { \
  123. if (!sp_global_static_##FUNCTION) \
  124. { \
  125. TYPE *p_temp = new TYPE; \
  126. if (!sp_global_static_##FUNCTION.testAndSetOrdered(0, \
  127. p_temp)) \
  128. delete p_temp; \
  129. } \
  130. return sp_global_static_##FUNCTION; \
  131. }
  132. #else
  133. #define LOG4QT_GLOBAL_STATIC(TYPE, FUNCTION) \
  134. static QBasicAtomicPointer<TYPE > sp_global_static_##FUNCTION = \
  135. Q_BASIC_ATOMIC_INITIALIZER(0); \
  136. TYPE *FUNCTION() \
  137. { \
  138. if (!sp_global_static_##FUNCTION.loadAcquire()) \
  139. { \
  140. TYPE *p_temp = new TYPE; \
  141. if (!sp_global_static_##FUNCTION.testAndSetOrdered(0, \
  142. p_temp)) \
  143. delete p_temp; \
  144. } \
  145. return sp_global_static_##FUNCTION.loadAcquire(); \
  146. }
  147. #endif
  148. /*!
  149. * LOG4QT_IMPLEMENT_INSTANCE implements an instance function for a
  150. * singleton class \a TYPE.
  151. *
  152. * The function works like the one created by
  153. * \ref Log4Qt::LOG4QT_GLOBAL_STATIC "LOG4QT_GLOBAL_STATIC".
  154. *
  155. * The following example illustrates how to use the macro to create a
  156. * singleton class:
  157. *
  158. * \code
  159. * #file: mysingleton.h
  160. *
  161. * class MySingleton
  162. * {
  163. * private:
  164. * MySingleton();
  165. * ~MySingleton();
  166. * public:
  167. * MySingleton *instance();
  168. * }
  169. * \endcode
  170. * \code
  171. * #file: mysingleton.cpp
  172. *
  173. * #include mysingleton.h
  174. *
  175. * MySingleton::MySingleton()
  176. * {}
  177. *
  178. * MySingleton::~MySingleton()
  179. * {}
  180. *
  181. * LOG4QT_IMPLEMENT_INSTANCE(MySingleton)
  182. *
  183. * \endcode
  184. *
  185. * \note The function created by the macro is thread-safe.
  186. *
  187. * \sa \ref Log4Qt::LOG4QT_GLOBAL_STATIC "LOG4QT_GLOBAL_STATIC",
  188. * \ref Log4Qt::InitialisationHelper "InitialisationHelper"
  189. */
  190. #if QT_VERSION < QT_VERSION_CHECK(4, 4, 0)
  191. #define LOG4QT_IMPLEMENT_INSTANCE(TYPE) \
  192. static TYPE *sp_singleton_##TYPE = 0; \
  193. TYPE *TYPE::instance() \
  194. { \
  195. if (!sp_singleton_##TYPE) \
  196. { \
  197. TYPE *p_temp = new TYPE; \
  198. if (!q_atomic_test_and_set_ptr(&sp_singleton_##TYPE, \
  199. 0, p_temp)) \
  200. delete p_temp; \
  201. } \
  202. return sp_singleton_##TYPE; \
  203. }
  204. #elif QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
  205. #define LOG4QT_IMPLEMENT_INSTANCE(TYPE) \
  206. static QBasicAtomicPointer<TYPE > sp_singleton_##TYPE = \
  207. Q_BASIC_ATOMIC_INITIALIZER(0); \
  208. TYPE *TYPE::instance() \
  209. { \
  210. if (!sp_singleton_##TYPE) \
  211. { \
  212. TYPE *p_temp = new TYPE; \
  213. if (!sp_singleton_##TYPE.testAndSetOrdered(0, p_temp)) \
  214. delete p_temp; \
  215. } \
  216. return sp_singleton_##TYPE; \
  217. }
  218. #else
  219. #define LOG4QT_IMPLEMENT_INSTANCE(TYPE) \
  220. static QBasicAtomicPointer<TYPE > sp_singleton_##TYPE = \
  221. Q_BASIC_ATOMIC_INITIALIZER(0); \
  222. TYPE *TYPE::instance() \
  223. { \
  224. if (!sp_singleton_##TYPE.loadAcquire()) \
  225. { \
  226. TYPE *p_temp = new TYPE; \
  227. if (!sp_singleton_##TYPE.testAndSetOrdered(0, p_temp)) \
  228. delete p_temp; \
  229. } \
  230. return sp_singleton_##TYPE.loadAcquire(); \
  231. }
  232. #endif
  233. /*!
  234. * \brief The class InitialisationHelper performs static initialisation
  235. * tasks.
  236. *
  237. * The InitialisationHelper is either created on the first call or through
  238. * static initialisation. It will capture the programs startup time,
  239. * which can be retrieved using startTime(). The system environment
  240. * is analysed for package related definitions. The result is available
  241. * over environmentSettings(). The packages custom types are registered with
  242. * the Qt type system.
  243. *
  244. * Settings for the package can be retrieved using setting(). Two macros
  245. * are available to help with the creation of singletons / global static
  246. * objects (\ref Log4Qt::LOG4QT_GLOBAL_STATIC "LOG4QT_GLOBAL_STATIC" and
  247. * \ref Log4Qt::LOG4QT_IMPLEMENT_INSTANCE "LOG4QT_IMPLEMENT_INSTANCE").
  248. *
  249. * \note All the functions declared in this class are thread-safe.
  250. *
  251. * \sa \ref Init "Initialization procedure",
  252. */
  253. class InitialisationHelper
  254. {
  255. private:
  256. InitialisationHelper();
  257. InitialisationHelper(const InitialisationHelper &rOther); // Not implemented
  258. virtual ~InitialisationHelper();
  259. InitialisationHelper &operator=(const InitialisationHelper &rOther); // Not implemented
  260. public:
  261. /*!
  262. * Returns a hash with the settings retrieved from the system
  263. * environment on startup.
  264. *
  265. * The following table shows the environment variables taken into
  266. * account and the setting key used for them.
  267. *
  268. * <table align="center" border="1" cellpadding="2" cellspacing="0" bordercolor="#84b0c7">
  269. * <tr bgcolor="#d5e1e8">
  270. * <th width="25%"> Environment variable </th>
  271. * <th width="25%"> Setting key </th>
  272. * </tr><tr>
  273. * <td> LOG4QT_DEBUG </td>
  274. * <td> Debug </td>
  275. * </tr><tr bgcolor="#ffffff">
  276. * <td> LOG4QT_DEFAULTINITOVERRIDE </td>
  277. * <td> DefaultInitOverride </td>
  278. * </tr><tr>
  279. * <td> LOG4QT_CONFIGURATION </td>
  280. * <td> Configuration </td>
  281. * </tr><tr bgcolor="#ffffff">
  282. * <td> LOG4QT_CONFIGURATORCLASS </td>
  283. * <td> ConfiguratorClass </td>
  284. * </tr>
  285. * </table>
  286. *
  287. * \sa \ref Env "Environment Variables",
  288. * setting()
  289. */
  290. static QHash<QString, QString> environmentSettings();
  291. /*!
  292. * Returns the InitialisationHelper instance.
  293. */
  294. static InitialisationHelper *instance();
  295. /*!
  296. * Returns the value for the setting \a rKey or \a rDefault, if it is
  297. * not defined.
  298. *
  299. * A setting can be either defined by an environment variable or by a
  300. * key in the application setting. The function will first test the
  301. * settings made by environment variables for the key \a rKey using
  302. * environmentSettings(). If the key is not present and a
  303. * QCoreApplication exists, the application settings are tested for
  304. * the key \a rKey in the group \c %Log4Qt.
  305. *
  306. * The following setting exists:
  307. *
  308. * <table align="center" border="1" cellpadding="2" cellspacing="0" bordercolor="#84b0c7">
  309. * <tr bgcolor="#d5e1e8">
  310. * <th width="25%"> Setting key </th>
  311. * <th> Description </th>
  312. * </tr><tr>
  313. * <td> Debug </td>
  314. * <td> The variable controls the Level value for the logger
  315. * LogManager::logLogger(). If the value is a valid Level string,
  316. * the level for the logger is set to the level. If the value is not
  317. * a valid Level string, \ref Level::DEBUG_INT "DEBUG_INT" is used.
  318. * Otherwise \ref Level::ERROR_INT "ERROR_INT" is used. </td>
  319. * </tr><tr bgcolor="#ffffff">
  320. * <td> DefaultInitOverride </td>
  321. * <td> The variable controls the \ref Init "initialization procedure"
  322. * performed by the \ref LogManager "LogManager" on startup.
  323. * If it is set to any other value then \c false the \ref Init
  324. * "initialization procedure" is skipped.</td>
  325. * </tr><tr>
  326. * <td> Configuration </td>
  327. * <td> Specifies the configuration file used for initialising the package.</td>
  328. * </tr><tr bgcolor="#ffffff">
  329. * <td> ConfiguratorClass </td>
  330. * <td> Specifies the configurator class used for initialising the package.</td>
  331. * </tr>
  332. * </table>
  333. *
  334. * \sa environmentSettings(), \ref Env "Environment Variables",
  335. * \ref Init "Initialization procedure",
  336. * LogManager::configureLogLogger(), LogManager::startup()
  337. */
  338. static QString setting(const QString &rKey,
  339. const QString &rDefault = QString());
  340. /*!
  341. * Returns the start time of the program as the number of milliseconds
  342. * that have passed since 1970-01-01T00:00:00,000, Coordinated
  343. * Universal Time (Qt::UTC).
  344. *
  345. * \sa DateTime::fromMilliSeconds(),
  346. * DateTime::toMilliSeconds()
  347. */
  348. static qint64 startTime();
  349. private:
  350. void doInitialiseEnvironmentSettings();
  351. void doRegisterTypes();
  352. QString doSetting(const QString &rKey,
  353. const QString &rDefault) const;
  354. static bool shutdown();
  355. static bool staticInitialisation();
  356. private:
  357. // QMutex mObjectGuard;
  358. const qint64 mStartTime;
  359. QHash <QString, QString> mEnvironmentSettings;
  360. static bool msStaticInitialisation;
  361. #ifndef QT_NO_DEBUG_STREAM
  362. // Needs to be friend to access details
  363. friend QDebug operator<<(QDebug debug,
  364. const InitialisationHelper &rInitialisationHelper);
  365. #endif // QT_NO_DEBUG_STREAM
  366. };
  367. /**************************************************************************
  368. * Operators, Helper
  369. **************************************************************************/
  370. #ifndef QT_NO_DEBUG_STREAM
  371. /*!
  372. * \relates InitialisationHelper
  373. *
  374. * Writes all object member variables to the given debug stream \a rDebug and
  375. * returns the stream.
  376. *
  377. * <tt>
  378. * %InitialisationHelper(InitialisationHelper(starttime:1193883677438(
  379. * QDateTime("Wed Oct 31 21:21:17 2007") )
  380. * environmentsettings: QHash(("configuration", "\myapp.log4j")
  381. * ("Debug", "DEBUG")) ) )
  382. * </tt>
  383. * \sa QDebug, InitialisationHelper::logManager()
  384. */
  385. QDebug operator<<(QDebug debug,
  386. const InitialisationHelper &rInitialisationHelper);
  387. #endif // QT_NO_DEBUG_STREAM
  388. /**************************************************************************
  389. * Inline
  390. **************************************************************************/
  391. inline QHash<QString, QString> InitialisationHelper::environmentSettings()
  392. { // QMutexLocker locker(&instance()->mObjectGuard); // Constant for object lifetime
  393. return instance()->mEnvironmentSettings; }
  394. inline QString InitialisationHelper::setting(const QString &rKey,
  395. const QString &rDefault)
  396. { // QMutexLocker locker(&instance()->mObjectGuard); // Reentrant and const
  397. return instance()->doSetting(rKey, rDefault); }
  398. inline qint64 InitialisationHelper::startTime()
  399. { // QMutexLocker locker(&instance()->mObjectGuard); // Constant for object lifetime
  400. return instance()->mStartTime; }
  401. } // namespace Log4Qt
  402. // Q_DECLARE_TYPEINFO(Log4Qt::InitialisationHelper, Q_COMPLEX_TYPE); // use default
  403. #endif // LOG4QT_HELPERS_INITIALISATIONHELPER_H