ctkServices.cpp 8.2 KB

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