ctkPlugins.cxx 9.2 KB

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