Procházet zdrojové kódy

Added support for uninstalling plugins.

Sascha Zelzer před 14 roky
rodič
revize
868877bc60

+ 101 - 0
Libs/PluginFramework/ctkPlugin.cpp

@@ -175,6 +175,107 @@ void ctkPlugin::stop(const StopOptions& options)
   }
 }
 
+void ctkPlugin::uninstall()
+{
+  bool wasResolved = false;
+
+  Q_D(ctkPlugin);
+  if (d->archive)
+  {
+    try
+    {
+      d->archive->setStartLevel(-2); // Mark as uninstalled
+    }
+    catch (...)
+    { }
+  }
+
+  d->cachedHeaders = getHeaders();
+
+  switch (d->state)
+  {
+  case UNINSTALLED:
+    throw std::logic_error("Plugin is in UNINSTALLED state");
+
+  case STARTING: // Lazy start
+  case ACTIVE:
+  case STOPPING:
+    try
+    {
+      //TODO: If activating or deactivating, wait a litle
+      // we don't use mutliple threads to start plugins for now
+      //d->waitOnActivation(fwCtx.packages, "Bundle.uninstall", false);
+      if (d->state & (ACTIVE | STARTING))
+      {
+        try
+        {
+          d->stop0(d->state == ACTIVE);
+        }
+        catch (const std::exception& exception)
+        {
+          // NYI! not call inside lock
+          d->fwCtx->listeners.frameworkError(this, exception);
+        }
+      }
+    }
+    catch (const std::exception& e)
+    {
+      d->deactivating = false;
+      //fwCtx.packages.notifyAll();
+      d->fwCtx->listeners.frameworkError(this, e);
+    }
+    // Fall through
+  case RESOLVED:
+    wasResolved = true;
+    // Fall through
+  case INSTALLED:
+    d->fwCtx->plugins->remove(d->location);
+    d->pluginActivator = 0;
+
+    //TODO: delete plugin specific storage area
+//    if (d->pluginDir != null)
+//    {
+//      if (!d->pluginDir.delete())
+//      {
+//        // Plugin dir is not deleted completely, make sure we mark
+//        // it as uninstalled for next framework restart
+//        if (null!=archive) {
+//          try {
+//            archive.setStartLevel(-2); // Mark as uninstalled
+//          } catch (Exception e) {
+//            // NYI! Generate FrameworkError if dir still exists!?
+//            fwCtx.debug.println("Failed to mark bundle " + id +
+//                                " as uninstalled, " + bundleDir +
+//                                " must be deleted manually: " + e);
+//          }
+//        }
+//      }
+//      bundleDir = null;
+//    }
+    if (d->archive)
+    {
+      d->archive->purge();
+    }
+
+    // id, location and headers survive after uninstall.
+    // TODO: UNRESOLVED must be sent out during installed state
+    // This needs to be reviewed. See OSGi bug #1374
+    d->state = INSTALLED;
+    d->modified();
+
+    // Broadcast events
+    if (wasResolved)
+    {
+      d->fwCtx->listeners.emitPluginChanged(ctkPluginEvent(ctkPluginEvent::UNRESOLVED, this));
+    }
+
+    d->state = UNINSTALLED;
+    d->fwCtx->listeners.emitPluginChanged(ctkPluginEvent(ctkPluginEvent::UNINSTALLED, this));
+
+    break;
+  }
+}
+
 ctkPluginContext* ctkPlugin::getPluginContext() const
 {
   //TODO security checks

+ 61 - 0
Libs/PluginFramework/ctkPlugin.h

@@ -425,6 +425,67 @@ public:
   virtual void stop(const StopOptions& options = 0);
 
   /**
+   * Uninstalls this plugin.
+   *
+   * <p>
+   * This method causes the Plugin Framework to notify other plugins that this
+   * plugin is being uninstalled, and then puts this plugin into the
+   * <code>UNINSTALLED</code> state. The Framework must remove any resources
+   * related to this plugin that it is able to remove.
+   *
+   * <p>
+   * If this plugin is required by other plugins which are already resolved,
+   * the Framework must keep this plugin loaded until the
+   * Framework is relaunched.
+   *
+   * <p>
+   * The following steps are required to uninstall a plugin:
+   * <ol>
+   * <li>If this plugin's state is <code>UNINSTALLED</code> then an
+   * <code>std::logic_error</code> is thrown.
+   *
+   * <li>If this plugin's state is <code>ACTIVE</code>, <code>STARTING</code>
+   * or <code>STOPPING</code>, this plugin is stopped as described in the
+   * <code>ctkPlugin::stop</code> method. If <code>ctkPlugin::stop</code> throws an
+   * exception, a Framework event of type ctkFrameworkEvent::ERROR is
+   * fired containing the exception.
+   *
+   * <li>This plugin's state is set to <code>UNINSTALLED</code>.
+   *
+   * <li>A plugin event of type ctkPluginEvent::UNINSTALLED is fired.
+   *
+   * <li>This plugin and any persistent storage area provided for this plugin
+   * by the Framework are removed.
+   * </ol>
+   *
+   * <b>Preconditions </b>
+   * <ul>
+   * <li><code>getState()</code> not in &#x007B; <code>UNINSTALLED</code>
+   * &#x007D;.
+   * </ul>
+   * <b>Postconditions, no exceptions thrown </b>
+   * <ul>
+   * <li><code>getState()</code> in &#x007B; <code>UNINSTALLED</code>
+   * &#x007D;.
+   * <li>This plugin has been uninstalled.
+   * </ul>
+   * <b>Postconditions, when an exception is thrown </b>
+   * <ul>
+   * <li><code>getState()</code> not in &#x007B; <code>UNINSTALLED</code>
+   * &#x007D;.
+   * <li>This plugin has not been uninstalled.
+   * </ul>
+   *
+   * @throws ctkPluginException If the uninstall failed. This can occur if
+   *         another thread is attempting to change this plugin's state and
+   *         does not complete in a timely manner.
+   * @throws std::logic_error If this plugin has been uninstalled or this
+   *         plugin tries to change its own state.
+   * @see #stop()
+   */
+  void uninstall();
+
+  /**
    * Returns this plugin's {@link ctkPluginContext}. The returned
    * <code>ctkPluginContext</code> can be used by the caller to act on behalf
    * of this plugin.

+ 4 - 4
Libs/PluginFramework/ctkPluginArchive.cpp

@@ -35,7 +35,7 @@ const QString ctkPluginArchive::AUTOSTART_SETTING_ACTIVATION_POLICY("activation_
 ctkPluginArchive::ctkPluginArchive(ctkPluginStorage* pluginStorage,
                                    const QUrl& pluginLocation, const QString& localPluginPath,
                                    int pluginId)
-                                     : autostartSetting(-1), id(pluginId), lastModified(0),
+                                     : autostartSetting(-1), id(pluginId),
                                      location(pluginLocation), localPluginPath(localPluginPath),
                                      storage(pluginStorage)
 {
@@ -99,14 +99,14 @@ void ctkPluginArchive::setStartLevel(int level)
   //    }
 }
 
-qtimestamp ctkPluginArchive::getLastModified() const
+QDateTime ctkPluginArchive::getLastModified() const
 {
   return lastModified;
 }
 
-void ctkPluginArchive::setLastModified(qtimestamp clockticks)
+void ctkPluginArchive::setLastModified(const QDateTime& dateTime)
 {
-  lastModified = clockticks;
+  lastModified = dateTime;
   //TDOO
   //putContent(...)
 }

+ 4 - 5
Libs/PluginFramework/ctkPluginArchive_p.h

@@ -25,14 +25,13 @@
 #include <QString>
 #include <QHash>
 #include <QUrl>
+#include <QDateTime>
 
 #include "ctkPluginManifest_p.h"
 
 // Qt forward declarations
 class QIODevice;
 
-typedef quint64 qtimestamp;
-
 // CTK foraward declarations
 class ctkPluginStorage;
 
@@ -66,7 +65,7 @@ private:
 
 int autostartSetting;
 int id;
-qtimestamp lastModified;
+QDateTime lastModified;
 QUrl location;
 QString localPluginPath;
 ctkPluginManifest manifest;
@@ -157,13 +156,13 @@ void setStartLevel(int level);
 /**
  * Get last modified timestamp.
  */
-qtimestamp getLastModified() const;
+QDateTime getLastModified() const;
 
 
 /**
  * Set stored last modified timestamp.
  */
-void setLastModified(qtimestamp timemillisecs);
+void setLastModified(const QDateTime& timemillisecs);
 
 
 /**

+ 12 - 3
Libs/PluginFramework/ctkPluginPrivate.cpp

@@ -43,7 +43,7 @@ ctkPluginPrivate::ctkPluginPrivate(
       : q_ptr(&qq), fwCtx(fw), id(pa->getPluginId()),
       location(pa->getPluginLocation().toString()), state(ctkPlugin::INSTALLED),
       archive(pa), pluginContext(0), pluginActivator(0), pluginLoader(pa->getLibLocation()),
-      lastModified(0), eagerActivation(false), activating(false), deactivating(false)
+      eagerActivation(false), activating(false), deactivating(false)
 {
   //TODO
   //checkCertificates(pa);
@@ -72,8 +72,8 @@ ctkPluginPrivate::ctkPluginPrivate(ctkPlugin& qq,
                                    long id, const QString& loc, const QString& sym, const ctkVersion& ver)
                                      : q_ptr(&qq), fwCtx(fw), id(id), location(loc), symbolicName(sym), version(ver),
                                      state(ctkPlugin::INSTALLED), archive(0), pluginContext(0),
-                                     pluginActivator(0), lastModified(0),
-                                     eagerActivation(false), activating(false), deactivating(false)
+                                     pluginActivator(0), eagerActivation(false), activating(false),
+                                     deactivating(false)
 {
 
 }
@@ -140,6 +140,15 @@ void ctkPluginPrivate::ignoreAutostartSetting()
   }
 }
 
+void ctkPluginPrivate::modified()
+{
+  lastModified = QDateTime::currentDateTime();
+  if (archive)
+  {
+    archive->setLastModified(lastModified);
+  }
+}
+
 void ctkPluginPrivate::checkManifestHeaders()
 {
   symbolicName = archive->getAttribute(ctkPluginConstants::PLUGIN_SYMBOLICNAME);

+ 4 - 1
Libs/PluginFramework/ctkPluginPrivate_p.h

@@ -28,6 +28,7 @@
 
 #include <QHash>
 #include <QPluginLoader>
+#include <QDateTime>
 
 
 class ctkPluginActivator;
@@ -88,6 +89,8 @@ public:
 
   void ignoreAutostartSetting();
 
+  void modified();
+
   /**
    * Performs the actual activation.
    */
@@ -153,7 +156,7 @@ public:
   /**
    * Time when the plugin was last modified
    */
-  long lastModified;
+  QDateTime lastModified;
 
   /**
    * Stores the default locale entries when uninstalled