ctkEAConfiguration.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. /*=============================================================================
  2. Library: CTK
  3. Copyright (c) German Cancer Research Center,
  4. Division of Medical and Biological Informatics
  5. Licensed under the Apache License, Version 2.0 (the "License");
  6. you may not use this file except in compliance with the License.
  7. You may obtain a copy of the License at
  8. http://www.apache.org/licenses/LICENSE-2.0
  9. Unless required by applicable law or agreed to in writing, software
  10. distributed under the License is distributed on an "AS IS" BASIS,
  11. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. See the License for the specific language governing permissions and
  13. limitations under the License.
  14. =============================================================================*/
  15. #include "ctkEAConfiguration_p.h"
  16. #include "ctkEventAdminService_p.h"
  17. #include "ctkEAMetaTypeProvider_p.h"
  18. #include "adapter/ctkEAFrameworkEventAdapter_p.h"
  19. #include "adapter/ctkEALogEventAdapter_p.h"
  20. #include "adapter/ctkEAPluginEventAdapter_p.h"
  21. #include "adapter/ctkEAServiceEventAdapter_p.h"
  22. #include <ctkPluginContext.h>
  23. #include <ctkPluginConstants.h>
  24. #include <QtConcurrentRun>
  25. const QString ctkEAConfiguration::PID = "org.commontk.eventadmin.impl.EventAdmin";
  26. const QString ctkEAConfiguration::PROP_CACHE_SIZE = "org.commontk.eventadmin.CacheSize";
  27. const QString ctkEAConfiguration::PROP_THREAD_POOL_SIZE = "org.commontk.eventadmin.ThreadPoolSize";
  28. const QString ctkEAConfiguration::PROP_TIMEOUT = "org.commontk.eventadmin.Timeout";
  29. const QString ctkEAConfiguration::PROP_REQUIRE_TOPIC = "org.commontk.eventadmin.RequireTopic";
  30. const QString ctkEAConfiguration::PROP_IGNORE_TIMEOUT = "org.commontk.eventadmin.IgnoreTimeout";
  31. const QString ctkEAConfiguration::PROP_LOG_LEVEL = "org.commontk.eventadmin.LogLevel";
  32. ctkEAConfiguration::ctkEAConfiguration(ctkPluginContext* pluginContext )
  33. : pluginContext(pluginContext), sync_pool(0), async_pool(0), admin(0)
  34. {
  35. // default configuration
  36. configure(ctkDictionary());
  37. startOrUpdate();
  38. try
  39. {
  40. QObject* service = this;
  41. // add meta type provider
  42. metaTypeService.reset(tryToCreateMetaTypeProvider(qobject_cast<ctkManagedService*>(service)));
  43. QStringList interfaceNames;
  44. if (metaTypeService.isNull())
  45. {
  46. interfaceNames.append(getIIDs<ctkManagedService>());
  47. }
  48. else
  49. {
  50. interfaceNames.append(getIIDs<ctkManagedService, ctkMetaTypeProvider>());
  51. service = metaTypeService.data();
  52. }
  53. ctkDictionary props;
  54. props.insert(ctkPluginConstants::SERVICE_PID, PID);
  55. managedServiceReg = pluginContext->registerService(interfaceNames, service, props);
  56. }
  57. catch (...)
  58. {
  59. // don't care
  60. }
  61. }
  62. ctkEAConfiguration::~ctkEAConfiguration()
  63. {
  64. this->destroy();
  65. }
  66. void ctkEAConfiguration::updateFromConfigAdmin(const ctkDictionary& config)
  67. {
  68. QMutexLocker l(&mutex);
  69. configure(config);
  70. startOrUpdate();
  71. }
  72. void ctkEAConfiguration::configure(const ctkDictionary& config )
  73. {
  74. if (config.isEmpty())
  75. {
  76. // The size of various internal caches. At the moment there are 4
  77. // internal caches affected. Each will cache the determined amount of
  78. // small but frequently used objects (i.e., in case of the default value
  79. // we end-up with a total of 120 small objects being cached). A value of less
  80. // then 10 triggers the default value.
  81. cacheSize = getIntProperty(PROP_CACHE_SIZE,
  82. pluginContext->getProperty(PROP_CACHE_SIZE), 30, 10);
  83. // The size of the internal thread pool. Note that we must execute
  84. // each synchronous event dispatch that happens in the synchronous event
  85. // dispatching thread in a new thread, hence a small thread pool is o.k.
  86. // A value of less then 2 triggers the default value. A value of 2
  87. // effectively disables thread pooling. Furthermore, this will be used by
  88. // a lazy thread pool (i.e., new threads are created when needed). Ones the
  89. // the size is reached and no cached thread is available new threads will
  90. // be created.
  91. threadPoolSize = getIntProperty(PROP_THREAD_POOL_SIZE,
  92. pluginContext->getProperty(PROP_THREAD_POOL_SIZE), 20, 2);
  93. // The timeout in milliseconds - A value of less then 100 turns timeouts off.
  94. // Any other value is the time in milliseconds granted to each EventHandler
  95. // before it gets blacklisted.
  96. timeout = getIntProperty(PROP_TIMEOUT,
  97. pluginContext->getProperty(PROP_TIMEOUT), 5000, INT_MIN);
  98. // Are EventHandler required to be registered with a topic? - The default is
  99. // true. The specification says that EventHandler must register with a list
  100. // of topics they are interested in. Setting this value to false will enable
  101. // that handlers without a topic are receiving all events
  102. // (i.e., they are treated the same as with a topic=*).
  103. requireTopic = getBoolProperty(pluginContext->getProperty(PROP_REQUIRE_TOPIC), true);
  104. QVariant value = pluginContext->getProperty(PROP_IGNORE_TIMEOUT);
  105. if (value.isValid())
  106. {
  107. ignoreTimeout = value.toStringList();
  108. }
  109. else
  110. {
  111. ignoreTimeout.clear();
  112. }
  113. logLevel = getIntProperty(PROP_LOG_LEVEL,
  114. pluginContext->getProperty(PROP_LOG_LEVEL),
  115. ctkLogService::LOG_WARNING, // default log level is WARNING
  116. ctkLogService::LOG_ERROR);
  117. }
  118. else
  119. {
  120. cacheSize = getIntProperty(PROP_CACHE_SIZE, config.value(PROP_CACHE_SIZE), 30, 10);
  121. threadPoolSize = getIntProperty(PROP_THREAD_POOL_SIZE, config.value(PROP_THREAD_POOL_SIZE), 20, 2);
  122. timeout = getIntProperty(PROP_TIMEOUT, config.value(PROP_TIMEOUT), 5000, INT_MIN);
  123. requireTopic = getBoolProperty(config.value(PROP_REQUIRE_TOPIC), true);
  124. ignoreTimeout.clear();
  125. QVariant value = config.value(PROP_IGNORE_TIMEOUT);
  126. if (value.canConvert<QStringList>())
  127. {
  128. ignoreTimeout = value.toStringList();
  129. }
  130. else
  131. {
  132. CTK_WARN(ctkEventAdminActivator::getLogService())
  133. << "Value for property:" << PROP_IGNORE_TIMEOUT << " cannot be converted to QStringList - Using default";
  134. }
  135. logLevel = getIntProperty(PROP_LOG_LEVEL,
  136. config.value(PROP_LOG_LEVEL),
  137. ctkLogService::LOG_WARNING, // default log level is WARNING
  138. ctkLogService::LOG_ERROR);
  139. }
  140. // a timeout less or equals to 100 means : disable timeout
  141. if (timeout <= 100)
  142. {
  143. timeout = 0;
  144. }
  145. }
  146. void ctkEAConfiguration::destroy()
  147. {
  148. QMutexLocker l(&mutex);
  149. if (!adapters.isEmpty())
  150. {
  151. foreach(ctkEAAbstractAdapter* adapter, adapters)
  152. {
  153. adapter->destroy(pluginContext);
  154. delete adapter;
  155. }
  156. adapters.clear();
  157. }
  158. if (managedServiceReg)
  159. {
  160. managedServiceReg.unregister();
  161. managedServiceReg = 0;
  162. }
  163. // We need to unregister manually
  164. if (registration)
  165. {
  166. registration.unregister();
  167. registration = 0;
  168. }
  169. if (admin)
  170. {
  171. admin->stop();
  172. delete admin;
  173. admin = 0;
  174. }
  175. if (async_pool)
  176. {
  177. async_pool->close();
  178. delete async_pool;
  179. async_pool = 0;
  180. }
  181. if (sync_pool)
  182. {
  183. sync_pool->close();
  184. delete sync_pool;
  185. sync_pool = 0;
  186. }
  187. }
  188. void ctkEAConfiguration::startOrUpdate()
  189. {
  190. CTK_DEBUG(ctkEventAdminActivator::getLogService())
  191. << PROP_LOG_LEVEL << "=" << logLevel;
  192. CTK_DEBUG(ctkEventAdminActivator::getLogService())
  193. << PROP_CACHE_SIZE << "=" << cacheSize;
  194. CTK_DEBUG(ctkEventAdminActivator::getLogService())
  195. << PROP_THREAD_POOL_SIZE << "=" << threadPoolSize;
  196. CTK_DEBUG(ctkEventAdminActivator::getLogService())
  197. << PROP_TIMEOUT << "=" << timeout;
  198. CTK_DEBUG(ctkEventAdminActivator::getLogService())
  199. << PROP_REQUIRE_TOPIC << "=" << requireTopic;
  200. ctkEventAdminService::TopicHandlerFiltersInterface* topicHandlerFilters =
  201. new ctkEventAdminService::TopicHandlerFilters(
  202. new ctkEventAdminService::TopicCacheMap(cacheSize), requireTopic);
  203. ctkEventAdminService::FiltersInterface* filters =
  204. new ctkEventAdminService::Filters(
  205. new ctkEventAdminService::LDAPCacheMap(cacheSize), pluginContext);
  206. // Note that this uses a lazy thread pool that will create new threads on
  207. // demand - in case none of its cached threads is free - until threadPoolSize
  208. // is reached. Subsequently, a threadPoolSize of 2 effectively disables
  209. // caching of threads.
  210. if (sync_pool == 0)
  211. {
  212. sync_pool = new ctkEADefaultThreadPool(threadPoolSize, true);
  213. }
  214. else
  215. {
  216. sync_pool->configure(threadPoolSize);
  217. }
  218. int asyncThreadPoolSize = threadPoolSize > 5 ? threadPoolSize / 2 : 2;
  219. if (async_pool == 0)
  220. {
  221. async_pool = new ctkEADefaultThreadPool(asyncThreadPoolSize, false);
  222. }
  223. else
  224. {
  225. async_pool->configure(asyncThreadPoolSize);
  226. }
  227. // The handlerTasks object is responsible to determine concerned ctkEventHandler
  228. // for a given event. Additionally, it keeps a list of blacklisted handlers.
  229. // Note that blacklisting is deactivated by selecting a different scheduler
  230. // below (and not in this HandlerTasks object!)
  231. ctkEventAdminService::HandlerTasksInterface* handlerTasks =
  232. new ctkEventAdminService::BlacklistingHandlerTasks(
  233. pluginContext, new ctkEventAdminService::BlackList(), topicHandlerFilters, filters);
  234. if (admin == 0)
  235. {
  236. admin = new ctkEventAdminService(pluginContext, handlerTasks, sync_pool, async_pool,
  237. timeout, ignoreTimeout);
  238. // Finally, adapt the outside events to our kind of events as per spec
  239. adaptEvents(admin);
  240. // register the admin wrapped in a service factory (SecureEventAdminFactory)
  241. // that hands-out the m_admin object wrapped in a decorator that checks
  242. // appropriated permissions of each calling plugin
  243. //TODO SecureEventAdminFactory
  244. //registration = pluginContext->registerService<ctkEventAdmin>(
  245. // new ctkEASecureEventAdminFactory(admin));
  246. registration = pluginContext->registerService<ctkEventAdmin>(admin);
  247. }
  248. else
  249. {
  250. admin->update(handlerTasks, timeout, ignoreTimeout);
  251. }
  252. }
  253. void ctkEAConfiguration::adaptEvents(ctkEventAdmin* admin)
  254. {
  255. adapters << new ctkEAFrameworkEventAdapter(pluginContext, admin);
  256. adapters << new ctkEAPluginEventAdapter(pluginContext, admin);
  257. adapters << new ctkEAServiceEventAdapter(pluginContext, admin);
  258. adapters << new ctkEALogEventAdapter(pluginContext, admin);
  259. }
  260. QObject* ctkEAConfiguration::tryToCreateMetaTypeProvider(ctkManagedService* managedService)
  261. {
  262. try
  263. {
  264. return new ctkEAMetaTypeProvider(managedService, cacheSize, threadPoolSize,
  265. timeout, requireTopic, ignoreTimeout);
  266. }
  267. catch (...)
  268. {
  269. // we simply ignore this
  270. }
  271. return 0;
  272. }
  273. void ctkEAConfiguration::updated(const ctkDictionary& properties)
  274. {
  275. // do this in the background as we don't want to stop
  276. // the config admin
  277. QtConcurrent::run(this, &ctkEAConfiguration::updateFromConfigAdmin, properties);
  278. }
  279. int ctkEAConfiguration::getIntProperty(const QString& key, const QVariant& value,
  280. int defaultValue, int min)
  281. {
  282. if(value.isValid())
  283. {
  284. int result = defaultValue;
  285. if (value.canConvert<int>())
  286. {
  287. bool ok;
  288. result = value.toInt(&ok);
  289. if (!ok)
  290. {
  291. CTK_WARN(ctkEventAdminActivator::getLogService())
  292. << "Unable to parse property: " << key << " - Using default: " << defaultValue;
  293. return defaultValue;
  294. }
  295. }
  296. else
  297. {
  298. CTK_WARN(ctkEventAdminActivator::getLogService())
  299. << "Unable to convert property to int: " << key << " - Using default: " << defaultValue;
  300. return defaultValue;
  301. }
  302. if(result >= min)
  303. {
  304. return result;
  305. }
  306. CTK_WARN(ctkEventAdminActivator::getLogService())
  307. << "Value for property: " << key << " is too low - Using default: " << defaultValue;
  308. }
  309. return defaultValue;
  310. }
  311. bool ctkEAConfiguration::getBoolProperty(const QVariant& value, bool defaultValue)
  312. {
  313. if(value.isValid())
  314. {
  315. if (value.canConvert<bool>())
  316. {
  317. return value.toBool();
  318. }
  319. }
  320. return defaultValue;
  321. }