]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[5528] Code and tests done
authorFrancis Dupont <fdupont@isc.org>
Sun, 11 Feb 2018 00:56:53 +0000 (01:56 +0100)
committerFrancis Dupont <fdupont@isc.org>
Sun, 11 Feb 2018 00:56:53 +0000 (01:56 +0100)
src/lib/dhcpsrv/host_data_source_factory.cc
src/lib/dhcpsrv/host_data_source_factory.h
src/lib/dhcpsrv/tests/Makefile.am

index c9e5203c91ca98063ea224891e0178b8e6367635..3a63770cba8e2f7114c7ec24bbcf749fd462ff6f 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2015-2017 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2015-2018 Internet Systems Consortium, Inc. ("ISC")
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -38,6 +38,8 @@ using namespace std;
 namespace isc {
 namespace dhcp {
 
+map<string, HostDataSourceFactory::Factory> HostDataSourceFactory::map_;
+
 HostDataSourcePtr&
 HostDataSourceFactory::getHostDataSourcePtr() {
     static HostDataSourcePtr hostDataSourcePtr;
@@ -45,7 +47,7 @@ HostDataSourceFactory::getHostDataSourcePtr() {
 }
 
 void
-HostDataSourceFactory::create(const std::string& dbaccess) {
+HostDataSourceFactory::create(const string& dbaccess) {
     // Parse the access string and create a redacted string for logging.
     DatabaseConnection::ParameterMap parameters =
             DatabaseConnection::parse(dbaccess);
@@ -57,38 +59,23 @@ HostDataSourceFactory::create(const std::string& dbaccess) {
                   "contain the 'type' keyword");
     }
 
-    std::string db_type = it->second;
+    string db_type = it->second;
+    auto index = map_.find(db_type);
 
-#ifdef HAVE_MYSQL
-    if (db_type == "mysql") {
-        LOG_INFO(dhcpsrv_logger, DHCPSRV_MYSQL_HOST_DB)
-            .arg(DatabaseConnection::redactedAccessString(parameters));
-        getHostDataSourcePtr().reset(new MySqlHostDataSource(parameters));
-        return;
+    // No match?
+    if (index == map_.end()) {
+        isc_throw(InvalidType, "Hosts database access parameter 'type': " <<
+                  db_type << " is invalid");
     }
-#endif
 
-#ifdef HAVE_PGSQL
-    if (db_type == "postgresql") {
-        LOG_INFO(dhcpsrv_logger, DHCPSRV_PGSQL_HOST_DB)
-            .arg(DatabaseConnection::redactedAccessString(parameters));
-        getHostDataSourcePtr().reset(new PgSqlHostDataSource(parameters));
-        return;
-    }
-#endif
+    // Call the factory
+    getHostDataSourcePtr().reset(index->second(parameters));
 
-#ifdef HAVE_CQL
-    if (db_type == "cql") {
-        LOG_INFO(dhcpsrv_logger, DHCPSRV_CQL_HOST_DB)
-            .arg(DatabaseConnection::redactedAccessString(parameters));
-        getHostDataSourcePtr().reset(new CqlHostDataSource(parameters));
-        return;
+    // Check the factory did not return NULL.
+    if (!getHostDataSourcePtr()) {
+        isc_throw(Unexpected, "Hosts database " << db_type <<
+                  " factory returned NULL");
     }
-#endif
-
-    // Get here on no match.
-    isc_throw(InvalidType, "Hosts database access parameter 'type': " <<
-                           db_type << " is invalid");
 }
 
 void
@@ -102,17 +89,111 @@ HostDataSourceFactory::destroy() {
     getHostDataSourcePtr().reset();
 }
 
-#if 0
-BaseHostDataSource&
-HostDataSourceFactory::instance() {
-    BaseHostDataSource* hdsptr = getHostDataSourcePtr().get();
-    if (hdsptr == NULL) {
-        isc_throw(NoHostDataSourceManager,
-                "no current host data source instance is available");
+bool
+HostDataSourceFactory::registerFactory(const string& db_type,
+                                       const Factory& factory) {
+    if (map_.count(db_type)) {
+        return (false);
+    }
+    map_.insert(pair<string, Factory>(db_type, factory));
+    return (true);
+}
+
+bool
+HostDataSourceFactory::deregisterFactory(const string& db_type) {
+    auto index = map_.find(db_type);
+    if (index != map_.end()) {
+        map_.erase(index);
+        return (true);
+    } else {
+        return (false);
     }
-    return (*hdsptr);
 }
-#endif
 
 }  // namespace dhcp
 }  // namespace isc
+
+//
+// Register database backends
+//
+
+using namespace isc::dhcp;
+
+namespace {
+
+#ifdef HAVE_MYSQL
+struct MySqlHostDataSourceInit {
+    // Constructor registers
+    MySqlHostDataSourceInit() {
+        HostDataSourceFactory::registerFactory("mysql", factory);
+    }
+
+    // Destructor deregisters
+    ~MySqlHostDataSourceInit() {
+        HostDataSourceFactory::deregisterFactory("mysql");
+    }
+
+    // Factory class method
+    static BaseHostDataSource*
+    factory(const DatabaseConnection::ParameterMap& parameters) {
+        LOG_INFO(dhcpsrv_logger, DHCPSRV_MYSQL_HOST_DB)
+            .arg(DatabaseConnection::redactedAccessString(parameters));
+        return (new MySqlHostDataSource(parameters));
+    }
+};
+
+// Database backend will be registered at object initialization
+MySqlHostDataSourceInit mysql_init;
+#endif
+
+#ifdef HAVE_PGSQL
+struct PgSqlHostDataSourceInit {
+    // Constructor registers
+    PgSqlHostDataSourceInit() {
+        HostDataSourceFactory::registerFactory("postgresql", factory);
+    }
+
+    // Destructor deregisters
+    ~PgSqlHostDataSourceInit() {
+        HostDataSourceFactory::deregisterFactory("postgresql");
+    }
+
+    // Factory class method
+    static BaseHostDataSource*
+    factory(const DatabaseConnection::ParameterMap& parameters) {
+        LOG_INFO(dhcpsrv_logger, DHCPSRV_PGSQL_HOST_DB)
+            .arg(DatabaseConnection::redactedAccessString(parameters));
+        return (new PgSqlHostDataSource(parameters));
+    }
+};
+
+// Database backend will be registered at object initialization
+PgSqlHostDataSourceInit mysql_init;
+#endif
+
+#ifdef HAVE_CQL
+struct CqlHostDataSourceInit {
+    // Constructor registers
+    CqlHostDataSourceInit() {
+        HostDataSourceFactory::registerFactory("cql", factory);
+    }
+
+    // Destructor deregisters
+    ~CqlHostDataSourceInit() {
+        HostDataSourceFactory::deregisterFactory("cql");
+    }
+
+    // Factory class method
+    static BaseHostDataSource*
+    factory(const DatabaseConnection::ParameterMap& parameters) {
+        LOG_INFO(dhcpsrv_logger, DHCPSRV_CQL_HOST_DB)
+            .arg(DatabaseConnection::redactedAccessString(parameters));
+        return (new CqlHostDataSource(parameters));
+    }
+};
+
+// Database backend will be registered at object initialization
+CqlHostDataSourceInit mysql_init;
+#endif
+
+} // end of anonymous namespace
index d7c3123a6b276c98f9d98c46712c94916a9c97ae..68492213dcd8b554137b1d402860267a47f412e1 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2015-2016 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2015-2018 Internet Systems Consortium, Inc. ("ISC")
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
 #include <dhcpsrv/database_connection.h>
 #include <exceptions/exceptions.h>
 #include <boost/scoped_ptr.hpp>
+#include <boost/function.hpp>
 
 #include <string>
+#include <map>
 
 namespace isc {
 namespace dhcp {
@@ -77,6 +79,36 @@ public:
     /// is encapsulated in this method to avoid a "static initialization
     /// fiasco" if defined in an external static variable.
     static HostDataSourcePtr& getHostDataSourcePtr();
+
+    /// @brief Type of host data source factory
+    ///
+    /// A factory takes a parameter map and returns a pointer to a host
+    /// data source. In case of failure it must throw and not return NULL.
+    typedef boost::function<BaseHostDataSource*(const DatabaseConnection::ParameterMap&)> Factory;
+
+    /// @brief Register a host data source factory
+    ///
+    /// Associate the factory to a database type in the map.
+    ///
+    /// @param db_type database type
+    /// @param factory host data source factory
+    /// @return true if the factory was successfully added to the map, false
+    /// if it already exists.
+    static bool registerFactory(const std::string& db_type,
+                                const Factory& factory);
+
+    /// @brief Deregister a host data source factory
+    ///
+    /// Disassociate the factory to a database type in the map.
+    ///
+    /// @param db_type database type
+    /// @return true if the factory was successfully removed from the map,
+    /// false if it was not found.
+    static bool deregisterFactory(const std::string& db_type);
+
+private:
+    /// @brief Factory map
+    static std::map<std::string, Factory> map_;
 };
 
 
index 83a178a0d33a9443fe6caacd4f78643919189851..95c5c4f7530a4dacc26e3c1d749c21d76684076d 100644 (file)
@@ -91,6 +91,7 @@ libdhcpsrv_unittests_SOURCES += dbaccess_parser_unittest.cc
 libdhcpsrv_unittests_SOURCES += dhcp4o6_ipc_unittest.cc
 libdhcpsrv_unittests_SOURCES += duid_config_parser_unittest.cc
 libdhcpsrv_unittests_SOURCES += expiration_config_parser_unittest.cc
+libdhcpsrv_unittests_SOURCES += host_data_source_factory_unittest.cc
 libdhcpsrv_unittests_SOURCES += host_mgr_unittest.cc
 libdhcpsrv_unittests_SOURCES += host_unittest.cc
 libdhcpsrv_unittests_SOURCES += host_reservation_parser_unittest.cc