瀏覽代碼

Added a launcher class for the Plugin Framework.

Sascha Zelzer 14 年之前
父節點
當前提交
a57143813a

+ 2 - 0
Libs/PluginFramework/CMakeLists.txt

@@ -34,6 +34,7 @@ SET(KIT_SRCS
   ctkPluginFrameworkContext.cpp
   ctkPluginFrameworkContext_p.h
   ctkPluginFrameworkEvent.cpp
+  ctkPluginFrameworkLauncher.cpp
   ctkPluginFrameworkListeners.cpp
   ctkPluginFrameworkListeners_p.h
   ctkPluginFrameworkPrivate.cpp
@@ -139,6 +140,7 @@ ctkFunctionGetTargetLibraries(KIT_target_libraries)
 ctkMacroBuildLib(
   NAME ${PROJECT_NAME}
   EXPORT_DIRECTIVE ${KIT_export_directive}
+  INCLUDE_DIRECTORIES ${CTK_SUPERBUILD_BINARY_DIR}
   SRCS ${KIT_SRCS}
   MOC_SRCS ${KIT_MOC_SRCS}
   UI_FORMS ${KIT_UI_FORMS}

+ 2 - 46
Libs/PluginFramework/Testing/Cpp/ctkPluginFrameworkTestRunner.cpp

@@ -26,6 +26,7 @@
 
 #include <ctkPluginFrameworkFactory.h>
 #include <ctkPluginFramework.h>
+#include <ctkPluginFrameworkLauncher.h>
 #include <ctkPluginContext.h>
 #include <ctkPluginException.h>
 
@@ -37,10 +38,6 @@
 #include <QThread>
 #include <QDebug>
 
-#ifdef _WIN32
-#include <windows.h>
-#include <stdlib.h>
-#endif // _WIN32
 
 //----------------------------------------------------------------------------
 class TestRunner : public QThread
@@ -206,48 +203,7 @@ void ctkPluginFrameworkTestRunner::addPluginPath(const QString& path, bool insta
 {
   Q_D(ctkPluginFrameworkTestRunner);
   d->pluginPaths.push_back(qMakePair(path, install));
-#ifdef _WIN32
-#ifdef __MINGW32__
-  QString pathVar("PATH");
-  QString oldPath(getenv("PATH"));
-  pathVar += "=" + oldPath + ";" + path;
-  if(_putenv(qPrintable(pathVar)))
-#else
-  std::size_t bufferLength;
-  getenv_s(&bufferLength, NULL, 0, "PATH");
-  QString newPath = path;
-  if (bufferLength > 0)
-  {
-    char* oldPath = new char[bufferLength];
-	getenv_s(&bufferLength, oldPath, bufferLength, "PATH");
-	newPath.append(";").append(oldPath);
-	delete[] oldPath;
-  }
-  qDebug() << "new PATH:" << newPath;
-  if(_putenv_s("PATH", qPrintable(newPath)))
-#endif
-  {
-    LPVOID lpMsgBuf;
-    DWORD dw = GetLastError(); 
-
-    FormatMessage(
-        FORMAT_MESSAGE_ALLOCATE_BUFFER | 
-        FORMAT_MESSAGE_FROM_SYSTEM |
-        FORMAT_MESSAGE_IGNORE_INSERTS,
-        NULL,
-        dw,
-        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
-        (LPTSTR) &lpMsgBuf,
-        0, NULL );
-
-    QString msg = QString("Adding '%1' to the PATH environment variable failed: %2")
-      .arg(path).arg(QString((LPCTSTR)lpMsgBuf));
-    
-    qWarning() << msg;
-
-    LocalFree(lpMsgBuf);
-  }
-#endif
+  ctkPluginFrameworkLauncher::appendPathEnv(path);
 }
 
 //----------------------------------------------------------------------------

+ 252 - 0
Libs/PluginFramework/ctkPluginFrameworkLauncher.cpp

@@ -0,0 +1,252 @@
+/*=============================================================================
+
+  Library: CTK
+
+  Copyright (c) German Cancer Research Center,
+    Division of Medical and Biological Informatics
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+=============================================================================*/
+
+#include <QStringList>
+#include <QDirIterator>
+#include <QFileInfo>
+#include <QDebug>
+
+#include "ctkPluginFrameworkLauncher.h"
+#include "ctkPluginFrameworkFactory.h"
+#include "ctkPluginFramework.h"
+#include "ctkPluginContext.h"
+#include "ctkPluginException.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#include <stdlib.h>
+#endif // _WIN32
+
+#include <CTKConfig.h>
+
+class ctkPluginFrameworkLauncherPrivate
+{
+public:
+
+  ctkPluginFrameworkLauncherPrivate()
+    : fwFactory(0)
+  {
+#ifdef CMAKE_INTDIR
+    QString pluginPath = CTK_PLUGIN_DIR CMAKE_INTDIR "/";
+#else
+    QString pluginPath = CTK_PLUGIN_DIR;
+#endif
+
+    pluginSearchPaths.append(pluginPath);
+
+    pluginLibFilter << "*.dll" << "*.so" << "*.dylib";
+  }
+
+  QStringList pluginSearchPaths;
+  QStringList pluginLibFilter;
+
+  ctkProperties fwProps;
+
+  ctkPluginFrameworkFactory* fwFactory;
+};
+
+const QScopedPointer<ctkPluginFrameworkLauncherPrivate> ctkPluginFrameworkLauncher::d(
+  new ctkPluginFrameworkLauncherPrivate());
+
+//----------------------------------------------------------------------------
+void ctkPluginFrameworkLauncher::setFrameworkProperties(const ctkProperties& props)
+{
+  d->fwProps = props;
+}
+
+//----------------------------------------------------------------------------
+bool ctkPluginFrameworkLauncher::install(const QString& symbolicName)
+{
+  QString pluginPath = getPluginPath(symbolicName);
+  if (pluginPath.isEmpty()) return false;
+
+  if (d->fwFactory == 0) {
+    d->fwFactory = new ctkPluginFrameworkFactory(d->fwProps);
+    try
+    {
+      d->fwFactory->getFramework()->init();
+    }
+    catch (const ctkPluginException& exc)
+    {
+      qCritical() << "Failed to initialize the plug-in framework:" << exc;
+      delete d->fwFactory;
+      d->fwFactory = 0;
+      return false;
+    }
+  }
+
+  try
+  {
+    getPluginContext()->installPlugin(QUrl::fromLocalFile(pluginPath));
+  }
+  catch (const ctkPluginException& exc)
+  {
+    qWarning() << "Failed to install plugin:" << exc;
+    return false;
+  }
+
+  return true;
+}
+
+//----------------------------------------------------------------------------
+bool ctkPluginFrameworkLauncher::start(const QString& symbolicName, ctkPlugin::StartOptions options)
+{
+  QString pluginPath = getPluginPath(symbolicName);
+  if (pluginPath.isEmpty()) return false;
+
+  if (d->fwFactory == 0) {
+    d->fwFactory = new ctkPluginFrameworkFactory(d->fwProps);
+    try
+    {
+      d->fwFactory->getFramework()->start();
+    }
+    catch (const ctkPluginException& exc)
+    {
+      qCritical() << "Failed to start the plug-in framework:" << exc;
+      delete d->fwFactory;
+      d->fwFactory = 0;
+      return false;
+    }
+  }
+  else if (d->fwFactory->getFramework()->getState() != ctkPlugin::ACTIVE)
+  {
+    try
+    {
+      d->fwFactory->getFramework()->start(options);
+    }
+    catch (const ctkPluginException& exc)
+    {
+      qCritical() << "Failed to start the plug-in framework:" << exc;
+      delete d->fwFactory;
+      d->fwFactory = 0;
+      return false;
+    }
+  }
+
+  try
+  {
+    getPluginContext()->installPlugin(QUrl::fromLocalFile(pluginPath))->start(options);
+  }
+  catch (const ctkPluginException& exc)
+  {
+    qWarning() << "Failed to install plugin:" << exc;
+    return false;
+  }
+
+  return true;
+}
+
+//----------------------------------------------------------------------------
+ctkPluginContext* ctkPluginFrameworkLauncher::getPluginContext()
+{
+  if (d->fwFactory == 0) return 0;
+  return d->fwFactory->getFramework()->getPluginContext();
+}
+
+//----------------------------------------------------------------------------
+QSharedPointer<ctkPluginFramework> ctkPluginFrameworkLauncher::getPluginFramework()
+{
+  if (d->fwFactory)
+    return d->fwFactory->getFramework();
+  return QSharedPointer<ctkPluginFramework>();
+}
+
+//----------------------------------------------------------------------------
+void ctkPluginFrameworkLauncher::appendPathEnv(const QString& path)
+{
+#ifdef _WIN32
+#ifdef __MINGW32__
+  QString pathVar("PATH");
+  QString oldPath(getenv("PATH"));
+  pathVar += "=" + oldPath + ";" + path;
+  if(_putenv(qPrintable(pathVar)))
+#else
+  std::size_t bufferLength;
+  getenv_s(&bufferLength, NULL, 0, "PATH");
+  QString newPath = path;
+  if (bufferLength > 0)
+  {
+    char* oldPath = new char[bufferLength];
+    getenv_s(&bufferLength, oldPath, bufferLength, "PATH");
+    newPath.append(";").append(oldPath);
+    delete[] oldPath;
+  }
+  qDebug() << "new PATH:" << newPath;
+  if(_putenv_s("PATH", qPrintable(newPath)))
+#endif
+  {
+    LPVOID lpMsgBuf;
+    DWORD dw = GetLastError();
+
+    FormatMessage(
+        FORMAT_MESSAGE_ALLOCATE_BUFFER |
+        FORMAT_MESSAGE_FROM_SYSTEM |
+        FORMAT_MESSAGE_IGNORE_INSERTS,
+        NULL,
+        dw,
+        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+        (LPTSTR) &lpMsgBuf,
+        0, NULL );
+
+    QString msg = QString("Adding '%1' to the PATH environment variable failed: %2")
+      .arg(path).arg(QString((LPCTSTR)lpMsgBuf));
+
+    qWarning() << msg;
+
+    LocalFree(lpMsgBuf);
+  }
+#else
+  Q_UNUSED(path)
+#endif
+}
+
+//----------------------------------------------------------------------------
+void ctkPluginFrameworkLauncher::addSearchPath(const QString& searchPath, bool addToPathEnv)
+{
+  d->pluginSearchPaths.prepend(searchPath);
+  if (addToPathEnv) appendPathEnv(searchPath);
+}
+
+//----------------------------------------------------------------------------
+QString ctkPluginFrameworkLauncher::getPluginPath(const QString& symbolicName)
+{
+  QString pluginFileName(symbolicName);
+  pluginFileName.replace(".", "_");
+  foreach(QString searchPath, d->pluginSearchPaths)
+  {
+    QDirIterator dirIter(searchPath, d->pluginLibFilter, QDir::Files);
+    while(dirIter.hasNext())
+    {
+      dirIter.next();
+      QFileInfo fileInfo = dirIter.fileInfo();
+      QString fileBaseName = fileInfo.baseName();
+      if (fileBaseName.startsWith("lib")) fileBaseName = fileBaseName.mid(3);
+
+      if (fileBaseName == pluginFileName)
+      {
+        return fileInfo.canonicalFilePath();
+      }
+    }
+  }
+
+  return QString();
+}
+

+ 166 - 0
Libs/PluginFramework/ctkPluginFrameworkLauncher.h

@@ -0,0 +1,166 @@
+/*=============================================================================
+
+  Library: CTK
+
+  Copyright (c) German Cancer Research Center,
+    Division of Medical and Biological Informatics
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+=============================================================================*/
+
+#ifndef CTKPLUGINFRAMEWORKLAUNCHER_H
+#define CTKPLUGINFRAMEWORKLAUNCHER_H
+
+#include <QString>
+#include <QScopedPointer>
+
+#include <ctkPluginFrameworkExport.h>
+#include "ctkPlugin.h"
+#include "ctkPluginFramework_global.h"
+
+class ctkPluginFramework;
+class ctkPluginFrameworkLauncherPrivate;
+
+/**
+ * \ingroup PluginFramework
+ *
+ * Sets up and starts the CTK Plugin Framework.
+ *
+ * This is a convenience class to start an instance of the CTK Plugin
+ * Framework and to install and start plugins.
+ */
+class CTK_PLUGINFW_EXPORT ctkPluginFrameworkLauncher
+{
+public:
+
+  /**
+   * Specify the set of framework properties to be used when
+   * initializing the Plugin Framework.
+   *
+   * <p>
+   * If the framework has already been initialized by a call
+   * to #install(const QString&) or #start(const QString&), the
+   * new properties do not have any effect until the framework
+   * is restarted.
+   *
+   * \param props The initial Plugin Framework properties.
+   */
+  static void setFrameworkProperties(const ctkProperties& props);
+
+  /**
+   * Install the plugin with the given symbolic name in the Plugin
+   * Framework.
+   *
+   * <p>
+   * This method instantiates and initializes an instance of a
+   * ctkPluginFramework object, if there is no framework already
+   * initialized.
+   *
+   * <p>
+   * The plugin is searched in the paths previously given by calls
+   * to #addSearchPath(const QString&, bool) and in the default
+   * CTK plugin installation path.
+   *
+   * \param symbolicName The symbolic name of the plugin to install.
+   * \return <code>true</code> if the plugin was found and successfully
+   *         installed, <code>false</code> otherwise.
+   */
+  static bool install(const QString& symbolicName);
+
+  /**
+   * Start the CTK Plugin Framework and/or the plugin with the given
+   * symbolic name.
+   *
+   * <p>
+   * This method creates and initializes the CTK Plugin Framework if it
+   * has not been previously initialized and starts it. It then optionally
+   * starts the plugin with the given symbolic name and start options.
+   *
+   * <p>
+   * If a symbolic name is given, the plugin is searched in the paths previously given by calls
+   * to #addSearchPath(const QString&, bool) and in the default
+   * CTK plugin installation path.
+   *
+   * \param symbolicName The symbolic name of the plugin to install.
+   * \param options The options used to start the plugin.
+   * \return <code>true</code> if the plugin was found and successfully
+   *         installed, <code>false</code> otherwise.
+   *
+   * \see ctkPlugin::StartOption
+   */
+  static bool start(const QString& symbolicName = QString(), ctkPlugin::StartOptions options = ctkPlugin::START_ACTIVATION_POLICY);
+
+  /**
+   * Get the plugin context for the Plugin Framework.
+   *
+   * \return The context associated to the Plugin Framework, or <code>null</code>
+   *         if the framework has not been initialized yet.
+   */
+  static ctkPluginContext* getPluginContext();
+
+  /**
+   * Get the Plugin Framework:
+   *
+   * \return The initialized Plugin Framework, or <code>null</code> if the
+   *         framework has not been initialized yet.
+   */
+  static QSharedPointer<ctkPluginFramework> getPluginFramework();
+
+  /**
+   * Append a path to the PATH environment variable.
+   *
+   * <p>
+   * This method appends the given path to the PATH environment variable.
+   * It does nothing on non-Windows platforms.
+   *
+   * \param path The path to be appended to PATH
+   */
+  static void appendPathEnv(const QString& path);
+
+  /**
+   * Add a path to the list of search paths for plugins.
+   *
+   * When calling #install(const QString&), #start(const QString&), or
+   * #getPluginPath(const QString&), the plugin is searched in the
+   * paths given as arguments to this method. The least recently added
+   * path is searched first.
+   *
+   * \param searchPath The path to add.
+   * \param addToPathEnv If <code>true</code>, add the given path to the
+   *        PATH environment variable, using #appendPathEnv(const QString&).
+   */
+  static void addSearchPath(const QString& searchPath, bool addToPathEnv = true);
+
+  /**
+   * Get the full path (including the file name) to the plugin with the
+   * given symbolic name.
+   *
+   * <p>
+   * The paths given by calls to #addSearchPath(const QString&, bool) are searched
+   * for a shared library with a base name equaling <code>symbolicName</code>.
+   *
+   * \param symbolicName The symbolic name of the plugin to find.
+   * \return The full path (including the file name) to the plugin (shared library)
+   *         or a null QString if the plugin was not found.
+   */
+  static QString getPluginPath(const QString& symbolicName);
+
+private:
+
+  static const QScopedPointer<ctkPluginFrameworkLauncherPrivate> d;
+
+  Q_DISABLE_COPY(ctkPluginFrameworkLauncher)
+};
+
+#endif // CTKPLUGINFRAMEWORKLAUNCHER_H