client_list.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  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 <dns/rrclass.h>
  18. #include <cc/data.h>
  19. #include <exceptions/exceptions.h>
  20. #include <vector>
  21. #include <boost/shared_ptr.hpp>
  22. #include <boost/noncopyable.hpp>
  23. namespace isc {
  24. namespace datasrc {
  25. class ZoneFinder;
  26. typedef boost::shared_ptr<ZoneFinder> ZoneFinderPtr;
  27. class DataSourceClient;
  28. typedef boost::shared_ptr<DataSourceClient> DataSourceClientPtr;
  29. class DataSourceClientContainer;
  30. typedef boost::shared_ptr<DataSourceClientContainer>
  31. DataSourceClientContainerPtr;
  32. class InMemoryClient;
  33. /// \brief The list of data source clients.
  34. ///
  35. /// The purpose of this class is to hold several data source clients and search
  36. /// through them to find one containing a zone best matching a request.
  37. ///
  38. /// All the data source clients should be for the same class. If you need
  39. /// to handle multiple classes, you need to create multiple separate lists.
  40. ///
  41. /// This is an abstract base class. It is not expected we would use multiple
  42. /// implementation inside the servers (but it is not forbidden either), we
  43. /// have it to allow easy testing. It is possible to create a mock-up class
  44. /// instead of creating a full-blown configuration. The real implementation
  45. /// is the ConfigurableClientList.
  46. class ClientList : public boost::noncopyable {
  47. protected:
  48. /// \brief Constructor.
  49. ///
  50. /// It is protected to prevent accidental creation of the abstract base
  51. /// class.
  52. ClientList() {}
  53. public:
  54. /// \brief Virtual destructor
  55. virtual ~ClientList() {}
  56. /// \brief Structure holding the (compound) result of find.
  57. ///
  58. /// As this is read-only structure, we don't bother to create accessors.
  59. /// Instead, all the member variables are defined as const and can be
  60. /// accessed directly.
  61. struct FindResult {
  62. /// \brief Internal class for holding a reference.
  63. ///
  64. /// This is used to make sure the data source client isn't released
  65. /// too soon.
  66. ///
  67. /// \see life_keeper_;
  68. class LifeKeeper {
  69. public:
  70. virtual ~LifeKeeper() {};
  71. };
  72. /// \brief Constructor.
  73. ///
  74. /// It simply fills in the member variables according to the
  75. /// parameters. See the member descriptions for their meaning.
  76. FindResult(DataSourceClient* dsrc_client, const ZoneFinderPtr& finder,
  77. bool exact_match,
  78. const boost::shared_ptr<LifeKeeper>& life_keeper) :
  79. dsrc_client_(dsrc_client),
  80. finder_(finder),
  81. exact_match_(exact_match),
  82. life_keeper_(life_keeper)
  83. {}
  84. /// \brief Negative answer constructor.
  85. ///
  86. /// This conscructs a result for negative answer. Both pointers are
  87. /// NULL, and exact_match_ is false.
  88. FindResult() :
  89. dsrc_client_(NULL),
  90. exact_match_(false)
  91. {}
  92. /// \brief Comparison operator.
  93. ///
  94. /// It is needed for tests and it might be of some use elsewhere
  95. /// too.
  96. bool operator ==(const FindResult& other) const {
  97. return (dsrc_client_ == other.dsrc_client_ &&
  98. finder_ == other.finder_ &&
  99. exact_match_ == other.exact_match_);
  100. }
  101. /// \brief The found data source client.
  102. ///
  103. /// The client of the data source containing the best matching zone.
  104. /// If no such data source exists, this is NULL pointer.
  105. ///
  106. /// Note that the pointer is valid only as long the ClientList which
  107. /// returned the pointer is alive and was not reconfigured or you hold
  108. /// a reference to life_keeper_. The ownership is preserved within the
  109. /// ClientList.
  110. DataSourceClient* const dsrc_client_;
  111. /// \brief The finder for the requested zone.
  112. ///
  113. /// This is the finder corresponding to the best matching zone.
  114. /// This may be NULL even in case the datasrc_ is something
  115. /// else, depending on the find options.
  116. ///
  117. /// \see find
  118. const ZoneFinderPtr finder_;
  119. /// \brief If the result is an exact match.
  120. const bool exact_match_;
  121. /// \brief Something that holds the dsrc_client_ valid.
  122. ///
  123. /// As long as you hold the life_keeper_, the dsrc_client_ is
  124. /// guaranteed to be valid.
  125. const boost::shared_ptr<LifeKeeper> life_keeper_;
  126. };
  127. /// \brief Search for a zone through the data sources.
  128. ///
  129. /// This searches the contained data source clients for a one that best
  130. /// matches the zone name.
  131. ///
  132. /// There are two expected usage scenarios. One is answering queries. In
  133. /// this case, the zone finder is needed and the best matching superzone
  134. /// of the searched name is needed. Therefore, the call would look like:
  135. ///
  136. /// \code FindResult result(list->find(queried_name));
  137. /// FindResult result(list->find(queried_name));
  138. /// if (result.datasrc_) {
  139. /// createTheAnswer(result.finder_);
  140. /// } else {
  141. /// createNotAuthAnswer();
  142. /// } \endcode
  143. ///
  144. /// The other scenario is manipulating zone data (XfrOut, XfrIn, DDNS,
  145. /// ...). In this case, the finder itself is not so important. However,
  146. /// we need an exact match (if we want to manipulate zone data, we must
  147. /// know exactly, which zone we are about to manipulate). Then the call
  148. ///
  149. /// \code FindResult result(list->find(zone_name, true, false));
  150. /// FindResult result(list->find(zone_name, true, false));
  151. /// if (result.datasrc_) {
  152. /// ZoneUpdaterPtr updater(result.datasrc_->getUpdater(zone_name);
  153. /// ...
  154. /// } \endcode
  155. ///
  156. /// \param zone The name of the zone to look for.
  157. /// \param want_exact_match If it is true, it returns only exact matches.
  158. /// If the best possible match is partial, a negative result is
  159. /// returned instead. It is possible the caller could check it and
  160. /// act accordingly if the result would be partial match, but with this
  161. /// set to true, the find might be actually faster under some
  162. /// circumstances.
  163. /// \param want_finder If this is false, the finder_ member of FindResult
  164. /// might be NULL even if the corresponding data source is found. This
  165. /// is because of performance, in some cases the finder is a side
  166. /// result of the searching algorithm (therefore asking for it again
  167. /// would be a waste), but under other circumstances it is not, so
  168. /// providing it when it is not needed would also be wasteful.
  169. ///
  170. /// Other things are never the side effect of searching, therefore the
  171. /// caller can get them explicitly (the updater, journal reader and
  172. /// iterator).
  173. /// \return A FindResult describing the data source and zone with the
  174. /// longest match against the zone parameter.
  175. virtual FindResult find(const dns::Name& zone,
  176. bool want_exact_match = false,
  177. bool want_finder = true) const = 0;
  178. };
  179. /// \brief Shared pointer to the list.
  180. typedef boost::shared_ptr<ClientList> ClientListPtr;
  181. /// \brief Shared const pointer to the list.
  182. typedef boost::shared_ptr<const ClientList> ConstClientListPtr;
  183. /// \Concrete implementation of the ClientList, which is constructed based on
  184. /// configuration.
  185. ///
  186. /// This is the implementation which is expected to be used in the servers.
  187. /// However, it is expected most of the code will use it as the ClientList,
  188. /// only the creation is expected to be direct.
  189. ///
  190. /// While it is possible to inherit this class, it is not expected to be
  191. /// inherited except for tests.
  192. class ConfigurableClientList : public ClientList {
  193. public:
  194. /// \brief Constructor
  195. ///
  196. /// \param rrclass For which class the list should work.
  197. ConfigurableClientList(const isc::dns::RRClass &rrclass) :
  198. rrclass_(rrclass)
  199. {}
  200. /// \brief Exception thrown when there's an error in configuration.
  201. class ConfigurationError : public Exception {
  202. public:
  203. ConfigurationError(const char* file, size_t line, const char* what) :
  204. Exception(file, line, what)
  205. {}
  206. };
  207. /// \brief Sets the configuration.
  208. ///
  209. /// This fills the ClientList with data source clients corresponding to the
  210. /// configuration. The data source clients are newly created or recycled
  211. /// from previous configuration.
  212. ///
  213. /// If any error is detected, an exception is thrown and the current
  214. /// configuration is preserved.
  215. ///
  216. /// \param configuration The JSON element describing the configuration to
  217. /// use.
  218. /// \param allow_cache If it is true, the 'cache' option of the
  219. /// configuration is used and some zones are cached into an In-Memory
  220. /// data source according to it. If it is false, it is ignored and
  221. /// no In-Memory data sources are created.
  222. /// \throw DataSourceError if there's a problem creating a data source
  223. /// client.
  224. /// \throw ConfigurationError if the configuration is invalid in some
  225. /// sense.
  226. /// \throw Unexpected if something misbehaves (like the data source
  227. /// returning NULL iterator).
  228. /// \throw NotImplemented if the auto-detection of list of zones is
  229. /// needed.
  230. /// \throw Whatever is propagated from within the data source.
  231. void configure(const data::Element& configuration, bool allow_cache);
  232. /// \brief Implementation of the ClientList::find.
  233. virtual FindResult find(const dns::Name& zone,
  234. bool want_exact_match = false,
  235. bool want_finder = true) const;
  236. /// \brief This holds one data source client and corresponding information.
  237. ///
  238. /// \todo The content yet to be defined.
  239. struct DataSourceInfo {
  240. // Plays a role of default constructor too (for vector)
  241. DataSourceInfo(bool has_cache = false);
  242. DataSourceInfo(DataSourceClient* data_src_client,
  243. const DataSourceClientContainerPtr& container,
  244. bool has_cache);
  245. DataSourceClient* data_src_client_;
  246. DataSourceClientContainerPtr container_;
  247. boost::shared_ptr<InMemoryClient> cache_;
  248. };
  249. /// \brief The collection of data sources.
  250. typedef std::vector<DataSourceInfo> DataSources;
  251. protected:
  252. /// \brief The data sources held here.
  253. ///
  254. /// All our data sources are stored here. It is protected to let the
  255. /// tests in. You should consider it private if you ever want to
  256. /// derive this class (which is not really recommended anyway).
  257. DataSources data_sources_;
  258. /// \brief Convenience type alias.
  259. ///
  260. /// \see getDataSource
  261. typedef std::pair<DataSourceClient*, DataSourceClientContainerPtr>
  262. DataSourcePair;
  263. /// \brief Create a data source client of given type and configuration.
  264. ///
  265. /// This is a thin wrapper around the DataSourceClientContainer
  266. /// constructor. The function is here to make it possible for tests
  267. /// to replace the DataSourceClientContainer with something else.
  268. /// Also, derived classes could want to create the data source clients
  269. /// in a different way, though inheriting this class is not recommended.
  270. ///
  271. /// The parameters are the same as of the constructor.
  272. /// \return Pair containing both the data source client and the container.
  273. /// The container might be NULL in the derived class, it is
  274. /// only stored so the data source client is properly destroyed when
  275. /// not needed. However, in such case, it is the caller's
  276. /// responsibility to ensure the data source client is deleted when
  277. /// needed.
  278. virtual DataSourcePair getDataSourceClient(const std::string& type,
  279. const data::ConstElementPtr&
  280. configuration);
  281. public:
  282. /// \brief Access to the data source clients.
  283. ///
  284. /// It can be used to examine the loaded list of data sources clients
  285. /// directly. It is not known if it is of any use other than testing, but
  286. /// it might be, so it is just made public (there's no real reason to
  287. /// hide it).
  288. const DataSources& getDataSources() const { return (data_sources_); }
  289. private:
  290. const isc::dns::RRClass rrclass_;
  291. };
  292. } // namespace datasrc
  293. } // namespace isc
  294. #endif // DATASRC_CONTAINER_H