ctkPlugins.cpp 9.9 KB

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