Author: aconway
Date: Thu Jun 26 14:39:28 2008
New Revision: 672032

URL: http://svn.apache.org/viewvc?rev=672032&view=rev
Log:
Plugin framework change: single PluginFactory creates per-target Plugin 
instances.

Removed:
    incubator/qpid/trunk/qpid/cpp/src/tests/qpid_test_plugin.h
Modified:
    incubator/qpid/trunk/qpid/cpp/src/qpid/Plugin.cpp
    incubator/qpid/trunk/qpid/cpp/src/qpid/Plugin.h
    incubator/qpid/trunk/qpid/cpp/src/qpid/broker/Broker.cpp
    incubator/qpid/trunk/qpid/cpp/src/qpid/cluster/ClusterPlugin.cpp
    incubator/qpid/trunk/qpid/cpp/src/qpid/cluster/Cpg.cpp
    incubator/qpid/trunk/qpid/cpp/src/qpid/sys/TCPIOPlugin.cpp
    incubator/qpid/trunk/qpid/cpp/src/qpidd.cpp
    incubator/qpid/trunk/qpid/cpp/src/tests/Makefile.am
    incubator/qpid/trunk/qpid/cpp/src/tests/cluster.mk
    incubator/qpid/trunk/qpid/cpp/src/tests/cluster_test.cpp

Modified: incubator/qpid/trunk/qpid/cpp/src/qpid/Plugin.cpp
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/Plugin.cpp?rev=672032&r1=672031&r2=672032&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpid/Plugin.cpp (original)
+++ incubator/qpid/trunk/qpid/cpp/src/qpid/Plugin.cpp Thu Jun 26 14:39:28 2008
@@ -19,36 +19,53 @@
  */
 
 #include "Plugin.h"
-#include "qpid/Options.h"
+#include <qpid/shared_ptr.h>
+#include <qpid/Options.h>
+#include <qpid/sys/Mutex.h>
 
 namespace qpid {
 
-namespace {
-Plugin::Plugins& thePlugins() {
-    // This is a single threaded singleton implementation so
-    // it is important to be sure that the first use of this
-    // singleton is when the program is still single threaded
-    static Plugin::Plugins plugins;
-    return plugins;
-}
+Plugin::Target::~Target() {}
+
+void Plugin::Target::createPlugins() {
+    typedef std::vector<Plugin::Factory*>::const_iterator Iter; 
+    for (Iter i = Factory::getList().begin(); i != Factory::getList().end(); 
++i) {
+        boost::shared_ptr<Plugin> plugin = (**i).create(*this);
+        if (plugin)
+            plugins.push_back(plugin);
+    }
 }
 
-Plugin::Plugin() {
-    // Register myself.
-    thePlugins().push_back(this);
+void Plugin::Target::initializePlugins() {
+    typedef std::vector<boost::shared_ptr<Plugin> >::iterator Iter; 
+    for (Iter i = plugins.begin(); i != plugins.end(); ++i) 
+        (**i).initialize(*this);
 }
 
-Plugin::~Plugin() {}
+void Plugin::Target::releasePlugins() { plugins.clear(); }
+
+Plugin::Factory::~Factory() {}
 
-Options*  Plugin::getOptions() { return 0; }
+Plugin::Factory::Factory() {
+    const_cast<std::vector<Plugin::Factory*>& >(getList()).push_back(this);
+}
+
+static sys::PODMutex PluginFactoryGetListLock;
 
-const Plugin::Plugins& Plugin::getPlugins() { return thePlugins(); }
+const std::vector<Plugin::Factory*>& Plugin::Factory::getList() {
+    sys::PODMutex::ScopedLock l(PluginFactoryGetListLock);
+    static std::vector<Plugin::Factory*> list;
+    return list;
+}
 
-void Plugin::addOptions(Options& opts) {
-    for (Plugins::const_iterator i = getPlugins().begin(); i != 
getPlugins().end(); ++i) {
-        if ((*i)->getOptions())
-            opts.add(*(*i)->getOptions());
+void Plugin::Factory::addOptions(Options& opts) {
+    typedef std::vector<Plugin::Factory*>::const_iterator Iter; 
+    for (Iter i = Factory::getList().begin(); i != Factory::getList().end(); 
++i) {
+        if ((**i).getOptions())
+            opts.add(*(**i).getOptions());
     }
 }
 
+Plugin::~Plugin() {}
+
 } // namespace qpid

Modified: incubator/qpid/trunk/qpid/cpp/src/qpid/Plugin.h
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/Plugin.h?rev=672032&r1=672031&r2=672032&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpid/Plugin.h (original)
+++ incubator/qpid/trunk/qpid/cpp/src/qpid/Plugin.h Thu Jun 26 14:39:28 2008
@@ -21,78 +21,123 @@
  *
  */
 
-#include "qpid/shared_ptr.h"
-#include <boost/noncopyable.hpp>
+#include <boost/shared_ptr.hpp>
 #include <vector>
-#include <boost/function.hpp>
-
 
 /[EMAIL PROTECTED] Generic plug-in framework. */
 
 namespace qpid {
+
 class Options;
 
 /**
  * Plug-in base class.
+ *
+ * A Plugin is created by a Plugin::Factory and attached to a Plugin::Target.
  */
-class Plugin : boost::noncopyable
-{
+class Plugin {
   public:
     /**
-     * Base interface for targets that receive plug-ins.
-     *
-     * The Broker is a plug-in target, there might be others
-     * in future.
+     * Base class for target objects that receive plug-ins.
      */
-    struct Target { virtual ~Target() {} };
+    class Target {
+      public:
+        virtual ~Target();
+
+      protected:
+        /** For each Factory create a plugin attached to this */
+        void createPlugins();
+
+        /** Initialize all attached plugins */
+        void initializePlugins();
+        
+        /** Release the attached plugins. Done automatically in destructor. */
+        void releasePlugins();
+
+      private:
+        std::vector<boost::shared_ptr<Plugin> > plugins;
+    };
+
+    /** Base class for a factory to create Plugins. */
+    class Factory {
+      public:
+        /**
+         * Constructor registers the factory so it will be included in 
getList().
+         *
+         * Derive your Plugin Factory class from Factory and create a
+         * single global instance in your plug-in library. Loading the
+         * library will automatically register your factory.
+         */
+        Factory();
+        
+        virtual ~Factory();
+
+        /** Get the list of Factories */
+        static const std::vector<Factory*>& getList();
+
+        /** For each Factory in Factory::getList() add options to opts. */
+        static void addOptions(Options& opts);
+
+        /**
+         * Configuration options for this factory.
+         * Then will be updated during option parsing by the host program.
+         * 
+         * @return An options group or 0 for no options.
+         */
+        virtual Options* getOptions() = 0;
+        
+        /**
+         * Create a Plugin for target.
+         * Uses option values set by getOptions().
+         * Target may not be fully initialized at this point.
+         * Actions that require a fully-initialized target should be
+         * done in initialize().
+         * 
+         * @returns 0 if the target type is not compatible with this Factory.
+         */
+        virtual boost::shared_ptr<Plugin> create(Target& target) = 0;
+    };
 
-    typedef std::vector<Plugin*> Plugins;
-    
     /**
-     * Construct registers the plug-in to appear in getPlugins().
-     * 
-     * A concrete Plugin is instantiated as a global or static
-     * member variable in a library so it is registered during static
-     * initialization when the library is loaded.
+     * Template factory implementation, checks target type is correct. 
      */
-    Plugin();
-    
-    virtual ~Plugin();
+    template <class TargetType> class FactoryT : public Factory {
+        Options* getOptions() { return 0; }
 
-    /**
-     * Configuration options for the plugin.
-     * Then will be updated during option parsing by the host program.
-     * 
-     * @return An options group or 0 for no options. Default returns 0.
-     * Plugin retains ownership of return value.
-     */
-    virtual Options* getOptions();
+        virtual boost::shared_ptr<Plugin> createT(TargetType& target) = 0;
 
-    /**
-     * Initialize Plugin functionality on a Target.
-     * Plugins should ignore targets they don't recognize.
-     *
-     * Called before the target itself is initialized.
-     */
-    virtual void earlyInitialize(Target&) = 0;
+        boost::shared_ptr<Plugin> create(Target& target) {
+            TargetType* tt = dynamic_cast<TargetType*>(&target);
+            if (tt)
+                return createT(*tt);
+            else
+                return boost::shared_ptr<Plugin>();
+        }
+    };
+
+    // Plugin functions.
 
+    virtual ~Plugin();
+    
     /**
-     * Initialize Plugin functionality on a Target.
-     * Plugins should ignore targets they don't recognize.
-     *
+     * Initialize the Plugin. 
      * Called after the target is fully initialized.
      */
     virtual void initialize(Target&) = 0;
+};
 
-    /** List of registered Plugin objects.
-     * Caller must not delete plugin pointers.
-     */
-    static const Plugins& getPlugins();
+/** Template plugin factory */
+template <class TargetType> class PluginT : public Plugin {
 
-    /** For each registered plugin, add plugin.getOptions() to opts. */
-    static void addOptions(Options& opts);
+    virtual void initializeT(TargetType&) = 0;
+
+    void initialize(Plugin::Target& target) {
+        TargetType* tt = dynamic_cast<TargetType*>(&target);
+        assert(tt);
+        initializeT(*tt);
+    }
 };
- 
+
 } // namespace qpid
 
 #endif  /*!QPID_PLUGIN_H*/

Modified: incubator/qpid/trunk/qpid/cpp/src/qpid/broker/Broker.cpp
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/broker/Broker.cpp?rev=672032&r1=672031&r2=672032&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpid/broker/Broker.cpp (original)
+++ incubator/qpid/trunk/qpid/cpp/src/qpid/broker/Broker.cpp Thu Jun 26 
14:39:28 2008
@@ -166,13 +166,7 @@
         links.setParent     (vhost);
     }
 
-    // Early-Initialize plugins
-    const Plugin::Plugins& plugins=Plugin::getPlugins();
-    for (Plugin::Plugins::const_iterator i = plugins.begin();
-         i != plugins.end();
-         i++)
-        (*i)->earlyInitialize(*this);
-
+    createPlugins();
     // If no plugin store module registered itself, set up the null store.
     if (store == 0)
         setStore (new NullMessageStore (false));
@@ -223,11 +217,7 @@
 #endif
     }
 
-    // Initialize plugins
-    for (Plugin::Plugins::const_iterator i = plugins.begin();
-         i != plugins.end();
-         i++)
-        (*i)->initialize(*this);
+    initializePlugins();
 }
 
 void Broker::declareStandardExchange(const std::string& name, const 
std::string& type)

Modified: incubator/qpid/trunk/qpid/cpp/src/qpid/cluster/ClusterPlugin.cpp
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/cluster/ClusterPlugin.cpp?rev=672032&r1=672031&r2=672032&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpid/cluster/ClusterPlugin.cpp (original)
+++ incubator/qpid/trunk/qpid/cpp/src/qpid/cluster/ClusterPlugin.cpp Thu Jun 26 
14:39:28 2008
@@ -33,47 +33,64 @@
 namespace cluster {
 
 using namespace std;
+using broker::Broker;
 
-struct ClusterOptions : public Options {
+struct OptionValues {
     string name;
     string url;
 
-    ClusterOptions() : Options("Cluster Options") {
+    Url getUrl(uint16_t port) const {
+        if (url.empty()) return Url::getIpAddressesUrl(port);
+        return Url(url);
+    }
+};
+
+// Note we update the values in a separate struct.
+// This is to work around boost::program_options differences,
+// older versions took a reference to the options, newer
+// ones take a copy (or require a shared_ptr)
+//
+struct ClusterOptions : public Options {
+
+    ClusterOptions(OptionValues* v) : Options("Cluster Options") {
         addOptions()
-            ("cluster-name", optValue(name, "NAME"), "Name of cluster to join")
-            ("cluster-url", optValue(url,"URL"),
+            ("cluster-name", optValue(v->name, "NAME"), "Name of cluster to 
join")
+            ("cluster-url", optValue(v->url,"URL"),
              "URL of this broker, advertized to the cluster.\n"
              "Defaults to a URL listing all the local IP addresses\n");
     }
+};
 
-    Url getUrl(uint16_t port) const {
-        if (url.empty()) return Url::getIpAddressesUrl(port);
-        return Url(url);
+struct ClusterPlugin : public PluginT<Broker> {
+    OptionValues values;
+    boost::optional<Cluster> cluster;
+
+    ClusterPlugin(const OptionValues& v) : values(v) {}
+    
+    void initializeT(Broker& broker) {
+        cluster = boost::in_place(values.name, 
values.getUrl(broker.getPort()), boost::ref(broker));
+        broker.getSessionManager().add(cluster->getObserver());        
     }
 };
 
-struct ClusterPlugin : public Plugin {
+struct PluginFactory : public Plugin::FactoryT<Broker> {
 
+    OptionValues values;
     ClusterOptions options;
-    boost::optional<Cluster> cluster;
 
-    Options* getOptions() { return &options; }
+    PluginFactory() : options(&values) {}
 
-    void earlyInitialize(Plugin::Target&) {}
+    Options* getOptions() { return &options; }
 
-    void initialize(Plugin::Target& target) {
-        broker::Broker* broker = dynamic_cast<broker::Broker*>(&target);
+    boost::shared_ptr<Plugin> createT(Broker&) {
         // Only provide to a Broker, and only if the --cluster config is set.
-        if (broker && !options.name.empty()) {
-            assert(!cluster); // A process can only belong to one cluster.
-            cluster = boost::in_place(options.name,
-                                      options.getUrl(broker->getPort()),
-                                      boost::ref(*broker));
-            broker->getSessionManager().add(cluster->getObserver());   
-        }
+        if (values.name.empty())
+            return boost::shared_ptr<Plugin>();
+        else
+            return make_shared_ptr(new ClusterPlugin(values));
     }
 };
 
-static ClusterPlugin instance; // Static initialization.
+static PluginFactory instance; // Static initialization.
     
 }} // namespace qpid::cluster

Modified: incubator/qpid/trunk/qpid/cpp/src/qpid/cluster/Cpg.cpp
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/cluster/Cpg.cpp?rev=672032&r1=672031&r2=672032&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpid/cluster/Cpg.cpp (original)
+++ incubator/qpid/trunk/qpid/cpp/src/qpid/cluster/Cpg.cpp Thu Jun 26 14:39:28 
2008
@@ -104,9 +104,8 @@
 }
 
 void Cpg::shutdown() {
-    QPID_LOG(debug, "Shutdown CPG handle " << handle);
     if (handles.get(handle)) {
-        QPID_LOG(debug, "Finalize CPG handle " << handle);
+        QPID_LOG(debug, "Finalize CPG handle " << std::hex << handle);
         handles.put(handle, 0);
         check(cpg_finalize(handle), "Error in shutdown of CPG");
     }

Modified: incubator/qpid/trunk/qpid/cpp/src/qpid/sys/TCPIOPlugin.cpp
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/sys/TCPIOPlugin.cpp?rev=672032&r1=672031&r2=672032&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpid/sys/TCPIOPlugin.cpp (original)
+++ incubator/qpid/trunk/qpid/cpp/src/qpid/sys/TCPIOPlugin.cpp Thu Jun 26 
14:39:28 2008
@@ -53,22 +53,20 @@
                      bool isClient);
 };
 
-// Static instance to initialise plugin
-static class TCPIOPlugin : public Plugin {
-    void earlyInitialize(Target&) {
+struct TCPIOPlugin : public PluginT<broker::Broker> {
+    void initializeT(broker::Broker& broker) {
+        const broker::Broker::Options& opts = broker.getOptions();
+        ProtocolFactory::shared_ptr protocol(new 
AsynchIOProtocolFactory(opts.port, opts.connectionBacklog));
+        QPID_LOG(info, "Listening on TCP port " << protocol->getPort());
+        broker.registerProtocolFactory(protocol);
     }
-    
-    void initialize(Target& target) {
-        broker::Broker* broker = dynamic_cast<broker::Broker*>(&target);
-        // Only provide to a Broker
-        if (broker) {
-            const broker::Broker::Options& opts = broker->getOptions();
-            ProtocolFactory::shared_ptr protocol(new 
AsynchIOProtocolFactory(opts.port, opts.connectionBacklog));
-            QPID_LOG(info, "Listening on TCP port " << protocol->getPort());
-            broker->registerProtocolFactory(protocol);
-        }
+};
+
+static struct TCPIOPluginFactory : public Plugin::FactoryT<broker::Broker> {
+    boost::shared_ptr<Plugin> createT(broker::Broker&) {
+        return make_shared_ptr(new TCPIOPlugin());
     }
-} tcpPlugin;
+} theTCPIOPluginFactory;   // Static plugin factory instance.
 
 AsynchIOProtocolFactory::AsynchIOProtocolFactory(int16_t port, int backlog) :
     listeningPort(listener.listen(port, backlog))

Modified: incubator/qpid/trunk/qpid/cpp/src/qpidd.cpp
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpidd.cpp?rev=672032&r1=672031&r2=672032&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpidd.cpp (original)
+++ incubator/qpid/trunk/qpid/cpp/src/qpidd.cpp Thu Jun 26 14:39:28 2008
@@ -102,7 +102,7 @@
         add(broker);
         add(daemon);
         add(log);
-        Plugin::addOptions(*this);
+        Plugin::Factory::addOptions(*this);
     }
 
     void usage() const {

Modified: incubator/qpid/trunk/qpid/cpp/src/tests/Makefile.am
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/tests/Makefile.am?rev=672032&r1=672031&r2=672032&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/tests/Makefile.am (original)
+++ incubator/qpid/trunk/qpid/cpp/src/tests/Makefile.am Thu Jun 26 14:39:28 2008
@@ -134,8 +134,7 @@
   MessageUtils.h                                                       \
   TestMessageStore.h                                                   \
   MockConnectionInputHandler.h                                         \
-  TxMocks.h                                                            \
-  qpid_test_plugin.h
+  TxMocks.h
 
 check_LTLIBRARIES += libdlclose_noop.la
 libdlclose_noop_la_LDFLAGS = -module -rpath $(abs_builddir)

Modified: incubator/qpid/trunk/qpid/cpp/src/tests/cluster.mk
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/tests/cluster.mk?rev=672032&r1=672031&r2=672032&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/tests/cluster.mk (original)
+++ incubator/qpid/trunk/qpid/cpp/src/tests/cluster.mk Thu Jun 26 14:39:28 2008
@@ -15,6 +15,6 @@
 
 check_PROGRAMS+=cluster_test
 cluster_test_SOURCES=unit_test.cpp cluster_test.cpp
-cluster_test_LDADD=$(lib_client) $(lib_cluster) -lboost_unit_test_framework
+cluster_test_LDADD=$(lib_client) $(lib_cluster) $(lib_broker) 
-lboost_unit_test_framework
 
 endif

Modified: incubator/qpid/trunk/qpid/cpp/src/tests/cluster_test.cpp
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/tests/cluster_test.cpp?rev=672032&r1=672031&r2=672032&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/tests/cluster_test.cpp (original)
+++ incubator/qpid/trunk/qpid/cpp/src/tests/cluster_test.cpp Thu Jun 26 
14:39:28 2008
@@ -157,14 +157,16 @@
 void ClusterFixture::add() {
     qpid::broker::Broker::Options opts;
     // Assumes the cluster plugin is loaded.
-    qpid::Plugin::addOptions(opts);
-    const char* argv[] = { "--cluster-name=$CLUSTER" };
+    qpid::Plugin::Factory::addOptions(opts);
+    const char* argv[] = { "--cluster-name", ::getenv("USERNAME") };
     // FIXME aconway 2008-06-26: fix parse() signature, should not need cast.
     opts.parse(sizeof(argv)/sizeof(*argv), const_cast<char**>(argv));
     push_back(new BrokerFixture(opts));
 }
 
 #if 0                           // FIXME aconway 2008-06-26: TODO
+
+
 QPID_AUTO_TEST_CASE(testWiringReplication) {
     const size_t SIZE=3;
     ClusterFixture cluster(SIZE);
@@ -175,14 +177,12 @@
     c0.session.exchangeDeclare("ex", arg::type="direct");
     BOOST_CHECK_EQUAL("q", c0.session.queueQuery("q").getQueue());
     BOOST_CHECK_EQUAL("direct", c0.session.exchangeQuery("ex").getType());
-    c0.close();
 
     // Verify all brokers get wiring update.
     for (size_t i = 1; i < cluster.size(); ++i) {
         Client c(cluster[i].getPort());
         BOOST_CHECK_EQUAL("q", c.session.queueQuery("q").getQueue());
         BOOST_CHECK_EQUAL("direct", c.session.exchangeQuery("ex").getType());
-        c.close();
     }    
 }
 


Reply via email to