container.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. // Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #ifndef DATASRC_CONTAINER_H
  15. #define DATASRC_CONTAINER_H
  16. #include <dns/name.h>
  17. #include <cc/data.h>
  18. #include <exceptions/exceptions.h>
  19. #include <vector>
  20. #include <boost/shared_ptr.hpp>
  21. #include <boost/noncopyable.hpp>
  22. namespace isc {
  23. namespace datasrc {
  24. class ZoneFinder;
  25. typedef boost::shared_ptr<ZoneFinder> ZoneFinderPtr;
  26. class DataSourceClient;
  27. typedef boost::shared_ptr<DataSourceClient> DataSourceClientPtr;
  28. class DataSourceClientContainer;
  29. typedef boost::shared_ptr<DataSourceClientContainer>
  30. DataSourceClientContainerPtr;
  31. /// \brief The container of data sources.
  32. ///
  33. /// The purpose of this class is to hold several data sources and search
  34. /// through them to find one containing a zone best matching a request.
  35. ///
  36. /// All the data source clients should be for the same class. If you need
  37. /// to handle multiple classes, you need to create multiple separate containers.
  38. ///
  39. /// This is an abstract base class. It is not expected we would use multiple
  40. /// implementation inside the servers (but it is not forbidden either), we
  41. /// have it to allow easy testing. It is possible to create a mock-up class
  42. /// instead of creating a full-blown configuration. The real implementation
  43. /// is the ConfigurableContainer.
  44. class Container : public boost::noncopyable {
  45. protected:
  46. /// \brief Constructor.
  47. ///
  48. /// It is protected to prevent accidental creation of the abstract base
  49. /// class.
  50. Container() {}
  51. public:
  52. /// \brief Structure holding the (compound) result of find.
  53. ///
  54. /// As this is read-only structure, we don't bother to create accessors.
  55. /// Instead, all the member variables are defined as const and can be
  56. /// accessed directly.
  57. struct FindResult {
  58. /// \brief Constructor.
  59. ///
  60. /// It simply fills in the member variables according to the
  61. /// parameters. See the member descriptions for their meaning.
  62. FindResult(DataSourceClient* datasrc,
  63. const ZoneFinderPtr& finder,
  64. uint8_t matched_labels, bool exact_match) :
  65. datasrc_(datasrc),
  66. finder_(finder),
  67. matched_labels_(matched_labels),
  68. exact_match_(exact_match)
  69. { }
  70. /// \brief Negative answer constructor.
  71. ///
  72. /// This conscructs a result for negative answer. Both pointers are
  73. /// NULL, matched_labels_ is 0 and exact_match_ is false.
  74. FindResult() :
  75. datasrc_(NULL),
  76. matched_labels_(0),
  77. exact_match_(false)
  78. { }
  79. /// \brief Comparison operator.
  80. ///
  81. /// It is needed for tests and it might be of some use elsewhere
  82. /// too.
  83. bool operator ==(const FindResult& other) const {
  84. return (datasrc_ == other.datasrc_ &&
  85. finder_ == other.finder_ &&
  86. matched_labels_ == other.matched_labels_ &&
  87. exact_match_ == other.exact_match_);
  88. }
  89. /// \brief The found data source.
  90. ///
  91. /// The data source containing the best matching zone. If no such
  92. /// data source exists, this is NULL pointer.
  93. ///
  94. /// Note that the pointer is valid only as long the Container which
  95. /// returned is alive and was not reconfigured. The ownership is
  96. /// preserved within the Container.
  97. DataSourceClient* const datasrc_;
  98. /// \brief The finder for the requested zone.
  99. ///
  100. /// This is the finder corresponding to the best matching zone.
  101. /// This may be NULL even in case the datasrc_ is something
  102. /// else, depending on the find options.
  103. ///
  104. /// \see find
  105. const ZoneFinderPtr finder_;
  106. /// \brief Number of matching labels.
  107. ///
  108. /// The number of labels the result have in common with the queried
  109. /// name of zone.
  110. const uint8_t matched_labels_;
  111. /// \brief If the result is an exact match.
  112. const bool exact_match_;
  113. };
  114. /// \brief Search for a zone through the data sources.
  115. ///
  116. /// This searches the contained data sources for a one that best matches
  117. /// the zone name.
  118. ///
  119. /// There are two expected usage scenarios. One is answering queries. In
  120. /// this case, the zone finder is needed and the best matching superzone
  121. /// of the searched name is needed. Therefore, the call would look like:
  122. ///
  123. /// FindResult result(container->find(queried_name));
  124. /// if (result.datasrc_) {
  125. /// createTheAnswer(result.finder_);
  126. /// } else {
  127. /// createNotAuthAnswer();
  128. /// }
  129. ///
  130. /// The other scenario is manipulating zone data (XfrOut, XfrIn, DDNS,
  131. /// ...). In this case, the finder itself is not so important. However,
  132. /// we need an exact match (if we want to manipulate zone data, we must
  133. /// know exactly, which zone we are about to manipulate). Then the call
  134. ///
  135. /// FindResult result(container->find(zone_name, true, false));
  136. /// if (result.datasrc_) {
  137. /// ZoneUpdaterPtr updater(result.datasrc_->getUpdater(zone_name);
  138. /// ...
  139. /// }
  140. ///
  141. /// \param zone The name of the zone to look for.
  142. /// \param want_exact_match If it is true, it returns only exact matches.
  143. /// If the best possible match is partial, a negative result is
  144. /// returned instead. It is possible the caller could check it and
  145. /// act accordingly if the result would be partial match, but with this
  146. /// set to true, the find might be actually faster under some
  147. /// circumstances.
  148. /// \param want_finder If this is false, the finder_ member of FindResult
  149. /// might be NULL even if the corresponding data source is found. This
  150. /// is because of performance, in some cases the finder is a side
  151. /// result of the searching algorithm (therefore asking for it again
  152. /// would be a waste), but under other circumstances it is not, so
  153. /// providing it when it is not needed would also be wasteful.
  154. ///
  155. /// Other things are never the side effect of searching, therefore the
  156. /// caller can get them explicitly (the updater, journal reader and
  157. /// iterator).
  158. /// \return A FindResult describing the data source and zone with the
  159. /// longest match against the zone parameter.
  160. virtual FindResult find(const dns::Name& zone,
  161. bool want_exact_match = false,
  162. bool want_finder = true) const = 0;
  163. };
  164. /// \brief Shared pointer to the container.
  165. typedef boost::shared_ptr<Container> ContainerPtr;
  166. /// \brief Shared const pointer to the container.
  167. typedef boost::shared_ptr<const Container> ConstContainerPtr;
  168. /// \Concrete implementation of the Container, which is constructed based on
  169. /// configuration.
  170. ///
  171. /// This is the implementation which is expected to be used in the servers.
  172. /// However, it is expected most of the code will use it as the Container,
  173. /// only the creation is expected to be direct.
  174. ///
  175. /// While it is possible to inherit this class, it is not expected to be
  176. /// inherited except for tests.
  177. class ConfigurableContainer : public Container {
  178. public:
  179. /// \brief Exception thrown when there's an error in configuration.
  180. class ConfigurationError : public Exception {
  181. public:
  182. ConfigurationError(const char* file, size_t line, const char* what) :
  183. Exception(file, line, what)
  184. { }
  185. };
  186. /// \brief Sets the configuration.
  187. ///
  188. /// This fills the Container with data sources corresponding to the
  189. /// configuration. The data sources are newly created or recycled from
  190. /// previous configuration.
  191. ///
  192. /// If any error is detected, an exception is thrown and the current
  193. /// configuration is preserved.
  194. ///
  195. /// \param configuration The JSON element describing the configuration to
  196. /// use.
  197. /// \param allow_cache If it is true, the 'cache' option of the
  198. /// configuration is used and some zones are cached into an In-Memory
  199. /// data source according to it. If it is false, it is ignored and
  200. /// no In-Memory data sources are created.
  201. /// \throw DataSourceError if there's a problem creating a data source.
  202. /// \throw ConfigurationError if the configuration is invalid in some
  203. /// sense.
  204. void configure(const data::Element& configuration, bool allow_cache);
  205. /// \brief Implementation of the Container::find.
  206. virtual FindResult find(const dns::Name& zone,
  207. bool want_exact_match = false,
  208. bool want_finder = true) const;
  209. /// \brief This holds one data source and corresponding information.
  210. ///
  211. /// \todo The content yet to be defined.
  212. struct DataSourceInfo {
  213. /// \brief Default constructor.
  214. ///
  215. /// Don't use directly. It is here so the structure can live in
  216. /// a vector.
  217. DataSourceInfo() :
  218. data_src_(NULL)
  219. {}
  220. DataSourceInfo(DataSourceClient* data_src,
  221. const DataSourceClientContainerPtr& container) :
  222. data_src_(data_src),
  223. container_(container)
  224. { }
  225. DataSourceClient* data_src_;
  226. DataSourceClientContainerPtr container_;
  227. };
  228. /// \brief The collection of data sources.
  229. typedef std::vector<DataSourceInfo> DataSources;
  230. protected:
  231. /// \brief The data sources held here.
  232. ///
  233. /// All our data sources are stored here. It is protected to let the
  234. /// tests in. You should consider it private if you ever want to
  235. /// derive this class (which is not really recommended anyway).
  236. DataSources data_sources_;
  237. /// \brief Convenience type alias.
  238. ///
  239. /// \see getDataSource
  240. typedef std::pair<DataSourceClient*, DataSourceClientContainerPtr>
  241. DataSourcePair;
  242. /// \brief Create a data source of given type and configuration.
  243. ///
  244. /// This is a thin wrapper around the DataSourceClientContainer
  245. /// constructor. The function is here to make it possible for tests
  246. /// to replace the DataSourceClientContainer with something else.
  247. /// Also, derived classes couldl want to create the data sources
  248. /// in a different way, though inheriting this class is not
  249. /// recommended.
  250. ///
  251. /// The parameters are the same as of the constructor.
  252. /// \return Pair containing both the data source and the container.
  253. /// The container might be NULL in the derived class, it is
  254. /// only stored so the data source is properly destroyed when
  255. /// not needed. However, in such case, it is the caller's
  256. /// responsibility to ensure the data source is deleted when
  257. /// needed.
  258. virtual DataSourcePair getDataSource(const std::string& type,
  259. const data::ConstElementPtr&
  260. configuration);
  261. public:
  262. /// \brief Access to the data sources.
  263. ///
  264. /// It can be used to examine the loaded list of data sources directly.
  265. /// It is not known if it is of any use other than testing, but it might
  266. /// be, so it is just made public.
  267. const DataSources& getDataSources() const { return (data_sources_); }
  268. };
  269. } // namespace datasrc
  270. } // namespace isc
  271. #endif // DATASRC_CONTAINER_H