ctkPluginFrameworkDebugOptions.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  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 "ctkPluginFrameworkDebugOptions_p.h"
  16. #include <ctkPluginContext.h>
  17. #include <ctkException.h>
  18. #include "ctkPluginFrameworkLauncher.h"
  19. #include "ctkPluginFrameworkProperties_p.h"
  20. #include <QSettings>
  21. #include <QMutex>
  22. #include <QDir>
  23. const QString ctkPluginFrameworkDebugOptions::CTK_DEBUG = "ctk.debug";
  24. const QString ctkPluginFrameworkDebugOptions::OPTIONS = ".ctk.options";
  25. //----------------------------------------------------------------------------
  26. ctkPluginFrameworkDebugOptions::ctkPluginFrameworkDebugOptions()
  27. : enabled(false)
  28. , context(NULL)
  29. {
  30. // if no debug option was specified, don't even bother to try.
  31. // Must ensure that the options slot is null as this is the signal to the
  32. // platform that debugging is not enabled.
  33. QVariant debugOptions = ctkPluginFrameworkProperties::getProperty(CTK_DEBUG);
  34. if (debugOptions.isNull()) return;
  35. QString debugOptionsFilename = debugOptions.toString();
  36. if (debugOptionsFilename.isEmpty())
  37. {
  38. // default options location is user.dir (install location may be r/o so
  39. // is not a good candidate for a trace options that need to be updatable by
  40. // by the user)
  41. QDir userDir(ctkPluginFrameworkProperties::getProperty(ctkPluginFrameworkLauncher::PROP_USER_DIR).toString());
  42. debugOptionsFilename = userDir.absoluteFilePath(OPTIONS);
  43. }
  44. QFile optionsFile(debugOptionsFilename);
  45. QString msgState;
  46. if (!optionsFile.exists())
  47. {
  48. msgState = "not found";
  49. }
  50. else
  51. {
  52. QSettings settings(debugOptionsFilename, QSettings::IniFormat);
  53. if (settings.status() != QSettings::NoError)
  54. {
  55. msgState = ".... did not parse";
  56. }
  57. else
  58. {
  59. foreach (const QString& key, settings.allKeys())
  60. {
  61. this->options.insert(key, settings.value(key));
  62. }
  63. this->enabled = true;
  64. }
  65. }
  66. qDebug() << "Debug options:\n " << optionsFile.fileName() << " " << msgState;
  67. }
  68. //----------------------------------------------------------------------------
  69. ctkPluginFrameworkDebugOptions*ctkPluginFrameworkDebugOptions::getDefault()
  70. {
  71. static ctkPluginFrameworkDebugOptions singleton;
  72. return &singleton;
  73. }
  74. //----------------------------------------------------------------------------
  75. void ctkPluginFrameworkDebugOptions::start(ctkPluginContext* pc)
  76. {
  77. this->context = pc;
  78. this->listenerTracker.reset(new ctkServiceTracker<ctkDebugOptionsListener*>(pc, this));
  79. this->listenerTracker->open();
  80. }
  81. //----------------------------------------------------------------------------
  82. void ctkPluginFrameworkDebugOptions::stop(ctkPluginContext* /*pc*/)
  83. {
  84. this->listenerTracker->close();
  85. this->listenerTracker.reset();
  86. this->context = NULL;
  87. }
  88. //----------------------------------------------------------------------------
  89. bool ctkPluginFrameworkDebugOptions::getBooleanOption(const QString& option, bool defaultValue) const
  90. {
  91. return this->getOption(option, defaultValue).toBool();
  92. }
  93. //----------------------------------------------------------------------------
  94. QVariant ctkPluginFrameworkDebugOptions::getOption(const QString& option) const
  95. {
  96. return getOption(option, QVariant());
  97. }
  98. //----------------------------------------------------------------------------
  99. QVariant ctkPluginFrameworkDebugOptions::getOption(const QString& option, const QVariant& defaultValue) const
  100. {
  101. QMutexLocker lock(&this->mutex);
  102. return this->options.value(option, defaultValue);
  103. }
  104. //----------------------------------------------------------------------------
  105. int ctkPluginFrameworkDebugOptions::getIntegerOption(const QString& option, int defaultValue) const
  106. {
  107. return this->options.value(option, defaultValue).toInt();
  108. }
  109. //----------------------------------------------------------------------------
  110. QHash<QString, QVariant> ctkPluginFrameworkDebugOptions::getOptions() const
  111. {
  112. QHash<QString, QVariant> snapShot;
  113. {
  114. QMutexLocker lock(&this->mutex);
  115. if (this->isDebugEnabled())
  116. {
  117. snapShot = this->options;
  118. }
  119. else
  120. {
  121. snapShot = this->disabledOptions;
  122. }
  123. }
  124. return snapShot;
  125. }
  126. //----------------------------------------------------------------------------
  127. void ctkPluginFrameworkDebugOptions::setOption(const QString& option, const QVariant& value)
  128. {
  129. if (!this->isDebugEnabled()) return;
  130. QString fireChangedEvent;
  131. {
  132. QMutexLocker lock(&this->mutex);
  133. // get the current value
  134. QHash<QString, QVariant>::iterator currentValue = this->options.find(option);
  135. if (currentValue != this->options.end())
  136. {
  137. if (currentValue.value() != value)
  138. {
  139. fireChangedEvent = this->getSymbolicName(option);
  140. }
  141. }
  142. else
  143. {
  144. if (!value.isNull())
  145. {
  146. fireChangedEvent = this->getSymbolicName(option);
  147. }
  148. }
  149. if (!fireChangedEvent.isEmpty())
  150. {
  151. this->options.insert(option, value);
  152. }
  153. }
  154. // Send the options change event outside the sync block
  155. if (!fireChangedEvent.isEmpty())
  156. {
  157. this->optionsChanged(fireChangedEvent);
  158. }
  159. }
  160. //----------------------------------------------------------------------------
  161. void ctkPluginFrameworkDebugOptions::setOptions(const QHash<QString, QVariant>& ops)
  162. {
  163. QHash<QString, QVariant> newOptions = ops;
  164. QSet<QString> fireChangesTo;
  165. {
  166. QMutexLocker lock(&this->mutex);
  167. if (!this->isDebugEnabled())
  168. {
  169. this->disabledOptions = newOptions;
  170. // no events to fire
  171. return;
  172. }
  173. // first check for removals
  174. foreach (const QString& key, this->options.keys())
  175. {
  176. if (!newOptions.contains(key))
  177. {
  178. QString symbolicName = this->getSymbolicName(key);
  179. if (!symbolicName.isEmpty())
  180. {
  181. fireChangesTo.insert(symbolicName);
  182. }
  183. }
  184. }
  185. // now check for changes to existing values
  186. for(QHash<QString, QVariant>::iterator iter = newOptions.begin(); iter != newOptions.end(); ++iter)
  187. {
  188. QVariant existingValue = this->options.value(iter.key());
  189. if (iter.value() != existingValue)
  190. {
  191. QString symbolicName = this->getSymbolicName(iter.key());
  192. if (!symbolicName.isEmpty())
  193. {
  194. fireChangesTo.insert(symbolicName);
  195. }
  196. }
  197. }
  198. // finally set the actual options
  199. this->options = newOptions;
  200. }
  201. foreach (const QString& symbolicName, fireChangesTo)
  202. {
  203. this->optionsChanged(symbolicName);
  204. }
  205. }
  206. //----------------------------------------------------------------------------
  207. void ctkPluginFrameworkDebugOptions::removeOption(const QString& option)
  208. {
  209. if (!this->isDebugEnabled()) return;
  210. QString fireChangedEvent;
  211. {
  212. QMutexLocker lock(&this->mutex);
  213. if (this->options.remove(option))
  214. {
  215. fireChangedEvent = this->getSymbolicName(option);
  216. }
  217. }
  218. // Send the options change event outside the sync block
  219. if (!fireChangedEvent.isEmpty())
  220. {
  221. this->optionsChanged(fireChangedEvent);
  222. }
  223. }
  224. //----------------------------------------------------------------------------
  225. bool ctkPluginFrameworkDebugOptions::isDebugEnabled() const
  226. {
  227. QMutexLocker lock(&this->mutex);
  228. return this->enabled;
  229. }
  230. //----------------------------------------------------------------------------
  231. void ctkPluginFrameworkDebugOptions::setDebugEnabled(bool enabled)
  232. {
  233. bool fireChangedEvent = false;
  234. {
  235. QMutexLocker lock(&this->mutex);
  236. if (enabled)
  237. {
  238. if (this->isDebugEnabled()) return;
  239. // enable platform debugging - there is no .options file
  240. ctkPluginFrameworkProperties::setProperty(CTK_DEBUG, QString(""));
  241. this->options = this->disabledOptions;
  242. this->disabledOptions.clear();
  243. this->enabled = true;
  244. if (!this->options.isEmpty())
  245. {
  246. // fire changed event to indicate some options were re-enabled
  247. fireChangedEvent = true;
  248. }
  249. }
  250. else
  251. {
  252. if (!this->isDebugEnabled()) return;
  253. // disable platform debugging.
  254. ctkPluginFrameworkProperties::clearProperty(CTK_DEBUG);
  255. if (!this->options.isEmpty())
  256. {
  257. // Save the current options off in case debug is re-enabled
  258. this->disabledOptions = this->options;
  259. // fire changed event to indicate some options were disabled
  260. fireChangedEvent = true;
  261. }
  262. this->options.clear();
  263. this->enabled = false;
  264. }
  265. }
  266. if (fireChangedEvent)
  267. {
  268. // need to fire event to listeners that options have been disabled
  269. this->optionsChanged("*");
  270. }
  271. }
  272. //----------------------------------------------------------------------------
  273. QString ctkPluginFrameworkDebugOptions::getSymbolicName(const QString& option) const
  274. {
  275. int firstSlashIndex = option.indexOf("/");
  276. if (firstSlashIndex > 0)
  277. return option.left(firstSlashIndex);
  278. return QString::null;
  279. }
  280. //----------------------------------------------------------------------------
  281. void ctkPluginFrameworkDebugOptions::optionsChanged(const QString& pluginSymbolicName)
  282. {
  283. // use osgi services to get the listeners
  284. if (context == NULL)
  285. return;
  286. // do not use the service tracker because that is only used to call all listeners initially when they are registered
  287. // here we only want the services with the specified name.
  288. QList<ctkServiceReference> listenerRefs;
  289. try
  290. {
  291. listenerRefs = context->getServiceReferences<ctkDebugOptionsListener>( "(" + ctkDebugOptions::LISTENER_SYMBOLICNAME + "=" + pluginSymbolicName + ")");
  292. }
  293. catch (const ctkInvalidArgumentException& /*e*/)
  294. {
  295. // consider logging; should not happen
  296. }
  297. if (listenerRefs.empty()) return;
  298. foreach (const ctkServiceReference& ref, listenerRefs)
  299. {
  300. ctkDebugOptionsListener* service = context->getService<ctkDebugOptionsListener>(ref);
  301. if (service == NULL) continue;
  302. try
  303. {
  304. service->optionsChanged(*this);
  305. }
  306. catch (const std::exception& /*e*/)
  307. {
  308. // TODO consider logging
  309. }
  310. context->ungetService(ref);
  311. }
  312. }
  313. //----------------------------------------------------------------------------
  314. ctkDebugOptionsListener* ctkPluginFrameworkDebugOptions::addingService(const ctkServiceReference& reference)
  315. {
  316. ctkDebugOptionsListener* listener = context->getService<ctkDebugOptionsListener>(reference);
  317. listener->optionsChanged(*this);
  318. return listener;
  319. }
  320. //----------------------------------------------------------------------------
  321. void ctkPluginFrameworkDebugOptions::modifiedService(const ctkServiceReference& /*reference*/,
  322. ctkDebugOptionsListener* /*service*/)
  323. {
  324. // nothing
  325. }
  326. //----------------------------------------------------------------------------
  327. void ctkPluginFrameworkDebugOptions::removedService(const ctkServiceReference& reference,
  328. ctkDebugOptionsListener* /*service*/)
  329. {
  330. context->ungetService(reference);
  331. }