ctkDefaultApplicationLauncher.cpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  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 "ctkDefaultApplicationLauncher_p.h"
  16. #include <service/application/ctkApplicationDescriptor.h>
  17. #include <ctkApplicationRunnable.h>
  18. #include <ctkException.h>
  19. #include <ctkPluginConstants.h>
  20. #include <ctkPluginContext.h>
  21. #include <ctkPluginFrameworkLauncher.h>
  22. #include <ctkPluginFrameworkProperties_p.h>
  23. #include <QVariant>
  24. #include <QDebug>
  25. //----------------------------------------------------------------------------
  26. struct FreeResources
  27. {
  28. ctkDefaultApplicationLauncher* launcher;
  29. FreeResources(ctkDefaultApplicationLauncher* launcher)
  30. : launcher(launcher)
  31. {}
  32. ~FreeResources()
  33. {
  34. //if (Profile.PROFILE && Profile.STARTUP)
  35. // Profile.logExit("ctkPluginFrameworkLauncher.run(QVariant)()");
  36. // free the runnable application and release the lock to allow another app to be launched.
  37. launcher->runnable = NULL;
  38. launcher->appContext.clear();
  39. launcher->runningLock.release();
  40. }
  41. };
  42. //----------------------------------------------------------------------------
  43. ctkDefaultApplicationLauncher::ctkDefaultApplicationLauncher(ctkPluginContext* context, bool relaunch, bool failOnNoDefault)
  44. : runnable(NULL)
  45. , runningLock(1)
  46. , waitForAppLock(0)
  47. , context(context)
  48. , relaunch(relaunch)
  49. , failOnNoDefault(failOnNoDefault)
  50. {
  51. }
  52. //----------------------------------------------------------------------------
  53. QVariant ctkDefaultApplicationLauncher::start(const QVariant& defaultContext)
  54. {
  55. // here we assume that launch has been called by runtime before we started
  56. // TODO this may be a bad assumption but it works for now because we register the app launcher as a service and runtime synchronously calls launch on the service
  57. if (failOnNoDefault && runnable == NULL)
  58. {
  59. throw ctkIllegalStateException("Unable to acquire application service. Ensure that an application container is active");
  60. }
  61. QVariant result;
  62. bool doRelaunch = false;
  63. do
  64. {
  65. try
  66. {
  67. result = runApplication(defaultContext);
  68. }
  69. catch (const std::exception& e)
  70. {
  71. if (!relaunch || (context->getPlugin()->getState() != ctkPlugin::ACTIVE))
  72. {
  73. throw;
  74. }
  75. qWarning() << "Application error:" << e.what();
  76. }
  77. doRelaunch = (relaunch && context->getPlugin()->getState() == ctkPlugin::ACTIVE) ||
  78. ctkPluginFrameworkProperties::getProperty(ctkPluginFrameworkLauncher::PROP_OSGI_RELAUNCH).toBool();
  79. }
  80. while (doRelaunch);
  81. return result;
  82. }
  83. //----------------------------------------------------------------------------
  84. void ctkDefaultApplicationLauncher::launch(ctkApplicationRunnable* app, const QVariant& applicationContext)
  85. {
  86. waitForAppLock.tryAcquire(); // clear out any pending apps notifications
  87. if (!runningLock.tryAcquire()) // check to see if an application is currently running
  88. {
  89. throw ctkIllegalStateException("An application is aready running.");
  90. }
  91. this->runnable = app;
  92. this->appContext = applicationContext;
  93. waitForAppLock.release(); // notify the main thread to launch an application.
  94. runningLock.release(); // release the running lock
  95. }
  96. //----------------------------------------------------------------------------
  97. void ctkDefaultApplicationLauncher::shutdown()
  98. {
  99. // this method will aquire and keep the runningLock to prevent
  100. // all future application launches.
  101. if (runningLock.tryAcquire())
  102. {
  103. return; // no application is currently running.
  104. }
  105. ctkApplicationRunnable* currentRunnable = runnable;
  106. currentRunnable->stop();
  107. runningLock.tryAcquire(1, 60000); // timeout after 1 minute.
  108. }
  109. //----------------------------------------------------------------------------
  110. QVariant ctkDefaultApplicationLauncher::reStart(const QVariant& argument)
  111. {
  112. QList<ctkServiceReference> refs;
  113. refs = context->getServiceReferences<ctkApplicationDescriptor>("(ctk.application.default=true)");
  114. if (!refs.isEmpty())
  115. {
  116. ctkApplicationDescriptor* defaultApp = context->getService<ctkApplicationDescriptor>(refs.front());
  117. defaultApp->launch(QHash<QString, QVariant>());
  118. return start(argument);
  119. }
  120. throw ctkIllegalStateException("Unable to acquire application service. Ensure that an application container is active");
  121. }
  122. //----------------------------------------------------------------------------
  123. QVariant ctkDefaultApplicationLauncher::runApplication(const QVariant& defaultContext)
  124. {
  125. // wait for an application to be launched.
  126. waitForAppLock.acquire();
  127. // an application is ready; acquire the running lock.
  128. // this must happen after we have acquired an application (by acquiring waitForAppLock above).
  129. runningLock.acquire();
  130. // run the actual application on the current thread (main).
  131. FreeResources cleanup(this);
  132. return runnable->run(appContext.isValid() ? appContext : defaultContext);
  133. }