AM_CXXFLAGS = $(KEA_CXXFLAGS)
lib_LTLIBRARIES = libkea-cc.la
-libkea_cc_la_SOURCES = data.cc data.h
+libkea_cc_la_SOURCES = base_stamped_element.cc base_stamped_element.h
+libkea_cc_la_SOURCES += data.cc data.h
libkea_cc_la_SOURCES += element_value.h
libkea_cc_la_SOURCES += cfg_to_element.h dhcp_config_error.h
libkea_cc_la_SOURCES += command_interpreter.cc command_interpreter.h
# Specify the headers for copying into the installation directory tree.
libkea_cc_includedir = $(pkgincludedir)/cc
libkea_cc_include_HEADERS = \
+ base_stamped_element.h \
cfg_to_element.h \
command_interpreter.h \
data.h \
--- /dev/null
+// Copyright (C) 2019 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
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <cc/base_stamped_element.h>
+
+namespace isc {
+namespace data {
+
+BaseStampedElement::BaseStampedElement()
+ /// @todo Change it to microsec_clock once we transition to subsecond
+ /// precision.
+ : id_(0), timestamp_(boost::posix_time::second_clock::local_time()) {
+}
+
+void
+BaseStampedElement::updateModificationTime() {
+ /// @todo Change it to microsec_clock once we transition to subsecond
+ /// precision.
+ setModificationTime(boost::posix_time::second_clock::local_time());
+}
+
+} // end of namespace isc::data
+} // end of namespace isc
--- /dev/null
+// Copyright (C) 2019 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
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef BASE_STAMPED_ELEMENT_H
+#define BASE_STAMPED_ELEMENT_H
+
+#include <cc/data.h>
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <cstdint>
+
+namespace isc {
+namespace data {
+
+/// @brief This class represents configuration element which is
+/// associated with database identifier and the modification
+/// timestamp.
+///
+/// The @c StampedElement class derives from this class to extend
+/// it with the capability to associate the configuration elements
+/// with server tags. The @c db::Server class derives from it to
+/// store a single server tag identifying a server it describes.
+///
+/// @note This class is not derived from @c Element and should not
+/// be confused with the classes being derived from @c Element class.
+/// Those classes are used to represent JSON structures, whereas this
+/// class represents data fetched from the database.
+class BaseStampedElement {
+public:
+
+ /// @brief Constructor.
+ ///
+ /// Sets timestamp to the current time.
+ BaseStampedElement();
+
+ /// @brief Sets element's database identifier.
+ ///
+ /// @param id New id.
+ void setId(const uint64_t id) {
+ id_ = id;
+ }
+
+ /// @brief Returns element's database identifier.
+ uint64_t getId() const {
+ return (id_);
+ }
+
+ /// @brief Sets timestamp to the explicitly provided value.
+ ///
+ /// @param timestamp New timestamp value.
+ void setModificationTime(const boost::posix_time::ptime& timestamp) {
+ timestamp_ = timestamp;
+ }
+
+ /// @brief Sets timestmp to the current time.
+ void updateModificationTime();
+
+ /// @brief Returns timestamp.
+ boost::posix_time::ptime getModificationTime() const {
+ return (timestamp_);
+ }
+
+protected:
+
+ /// @brief Database identifier of the configuration element.
+ ///
+ /// The default value of 0 indicates that the identifier is
+ /// not set.
+ uint64_t id_;
+
+ /// @brief Holds timestamp value.
+ boost::posix_time::ptime timestamp_;
+};
+
+} // end of namespace isc::data
+} // end of namespace isc
+
+#endif
namespace data {
StampedElement::StampedElement()
- /// @todo Change it to microsec_clock once we transition to subsecond
- /// precision.
- : id_(0), timestamp_(boost::posix_time::second_clock::local_time()),
- server_tag_() {
+ : BaseStampedElement(), server_tags_() {
}
-void
-StampedElement::updateModificationTime() {
- /// @todo Change it to microsec_clock once we transition to subsecond
- /// precision.
- setModificationTime(boost::posix_time::second_clock::local_time());
-}
-
-std::string
-StampedElement:: getServerTag() const {
- return (server_tag_.get());
+bool
+StampedElement::hasServerTag(const ServerTag& server_tag) const {
+ for (auto tag : server_tags_) {
+ if (tag.get() == server_tag.get()) {
+ return (true);
+ }
+ }
+ return (false);
}
bool
-StampedElement::allServers() const {
- return (server_tag_.amAll());
+StampedElement::hasAllServerTag() const {
+ return (hasServerTag(ServerTag(ServerTag::ALL)));
}
+
ElementPtr
StampedElement::getMetadata() const {
ElementPtr metadata = Element::createMap();
- metadata->set("server-tag", Element::create(getServerTag()));
+ ElementPtr tags = Element::createList();
+
+ for (auto server_tag : server_tags_) {
+ tags->add(Element::create(server_tag.get()));
+ }
+
+ metadata->set("server-tags", tags);
return (metadata);
}
#ifndef STAMPED_ELEMENT_H
#define STAMPED_ELEMENT_H
-#include <cc/data.h>
+#include <cc/base_stamped_element.h>
#include <cc/server_tag.h>
-#include <boost/date_time/posix_time/posix_time.hpp>
-#include <boost/scoped_ptr.hpp>
-#include <cstdint>
-#include <string>
+#include <vector>
namespace isc {
namespace data {
/// @brief This class represents configuration element which is
-/// associated with database identifier and the modification
-/// timestamp.
+/// associated with database identifiee, modification timestamp
+/// and servers.
///
/// Classes storing Kea configuration should derive from this object
/// to track ids and modification times of the configuration objects.
/// Those classes are used to represent JSON structures, whereas this
/// class represents data fetched from the database.
///
-/// @todo Find a better name for @c StamepedElement.
-class StampedElement {
+/// @todo Find a better name for @c StampedElement.
+class StampedElement : public BaseStampedElement {
public:
/// @brief Constructor.
/// Sets timestamp to the current time.
StampedElement();
- /// @brief Sets element's database identifier.
- ///
- /// @param id New id.
- void setId(const uint64_t id) {
- id_ = id;
- }
-
- /// @brief Returns element's database identifier.
- uint64_t getId() const {
- return (id_);
- }
-
- /// @brief Sets timestamp to the explicitly provided value.
- ///
- /// @param timestamp New timestamp value.
- void setModificationTime(const boost::posix_time::ptime& timestamp) {
- timestamp_ = timestamp;
- }
-
- /// @brief Sets timestmp to the current time.
- void updateModificationTime();
-
- /// @brief Returns timestamp.
- boost::posix_time::ptime getModificationTime() const {
- return (timestamp_);
- }
-
- /// @brief Sets new server tag.
+ /// @brief Adds new server tag.
///
/// @param server_tag new server tag.
/// @throw BadValue if the server tag length exceeds 256 characters.
void setServerTag(const std::string& server_tag) {
- server_tag_ = ServerTag(server_tag);
+ server_tags_.push_back(ServerTag(server_tag));
}
- /// @brief Returns server tag.
+ /// @brief Returns server tags.
///
/// @return Server tag as string.
- std::string getServerTag() const;
+ std::vector<ServerTag> getServerTags() const {
+ return (server_tags_);
+ }
+
+ /// @brief Checks if the element has the given server tag.
+ ///
+ /// @param server_tag Server tag to be found.
+ /// @return true if the server tag was found, false otherwise.
+ bool hasServerTag(const ServerTag& server_tag) const;
- /// @brief Checks if the stamped element is for all servers.
+ /// @brief Checks if the element has 'all' server tag.
///
- /// @return true if the stamped element is associated with all servers,
- /// false otherwise.
- bool allServers() const;
+ /// @return true if the server tag was found, false otherwise.
+ bool hasAllServerTag() const;
/// @brief Returns an object representing metadata to be returned
/// with objects from the configuration backend.
private:
- /// @brief Database identifier of the configuration element.
- ///
- /// The default value of 0 indicates that the identifier is
- /// not set.
- uint64_t id_;
-
- /// @brief Holds timestamp value.
- boost::posix_time::ptime timestamp_;
-
- /// @brief Holds server tag.
- ServerTag server_tag_;
+ /// @brief Holds server tags.
+ std::vector<ServerTag> server_tags_;
};
} // end of namespace isc::data
boost::multi_index::ordered_non_unique<
boost::multi_index::tag<StampedValueModificationTimeIndexTag>,
boost::multi_index::const_mem_fun<
- StampedElement,
+ BaseStampedElement,
boost::posix_time::ptime,
- &StampedElement::getModificationTime
+ &BaseStampedElement::getModificationTime
>
>
>
// Default identifier is 0.
EXPECT_EQ(0, element.getId());
- // Default server tag is 'all'.
- EXPECT_EQ(ServerTag::ALL, element.getServerTag());
+ // By default there is no server tag.
+ EXPECT_TRUE(element.getServerTags().empty());
// Checking that the delta between now and the timestamp is within
// 5s range should be sufficient.
EXPECT_LT(delta.seconds(), 5);
}
-// Tests that server tag can be overriden by a new value.
-TEST(StampedElementTest, setServerTag) {
+// Tests that one or more server tag can be specified.
+TEST(StampedElementTest, setServerTags) {
StampedElement element;
element.setServerTag("foo");
- EXPECT_EQ("foo", element.getServerTag());
+ EXPECT_EQ(1, element.getServerTags().size());
+ EXPECT_EQ("foo", element.getServerTags()[0].get());
+
+ element.setServerTag("bar");
+ EXPECT_EQ(2, element.getServerTags().size());
+ EXPECT_EQ("foo", element.getServerTags()[0].get());
+ EXPECT_EQ("bar", element.getServerTags()[1].get());
+
+ EXPECT_TRUE(element.hasServerTag(ServerTag("foo")));
+ EXPECT_TRUE(element.hasServerTag(ServerTag("bar")));
+ EXPECT_FALSE(element.hasServerTag(ServerTag("xyz")));
+ EXPECT_FALSE(element.hasAllServerTag());
+
+ element.setServerTag(ServerTag::ALL);
+ EXPECT_TRUE(element.hasAllServerTag());
}
// Test that metadata can be created from the StampedElement.
ASSERT_TRUE(metadata);
ASSERT_EQ(Element::map, metadata->getType());
- auto server_tag_element = metadata->get("server-tag");
+ auto server_tags_element = metadata->get("server-tags");
+ ASSERT_TRUE(server_tags_element);
+ EXPECT_EQ(Element::list, server_tags_element->getType());
+ EXPECT_EQ(1, server_tags_element->size());
+
+ auto server_tag_element = server_tags_element->get(0);
ASSERT_TRUE(server_tag_element);
EXPECT_EQ(Element::string, server_tag_element->getType());
EXPECT_EQ("world", server_tag_element->stringValue());
namespace db {
Server::Server(const ServerTag& tag, const std::string& description)
- : StampedElement(), description_(description) {
+ : BaseStampedElement(), server_tag_(tag), description_(description) {
if (description_.length() > 65536) {
isc_throw(BadValue, "server description must not be longer than"
" 65536 characters");
}
-
- setServerTag(tag.get());
}
ServerPtr
#ifndef DB_SERVER_H
#define DB_SERVER_H
-#include <cc/stamped_element.h>
+#include <cc/base_stamped_element.h>
+#include <cc/server_tag.h>
#include <boost/shared_ptr.hpp>
#include <string>
/// provided by the administrator and the metadata.
///
/// This class extends the base class with the server description field.
-class Server : public data::StampedElement {
+class Server : public data::BaseStampedElement {
public:
/// @brief Constructor.
static ServerPtr create(const data::ServerTag& tag,
const std::string& description = "");
+ /// @brief Returns server tag.
+ data::ServerTag getServerTag() const {
+ return (server_tag_);
+ }
+
+ /// @brief Returns server tag as text.
+ ///
+ /// @return Server tag as text.
+ std::string getServerTagAsText() const {
+ return (server_tag_.get());
+ }
+
/// @brief Returns the description of the server.
///
/// @return Description of the server or an empty string if no
private:
+ /// @brief Server tag.
+ data::ServerTag server_tag_;
+
/// @brief Description of the server.
std::string description_;
};
boost::multi_index::indexed_by<
boost::multi_index::ordered_unique<
boost::multi_index::tag<ServerTagIndexTag>,
- boost::multi_index::const_mem_fun<data::StampedElement, std::string,
- &Server::getServerTag>
+ boost::multi_index::const_mem_fun<Server, std::string,
+ &Server::getServerTagAsText>
>
>
> ServerCollection;
server = Server::create(ServerTag("xyz"), "my first server")
);
ASSERT_TRUE(server);
- EXPECT_EQ("xyz", server->getServerTag());
+ EXPECT_EQ("xyz", server->getServerTagAsText());
EXPECT_EQ("my first server", server->getDescription());
}
auto alpha = ServerFetcher::get(servers, ServerTag("alpha"));
ASSERT_TRUE(alpha);
- EXPECT_EQ("alpha", alpha->getServerTag());
+ EXPECT_EQ("alpha", alpha->getServerTagAsText());
EXPECT_EQ("alpha description", alpha->getDescription());
auto beta = ServerFetcher::get(servers, ServerTag("beta"));
ASSERT_TRUE(beta);
- EXPECT_EQ("beta", beta->getServerTag());
+ EXPECT_EQ("beta", beta->getServerTagAsText());
EXPECT_EQ("beta description", beta->getDescription());
auto gamma = ServerFetcher::get(servers, ServerTag("gamma"));
ASSERT_TRUE(gamma);
- EXPECT_EQ("gamma", gamma->getServerTag());
+ EXPECT_EQ("gamma", gamma->getServerTagAsText());
EXPECT_EQ("gamma description", gamma->getDescription());
// Null pointer should be returned when a given server does not exist.
// Start definition of index #3
boost::multi_index::ordered_non_unique<
// Use option definition modification time as the index key.
- // This value is returned by the StampedElement::getModificationTime
+ // This value is returned by the BaseStampedElement::getModificationTime
boost::multi_index::const_mem_fun<
- data::StampedElement,
+ data::BaseStampedElement,
boost::posix_time::ptime,
&data::StampedElement::getModificationTime
>
// Use StampedElement::getId as a key.
boost::multi_index::hashed_non_unique<
boost::multi_index::tag<OptionIdIndexTag>,
- boost::multi_index::const_mem_fun<data::StampedElement, uint64_t,
- &data::StampedElement::getId>
+ boost::multi_index::const_mem_fun<data::BaseStampedElement, uint64_t,
+ &data::BaseStampedElement::getId>
>
>
> OptionDefContainer;
>
>,
// Start definition of index #3.
- // Use StampedElement::getModificationTime as a key.
+ // Use BaseStampedElement::getModificationTime as a key.
boost::multi_index::ordered_non_unique<
boost::multi_index::const_mem_fun<
- data::StampedElement,
+ data::BaseStampedElement,
boost::posix_time::ptime,
- &data::StampedElement::getModificationTime
+ &data::BaseStampedElement::getModificationTime
>
>,
// Start definition of index #4.
- // Use StampedElement::getId as a key.
+ // Use BaseStampedElement::getId as a key.
boost::multi_index::hashed_non_unique<
boost::multi_index::tag<OptionIdIndexTag>,
- boost::multi_index::const_mem_fun<data::StampedElement, uint64_t,
- &data::StampedElement::getId>
+ boost::multi_index::const_mem_fun<data::BaseStampedElement, uint64_t,
+ &data::BaseStampedElement::getId>
>
>
> OptionContainer;
// Second index allows for access by shared network id.
boost::multi_index::hashed_non_unique<
boost::multi_index::tag<SharedNetworkIdIndexTag>,
- boost::multi_index::const_mem_fun<data::StampedElement, uint64_t,
- &data::StampedElement::getId>
+ boost::multi_index::const_mem_fun<data::BaseStampedElement, uint64_t,
+ &data::BaseStampedElement::getId>
>,
// Third index allows for access by shared network's name.
boost::multi_index::ordered_unique<
// Fifth index allows for searching using subnet modification time.
boost::multi_index::ordered_non_unique<
boost::multi_index::tag<SharedNetworkModificationTimeIndexTag>,
- boost::multi_index::const_mem_fun<data::StampedElement,
+ boost::multi_index::const_mem_fun<data::BaseStampedElement,
boost::posix_time::ptime,
- &data::StampedElement::getModificationTime>
+ &data::BaseStampedElement::getModificationTime>
>
>
> SharedNetwork4Collection;
// Second index allows for access by shared network id.
boost::multi_index::hashed_non_unique<
boost::multi_index::tag<SharedNetworkIdIndexTag>,
- boost::multi_index::const_mem_fun<data::StampedElement, uint64_t,
- &data::StampedElement::getId>
+ boost::multi_index::const_mem_fun<data::BaseStampedElement, uint64_t,
+ &data::BaseStampedElement::getId>
>,
// Third index allows for access by shared network's name.
boost::multi_index::ordered_unique<
// Fourth index allows for searching using subnet modification time.
boost::multi_index::ordered_non_unique<
boost::multi_index::tag<SharedNetworkModificationTimeIndexTag>,
- boost::multi_index::const_mem_fun<data::StampedElement,
+ boost::multi_index::const_mem_fun<data::BaseStampedElement,
boost::posix_time::ptime,
- &data::StampedElement::getModificationTime>
+ &data::BaseStampedElement::getModificationTime>
>
>
> SharedNetwork6Collection;
// Fifth index allows for searching using subnet modification time.
boost::multi_index::ordered_non_unique<
boost::multi_index::tag<SubnetModificationTimeIndexTag>,
- boost::multi_index::const_mem_fun<data::StampedElement,
+ boost::multi_index::const_mem_fun<data::BaseStampedElement,
boost::posix_time::ptime,
- &data::StampedElement::getModificationTime>
+ &data::BaseStampedElement::getModificationTime>
>
>
> Subnet4Collection;
// Fourth index allows for searching using subnet modification time.
boost::multi_index::ordered_non_unique<
boost::multi_index::tag<SubnetModificationTimeIndexTag>,
- boost::multi_index::const_mem_fun<data::StampedElement,
+ boost::multi_index::const_mem_fun<data::BaseStampedElement,
boost::posix_time::ptime,
- &data::StampedElement::getModificationTime>
+ &data::BaseStampedElement::getModificationTime>
>
>
> Subnet6Collection;
void
TestConfigBackendDHCPv4::createUpdateServer4(const db::ServerPtr& server) {
auto& index = servers_.get<ServerTagIndexTag>();
- auto server_it = index.find(server->getServerTag());
+ auto server_it = index.find(server->getServerTagAsText());
if (server_it != index.end()) {
index.replace(server_it, server);
void
TestConfigBackendDHCPv6::createUpdateServer6(const db::ServerPtr& server) {
auto& index = servers_.get<ServerTagIndexTag>();
- auto server_it = index.find(server->getServerTag());
+ auto server_it = index.find(server->getServerTagAsText());
if (server_it != index.end()) {
index.replace(server_it, server);