ctkServices.cpp 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  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 "ctkServices_p.h"
  16. #include <QStringListIterator>
  17. #include <QMutexLocker>
  18. #include <QBuffer>
  19. #include <algorithm>
  20. #include "ctkServiceFactory.h"
  21. #include "ctkPluginConstants.h"
  22. #include "ctkPluginFrameworkContext_p.h"
  23. #include "ctkServiceException.h"
  24. #include "ctkServiceRegistrationPrivate.h"
  25. #include "ctkLDAPExpr_p.h"
  26. //----------------------------------------------------------------------------
  27. struct ServiceRegistrationComparator
  28. {
  29. bool operator()(const ctkServiceRegistration& a, const ctkServiceRegistration& b) const
  30. {
  31. return a < b;
  32. }
  33. };
  34. //----------------------------------------------------------------------------
  35. ctkDictionary ctkServices::createServiceProperties(const ctkDictionary& in,
  36. const QStringList& classes,
  37. long sid)
  38. {
  39. static qlonglong nextServiceID = 1;
  40. ctkDictionary props = in;
  41. if (!classes.isEmpty())
  42. {
  43. props.insert(ctkPluginConstants::OBJECTCLASS, classes);
  44. }
  45. props.insert(ctkPluginConstants::SERVICE_ID, sid != -1 ? sid : nextServiceID++);
  46. return props;
  47. }
  48. //----------------------------------------------------------------------------
  49. ctkServices::ctkServices(ctkPluginFrameworkContext* fwCtx)
  50. : mutex(), framework(fwCtx)
  51. {
  52. }
  53. //----------------------------------------------------------------------------
  54. ctkServices::~ctkServices()
  55. {
  56. clear();
  57. }
  58. //----------------------------------------------------------------------------
  59. void ctkServices::clear()
  60. {
  61. services.clear();
  62. classServices.clear();
  63. framework = 0;
  64. }
  65. //----------------------------------------------------------------------------
  66. ctkServiceRegistration ctkServices::registerService(ctkPluginPrivate* plugin,
  67. const QStringList& classes,
  68. QObject* service,
  69. const ctkDictionary& properties)
  70. {
  71. if (service == 0)
  72. {
  73. throw ctkInvalidArgumentException("Can't register 0 as a service");
  74. }
  75. // Check if service implements claimed classes and that they exist.
  76. for (QStringListIterator i(classes); i.hasNext();)
  77. {
  78. QString cls = i.next();
  79. if (cls.isEmpty())
  80. {
  81. throw ctkInvalidArgumentException("Can't register as null class");
  82. }
  83. if (!(qobject_cast<ctkServiceFactory*>(service)))
  84. {
  85. if (!checkServiceClass(service, cls))
  86. {
  87. QString msg = QString("Service class %1 is not an instance of %2. Maybe you forgot the Q_INTERFACES macro in the service class.")
  88. .arg(service->metaObject()->className()).arg(cls);
  89. throw ctkInvalidArgumentException(msg);
  90. }
  91. }
  92. }
  93. ctkServiceRegistration res(plugin, service,
  94. createServiceProperties(properties, classes));
  95. {
  96. QMutexLocker lock(&mutex);
  97. services.insert(res, classes);
  98. for (QStringListIterator i(classes); i.hasNext(); )
  99. {
  100. QString currClass = i.next();
  101. QList<ctkServiceRegistration>& s = classServices[currClass];
  102. QList<ctkServiceRegistration>::iterator ip =
  103. std::lower_bound(s.begin(), s.end(), res, ServiceRegistrationComparator());
  104. s.insert(ip, res);
  105. }
  106. }
  107. ctkServiceReference r = res.getReference();
  108. plugin->fwCtx->listeners.serviceChanged(
  109. plugin->fwCtx->listeners.getMatchingServiceSlots(r),
  110. ctkServiceEvent(ctkServiceEvent::REGISTERED, r));
  111. return res;
  112. }
  113. //----------------------------------------------------------------------------
  114. void ctkServices::updateServiceRegistrationOrder(const ctkServiceRegistration& sr,
  115. const QStringList& classes)
  116. {
  117. QMutexLocker lock(&mutex);
  118. for (QStringListIterator i(classes); i.hasNext(); )
  119. {
  120. QList<ctkServiceRegistration>& s = classServices[i.next()];
  121. s.removeAll(sr);
  122. s.insert(std::lower_bound(s.begin(), s.end(), sr, ServiceRegistrationComparator()), sr);
  123. }
  124. }
  125. //----------------------------------------------------------------------------
  126. bool ctkServices::checkServiceClass(QObject* service, const QString& cls) const
  127. {
  128. return service->inherits(cls.toAscii());
  129. }
  130. //----------------------------------------------------------------------------
  131. QList<ctkServiceRegistration> ctkServices::get(const QString& clazz) const
  132. {
  133. QMutexLocker lock(&mutex);
  134. return classServices.value(clazz);
  135. }
  136. //----------------------------------------------------------------------------
  137. ctkServiceReference ctkServices::get(ctkPluginPrivate* plugin, const QString& clazz) const
  138. {
  139. QMutexLocker lock(&mutex);
  140. try {
  141. QList<ctkServiceReference> srs = get_unlocked(clazz, QString(), plugin);
  142. if (framework->debug.service_reference)
  143. {
  144. qDebug() << "get service ref" << clazz << "for plugin"
  145. << plugin->location << " = " << srs.size() << "refs";
  146. }
  147. if (!srs.isEmpty()) {
  148. return srs.front();
  149. }
  150. }
  151. catch (const ctkInvalidArgumentException& )
  152. { }
  153. return ctkServiceReference();
  154. }
  155. //----------------------------------------------------------------------------
  156. QList<ctkServiceReference> ctkServices::get(const QString& clazz, const QString& filter,
  157. ctkPluginPrivate* plugin) const
  158. {
  159. QMutexLocker lock(&mutex);
  160. return get_unlocked(clazz, filter, plugin);
  161. }
  162. //----------------------------------------------------------------------------
  163. QList<ctkServiceReference> ctkServices::get_unlocked(const QString& clazz, const QString& filter,
  164. ctkPluginPrivate* plugin) const
  165. {
  166. Q_UNUSED(plugin)
  167. QListIterator<ctkServiceRegistration>* s = 0;
  168. QList<ctkServiceRegistration> v;
  169. ctkLDAPExpr ldap;
  170. if (clazz.isEmpty())
  171. {
  172. if (!filter.isEmpty())
  173. {
  174. ldap = ctkLDAPExpr(filter);
  175. QSet<QString> matched;
  176. if (ldap.getMatchedObjectClasses(matched))
  177. {
  178. v.clear();
  179. foreach (QString className, matched)
  180. {
  181. const QList<ctkServiceRegistration>& cl = classServices[className];
  182. v += cl;
  183. }
  184. if (!v.isEmpty())
  185. {
  186. s = new QListIterator<ctkServiceRegistration>(v);
  187. }
  188. else
  189. {
  190. return QList<ctkServiceReference>();
  191. }
  192. }
  193. else
  194. {
  195. s = new QListIterator<ctkServiceRegistration>(services.keys());
  196. }
  197. }
  198. else
  199. {
  200. s = new QListIterator<ctkServiceRegistration>(services.keys());
  201. }
  202. }
  203. else
  204. {
  205. QList<ctkServiceRegistration> v = classServices.value(clazz);
  206. if (!v.isEmpty())
  207. {
  208. s = new QListIterator<ctkServiceRegistration>(v);
  209. }
  210. else
  211. {
  212. return QList<ctkServiceReference>();
  213. }
  214. if (!filter.isEmpty())
  215. {
  216. ldap = ctkLDAPExpr(filter);
  217. }
  218. }
  219. QList<ctkServiceReference> res;
  220. while (s->hasNext())
  221. {
  222. ctkServiceRegistration sr = s->next();
  223. ctkServiceReference sri = sr.getReference();
  224. if (filter.isEmpty() || ldap.evaluate(sr.d_func()->properties, false))
  225. {
  226. res.push_back(sri);
  227. }
  228. }
  229. delete s;
  230. return res;
  231. }
  232. //----------------------------------------------------------------------------
  233. void ctkServices::removeServiceRegistration(const ctkServiceRegistration& sr)
  234. {
  235. QMutexLocker lock(&mutex);
  236. QStringList classes = sr.d_func()->properties.value(ctkPluginConstants::OBJECTCLASS).toStringList();
  237. services.remove(sr);
  238. for (QStringListIterator i(classes); i.hasNext(); )
  239. {
  240. QString currClass = i.next();
  241. QList<ctkServiceRegistration>& s = classServices[currClass];
  242. if (s.size() > 1)
  243. {
  244. s.removeAll(sr);
  245. }
  246. else
  247. {
  248. classServices.remove(currClass);
  249. }
  250. }
  251. }
  252. //----------------------------------------------------------------------------
  253. QList<ctkServiceRegistration> ctkServices::getRegisteredByPlugin(ctkPluginPrivate* p) const
  254. {
  255. QMutexLocker lock(&mutex);
  256. QList<ctkServiceRegistration> res;
  257. for (QHashIterator<ctkServiceRegistration, QStringList> i(services); i.hasNext(); )
  258. {
  259. ctkServiceRegistration sr = i.next().key();
  260. if (sr.d_func()->plugin == p)
  261. {
  262. res.push_back(sr);
  263. }
  264. }
  265. return res;
  266. }
  267. //----------------------------------------------------------------------------
  268. QList<ctkServiceRegistration> ctkServices::getUsedByPlugin(QSharedPointer<ctkPlugin> p) const
  269. {
  270. QMutexLocker lock(&mutex);
  271. QList<ctkServiceRegistration> res;
  272. for (QHashIterator<ctkServiceRegistration, QStringList> i(services); i.hasNext(); )
  273. {
  274. ctkServiceRegistration sr = i.next().key();
  275. if (sr.d_func()->isUsedByPlugin(p))
  276. {
  277. res.push_back(sr);
  278. }
  279. }
  280. return res;
  281. }