Explorar el Código

ENH: PluginFramework: added more framework classes

Sascha Zelzer hace 15 años
padre
commit
80908c7265

+ 3 - 1
Libs/Core/CMakeLists.txt

@@ -48,8 +48,10 @@ SET(KIT_SRCS
   PluginFramework/ctkLDAPSearchFilter.cxx
   PluginFramework/ctkPlugin.cxx
   PluginFramework/ctkPluginContext.cxx
+  PluginFramework/ctkPluginFrameworkContext.cxx
+  PluginFramework/ctkPluginFrameworkContextPrivate.cxx
   PluginFramework/ctkPluginManager.cxx
-  PluginFramework/ctkPluginRepository.cxx
+  #PluginFramework/ctkPluginRepository.cxx
   PluginFramework/ctkServiceReference.cxx
   PluginFramework/ctkServiceRegistration.cxx
   #PluginFramework/ctkServiceRegistry.cxx

+ 3 - 2
Libs/Core/PluginFramework/ctkPlugin.cxx

@@ -4,8 +4,9 @@
 
 namespace ctk {
 
-  Plugin::Plugin()
-    : d_ptr(new PluginPrivate)
+  Plugin::Plugin(PluginFrameworkContext* fw,
+                 PluginArchiveInterface* ba)
+    : d_ptr(new PluginPrivate(fw, ba))
   {
 
   }

+ 9 - 1
Libs/Core/PluginFramework/ctkPlugin.h

@@ -7,6 +7,8 @@
 
 namespace ctk {
 
+  class PluginArchiveInterface;
+  class PluginFrameworkContext;
   class PluginPrivate;
   class Plugin {
 
@@ -23,6 +25,10 @@ namespace ctk {
       ACTIVE
     };
 
+    Q_DECLARE_FLAGS(States, State)
+
+    virtual ~Plugin();
+
     State state() const;
 
     virtual void start();
@@ -41,10 +47,12 @@ namespace ctk {
 
     PluginPrivate * const d_ptr;
 
-    Plugin();
+    Plugin(PluginFrameworkContext* fw, PluginArchiveInterface* ba);
     Plugin(PluginPrivate& dd);
   };
 
 }
 
+Q_DECLARE_OPERATORS_FOR_FLAGS(ctk::Plugin::States)
+
 #endif // CTKPLUGIN_H

+ 172 - 0
Libs/Core/PluginFramework/ctkPluginArchiveInterface_p.h

@@ -0,0 +1,172 @@
+#ifndef CTKPLUGINARCHIVEINTERFACE_P_H
+#define CTKPLUGINARCHIVEINTERFACE_P_H
+
+#include <QString>
+
+typedef quint64 qtimestamp;
+
+/**
+ * Interface for managing plugin data.
+ *
+ */
+struct PluginArchiveInterface {
+
+  /**
+   * Autostart setting stopped.
+   * @see PluginArchiveInterface#setAutostartSetting(const QString&)
+   */
+  static const QString AUTOSTART_SETTING_STOPPED; // = "stopped"
+
+  /**
+   * Autostart setting eager.
+   * @see PluginArchiveInterface#setAutostartSetting(const QString&)
+   */
+  static const QString AUTOSTART_SETTING_EAGER; // = "eager"
+
+  /**
+   * Autostart setting declared activation policy.
+   * @see PluginArchiveInterface#setAutostartSetting(const QString&)
+   */
+  static const QString AUTOSTART_SETTING_ACTIVATION_POLICY; // = "activation_policy"
+
+
+  /**
+   * Get an attribute from the manifest of a plugin.
+   *
+   * Not localized
+   *
+   * @param key Name of attribute to get.
+   * @return A string with result or null if the entry doesn't exists.
+   */
+  QString getAttribute(const QString& key) const = 0;
+
+  /**
+   * Gets all localization entries from this plugin. Will typically
+   * read the file OSGI-INF/plugin_&lt;locale&gt;.properties.
+   *
+   * @param localeFile Filename within archive for localization properties.
+   * @return null or a mapping of the entries.
+   */
+  QHash<QString,QString> getLocalizationEntries(const QString& localeFile) const = 0;
+
+
+  /**
+   * @returns the (raw/unlocalized) attributes
+   */
+  QHash<QString,QString> getUnlocalizedAttributes() const = 0;
+
+
+  /**
+   * Get plugin identifier for this plugin archive.
+   *
+   * @return Plugin identifier.
+   */
+  int getPluginId() const = 0;
+
+
+  /**
+   * Get bundle location for this plugin archive.
+   *
+   * @return Bundle location.
+   */
+  QString getPluginLocation() const = 0;
+
+
+  /**
+   * Get a QIODevice to a named entry inside a plugin.
+   * Leading '/' is stripped.
+   *
+   * @param component Entry to get reference to.
+   * @return QIODevice to entry or null if it doesn't exist.
+   */
+  QIODevice* getPluginResource(const QString& component) const = 0;
+
+
+  /**
+   * Returns a QStringList of all the paths
+   * to entries within the plugin whose longest sub-path matches the supplied
+   * path argument.
+   *
+   * @param name
+   * @return
+   */
+  QStringList findResourcesPath(const QString& path) const = 0;
+
+
+  /**
+   * Get stored plugin start level.
+   */
+  int getStartLevel() const = 0;
+
+
+  /**
+   * Set stored plugin start level.
+   */
+  void setStartLevel(int level) = 0;
+
+
+  /**
+   * Get last modified timestamp.
+   */
+  qtimestamp getLastModified() const = 0;
+
+
+  /**
+   * Set stored last modified timestamp.
+   */
+  void setLastModified(qtimestamp timemillisecs) = 0;
+
+
+  /**
+   * Get auto-start setting.
+   *
+   * @return the autostart setting. "-1" if the plugin is not started.
+   */
+  int getAutostartSetting() const = 0;
+
+
+  /**
+   * Set the auto-start setting.
+   *
+   * @param setting the autostart setting to use.
+   */
+  void setAutostartSetting(int setting) = 0;
+
+
+  /**
+   * @return the location of the cached plugin.
+   */
+  QString getLibLocation() const = 0;
+
+
+  /**
+   * Get certificate chains associated with a plugin.
+   *
+   * @param onlyTrusted Only return trusted certificates.
+   * @return All certificates or null if bundle is unsigned.
+   */
+  //QList<> getCertificateChains(bool onlyTrusted) const = 0;
+
+
+  /**
+   * Mark certificate associated with the plugin as trusted.
+   *
+   */
+  //void trustCertificateChain(QList<> trustedChain) = 0;
+
+
+  /**
+   * Remove plugin from persistent storage.
+   */
+  void purge() = 0;
+
+
+  /**
+   * Close archive and all its open files.
+   */
+  void close() = 0;
+
+}
+
+
+#endif // CTKPLUGINARCHIVEINTERFACE_P_H

+ 8 - 0
Libs/Core/PluginFramework/ctkPluginConstants.cxx

@@ -0,0 +1,8 @@
+#include "ctkPluginConstants.h"
+
+namespace ctk {
+
+  const QString PluginConstants::FRAMEWORK_STORAGE = "org.commontk.pluginfw.storage";
+  const QString PluginConstants::PLUGIN_DIRECTORIES = "org.commontk.pluginfw.plugindirs";
+
+}

+ 17 - 0
Libs/Core/PluginFramework/ctkPluginConstants.h

@@ -0,0 +1,17 @@
+#ifndef CTKPLUGINCONSTANTS_H
+#define CTKPLUGINCONSTANTS_H
+
+#include <QString>
+
+namespace ctk {
+
+  struct PluginConstants {
+
+    static const QString FRAMEWORK_STORAGE;
+    static const QString PLUGIN_DIRECTORIES;
+
+  };
+
+}
+
+#endif // CTKPLUGINCONSTANTS_H

+ 63 - 0
Libs/Core/PluginFramework/ctkPluginException.cxx

@@ -0,0 +1,63 @@
+#include "ctkPluginException.h"
+
+namespace ctk {
+
+  PluginException::PluginException(const QString& msg, const Type& type = UNSPECIFIED, const std::exception& cause = std::exception())
+    : msg(msg), type(type), cause(cause)
+  {
+
+  }
+
+  PluginException::PluginException(const QString& msg, const std::exception& cause)
+    : msg(msg), type(UNSPECIFIED), cause(cause)
+  {
+
+  }
+
+  PluginException::PluginException(const PluginException& o)
+    : msg(o.msg), type(o.type), cause(o.cause)
+  {
+
+  }
+
+  PluginException& PluginException::operator=(const PluginException& o)
+  {
+    msg = o.msg;
+    type = o.type;
+    cause = o.cause;
+    return *this;
+  }
+
+  std::exception PluginException::getCause() const
+  {
+    return cause;
+  }
+
+  void PluginException::setCause(const std::exception& cause) throw(std::logic_error)
+  {
+    if (!cause.what()) throw std::logic_error("The cause for this PluginException instance is already set");
+
+    this->cause = cause;
+  }
+
+  Type PluginException::getType() const
+  {
+    return type;
+  }
+
+  const char* PluginException::what() const throw()
+  {
+    return qPrintable(*this);
+  }
+
+}
+
+QDebug operator<<(QDebug dbg, const PluginException& exc)
+{
+  dbg << "PluginException:" << msg;
+
+  const char* causeMsg = cause.what();
+  if (causeMsg) dbg << "  Caused by:" << cause.what();
+
+  return dbg.maybeSpace();
+}

+ 81 - 0
Libs/Core/PluginFramework/ctkPluginException.h

@@ -0,0 +1,81 @@
+#ifndef CTKPLUGINEXCEPTION_H
+#define CTKPLUGINEXCEPTION_H
+
+#include <stdexcept>
+
+#include <QString>
+#include <QDebug>
+
+namespace ctk {
+
+  class PluginException : public std::runtime_error
+  {
+  public:
+
+    enum Type {
+      /**
+       * No exception type is unspecified.
+       */
+      UNSPECIFIED,
+      /**
+       * The operation was unsupported.
+       */
+      UNSUPPORTED_OPERATION,
+      /**
+       * The operation was invalid.
+       */
+      INVALID_OPERATION,
+      /**
+       * The bundle manifest contains errors.
+       */
+      MANIFEST_ERROR,
+      /**
+       * The bundle was not resolved.
+       */
+      RESOLVE_ERROR,
+      /**
+       * The bundle activator was in error.
+       */
+      ACTIVATOR_ERROR,
+      /**
+       * The operation failed due to insufficient permissions.
+       */
+      SECURITY_ERROR,
+      /**
+       * The operation failed to complete the requested lifecycle state change.
+       */
+      STATECHANGE_ERROR,
+      /**
+       * The install or update operation failed because another
+       * already installed bundle has the same symbolic name and version.
+       */
+      DUPLICATE_BUNDLE_ERROR
+    };
+
+    PluginException(const QString& msg, const Type& type = UNSPECIFIED, const std::exception& cause = std::exception());
+    PluginException(const QString& msg, const std::exception& cause);
+
+    PluginException(const PluginException& o);
+    PluginException& operator=(const PluginException& o);
+
+    ~PluginException() throw() {}
+
+    std::exception getCause() const;
+    void setCause(const std::exception&) throw(std::logic_error);
+    Type getType() const;
+
+    const char* what() const throw();
+
+  private:
+
+    const QString msg;
+    const Type type;
+    std::exception cause;
+
+  };
+
+}
+
+QDebug operator<<(QDebug dbg, const ctk::PluginException& exc);
+
+#endif // CTKPLUGINEXCEPTION_H

+ 16 - 0
Libs/Core/PluginFramework/ctkPluginFramework.cxx

@@ -0,0 +1,16 @@
+#include "ctkPluginFramework.h"
+
+namespace ctk {
+
+  class PluginFrameworkPrivate : public PluginPrivate
+  {
+
+  };
+
+  PluginFramework::PluginFramework()
+    : Plugin(*new PluginFrameworkPrivate())
+  {
+
+  }
+
+}

+ 8 - 3
Libs/Core/PluginFramework/ctkPluginFramework.h

@@ -7,13 +7,18 @@
 
 namespace ctk {
 
-  class PluginFramework
+  class PluginFramework : public Plugin
   {
 
   public:
 
-    void launch();
-    void shutdown();
+    PluginFramework();
+
+    void init();
+
+    // TODO return info about the reason why this
+    // method returned
+    void waitForStop(int timeout);
 
   protected:
 

+ 18 - 0
Libs/Core/PluginFramework/ctkPluginFrameworkContext.cxx

@@ -0,0 +1,18 @@
+#include "ctkPluginFrameworkContext.h"
+
+#include "ctkPluginFrameworkContextPrivate_p.h"
+
+namespace ctk {
+
+  PluginFrameworkContext::PluginFrameworkContext(const Properties& initProps)
+    : d_ptr(new PluginFrameworkContextPrivate(initProps))
+  {
+
+  }
+
+  PluginFrameworkContext::~PluginFrameworkContext()
+  {
+    delete d_ptr;
+  }
+
+}

+ 31 - 0
Libs/Core/PluginFramework/ctkPluginFrameworkContext.h

@@ -0,0 +1,31 @@
+#ifndef CTKPLUGINFRAMEWORKCONTEXT_H
+#define CTKPLUGINFRAMEWORKCONTEXT_H
+
+#include <QHash>
+#include <QString>
+#include <QVariant>
+
+namespace ctk {
+
+  class PluginFrameworkContextPrivate;
+
+  class PluginFrameworkContext {
+
+    Q_DECLARE_PRIVATE(PluginFrameworkContext)
+
+  public:
+
+    typedef QHash<QString, QVariant> Properties;
+
+    PluginFrameworkContext(const Properties& initProps);
+    ~PluginFrameworkContext();
+
+  private:
+
+    PluginFrameworkContextPrivate * const d_ptr;
+
+  };
+
+}
+
+#endif // CTKPLUGINFRAMEWORKCONTEXT_H

+ 80 - 0
Libs/Core/PluginFramework/ctkPluginFrameworkContextPrivate.cxx

@@ -0,0 +1,80 @@
+#include "ctkPluginFrameworkContextPrivate_p.h"
+
+namespace ctk {
+
+  QMutex PluginFrameworkContextPrivate::globalFwLock;
+  int PluginFrameworkContextPrivate::globalId = 1;
+
+
+  PluginFrameworkContextPrivate::PluginFrameworkContextPrivate(
+      const PluginFrameworkContext::Properties& initProps)
+        : /*plugins(this), services(this), systemPlugin(this)*/
+        props(initProps)
+  {
+
+    {
+      QMutexLocker lock(&globalFwLock);
+      id = globalId++;
+    }
+
+    log() << "created";
+  }
+
+  void PluginFrameworkContextPrivate::init()
+  {
+    log() << "initializing";
+
+//    if (Constants.FRAMEWORK_STORAGE_CLEAN_ONFIRSTINIT
+//        .equals(props.getProperty(Constants.FRAMEWORK_STORAGE_CLEAN))) {
+//      deleteFWDir();
+//      // Must remove the storage clean property since it should not be
+//      // used more than once!
+//      props.removeProperty(Constants.FRAMEWORK_STORAGE_CLEAN);
+//    }
+//    props.save();
+
+
+//    systemPlugin.initSystemBundle();
+
+//    plugins.load();
+
+    log() << "inited";
+
+    log() << "Installed bundles:";
+//    // Use the ordering in the bundle storage to get a sorted list of bundles.
+//    final BundleArchive [] allBAs = storage.getAllBundleArchives();
+//    for (int i = 0; i<allBAs.length; i++) {
+//      final BundleArchive ba = allBAs[i];
+//      final Bundle b = bundles.getBundle(ba.getBundleLocation());
+//      log(" #" +b.getBundleId() +" " +b.getSymbolicName() +":"
+//          +b.getVersion() +" location:" +b.getLocation());
+//    }
+  }
+
+  void PluginFrameworkContextPrivate::uninit()
+  {
+    log() << "uninit";
+
+    //systemBundle.uninitSystemBundle();
+
+    //storage.close();
+
+  }
+
+  int PluginFrameworkContextPrivate::getId() {
+    return id;
+  }
+
+  void PluginFrameworkContextPrivate::checkOurPlugin(Plugin* b) {
+//    if (this != ((BundleImpl)b).fwCtx) {
+//      throw new IllegalArgumentException("Bundle does not belong to this framework: " + b);
+//    }
+  }
+
+  QDebug PluginFrameworkContextPrivate::log() {
+    QDebug dbg(qDebug());
+    dbg << "Framework instance " << getId() << ": ";
+    return dbg;
+  }
+
+}

+ 98 - 0
Libs/Core/PluginFramework/ctkPluginFrameworkContextPrivate_p.h

@@ -0,0 +1,98 @@
+#ifndef CTKPLUGINFRAMEWORKCONTEXTPRIVATE_P_H
+#define CTKPLUGINFRAMEWORKCONTEXTPRIVATE_P_H
+
+#include <QDebug>
+#include <QMutex>
+
+#include "ctkPluginFrameworkContext.h"
+
+namespace ctk {
+
+  class Plugin;
+
+  class PluginFrameworkContextPrivate {
+
+  private:
+
+
+      /**
+       * All plugins in this framework.
+       */
+      //Plugins plugins;
+
+      /**
+       * All registered services in this framework.
+       */
+      //Services services;
+
+      /**
+       * System bundle
+       */
+      //SystemPlugin systemPlugin;
+
+      /**
+       * Framework id.
+       */
+      int id;
+
+  public:
+
+
+      /**
+       * global lock.
+       */
+      static QMutex globalFwLock;
+
+      /**
+       * Id to use for next instance of plugin framework.
+       */
+      static int globalId;
+
+      PluginFrameworkContext::Properties props;
+
+      /**
+       * Contruct a framework context
+       *
+       */
+      PluginFrameworkContextPrivate(const PluginFrameworkContext::Properties& initProps);
+
+
+      /**
+       * Initialize the framework
+       *
+       */
+      void init();
+
+
+      /**
+       * Undo as much as possible of what init() does.
+       *
+       */
+      void uninit();
+
+
+      /**
+       *
+       */
+      int getId();
+
+
+      /**
+       * Check that the plugin belongs to this framework instance.
+       *
+       */
+      void checkOurPlugin(Plugin* b);
+
+
+      /**
+       * Log message for debugging framework
+       *
+       */
+      QDebug log();
+
+
+  };
+
+}
+
+#endif // CTKPLUGINFRAMEWORKCONTEXTPRIVATE_P_H

+ 7 - 0
Libs/Core/PluginFramework/ctkPluginPrivate.cxx

@@ -0,0 +1,7 @@
+#include "ctkPluginPrivate_p.h"
+
+namespace ctk {
+
+  const Plugin::States PluginPrivate::RESOLVED_FLAGS = Plugin::RESOLVED | Plugin::STARTING | Plugin::ACTIVE | Plugin::STOPPING;
+
+}

+ 95 - 2
Libs/Core/PluginFramework/ctkPluginPrivate_p.h

@@ -1,17 +1,110 @@
 #ifndef CTKPLUGINPRIVATE_P_H
 #define CTKPLUGINPRIVATE_P_H
 
+#include "ctkPlugin.h"
+#include "ctkPluginException.h"
+
+#include <QHash>
+
 namespace ctk {
 
+  class PluginActivator;
+  class PluginArchiveInterface;
+  class PluginFrameworkContext;
+
   class PluginPrivate {
 
   public:
 
+    /**
+     * Construct a new plugin based on a PluginArchive.
+     *
+     * @param fw PluginFrameworkContext for this plugin.
+     * @param ba Plugin archive representing the shared library and cached data
+     * @param checkContext AccessConrolContext to do permission checks against.
+     * @exception std::invalid_argument Faulty manifest for bundle
+     */
+    PluginPrivate(PluginFrameworkContext* fw,
+               PluginArchiveInterface* ba /*, Object checkContext*/);
+
+    /**
+     * Construct a new empty Plugin.
+     *
+     * Only called for the system plugin
+     *
+     * @param fw Framework for this plugin.
+     */
+    PluginPrivate(PluginFrameworkContext* fw,
+                  int id,
+                  QString loc,
+                  QString sym,
+                  const Version& ver);
+
     virtual ~PluginPrivate();
 
-    void load();
+    QHash<QString, QString> getHeaders(const QString& locale);
+
+
+  protected:
+
+    /**
+     * Union of flags allowing plugin class access
+     */
+    static const Plugin::States RESOLVED_FLAGS;
+
+    PluginFrameworkContext * const fwCtx;
+
+    /**
+     * Plugin identifier
+     */
+    const int id;
+
+    /**
+     * Plugin symbolic name
+     */
+    QString symbolicName;
+
+    /**
+     * Plugin version
+     */
+    Version version;
+
+    /**
+     * State of the plugin
+     */
+    Plugin::States state;
+
+    /**
+     * PluginContext for the plugin
+     */
+    PluginContext* pluginContext;
+
+    /**
+     * PluginActivator for the plugin
+     */
+    PluginActivator* pluginActivator;
+
+    /**
+     * Stores the default locale entries when uninstalled
+     */
+    QHash<QString, QString> cachedHeaders;
+
+    /**
+     * Stores the raw manifest headers
+     */
+    QHash<QString, QString> cachedRawHeaders;
+
+    bool lazyActivation;
+
+    /** True during the finalization of an activation. */
+    bool activating;
+
+    /** True during the state change from active to resolved. */
+    bool deactivating;
+
+    /** Saved exception of resolve failure */
+    PluginException resolveFailException;
 
-    QHash<QString, QString> getHeaders(const QString& )
 
   };
 

+ 243 - 0
Libs/Core/PluginFramework/ctkPluginStorage_p.h

@@ -0,0 +1,243 @@
+#ifndef CTKPLUGINSTORAGE_P_H
+#define CTKPLUGINSTORAGE_P_H
+
+#include "ctkPluginFrameworkContext.h"
+#include "ctkPluginArchiveInterface_p.h"
+
+namespace ctk {
+
+  class PluginStorage {
+
+  private:
+
+    /**
+     * Plugin id sorted list of all active plugin archives.
+     */
+    QList<PluginArchiveInterface*> archives;
+
+     /**
+      * Framework handle.
+      */
+     PluginFrameworkContext* framework;
+
+  public:
+
+     /**
+      * Create a container for all plugin data in this framework.
+      * Try to restore all saved plugin archive state.
+      *
+      */
+     PluginStorage(PluginFrameworkContext* framework)
+       : framework(framework)
+     {
+       // See if we have a storage database
+       bundlesDir = Util.getFileStorage(framework, "bs");
+       if (bundlesDir == null) {
+         throw new RuntimeException("No bundle storage area available!");
+       }
+       // Restore all saved bundles
+       String [] list = bundlesDir.list();
+       for (int i = 0; list != null & i < list.length; i++) {
+         long id;
+         try {
+           id = Long.parseLong(list[i]);
+         } catch (NumberFormatException e) {
+           continue;
+         }
+         if (id == 0) {
+           System.err.println("Saved bundle with illegal id 0 is ignored.");
+         }
+         int pos = find(id);
+         if (pos < archives.size() && ((BundleArchive)archives.get(pos)).getBundleId() == id) {
+           System.err.println("There are two bundle directories with id: " + id);
+           break;
+         }
+         FileTree dir = new FileTree(bundlesDir, list[i]);
+         if (dir.isDirectory()) {
+           try {
+             boolean bUninstalled = BundleArchiveImpl.isUninstalled(dir);
+             if(bUninstalled) {
+               // silently remove any bundle marked as uninstalled
+               dir.delete();
+             } else {
+               BundleArchive ba = new BundleArchiveImpl(this, dir, id);
+               archives.add(pos, ba);
+             }
+             if (id >= nextFreeId) {
+               nextFreeId = id + 1;
+             }
+           } catch (Exception e) {
+             dir.delete();
+             System.err.println("Removed corrupt bundle dir (" + e.getMessage() + "): " + dir);
+           }
+         }
+       }
+     }
+
+
+     /**
+      * Insert bundle into persistent storage
+      *
+      * @param location Location of bundle.
+      * @param is Inputstrem with bundle content.
+      * @return Bundle archive object.
+      */
+     public BundleArchive insertBundleJar(String location, InputStream is)
+       throws Exception
+     {
+       long id = nextFreeId++;
+       FileTree dir = new FileTree(bundlesDir, String.valueOf(id));
+       if (dir.exists()) {
+         // remove any old garbage
+         dir.delete();
+       }
+       dir.mkdir();
+       try {
+         BundleArchive ba = new BundleArchiveImpl(this, dir, is, location, id);
+         archives.add(ba);
+         return ba;
+       } catch (Exception e) {
+         dir.delete();
+         throw e;
+       }
+     }
+
+
+     /**
+      * Insert a new jar file into persistent storagedata as an update
+      * to an existing bundle archive. To commit this data a call to
+      * <code>replaceBundleArchive</code> is needed.
+      *
+      * @param old BundleArchive to be replaced.
+      * @param is Inputstrem with bundle content.
+      * @return Bundle archive object.
+      */
+     public BundleArchive updateBundleArchive(BundleArchive old, InputStream is)
+       throws Exception
+     {
+       return new BundleArchiveImpl((BundleArchiveImpl)old, is);
+     }
+
+
+     /**
+      * Replace old bundle archive with a new updated bundle archive, that
+      * was created with updateBundleArchive.
+      *
+      * @param oldBA BundleArchive to be replaced.
+      * @param newBA Inputstrem with bundle content.
+      * @return New bundle archive object.
+      */
+     public void replaceBundleArchive(BundleArchive oldBA, BundleArchive newBA)
+       throws Exception
+     {
+       int pos;
+       long id = oldBA.getBundleId();
+       synchronized (archives) {
+         pos = find(id);
+         if (pos >= archives.size() || archives.get(pos) != oldBA) {
+           throw new Exception("replaceBundleJar: Old bundle archive not found, pos=" + pos);
+         }
+         archives.set(pos, newBA);
+       }
+     }
+
+
+     /**
+      * Get all bundle archive objects.
+      *
+      * @return Private array of all BundleArchives.
+      */
+     public BundleArchive [] getAllBundleArchives() {
+       synchronized (archives) {
+         return (BundleArchive [])archives.toArray(new BundleArchive[archives.size()]);
+       }
+     }
+
+
+     /**
+      * Get all bundles to start at next launch of framework.
+      * This list is sorted in increasing bundle id order.
+      *
+      * @return Private copy of a List with bundle id's.
+      */
+     public List getStartOnLaunchBundles() {
+       ArrayList res = new ArrayList();
+       for (Iterator i = archives.iterator(); i.hasNext(); ) {
+         BundleArchive ba = (BundleArchive)i.next();
+         if (ba.getAutostartSetting()!=-1) {
+           res.add(ba.getBundleLocation());
+         }
+       }
+       return res;
+     }
+
+
+     /**
+      * Close bundle storage.
+      *
+      */
+     public void close()
+     {
+       for (Iterator i = archives.iterator(); i.hasNext(); ) {
+         BundleArchive ba = (BundleArchive) i.next();
+         ba.close();
+         i.remove();
+       }
+       framework = null;
+       bundlesDir = null;
+     }
+
+
+   private:
+
+     /**
+      * Remove bundle archive from archives list.
+      *
+      * @param id Bundle archive id to find.
+      * @return true if element was removed.
+      */
+     bool removeArchive(PluginArchiveInterface* ba) {
+       synchronized (archives) {
+         int pos = find(ba.getBundleId());
+         if (pos < archives.size() && archives.get(pos) == ba) {
+           archives.remove(pos);
+           return true;
+         } else {
+           return false;
+         }
+       }
+     }
+
+     /**
+      * Find posisition for BundleArchive with specified id
+      *
+      * @param id Bundle archive id to find.
+      * @return String to write
+      */
+     int find(long id) {
+       int lb = 0;
+       int ub = archives.size() - 1;
+       int x = 0;
+       while (lb < ub) {
+         x = (lb + ub) / 2;
+         long xid = ((BundleArchive)archives.get(x)).getBundleId();
+         if (id == xid) {
+           return x;
+         } else if (id < xid) {
+           ub = x;
+         } else {
+           lb = x+1;
+         }
+       }
+       if (lb < archives.size() && ((BundleArchive)archives.get(lb)).getBundleId() < id) {
+         return lb + 1;
+       }
+       return lb;
+     }
+
+
+  };
+
+}
+
+#endif // CTKPLUGINSTORAGE_P_H