ctkPluginFrameworkLauncher.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763
  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 "ctkPluginFrameworkLauncher.h"
  16. #include "ctkPluginFrameworkFactory.h"
  17. #include "ctkPluginFrameworkProperties_p.h"
  18. #include "ctkPluginFramework.h"
  19. #include "ctkPluginContext.h"
  20. #include "ctkPluginException.h"
  21. #include "ctkDefaultApplicationLauncher_p.h"
  22. #include "ctkLocationManager_p.h"
  23. #include "ctkBasicLocation_p.h"
  24. #include <ctkConfig.h>
  25. #include <QStringList>
  26. #include <QDirIterator>
  27. #include <QFileInfo>
  28. #include <QDebug>
  29. #include <QRunnable>
  30. #include <QSettings>
  31. #include <QProcessEnvironment>
  32. #ifdef _WIN32
  33. #include <windows.h>
  34. #include <cstdlib>
  35. #endif // _WIN32
  36. const QString ctkPluginFrameworkLauncher::PROP_USER_HOME = "user.home";
  37. const QString ctkPluginFrameworkLauncher::PROP_USER_DIR = "user.dir";
  38. // Framework properties
  39. const QString ctkPluginFrameworkLauncher::PROP_PLUGINS = "ctk.plugins";
  40. const QString ctkPluginFrameworkLauncher::PROP_DEBUG = "ctk.debug";
  41. const QString ctkPluginFrameworkLauncher::PROP_DEV = "ctk.dev";
  42. const QString ctkPluginFrameworkLauncher::PROP_CONSOLE = "ctk.console";
  43. const QString ctkPluginFrameworkLauncher::PROP_OS = "ctk.os";
  44. const QString ctkPluginFrameworkLauncher::PROP_ARCH = "ctk.arch";
  45. const QString ctkPluginFrameworkLauncher::PROP_NOSHUTDOWN = "ctk.noShutdown";
  46. const QString ctkPluginFrameworkLauncher::PROP_IGNOREAPP = "ctk.ignoreApp";
  47. const QString ctkPluginFrameworkLauncher::PROP_INSTALL_AREA = "ctk.install.area";
  48. const QString ctkPluginFrameworkLauncher::PROP_CONFIG_AREA = "ctk.configuration.area";
  49. const QString ctkPluginFrameworkLauncher::PROP_SHARED_CONFIG_AREA = "ctk.sharedConfiguration.area";
  50. const QString ctkPluginFrameworkLauncher::PROP_INSTANCE_AREA = "ctk.instance.area";
  51. const QString ctkPluginFrameworkLauncher::PROP_USER_AREA = "ctk.user.area";
  52. const QString ctkPluginFrameworkLauncher::PROP_HOME_LOCATION_AREA = "ctk.home.location";
  53. const QString ctkPluginFrameworkLauncher::PROP_CONFIG_AREA_DEFAULT = "ctk.configuration.area.default";
  54. const QString ctkPluginFrameworkLauncher::PROP_INSTANCE_AREA_DEFAULT = "ctk.instance.area.default";
  55. const QString ctkPluginFrameworkLauncher::PROP_USER_AREA_DEFAULT = "ctk.user.area.default";
  56. const QString ctkPluginFrameworkLauncher::PROP_EXITCODE = "ctk.exitcode";
  57. const QString ctkPluginFrameworkLauncher::PROP_EXITDATA = "ctk.exitdata";
  58. const QString ctkPluginFrameworkLauncher::PROP_CONSOLE_LOG = "ctk.consoleLog";
  59. const QString ctkPluginFrameworkLauncher::PROP_ALLOW_APPRELAUNCH = "ctk.allowAppRelaunch";
  60. const QString ctkPluginFrameworkLauncher::PROP_APPLICATION_LAUNCHDEFAULT = "ctk.application.launchDefault";
  61. const QString ctkPluginFrameworkLauncher::PROP_OSGI_RELAUNCH = "ctk.pluginfw.relaunch";
  62. static const QString PROP_FORCED_RESTART = "ctk.forcedRestart";
  63. class ctkPluginFrameworkLauncherPrivate
  64. {
  65. public:
  66. //----------------------------------------------------------------------------
  67. ctkPluginFrameworkLauncherPrivate()
  68. : fwFactory(0)
  69. , running(false)
  70. , endSplashHandler(NULL)
  71. , processEnv(QProcessEnvironment::systemEnvironment())
  72. {
  73. #ifdef CMAKE_INTDIR
  74. QString pluginPath = CTK_PLUGIN_DIR CMAKE_INTDIR "/";
  75. #else
  76. QString pluginPath = CTK_PLUGIN_DIR;
  77. #endif
  78. pluginSearchPaths.append(pluginPath);
  79. pluginLibFilter << "*.dll" << "*.so" << "*.dylib";
  80. }
  81. //----------------------------------------------------------------------------
  82. bool isForcedRestart() const
  83. {
  84. return ctkPluginFrameworkProperties::getProperty(PROP_FORCED_RESTART).toBool();
  85. }
  86. //----------------------------------------------------------------------------
  87. void loadConfigurationInfo()
  88. {
  89. ctkBasicLocation* configArea = ctkLocationManager::getConfigurationLocation();
  90. if (configArea == NULL)
  91. {
  92. return;
  93. }
  94. QUrl location(configArea->getUrl().toString() + ctkLocationManager::CONFIG_FILE);
  95. mergeProperties(ctkPluginFrameworkProperties::getProperties(), loadProperties(location));
  96. }
  97. //----------------------------------------------------------------------------
  98. void mergeProperties(ctkProperties& destination, const ctkProperties& source)
  99. {
  100. for (ctkProperties::const_iterator iter = source.begin(); iter != source.end(); ++iter)
  101. {
  102. if (!destination.contains(iter.key()))
  103. {
  104. destination.insert(iter.key(), iter.value());
  105. }
  106. }
  107. }
  108. //----------------------------------------------------------------------------
  109. ctkProperties loadProperties(const QUrl& location)
  110. {
  111. ctkProperties result;
  112. if (!location.isValid() || !QFileInfo(location.toLocalFile()).exists())
  113. {
  114. return result;
  115. }
  116. QSettings iniProps(location.toLocalFile(), QSettings::IniFormat);
  117. foreach (const QString& key, iniProps.allKeys())
  118. {
  119. result.insert(key, iniProps.value(key));
  120. }
  121. return substituteVars(result);
  122. }
  123. //----------------------------------------------------------------------------
  124. ctkProperties& substituteVars(ctkProperties& result)
  125. {
  126. for (ctkProperties::iterator iter = result.begin(); iter != result.end(); ++iter)
  127. {
  128. if (iter.value().type() == QVariant::String)
  129. {
  130. iter.value() = substituteVars(iter.value().toString());
  131. }
  132. }
  133. return result;
  134. }
  135. //----------------------------------------------------------------------------
  136. QString substituteVars(const QString& path)
  137. {
  138. QString buf;
  139. bool varStarted = false; // indicates we are processing a var subtitute
  140. QString var; // the current var key
  141. for (QString::const_iterator iter = path.begin(); iter != path.end(); ++iter)
  142. {
  143. QChar tok = *iter;
  144. if (tok == '$')
  145. {
  146. if (!varStarted)
  147. {
  148. varStarted = true; // we found the start of a var
  149. var.clear();
  150. }
  151. else
  152. {
  153. // we have found the end of a var
  154. QVariant prop;
  155. // get the value of the var from system properties
  156. if (!var.isEmpty())
  157. {
  158. prop = ctkPluginFrameworkProperties::getProperty(var);
  159. }
  160. if (prop.isNull() && processEnv.contains(var))
  161. {
  162. prop = processEnv.value(var);
  163. }
  164. if (!prop.isNull())
  165. {
  166. // found a value; use it
  167. buf.append(prop.toString());
  168. }
  169. else
  170. {
  171. // could not find a value append the var name w/o delims
  172. buf.append(var);
  173. }
  174. varStarted = false;
  175. var.clear();
  176. }
  177. }
  178. else
  179. {
  180. if (!varStarted)
  181. {
  182. buf.append(tok); // the token is not part of a var
  183. }
  184. else
  185. {
  186. var.append(tok); // the token is part of the var key; save the key to process when we find the end token
  187. }
  188. }
  189. }
  190. if (!var.isEmpty())
  191. {
  192. // found a case of $var at the end of the path with no trailing $; just append it as is.
  193. buf.append('$').append(var);
  194. }
  195. return buf;
  196. }
  197. //----------------------------------------------------------------------------
  198. QSharedPointer<ctkPlugin> install(const QUrl& pluginPath, ctkPluginContext* context)
  199. {
  200. try
  201. {
  202. return context->installPlugin(pluginPath);
  203. }
  204. catch (const ctkPluginException& exc)
  205. {
  206. qWarning() << "Failed to install plugin " << pluginPath << ":" << exc.printStackTrace();
  207. return QSharedPointer<ctkPlugin>();
  208. }
  209. }
  210. //----------------------------------------------------------------------------
  211. QSharedPointer<ctkPlugin> install(const QString& symbolicName, ctkPluginContext* context)
  212. {
  213. QString pluginPath = ctkPluginFrameworkLauncher::getPluginPath(symbolicName);
  214. if (pluginPath.isEmpty()) return QSharedPointer<ctkPlugin>();
  215. ctkPluginContext* pc = context;
  216. if (pc == 0 && fwFactory == 0)
  217. {
  218. fwFactory.reset(new ctkPluginFrameworkFactory(fwProps));
  219. try
  220. {
  221. fwFactory->getFramework()->init();
  222. pc = fwFactory->getFramework()->getPluginContext();
  223. }
  224. catch (const ctkPluginException& exc)
  225. {
  226. qCritical() << "Failed to initialize the plug-in framework:" << exc;
  227. fwFactory.reset();
  228. return QSharedPointer<ctkPlugin>();
  229. }
  230. }
  231. return install(QUrl::fromLocalFile(pluginPath), pc);
  232. }
  233. /*
  234. * Ensure all basic plugins are installed, resolved and scheduled to start. Returns a list containing
  235. * all basic bundles that are marked to start.
  236. */
  237. //----------------------------------------------------------------------------
  238. void loadBasicPlugins()
  239. {
  240. QVariant pluginsProp = ctkPluginFrameworkProperties::getProperty(ctkPluginFrameworkLauncher::PROP_PLUGINS);
  241. QStringList installEntries;
  242. if (pluginsProp.type() == QVariant::StringList)
  243. {
  244. installEntries = pluginsProp.toStringList();
  245. }
  246. else
  247. {
  248. installEntries = pluginsProp.toString().split(',');
  249. }
  250. QList<QSharedPointer<ctkPlugin> > startEntries;
  251. ctkPluginContext* context = fwFactory->getFramework()->getPluginContext();
  252. foreach(const QString& installEntry, installEntries)
  253. {
  254. QUrl pluginUrl(installEntry);
  255. if (pluginUrl.isValid() && pluginUrl.scheme().isEmpty())
  256. {
  257. // try a local file path
  258. QFileInfo installFileInfo(installEntry);
  259. if (installFileInfo.exists())
  260. {
  261. pluginUrl = QUrl::fromLocalFile(installFileInfo.absoluteFilePath());
  262. }
  263. else
  264. {
  265. pluginUrl.clear();
  266. }
  267. }
  268. if (pluginUrl.isValid())
  269. {
  270. QSharedPointer<ctkPlugin> plugin = install(pluginUrl, context);
  271. if (plugin)
  272. {
  273. startEntries.push_back(plugin);
  274. }
  275. }
  276. else
  277. {
  278. QSharedPointer<ctkPlugin> plugin = install(installEntry, context);
  279. if (plugin)
  280. {
  281. // schedule all basic bundles to be started
  282. startEntries.push_back(plugin);
  283. }
  284. }
  285. }
  286. foreach(QSharedPointer<ctkPlugin> plugin, startEntries)
  287. {
  288. plugin->start();
  289. }
  290. }
  291. QStringList pluginSearchPaths;
  292. QStringList pluginLibFilter;
  293. ctkProperties fwProps;
  294. QScopedPointer<ctkPluginFrameworkFactory> fwFactory;
  295. bool running;
  296. QRunnable* endSplashHandler;
  297. QScopedPointer<ctkDefaultApplicationLauncher> appLauncher;
  298. ctkServiceRegistration appLauncherRegistration;
  299. QProcessEnvironment processEnv;
  300. };
  301. const QScopedPointer<ctkPluginFrameworkLauncherPrivate> ctkPluginFrameworkLauncher::d(
  302. new ctkPluginFrameworkLauncherPrivate());
  303. //----------------------------------------------------------------------------
  304. void ctkPluginFrameworkLauncher::setFrameworkProperties(const ctkProperties& props)
  305. {
  306. ctkPluginFrameworkProperties::setProperties(props);
  307. }
  308. //----------------------------------------------------------------------------
  309. QVariant ctkPluginFrameworkLauncher::run(QRunnable* endSplashHandler)
  310. {
  311. if (d->running)
  312. {
  313. throw ctkIllegalStateException("Framework already running");
  314. }
  315. {
  316. struct Finalize {
  317. ~Finalize()
  318. {
  319. try
  320. {
  321. // The application typically sets the exit code however the framework can request that
  322. // it be re-started. We need to check for this and potentially override the exit code.
  323. if (d->isForcedRestart())
  324. {
  325. ctkPluginFrameworkProperties::setProperty(PROP_EXITCODE, "23");
  326. }
  327. if (!ctkPluginFrameworkProperties::getProperty(PROP_NOSHUTDOWN).toBool())
  328. {
  329. shutdown();
  330. }
  331. }
  332. catch (const std::exception& e)
  333. {
  334. qWarning() << "Shutdown error:" << e.what();
  335. }
  336. }
  337. };
  338. Finalize finalizer;
  339. Q_UNUSED(finalizer)
  340. try
  341. {
  342. startup(d->endSplashHandler);
  343. if (ctkPluginFrameworkProperties::getProperty(PROP_IGNOREAPP).toBool() || d->isForcedRestart())
  344. {
  345. return QVariant();
  346. }
  347. return run(QVariant());
  348. }
  349. catch (const std::exception& e)
  350. {
  351. // ensure the splash screen is down
  352. if (endSplashHandler != NULL)
  353. {
  354. endSplashHandler->run();
  355. }
  356. // may use startupFailed to understand where the error happened
  357. if (const ctkException* ce = dynamic_cast<const ctkException*>(&e))
  358. {
  359. qWarning() << "Startup error:" << ce->printStackTrace();
  360. }
  361. else
  362. {
  363. qWarning() << "Startup error:" << e.what();
  364. }
  365. }
  366. }
  367. // we only get here if an error happened
  368. if (ctkPluginFrameworkProperties::getProperty(PROP_EXITCODE).isNull())
  369. {
  370. ctkPluginFrameworkProperties::setProperty(PROP_EXITCODE, "13");
  371. ctkPluginFrameworkProperties::setProperty(PROP_EXITDATA, QString("An error has occured. See the console output and log file for details."));
  372. }
  373. return QVariant();
  374. }
  375. //----------------------------------------------------------------------------
  376. QVariant ctkPluginFrameworkLauncher::run(const QVariant& argument)
  377. {
  378. if (!d->running)
  379. {
  380. throw ctkIllegalStateException("Framework not running.");
  381. }
  382. // if we are just initializing, do not run the application just return.
  383. /*
  384. if (d->initialize)
  385. {
  386. return 0;
  387. }
  388. */
  389. try
  390. {
  391. if (!d->appLauncher)
  392. {
  393. bool launchDefault = ctkPluginFrameworkProperties::getProperty(PROP_APPLICATION_LAUNCHDEFAULT, true).toBool();
  394. // create the ApplicationLauncher and register it as a service
  395. d->appLauncher.reset(new ctkDefaultApplicationLauncher(d->fwFactory->getFramework()->getPluginContext(),
  396. ctkPluginFrameworkProperties::getProperty(PROP_ALLOW_APPRELAUNCH).toBool(),
  397. launchDefault));
  398. d->appLauncherRegistration = d->fwFactory->getFramework()->getPluginContext()->
  399. registerService<ctkApplicationLauncher>(d->appLauncher.data());
  400. // must start the launcher AFTER service registration because this method
  401. // blocks and runs the application on the current thread. This method
  402. // will return only after the application has stopped.
  403. return d->appLauncher->start(argument);
  404. }
  405. return d->appLauncher->reStart(argument);
  406. }
  407. catch (const ctkException& e)
  408. {
  409. qWarning() << "Application launch failed:" << e.printStackTrace();
  410. throw;
  411. }
  412. catch (const std::exception& e)
  413. {
  414. qWarning() << "Application launch failed:" << e.what();
  415. throw;
  416. }
  417. }
  418. //----------------------------------------------------------------------------
  419. ctkPluginContext* ctkPluginFrameworkLauncher::startup(QRunnable* /*endSplashHandler*/)
  420. {
  421. if (d->running)
  422. {
  423. throw ctkIllegalStateException("Framework already running.");
  424. }
  425. ctkPluginFrameworkProperties::initializeProperties();
  426. //processCommandLine(args);
  427. ctkLocationManager::initializeLocations();
  428. d->loadConfigurationInfo();
  429. //finalizeProperties();
  430. d->fwFactory.reset(new ctkPluginFrameworkFactory(ctkPluginFrameworkProperties::getProperties()));
  431. //d->context = framework.getBundle(0).getBundleContext();
  432. //registerFrameworkShutdownHandlers();
  433. //publishSplashScreen(endSplashHandler);
  434. //consoleMgr = ConsoleManager.startConsole(framework);
  435. d->fwFactory->getFramework()->start();
  436. d->loadBasicPlugins();
  437. d->running = true;
  438. return d->fwFactory->getFramework()->getPluginContext();
  439. }
  440. void ctkPluginFrameworkLauncher::shutdown()
  441. {
  442. if (!d->running || d->fwFactory == NULL)
  443. return;
  444. //if (appLauncherRegistration != null)
  445. // appLauncherRegistration.unregister();
  446. //if (splashStreamRegistration != null)
  447. // splashStreamRegistration.unregister();
  448. //if (defaultMonitorRegistration != null)
  449. // defaultMonitorRegistration.unregister();
  450. if (d->appLauncher)
  451. {
  452. d->appLauncher->shutdown();
  453. }
  454. //appLauncherRegistration = null;
  455. //appLauncher = null;
  456. //splashStreamRegistration = null;
  457. //defaultMonitorRegistration = null;
  458. //d->fwFactory.reset();
  459. stop();
  460. d->running = false;
  461. }
  462. //----------------------------------------------------------------------------
  463. long ctkPluginFrameworkLauncher::install(const QString& symbolicName, ctkPluginContext* context)
  464. {
  465. QSharedPointer<ctkPlugin> plugin = d->install(symbolicName, context);
  466. if (plugin) return plugin->getPluginId();
  467. return -1;
  468. }
  469. //----------------------------------------------------------------------------
  470. bool ctkPluginFrameworkLauncher::start(const QString& symbolicName, ctkPlugin::StartOptions options,
  471. ctkPluginContext* context)
  472. {
  473. // instantiate and start the framework
  474. if (context == 0 && d->fwFactory == 0) {
  475. d->fwFactory.reset(new ctkPluginFrameworkFactory(d->fwProps));
  476. try
  477. {
  478. d->fwFactory->getFramework()->start();
  479. }
  480. catch (const ctkPluginException& exc)
  481. {
  482. qCritical() << "Failed to start the plug-in framework:" << exc;
  483. d->fwFactory.reset();
  484. return false;
  485. }
  486. }
  487. else if (context == 0 && d->fwFactory->getFramework()->getState() != ctkPlugin::ACTIVE)
  488. {
  489. try
  490. {
  491. d->fwFactory->getFramework()->start(options);
  492. }
  493. catch (const ctkPluginException& exc)
  494. {
  495. qCritical() << "Failed to start the plug-in framework:" << exc;
  496. d->fwFactory.reset();
  497. return false;
  498. }
  499. }
  500. if(!symbolicName.isEmpty())
  501. {
  502. QString pluginPath = getPluginPath(symbolicName);
  503. if (pluginPath.isEmpty()) return false;
  504. ctkPluginContext* pc = context ? context : getPluginContext();
  505. try
  506. {
  507. pc->installPlugin(QUrl::fromLocalFile(pluginPath))->start(options);
  508. }
  509. catch (const ctkPluginException& exc)
  510. {
  511. qWarning() << "Failed to install plugin:" << exc;
  512. return false;
  513. }
  514. }
  515. return true;
  516. }
  517. //----------------------------------------------------------------------------
  518. bool ctkPluginFrameworkLauncher::stop(const QString& symbolicName,
  519. ctkPlugin::StopOptions options, ctkPluginContext* context)
  520. {
  521. if (d->fwFactory == 0) return true;
  522. ctkPluginContext* pc = context ? context : getPluginContext();
  523. if (pc == 0)
  524. {
  525. qWarning() << "No valid plug-in context available";
  526. return false;
  527. }
  528. if(!symbolicName.isEmpty())
  529. {
  530. QString pluginPath = getPluginPath(symbolicName);
  531. if (pluginPath.isEmpty()) return false;
  532. try
  533. {
  534. QList<QSharedPointer<ctkPlugin> > plugins = pc->getPlugins();
  535. foreach(QSharedPointer<ctkPlugin> plugin, plugins)
  536. {
  537. if (plugin->getSymbolicName() == symbolicName)
  538. {
  539. plugin->stop(options);
  540. return true;
  541. }
  542. }
  543. qWarning() << "Plug-in" << symbolicName << "not found";
  544. return false;
  545. }
  546. catch (const ctkPluginException& exc)
  547. {
  548. qWarning() << "Failed to stop plug-in:" << exc;
  549. return false;
  550. }
  551. }
  552. else
  553. {
  554. // stop the framework
  555. QSharedPointer<ctkPluginFramework> fw =
  556. qSharedPointerCast<ctkPluginFramework>(pc->getPlugin(0));
  557. try
  558. {
  559. fw->stop();
  560. ctkPluginFrameworkEvent fe = fw->waitForStop(5000);
  561. if (fe.getType() == ctkPluginFrameworkEvent::FRAMEWORK_WAIT_TIMEDOUT)
  562. {
  563. qWarning() << "Stopping the plugin framework timed out";
  564. return false;
  565. }
  566. }
  567. catch (const ctkRuntimeException& e)
  568. {
  569. qWarning() << "Stopping the plugin framework failed: " << e;
  570. return false;
  571. }
  572. return true;
  573. }
  574. }
  575. //----------------------------------------------------------------------------
  576. ctkPluginContext* ctkPluginFrameworkLauncher::getPluginContext()
  577. {
  578. if (d->fwFactory == 0) return 0;
  579. return d->fwFactory->getFramework()->getPluginContext();
  580. }
  581. //----------------------------------------------------------------------------
  582. QSharedPointer<ctkPluginFramework> ctkPluginFrameworkLauncher::getPluginFramework()
  583. {
  584. if (d->fwFactory)
  585. return d->fwFactory->getFramework();
  586. return QSharedPointer<ctkPluginFramework>();
  587. }
  588. //----------------------------------------------------------------------------
  589. void ctkPluginFrameworkLauncher::appendPathEnv(const QString& path)
  590. {
  591. #ifdef _WIN32
  592. #ifdef __MINGW32__
  593. QString pathVar("PATH");
  594. QString oldPath(getenv("PATH"));
  595. pathVar += "=" + oldPath + ";" + path;
  596. if(_putenv(qPrintable(pathVar)))
  597. #else
  598. std::size_t bufferLength;
  599. getenv_s(&bufferLength, NULL, 0, "PATH");
  600. QString newPath = path;
  601. if (bufferLength > 0)
  602. {
  603. char* oldPath = new char[bufferLength];
  604. getenv_s(&bufferLength, oldPath, bufferLength, "PATH");
  605. newPath.append(";").append(oldPath);
  606. delete[] oldPath;
  607. }
  608. qDebug() << "new PATH:" << newPath;
  609. if(_putenv_s("PATH", qPrintable(newPath)))
  610. #endif
  611. {
  612. LPVOID lpMsgBuf;
  613. DWORD dw = GetLastError();
  614. FormatMessageW(
  615. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  616. FORMAT_MESSAGE_FROM_SYSTEM |
  617. FORMAT_MESSAGE_IGNORE_INSERTS,
  618. NULL,
  619. dw,
  620. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  621. (LPWSTR) &lpMsgBuf,
  622. 0, NULL );
  623. // Avoid project configuration conflicts regarding wchar_t considered
  624. // a built-in type or not by using QString::fromUtf16 instead of
  625. // QString::fromWCharArray
  626. // sa http://qt-project.org/wiki/toStdWStringAndBuiltInWchar
  627. QString msg = QString("Adding '%1' to the PATH environment variable failed: %2")
  628. .arg(path).arg(QString::fromUtf16(reinterpret_cast<const ushort*>(lpMsgBuf)));
  629. qWarning() << msg;
  630. LocalFree(lpMsgBuf);
  631. }
  632. #else
  633. Q_UNUSED(path)
  634. #endif
  635. }
  636. //----------------------------------------------------------------------------
  637. void ctkPluginFrameworkLauncher::addSearchPath(const QString& searchPath, bool addToPathEnv)
  638. {
  639. d->pluginSearchPaths.prepend(searchPath);
  640. if (addToPathEnv) appendPathEnv(searchPath);
  641. }
  642. //----------------------------------------------------------------------------
  643. QString ctkPluginFrameworkLauncher::getPluginPath(const QString& symbolicName)
  644. {
  645. QString pluginFileName(symbolicName);
  646. pluginFileName.replace(".", "_");
  647. foreach(QString searchPath, d->pluginSearchPaths)
  648. {
  649. QDirIterator dirIter(searchPath, d->pluginLibFilter, QDir::Files);
  650. while(dirIter.hasNext())
  651. {
  652. dirIter.next();
  653. QFileInfo fileInfo = dirIter.fileInfo();
  654. QString fileBaseName = fileInfo.baseName();
  655. if (fileBaseName.startsWith("lib")) fileBaseName = fileBaseName.mid(3);
  656. if (fileBaseName == pluginFileName)
  657. {
  658. return fileInfo.canonicalFilePath();
  659. }
  660. }
  661. }
  662. return QString();
  663. }
  664. //----------------------------------------------------------------------------
  665. QStringList ctkPluginFrameworkLauncher::getPluginSymbolicNames(const QString& searchPath)
  666. {
  667. QStringList result;
  668. QDirIterator dirIter(searchPath, d->pluginLibFilter, QDir::Files);
  669. while(dirIter.hasNext())
  670. {
  671. dirIter.next();
  672. QFileInfo fileInfo = dirIter.fileInfo();
  673. QString fileBaseName = fileInfo.baseName();
  674. if (fileBaseName.startsWith("lib")) fileBaseName = fileBaseName.mid(3);
  675. result << fileBaseName.replace("_", ".");
  676. }
  677. return result;
  678. }