-// 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
namespace isc {
namespace dhcp {
+map<string, HostDataSourceFactory::Factory> HostDataSourceFactory::map_;
+
HostDataSourcePtr&
HostDataSourceFactory::getHostDataSourcePtr() {
static HostDataSourcePtr hostDataSourcePtr;
}
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);
"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
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
-// 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 {
/// 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_;
};