ctkPlugins.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  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 "ctkPlugins_p.h"
  16. #include "ctkPluginPrivate_p.h"
  17. #include "ctkPluginArchive_p.h"
  18. #include "ctkPluginException.h"
  19. #include "ctkPluginFrameworkContext_p.h"
  20. #include "ctkVersionRange_p.h"
  21. #include <stdexcept>
  22. #include <iostream>
  23. #include <QUrl>
  24. //----------------------------------------------------------------------------
  25. ctkPlugins::ctkPlugins(ctkPluginFrameworkContext* fw)
  26. {
  27. fwCtx = fw;
  28. plugins.insert(fw->systemPlugin->getLocation(), fw->systemPlugin);
  29. }
  30. //----------------------------------------------------------------------------
  31. void ctkPlugins::clear()
  32. {
  33. QWriteLocker lock(&pluginsLock);
  34. plugins.clear();
  35. fwCtx = 0;
  36. }
  37. //----------------------------------------------------------------------------
  38. QSharedPointer<ctkPlugin> ctkPlugins::install(const QUrl& location, QIODevice* in)
  39. {
  40. if (!fwCtx)
  41. { // This ctkPlugins instance has been closed!
  42. throw std::logic_error("ctkPlugins::install(location, inputStream) called on closed plugins object.");
  43. }
  44. QSharedPointer<ctkPlugin> res;
  45. {
  46. QMutexLocker lock(&objectLock);
  47. QHash<QString, QSharedPointer<ctkPlugin> >::const_iterator it = plugins.find(location.toString());
  48. if (it != plugins.end())
  49. {
  50. return it.value();
  51. }
  52. // install new plugin
  53. ctkPluginArchive* pa = 0;
  54. QString localPluginPath;
  55. try
  56. {
  57. if (!in)
  58. {
  59. // extract the input stream from the given location
  60. // //TODO Support for http proxy authentication
  61. // //TODO put in update as well
  62. // String auth = fwCtx.props.getProperty("http.proxyAuth");
  63. // if (auth != null && !"".equals(auth)) {
  64. // if ("http".equals(url.getProtocol()) ||
  65. // "https".equals(url.getProtocol())) {
  66. // String base64 = Util.base64Encode(auth);
  67. // conn.setRequestProperty("Proxy-Authorization",
  68. // "Basic " + base64);
  69. // }
  70. // }
  71. // // Support for http basic authentication
  72. // String basicAuth = fwCtx.props.getProperty("http.basicAuth");
  73. // if (basicAuth != null && !"".equals(basicAuth)) {
  74. // if ("http".equals(url.getProtocol()) ||
  75. // "https".equals(url.getProtocol())) {
  76. // String base64 = Util.base64Encode(basicAuth);
  77. // conn.setRequestProperty("Authorization",
  78. // "Basic " +base64);
  79. // }
  80. // }
  81. if (location.scheme() != "file")
  82. {
  83. throw std::runtime_error(std::string("Unsupported url scheme: ") + qPrintable(location.scheme()));
  84. }
  85. else
  86. {
  87. qDebug() << QString("Trying to install file:") << location.path();
  88. localPluginPath = location.toLocalFile();
  89. }
  90. }
  91. else
  92. {
  93. //TODO copy the QIODevice to a local cache
  94. }
  95. pa = fwCtx->storage->insertPlugin(location, localPluginPath);
  96. res = QSharedPointer<ctkPlugin>(new ctkPlugin());
  97. res->init(res, fwCtx, pa);
  98. plugins.insert(location.toString(), res);
  99. }
  100. catch (const std::exception& e)
  101. {
  102. if (pa)
  103. {
  104. pa->purge();
  105. }
  106. // if (dynamic_cast<const SecurityException&>(e)) {
  107. // throw;
  108. // }
  109. // else
  110. // {
  111. throw ctkPluginException(QString("Failed to install plugin: ") + QString(e.what()),
  112. ctkPluginException::UNSPECIFIED, &e);
  113. // }
  114. }
  115. }
  116. fwCtx->listeners.emitPluginChanged(ctkPluginEvent(ctkPluginEvent::INSTALLED, res));
  117. return res;
  118. }
  119. //----------------------------------------------------------------------------
  120. void ctkPlugins::remove(const QUrl& location)
  121. {
  122. QWriteLocker lock(&pluginsLock);
  123. plugins.remove(location.toString());
  124. }
  125. //----------------------------------------------------------------------------
  126. QSharedPointer<ctkPlugin> ctkPlugins::getPlugin(int id) const
  127. {
  128. if (!fwCtx)
  129. { // This plugins instance has been closed!
  130. throw std::logic_error("ctkPlugins::getPlugin(id) called on closed plugins object.");
  131. }
  132. {
  133. QReadLocker lock(&pluginsLock);
  134. QHashIterator<QString, QSharedPointer<ctkPlugin> > it(plugins);
  135. while (it.hasNext())
  136. {
  137. QSharedPointer<ctkPlugin> plugin = it.next().value();
  138. if (plugin->getPluginId() == id)
  139. {
  140. return plugin;
  141. }
  142. }
  143. }
  144. return QSharedPointer<ctkPlugin>();
  145. }
  146. //----------------------------------------------------------------------------
  147. QSharedPointer<ctkPlugin> ctkPlugins::getPlugin(const QString& location) const
  148. {
  149. if (!fwCtx)
  150. { // This plugins instance has been closed!
  151. throw std::logic_error("ctkPlugins::getPlugin(location) called on closed plugins object.");
  152. }
  153. QReadLocker lock(&pluginsLock);
  154. QHash<QString, QSharedPointer<ctkPlugin> >::const_iterator it = plugins.find(location);
  155. if (it != plugins.end()) return it.value();
  156. return QSharedPointer<ctkPlugin>(0);
  157. }
  158. //----------------------------------------------------------------------------
  159. QSharedPointer<ctkPlugin> ctkPlugins::getPlugin(const QString& name, const ctkVersion& version) const
  160. {
  161. if (!fwCtx)
  162. { // This ctkPlugins instance has been closed!
  163. throw std::logic_error("ctkPlugins::getPlugin(name, version) called on closed plugins object.");
  164. }
  165. {
  166. QReadLocker lock(&pluginsLock);
  167. QHashIterator<QString, QSharedPointer<ctkPlugin> > it(plugins);
  168. while (it.hasNext())
  169. {
  170. QSharedPointer<ctkPlugin> plugin = it.next().value();
  171. if ((name == plugin->getSymbolicName()) && (version == plugin->getVersion()))
  172. {
  173. return plugin;
  174. }
  175. }
  176. }
  177. return QSharedPointer<ctkPlugin>(0);
  178. }
  179. //----------------------------------------------------------------------------
  180. QList<QSharedPointer<ctkPlugin> > ctkPlugins::getPlugins() const
  181. {
  182. if (!fwCtx)
  183. { // This plugins instance has been closed!
  184. throw std::logic_error("ctkPlugins::getPlugins() called on closed plugins object.");
  185. }
  186. {
  187. QReadLocker lock(&pluginsLock);
  188. return plugins.values();
  189. }
  190. }
  191. //----------------------------------------------------------------------------
  192. QList<ctkPlugin*> ctkPlugins::getPlugins(const QString& name) const
  193. {
  194. QList<ctkPlugin*> res;
  195. {
  196. QReadLocker lock(&pluginsLock);
  197. QHashIterator<QString, QSharedPointer<ctkPlugin> > it(plugins);
  198. while (it.hasNext())
  199. {
  200. ctkPlugin* plugin = it.next().value().data();
  201. if (name == plugin->getSymbolicName())
  202. {
  203. res.push_back(plugin);
  204. }
  205. }
  206. }
  207. return res;
  208. }
  209. //----------------------------------------------------------------------------
  210. QList<ctkPlugin*> ctkPlugins::getPlugins(const QString& name, const ctkVersionRange& range) const
  211. {
  212. if (!fwCtx)
  213. { // This plugins instance has been closed!
  214. throw std::logic_error("ctkPlugins::getPlugins(name, versionRange) called on closed plugins object.");
  215. }
  216. QList<ctkPlugin*> pluginsWithName = getPlugins(name);
  217. QList<ctkPlugin*> res;
  218. QListIterator<ctkPlugin*> it(pluginsWithName);
  219. while (it.hasNext()) {
  220. ctkPlugin* plugin = it.next();
  221. if (range.withinRange(plugin->getVersion()))
  222. {
  223. int j = res.size();
  224. while (--j >= 0)
  225. {
  226. if (plugin->getVersion().compare(res.at(j)->getVersion()) <= 0)
  227. {
  228. break;
  229. }
  230. }
  231. res.insert(j + 1, plugin);
  232. }
  233. }
  234. return res;
  235. }
  236. //----------------------------------------------------------------------------
  237. QList<ctkPlugin*> ctkPlugins::getActivePlugins() const
  238. {
  239. if (!fwCtx)
  240. { // This plugins instance has been closed!
  241. throw std::logic_error("ctkPlugins::getActivePlugins() called on closed plugins object.");
  242. }
  243. QList<ctkPlugin*> slist;
  244. {
  245. QReadLocker lock(&pluginsLock);
  246. QHashIterator<QString, QSharedPointer<ctkPlugin> > it(plugins);
  247. while (it.hasNext())
  248. {
  249. QSharedPointer<ctkPlugin> plugin = it.next().value();
  250. ctkPlugin::State s = plugin->getState();
  251. if (s == ctkPlugin::ACTIVE || s == ctkPlugin::STARTING) {
  252. slist.push_back(plugin.data());
  253. }
  254. }
  255. }
  256. return slist;
  257. }
  258. //----------------------------------------------------------------------------
  259. void ctkPlugins::load()
  260. {
  261. QList<ctkPluginArchive*> pas = fwCtx->storage->getAllPluginArchives();
  262. QListIterator<ctkPluginArchive*> it(pas);
  263. {
  264. QMutexLocker lock(&objectLock);
  265. while (it.hasNext())
  266. {
  267. ctkPluginArchive* pa = it.next();
  268. try
  269. {
  270. QSharedPointer<ctkPlugin> plugin(new ctkPlugin());
  271. plugin->init(plugin, fwCtx, pa);
  272. plugins.insert(pa->getPluginLocation().toString(), plugin);
  273. }
  274. catch (const std::exception& e)
  275. {
  276. pa->setAutostartSetting(-1); // Do not start on launch
  277. pa->setStartLevel(-2); // Mark as uninstalled
  278. std::cerr << "Error: Failed to load bundle "
  279. << pa->getPluginId()
  280. << " (" << qPrintable(pa->getPluginLocation().toString()) << ")"
  281. << " uninstalled it!\n";
  282. std::cerr << e.what() << std::endl;
  283. }
  284. }
  285. }
  286. }
  287. //----------------------------------------------------------------------------
  288. void ctkPlugins::startPlugins(const QList<ctkPlugin*>& slist) const
  289. {
  290. // Sort in start order
  291. // Resolve first to avoid dead lock
  292. QListIterator<ctkPlugin*> it(slist);
  293. while (it.hasNext())
  294. {
  295. ctkPlugin* plugin = it.next();
  296. ctkPluginPrivate* pp = plugin->d_func();
  297. pp->getUpdatedState();
  298. }
  299. it.toFront();
  300. while (it.hasNext())
  301. {
  302. ctkPlugin* plugin = it.next();
  303. ctkPluginPrivate* pp = plugin->d_func();
  304. if (pp->getUpdatedState() == ctkPlugin::RESOLVED)
  305. {
  306. try
  307. {
  308. plugin->start(0);
  309. }
  310. catch (const ctkPluginException& pe)
  311. {
  312. pp->fwCtx->listeners.frameworkError(pp->q_func(), pe);
  313. }
  314. }
  315. }
  316. }