ctkServiceTracker.tpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  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 "ctkServiceTracker_p.h"
  16. #include "ctkTrackedService_p.h"
  17. #include "ctkServiceException.h"
  18. #include "ctkPluginConstants.h"
  19. #include "ctkPluginContext.h"
  20. #include <QVarLengthArray>
  21. #include <QDebug>
  22. #include <stdexcept>
  23. #include <limits>
  24. //----------------------------------------------------------------------------
  25. template<class S, class T>
  26. ctkServiceTracker<S,T>::~ctkServiceTracker()
  27. {
  28. }
  29. //----------------------------------------------------------------------------
  30. template<class S, class T>
  31. ctkServiceTracker<S,T>::ctkServiceTracker(ctkPluginContext* context,
  32. const ctkServiceReference& reference,
  33. ServiceTrackerCustomizer* customizer)
  34. : d_ptr(new ServiceTrackerPrivate(this, context, reference, customizer))
  35. {
  36. }
  37. //----------------------------------------------------------------------------
  38. template<class S, class T>
  39. ctkServiceTracker<S,T>::ctkServiceTracker(ctkPluginContext* context, const QString& clazz,
  40. ServiceTrackerCustomizer* customizer)
  41. : d_ptr(new ServiceTrackerPrivate(this, context, clazz, customizer))
  42. {
  43. }
  44. //----------------------------------------------------------------------------
  45. template<class S, class T>
  46. ctkServiceTracker<S,T>::ctkServiceTracker(ctkPluginContext* context, const ctkLDAPSearchFilter& filter,
  47. ServiceTrackerCustomizer* customizer)
  48. : d_ptr(new ServiceTrackerPrivate(this, context, filter, customizer))
  49. {
  50. }
  51. //----------------------------------------------------------------------------
  52. template<class S, class T>
  53. ctkServiceTracker<S,T>::ctkServiceTracker(ctkPluginContext *context, ctkServiceTrackerCustomizer<T> *customizer)
  54. : d_ptr(new ServiceTrackerPrivate(this, context, qobject_interface_iid<S>(), customizer))
  55. {
  56. const char* clazz = qobject_interface_iid<S>();
  57. if (clazz == 0) throw ctkServiceException("The service interface class has no Q_DECLARE_INTERFACE macro");
  58. }
  59. //----------------------------------------------------------------------------
  60. template<class S, class T>
  61. void ctkServiceTracker<S,T>::open()
  62. {
  63. Q_D(ServiceTracker);
  64. QSharedPointer<TrackedService> t;
  65. {
  66. QMutexLocker lock(&d->mutex);
  67. if (d->trackedService)
  68. {
  69. return;
  70. }
  71. if (d->DEBUG)
  72. {
  73. qDebug() << "ctkServiceTracker<S,T>::open: " << d->filter;
  74. }
  75. t = QSharedPointer<TrackedService>(
  76. new TrackedService(this, d->customizer));
  77. {
  78. QMutexLocker lockT(t.data());
  79. try {
  80. d->context->connectServiceListener(t.data(), "serviceChanged", d->listenerFilter);
  81. QList<ctkServiceReference> references;
  82. if (!d->trackClass.isEmpty())
  83. {
  84. references = d->getInitialReferences(d->trackClass, QString());
  85. }
  86. else
  87. {
  88. if (!d->trackReference.getPlugin().isNull())
  89. {
  90. references.push_back(d->trackReference);
  91. }
  92. else
  93. { /* user supplied filter */
  94. references = d->getInitialReferences(QString(),
  95. (d->listenerFilter.isNull()) ? d->filter.toString() : d->listenerFilter);
  96. }
  97. }
  98. /* set tracked with the initial references */
  99. t->setInitial(references);
  100. }
  101. catch (const ctkInvalidArgumentException& e)
  102. {
  103. throw ctkRuntimeException(QString("unexpected ctkInvalidArgumentException exception: %1").arg(e.what()));
  104. }
  105. }
  106. d->trackedService = t;
  107. }
  108. /* Call tracked outside of synchronized region */
  109. t->trackInitial(); /* process the initial references */
  110. }
  111. //----------------------------------------------------------------------------
  112. template<class S, class T>
  113. void ctkServiceTracker<S,T>::close()
  114. {
  115. Q_D(ServiceTracker);
  116. QSharedPointer<TrackedService> outgoing;
  117. QList<ctkServiceReference> references;
  118. {
  119. QMutexLocker lock(&d->mutex);
  120. outgoing = d->trackedService;
  121. if (outgoing.isNull())
  122. {
  123. return;
  124. }
  125. if (d->DEBUG)
  126. {
  127. qDebug() << "ctkServiceTracker<S,T>::close:" << d->filter;
  128. }
  129. outgoing->close();
  130. references = getServiceReferences();
  131. d->trackedService.clear();;
  132. try
  133. {
  134. d->context->disconnectServiceListener(outgoing.data(), "serviceChanged");
  135. }
  136. catch (const ctkIllegalStateException& /*e*/)
  137. {
  138. /* In case the context was stopped. */
  139. }
  140. }
  141. d->modified(); /* clear the cache */
  142. {
  143. QMutexLocker lockT(outgoing.data());
  144. outgoing->wakeAll(); /* wake up any waiters */
  145. }
  146. foreach (ctkServiceReference ref, references)
  147. {
  148. outgoing->untrack(ref, ctkServiceEvent());
  149. }
  150. if (d->DEBUG)
  151. {
  152. QMutexLocker lock(&d->mutex);
  153. if ((d->cachedReference.getPlugin().isNull()) && (d->cachedService == 0))
  154. {
  155. qDebug() << "ctkServiceTracker<S,T>::close[cached cleared]:"
  156. << d->filter;
  157. }
  158. }
  159. }
  160. //----------------------------------------------------------------------------
  161. template<class S, class T>
  162. T ctkServiceTracker<S,T>::waitForService(unsigned long timeout)
  163. {
  164. Q_D(ServiceTracker);
  165. T object = getService();
  166. while (object == 0)
  167. {
  168. QSharedPointer<TrackedService> t = d->tracked();
  169. if (t.isNull())
  170. { /* if ServiceTracker is not open */
  171. return 0;
  172. }
  173. {
  174. QMutexLocker lockT(t.data());
  175. if (t->size() == 0)
  176. {
  177. t->wait(timeout);
  178. }
  179. }
  180. object = getService();
  181. if (timeout > 0)
  182. {
  183. return object;
  184. }
  185. }
  186. return object;
  187. }
  188. //----------------------------------------------------------------------------
  189. template<class S, class T>
  190. QList<ctkServiceReference> ctkServiceTracker<S,T>::getServiceReferences() const
  191. {
  192. Q_D(const ServiceTracker);
  193. QSharedPointer<TrackedService> t = d->tracked();
  194. if (t.isNull())
  195. { /* if ServiceTracker is not open */
  196. return QList<ctkServiceReference>();
  197. }
  198. {
  199. QMutexLocker lockT(t.data());
  200. return d->getServiceReferences_unlocked(t.data());
  201. }
  202. }
  203. //----------------------------------------------------------------------------
  204. template<class S, class T>
  205. ctkServiceReference ctkServiceTracker<S,T>::getServiceReference() const
  206. {
  207. Q_D(const ServiceTracker);
  208. ctkServiceReference reference(0);
  209. {
  210. QMutexLocker lock(&d->mutex);
  211. reference = d->cachedReference;
  212. }
  213. if (!reference.getPlugin().isNull())
  214. {
  215. if (d->DEBUG)
  216. {
  217. qDebug() << "ctkServiceTracker<S,T>::getServiceReference[cached]:"
  218. << d->filter;
  219. }
  220. return reference;
  221. }
  222. if (d->DEBUG)
  223. {
  224. qDebug() << "ctkServiceTracker<S,T>::getServiceReference:" << d->filter;
  225. }
  226. QList<ctkServiceReference> references = getServiceReferences();
  227. int length = references.size();
  228. if (length == 0)
  229. { /* if no service is being tracked */
  230. throw ctkServiceException("No service is being tracked");
  231. }
  232. int index = 0;
  233. if (length > 1)
  234. { /* if more than one service, select highest ranking */
  235. QVarLengthArray<int, 10> rankings(length);
  236. int count = 0;
  237. int maxRanking = std::numeric_limits<int>::min();
  238. for (int i = 0; i < length; i++)
  239. {
  240. bool ok = false;
  241. int ranking = references[i].getProperty(ctkPluginConstants::SERVICE_RANKING).toInt(&ok);
  242. if (!ok) ranking = 0;
  243. rankings[i] = ranking;
  244. if (ranking > maxRanking)
  245. {
  246. index = i;
  247. maxRanking = ranking;
  248. count = 1;
  249. }
  250. else
  251. {
  252. if (ranking == maxRanking)
  253. {
  254. count++;
  255. }
  256. }
  257. }
  258. if (count > 1)
  259. { /* if still more than one service, select lowest id */
  260. qlonglong minId = std::numeric_limits<qlonglong>::max();
  261. for (int i = 0; i < length; i++)
  262. {
  263. if (rankings[i] == maxRanking)
  264. {
  265. qlonglong id = references[i].getProperty(ctkPluginConstants::SERVICE_ID).toLongLong();
  266. if (id < minId)
  267. {
  268. index = i;
  269. minId = id;
  270. }
  271. }
  272. }
  273. }
  274. }
  275. {
  276. QMutexLocker lock(&d->mutex);
  277. d->cachedReference = references[index];
  278. return d->cachedReference;
  279. }
  280. }
  281. //----------------------------------------------------------------------------
  282. template<class S, class T>
  283. T ctkServiceTracker<S,T>::getService(const ctkServiceReference& reference) const
  284. {
  285. Q_D(const ServiceTracker);
  286. QSharedPointer<TrackedService> t = d->tracked();
  287. if (t.isNull())
  288. { /* if ServiceTracker is not open */
  289. return 0;
  290. }
  291. {
  292. QMutexLocker lockT(t.data());
  293. return t->getCustomizedObject(reference);
  294. }
  295. }
  296. //----------------------------------------------------------------------------
  297. template<class S, class T>
  298. QList<T> ctkServiceTracker<S,T>::getServices() const
  299. {
  300. Q_D(const ServiceTracker);
  301. QSharedPointer<TrackedService> t = d->tracked();
  302. if (t.isNull())
  303. { /* if ServiceTracker is not open */
  304. return QList<T>();
  305. }
  306. {
  307. QMutexLocker lockT(t.data());
  308. QList<ctkServiceReference> references = d->getServiceReferences_unlocked(t.data());
  309. QList<T> objects;
  310. foreach (ctkServiceReference ref, references)
  311. {
  312. //objects << getService(ref);
  313. objects << t->getCustomizedObject(ref);
  314. }
  315. return objects;
  316. }
  317. }
  318. //----------------------------------------------------------------------------
  319. template<class S, class T>
  320. T ctkServiceTracker<S,T>::getService() const
  321. {
  322. Q_D(const ServiceTracker);
  323. T service = d->cachedService;
  324. if (service != 0)
  325. {
  326. if (d->DEBUG)
  327. {
  328. qDebug() << "ctkServiceTracker<S,T>::getService[cached]:"
  329. << d->filter;
  330. }
  331. return service;
  332. }
  333. if (d->DEBUG)
  334. {
  335. qDebug() << "ctkServiceTracker<S,T>::getService:" << d->filter;
  336. }
  337. try
  338. {
  339. ctkServiceReference reference = getServiceReference();
  340. if (reference.getPlugin().isNull())
  341. {
  342. return 0;
  343. }
  344. return d->cachedService = getService(reference);
  345. }
  346. catch (const ctkServiceException&)
  347. {
  348. return 0;
  349. }
  350. }
  351. //----------------------------------------------------------------------------
  352. template<class S, class T>
  353. void ctkServiceTracker<S,T>::remove(const ctkServiceReference& reference)
  354. {
  355. Q_D(ServiceTracker);
  356. QSharedPointer<TrackedService> t = d->tracked();
  357. if (t.isNull())
  358. { /* if ServiceTracker is not open */
  359. return;
  360. }
  361. t->untrack(reference, ctkServiceEvent());
  362. }
  363. //----------------------------------------------------------------------------
  364. template<class S, class T>
  365. int ctkServiceTracker<S,T>::size() const
  366. {
  367. Q_D(const ServiceTracker);
  368. QSharedPointer<TrackedService> t = d->tracked();
  369. if (t.isNull())
  370. { /* if ServiceTracker is not open */
  371. return 0;
  372. }
  373. {
  374. QMutexLocker lockT(t.data());
  375. return t->size();
  376. }
  377. }
  378. //----------------------------------------------------------------------------
  379. template<class S, class T>
  380. int ctkServiceTracker<S,T>::getTrackingCount() const
  381. {
  382. Q_D(const ServiceTracker);
  383. QSharedPointer<TrackedService> t = d->tracked();
  384. if (t.isNull())
  385. { /* if ServiceTracker is not open */
  386. return -1;
  387. }
  388. {
  389. QMutexLocker lockT(t.data());
  390. return t->getTrackingCount();
  391. }
  392. }
  393. //----------------------------------------------------------------------------
  394. template<class S, class T>
  395. QMap<ctkServiceReference, T> ctkServiceTracker<S,T>::getTracked() const
  396. {
  397. QMap<ctkServiceReference, T> map;
  398. Q_D(const ServiceTracker);
  399. QSharedPointer<TrackedService> t = d->tracked();
  400. if (t.isNull())
  401. { /* if ServiceTracker is not open */
  402. return map;
  403. }
  404. {
  405. QMutexLocker lockT(t.data());
  406. return t->copyEntries(map);
  407. }
  408. }
  409. //----------------------------------------------------------------------------
  410. template<class S, class T>
  411. bool ctkServiceTracker<S,T>::isEmpty() const
  412. {
  413. Q_D(const ServiceTracker);
  414. QSharedPointer<TrackedService> t = d->tracked();
  415. if (t.isNull())
  416. { /* if ServiceTracker is not open */
  417. return true;
  418. }
  419. {
  420. QMutexLocker lockT(t.data());
  421. return t->isEmpty();
  422. }
  423. }
  424. //----------------------------------------------------------------------------
  425. template<class S, class T>
  426. T ctkServiceTracker<S,T>::addingService(const ctkServiceReference& reference)
  427. {
  428. Q_D(ServiceTracker);
  429. return qobject_cast<T>(d->context->getService(reference));
  430. }
  431. //----------------------------------------------------------------------------
  432. template<class S, class T>
  433. void ctkServiceTracker<S,T>::modifiedService(const ctkServiceReference& reference, T service)
  434. {
  435. Q_UNUSED(reference)
  436. Q_UNUSED(service)
  437. /* do nothing */
  438. }
  439. //----------------------------------------------------------------------------
  440. template<class S, class T>
  441. void ctkServiceTracker<S,T>::removedService(const ctkServiceReference& reference, T service)
  442. {
  443. Q_UNUSED(service)
  444. Q_D(ServiceTracker);
  445. d->context->ungetService(reference);
  446. }