ctkServices.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483
  1. /*=============================================================================
  2. Library: CTK
  3. Copyright (c) 2010 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 "ctkServiceRegistrationPrivate.h"
  23. #include "ctkQtServiceRegistration_p.h"
  24. namespace ctk {
  25. using namespace QtMobility;
  26. //TODO: this is just a mock class. Wait for the real thing
  27. class LDAPExpr
  28. {
  29. public:
  30. LDAPExpr(const QString& filter)
  31. {
  32. }
  33. /**
  34. * Get object class set matched by this LDAP expression. This will not work
  35. * with wildcards and NOT expressions. If a set can not be determined return null.
  36. *
  37. * @return Set of classes matched, otherwise <code>null</code>.
  38. */
  39. QSet<QString> getMatchedObjectClasses() const
  40. {
  41. QSet<QString> objClasses;
  42. return objClasses;
  43. }
  44. /**
  45. * Evaluate this LDAP filter.
  46. */
  47. bool evaluate(const ServiceProperties& p, bool matchCase)
  48. {
  49. return true;
  50. }
  51. };
  52. struct ServiceRegistrationComparator
  53. {
  54. bool operator()(const ServiceRegistration* a, const ServiceRegistration* b) const
  55. {
  56. return *a < *b;
  57. }
  58. };
  59. ServiceProperties Services::createServiceProperties(const ServiceProperties& in,
  60. const QStringList& classes,
  61. long sid)
  62. {
  63. static qlonglong nextServiceID = 1;
  64. ServiceProperties props;
  65. if (!in.isEmpty())
  66. {
  67. for (ServiceProperties::const_iterator it = in.begin(); it != in.end(); ++it)
  68. {
  69. const QString key = it.key();
  70. const QString lcKey = it.key().toLower();
  71. for (QListIterator<QString> i(props.keys()); i.hasNext(); )
  72. {
  73. if (lcKey == i.next())
  74. {
  75. throw std::invalid_argument(std::string("Several entries for property: ") + key.toStdString());
  76. }
  77. }
  78. props.insert(lcKey, in.value(key));
  79. }
  80. }
  81. if (!classes.isEmpty())
  82. {
  83. props.insert(PluginConstants::OBJECTCLASS, classes);
  84. }
  85. props.insert(PluginConstants::SERVICE_ID, sid != -1 ? sid : nextServiceID++);
  86. return props;
  87. }
  88. Services::Services(PluginFrameworkContext* fwCtx)
  89. : mutex(QMutex::Recursive), framework(fwCtx)
  90. {
  91. }
  92. Services::~Services()
  93. {
  94. clear();
  95. }
  96. void Services::clear()
  97. {
  98. QList<ServiceRegistration*> serviceRegs = services.keys();
  99. qDeleteAll(serviceRegs);
  100. services.clear();
  101. classServices.clear();
  102. framework = 0;
  103. }
  104. ServiceRegistration* Services::registerService(PluginPrivate* plugin,
  105. const QStringList& classes,
  106. QObject* service,
  107. const ServiceProperties& properties)
  108. {
  109. if (service == 0)
  110. {
  111. throw std::invalid_argument("Can't register 0 as a service");
  112. }
  113. // Check if service implements claimed classes and that they exist.
  114. for (QStringListIterator i(classes); i.hasNext();)
  115. {
  116. QString cls = i.next();
  117. if (cls.isEmpty())
  118. {
  119. throw std::invalid_argument("Can't register as null class");
  120. }
  121. if (!(qobject_cast<ServiceFactory*>(service)))
  122. {
  123. if (!checkServiceClass(service, cls))
  124. {
  125. throw std::invalid_argument
  126. (std::string("Service object is not an instance of ") + cls.toStdString());
  127. }
  128. }
  129. }
  130. ServiceRegistration* res = new ServiceRegistration(plugin, service,
  131. createServiceProperties(properties, classes));
  132. {
  133. QMutexLocker lock(&mutex);
  134. services.insert(res, classes);
  135. for (QStringListIterator i(classes); i.hasNext(); )
  136. {
  137. QString currClass = i.next();
  138. QList<ServiceRegistration*>& s = classServices[currClass];
  139. QList<ServiceRegistration*>::iterator ip =
  140. std::lower_bound(s.begin(), s.end(), res, ServiceRegistrationComparator());
  141. s.insert(ip, res);
  142. }
  143. }
  144. ServiceReference* r = res->getReference();
  145. // TODO
  146. //Listeners l = bundle.fwCtx.listeners;
  147. //l.serviceChanged(l.getMatchingServiceListeners(r),
  148. // new ServiceEvent(ServiceEvent.REGISTERED, r),
  149. // null);
  150. return res;
  151. }
  152. void Services::registerService(PluginPrivate* plugin, QByteArray serviceDescription)
  153. {
  154. QMutexLocker lock(&mutex);
  155. QBuffer serviceBuffer(&serviceDescription);
  156. qServiceManager.addService(&serviceBuffer);
  157. QServiceManager::Error error = qServiceManager.error();
  158. if (!(error == QServiceManager::NoError || error == QServiceManager::ServiceAlreadyExists))
  159. {
  160. throw std::invalid_argument(std::string("Registering the service descriptor for plugin ")
  161. + plugin->symbolicName.toStdString() + " failed: " +
  162. getQServiceManagerErrorString(error).toStdString());
  163. }
  164. QString serviceName = plugin->symbolicName + "_" + plugin->version.toString();
  165. QList<QServiceInterfaceDescriptor> descriptors = qServiceManager.findInterfaces(serviceName);
  166. if (descriptors.isEmpty())
  167. {
  168. qDebug().nospace() << "Warning: No interfaces found for service name " << serviceName
  169. << " in plugin " << plugin->symbolicName << " (Version " << plugin->version.toString() << ")";
  170. }
  171. QListIterator<QServiceInterfaceDescriptor> it(descriptors);
  172. while (it.hasNext())
  173. {
  174. QServiceInterfaceDescriptor descr = it.next();
  175. qDebug() << "Registering:" << descr.interfaceName();
  176. QStringList classes;
  177. ServiceProperties props;
  178. QStringList customKeys = descr.customAttributes();
  179. QStringListIterator keyIt(customKeys);
  180. bool classAttrFound = false;
  181. while (keyIt.hasNext())
  182. {
  183. QString key = keyIt.next();
  184. if (key == PluginConstants::OBJECTCLASS)
  185. {
  186. classAttrFound = true;
  187. classes << descr.customAttribute(key);
  188. }
  189. else
  190. {
  191. props.insert(key, descr.customAttribute(key));
  192. }
  193. }
  194. if (!classAttrFound)
  195. {
  196. throw std::invalid_argument(std::string("The custom attribute \"") +
  197. PluginConstants::OBJECTCLASS.toStdString() +
  198. "\" is missing in the interface description of \"" +
  199. descr.interfaceName().toStdString());
  200. }
  201. ServiceRegistration* res = new QtServiceRegistration(plugin,
  202. descr,
  203. createServiceProperties(props, classes));
  204. services.insert(res, classes);
  205. for (QStringListIterator i(classes); i.hasNext(); )
  206. {
  207. QString currClass = i.next();
  208. QList<ServiceRegistration*>& s = classServices[currClass];
  209. QList<ServiceRegistration*>::iterator ip =
  210. std::lower_bound(s.begin(), s.end(), res, ServiceRegistrationComparator());
  211. s.insert(ip, res);
  212. }
  213. //ServiceReference* r = res->getReference();
  214. // TODO
  215. //Listeners l = bundle.fwCtx.listeners;
  216. //l.serviceChanged(l.getMatchingServiceListeners(r),
  217. // new ServiceEvent(ServiceEvent.REGISTERED, r),
  218. // null);
  219. }
  220. }
  221. QString Services::getQServiceManagerErrorString(QServiceManager::Error error)
  222. {
  223. switch (error)
  224. {
  225. case QServiceManager::NoError:
  226. return QString("No error occurred.");
  227. case QServiceManager::StorageAccessError:
  228. return QString("The service data storage is not accessible. This could be because the caller does not have the required permissions.");
  229. case QServiceManager::InvalidServiceLocation:
  230. return QString("The service was not found at its specified location.");
  231. case QServiceManager::InvalidServiceXml:
  232. return QString("The XML defining the service metadata is invalid.");
  233. case QServiceManager::InvalidServiceInterfaceDescriptor:
  234. return QString("The service interface descriptor is invalid, or refers to an interface implementation that cannot be accessed in the current scope.");
  235. case QServiceManager::ServiceAlreadyExists:
  236. return QString("Another service has previously been registered with the same location.");
  237. case QServiceManager::ImplementationAlreadyExists:
  238. return QString("Another service that implements the same interface version has previously been registered.");
  239. case QServiceManager::PluginLoadingFailed:
  240. return QString("The service plugin cannot be loaded.");
  241. case QServiceManager::ComponentNotFound:
  242. return QString("The service or interface implementation has not been registered.");
  243. case QServiceManager::ServiceCapabilityDenied:
  244. return QString("The security session does not allow the service based on its capabilities.");
  245. case QServiceManager::UnknownError:
  246. return QString("An unknown error occurred.");
  247. default:
  248. return QString("Unknown error enum.");
  249. }
  250. }
  251. void Services::updateServiceRegistrationOrder(ServiceRegistration* sr,
  252. const QStringList& classes)
  253. {
  254. QMutexLocker lock(&mutex);
  255. for (QStringListIterator i(classes); i.hasNext(); )
  256. {
  257. QList<ServiceRegistration*>& s = classServices[i.next()];
  258. s.removeAll(sr);
  259. s.insert(std::lower_bound(s.begin(), s.end(), sr, ServiceRegistrationComparator()), sr);
  260. }
  261. }
  262. bool Services::checkServiceClass(QObject* service, const QString& cls) const
  263. {
  264. return service->inherits(cls.toAscii());
  265. }
  266. QList<ServiceRegistration*> Services::get(const QString& clazz) const
  267. {
  268. QMutexLocker lock(&mutex);
  269. return classServices.value(clazz);
  270. }
  271. ServiceReference* Services::get(PluginPrivate* plugin, const QString& clazz) const
  272. {
  273. QMutexLocker lock(&mutex);
  274. try {
  275. QList<ServiceReference*> srs = get(clazz, QString());
  276. qDebug() << "get service ref" << clazz << "for plugin"
  277. << plugin->location << " = " << srs;
  278. if (!srs.isEmpty()) {
  279. return srs.front();
  280. }
  281. }
  282. catch (const std::invalid_argument& )
  283. { }
  284. return 0;
  285. }
  286. QList<ServiceReference*> Services::get(const QString& clazz, const QString& filter) const
  287. {
  288. QMutexLocker lock(&mutex);
  289. QListIterator<ServiceRegistration*>* s = 0;
  290. LDAPExpr ldap("");
  291. if (clazz.isEmpty())
  292. {
  293. if (!filter.isEmpty())
  294. {
  295. ldap = LDAPExpr(filter);
  296. QSet<QString> matched = ldap.getMatchedObjectClasses();
  297. if (!matched.isEmpty())
  298. {
  299. //TODO
  300. // ArrayList v = null;
  301. // boolean vReadOnly = true;;
  302. // for (Iterator i = matched.iterator(); i.hasNext(); ) {
  303. // ArrayList cl = (ArrayList) classServices.get(i.next());
  304. // if (cl != null) {
  305. // if (v == null) {
  306. // v = cl;
  307. // } else {
  308. // if (vReadOnly) {
  309. // v = new ArrayList(v);
  310. // vReadOnly = false;
  311. // }
  312. // v.addAll(cl);
  313. // }
  314. // }
  315. // }
  316. // if (v != null) {
  317. // s = v.iterator();
  318. // } else {
  319. // return null;
  320. // }
  321. }
  322. else
  323. {
  324. s = new QListIterator<ServiceRegistration*>(services.keys());
  325. }
  326. }
  327. else
  328. {
  329. s = new QListIterator<ServiceRegistration*>(services.keys());
  330. }
  331. }
  332. else
  333. {
  334. QList<ServiceRegistration*> v = classServices.value(clazz);
  335. if (!v.isEmpty())
  336. {
  337. s = new QListIterator<ServiceRegistration*>(v);
  338. }
  339. else
  340. {
  341. return QList<ServiceReference*>();
  342. }
  343. if (!filter.isEmpty())
  344. {
  345. ldap = LDAPExpr(filter);
  346. }
  347. }
  348. QList<ServiceReference*> res;
  349. while (s->hasNext())
  350. {
  351. ServiceRegistration* sr = s->next();
  352. ServiceReference* sri = sr->getReference();
  353. if (filter.isEmpty() || ldap.evaluate(sr->d_func()->properties, false))
  354. {
  355. res.push_back(sri);
  356. }
  357. }
  358. delete s;
  359. return res;
  360. }
  361. void Services::removeServiceRegistration(ServiceRegistration* sr)
  362. {
  363. QMutexLocker lock(&mutex);
  364. QStringList classes = sr->d_func()->properties.value(PluginConstants::OBJECTCLASS).toStringList();
  365. services.remove(sr);
  366. for (QStringListIterator i(classes); i.hasNext(); )
  367. {
  368. QString currClass = i.next();
  369. QList<ServiceRegistration*>& s = classServices[currClass];
  370. if (s.size() > 1)
  371. {
  372. s.removeAll(sr);
  373. }
  374. else
  375. {
  376. classServices.remove(currClass);
  377. }
  378. }
  379. }
  380. QList<ServiceRegistration*> Services::getRegisteredByPlugin(PluginPrivate* p) const
  381. {
  382. QMutexLocker lock(&mutex);
  383. QList<ServiceRegistration*> res;
  384. for (QHashIterator<ServiceRegistration*, QStringList> i(services); i.hasNext(); )
  385. {
  386. ServiceRegistration* sr = i.next().key();
  387. if (sr->d_func()->plugin = p)
  388. {
  389. res.push_back(sr);
  390. }
  391. }
  392. return res;
  393. }
  394. QList<ServiceRegistration*> Services::getUsedByPlugin(Plugin* p) const
  395. {
  396. QMutexLocker lock(&mutex);
  397. QList<ServiceRegistration*> res;
  398. for (QHashIterator<ServiceRegistration*, QStringList> i(services); i.hasNext(); )
  399. {
  400. ServiceRegistration* sr = i.next().key();
  401. if (sr->d_func()->isUsedByPlugin(p))
  402. {
  403. res.push_back(sr);
  404. }
  405. }
  406. return res;
  407. }
  408. }