factory.h 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. // Copyright (C) 2011 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 DATA_SOURCE_FACTORY_H
  15. #define DATA_SOURCE_FACTORY_H 1
  16. #include <datasrc/exceptions.h>
  17. #include <datasrc/client.h>
  18. #include <cc/data.h>
  19. #include <boost/noncopyable.hpp>
  20. #include <boost/shared_ptr.hpp>
  21. namespace isc {
  22. namespace datasrc {
  23. /// \brief Raised if there is an error in the datasource implementation
  24. /// library
  25. class DataSourceLibraryError : public DataSourceError {
  26. public:
  27. DataSourceLibraryError(const char* file, size_t line, const char* what) :
  28. DataSourceError(file, line, what) {}
  29. };
  30. /// \brief Raised if there is an error opening the the datasource
  31. /// implementation library
  32. class DataSourceLibraryOpenError : public DataSourceLibraryError {
  33. public:
  34. DataSourceLibraryOpenError(const char* file, size_t line,
  35. const char* what) :
  36. DataSourceLibraryError(file, line, what) {}
  37. };
  38. /// \brief Raised if there is an error reading a symbol from the datasource
  39. /// implementation library
  40. class DataSourceLibrarySymbolError : public DataSourceLibraryError {
  41. public:
  42. DataSourceLibrarySymbolError(const char* file, size_t line,
  43. const char* what) :
  44. DataSourceLibraryError(file, line, what) {}
  45. };
  46. typedef DataSourceClient* ds_creator(isc::data::ConstElementPtr config,
  47. std::string& error);
  48. typedef void ds_destructor(DataSourceClient* instance);
  49. /// \brief Container class for dynamically loaded libraries
  50. ///
  51. /// This class is used to dlopen() a library, provides access to dlsym(),
  52. /// and cleans up the dlopened library when the instance of this class is
  53. /// destroyed.
  54. ///
  55. /// Its main function is to provide RAII-style access to dlopen'ed libraries.
  56. ///
  57. /// \note Currently it is Datasource-backend specific. If we have need for this
  58. /// in other places than for dynamically loading datasources, then, apart
  59. /// from moving it to another location, we also need to make the
  60. /// exceptions raised more general.
  61. class LibraryContainer : boost::noncopyable {
  62. public:
  63. /// \brief Constructor
  64. ///
  65. /// \param name The name of the library (.so) file. This file must be in
  66. /// the library path.
  67. ///
  68. /// \exception DataSourceLibraryError If the library cannot be found or
  69. /// cannot be loaded, or if name is an empty string.
  70. LibraryContainer(const std::string& name);
  71. /// \brief Destructor
  72. ///
  73. /// Cleans up the library by calling dlclose()
  74. ~LibraryContainer();
  75. /// \brief Retrieve a symbol
  76. ///
  77. /// This retrieves a symbol from the loaded library.
  78. ///
  79. /// \exception DataSourceLibrarySymbolError if the symbol cannot be found,
  80. /// or if another error (as reported by dlerror() occurs.
  81. ///
  82. /// \param name The name of the symbol to retrieve
  83. /// \return A pointer to the symbol. This may be NULL, and if so, indicates
  84. /// the symbol does indeed exist, but has the value NULL itself.
  85. /// If the symbol does not exist, a DataSourceLibrarySymbolError is
  86. /// raised.
  87. ///
  88. /// \note The argument is a const char* (and not a std::string like the
  89. /// argument in the constructor). This argument is always a fixed
  90. /// string in the code, while the other can be read from
  91. /// configuration, and needs modification
  92. void* getSym(const char* name);
  93. private:
  94. /// Pointer to the dynamically loaded library structure
  95. void *ds_lib_;
  96. };
  97. /// \brief Container for a specific instance of a dynamically loaded
  98. /// DataSourceClient implementation
  99. ///
  100. /// Given a datasource type and a type-specific set of configuration data,
  101. /// the corresponding dynamic library is loaded (if it hadn't been already),
  102. /// and an instance is created. This instance is stored within this structure,
  103. /// and can be accessed through getInstance(). Upon destruction of this
  104. /// container, the stored instance of the DataSourceClient is deleted with
  105. /// the destructor function provided by the loaded library.
  106. ///
  107. /// The 'type' is actually the name of the library, minus the '_ds.so' postfix
  108. /// Datasource implementation libraries therefore have a fixed name, both for
  109. /// easy recognition and to reduce potential mistakes.
  110. /// For example, the sqlite3 implementation has the type 'sqlite3', and the
  111. /// derived filename 'sqlite3_ds.so'
  112. /// The value of type can be a specific loadable library; if it already ends
  113. /// with '.so', the loader will not add '_ds.so'.
  114. /// It may also be an absolute path; if it starts with '/', nothing is
  115. /// prepended. If it does not, the loadable library will be taken from the
  116. /// installation directory, see the value of
  117. /// isc::datasrc::BACKEND_LIBRARY_PATH in datasrc_config.h for the exact path.
  118. ///
  119. /// \note When 'B10_FROM_BUILD' is set in the environment, the build
  120. /// directory is used instead of the install directory.
  121. ///
  122. /// There are of course some demands to an implementation, not all of which
  123. /// can be verified compile-time. It must provide a creator and destructor
  124. /// functions. The creator function must return an instance of a subclass of
  125. /// DataSourceClient. The prototypes of these functions are as follows:
  126. /// \code
  127. /// extern "C" DataSourceClient* createInstance(isc::data::ConstElementPtr cfg);
  128. ///
  129. /// extern "C" void destroyInstance(isc::data::DataSourceClient* instance);
  130. /// \endcode
  131. ///
  132. /// \note This class is relatively recent, and its design is not yet fully
  133. /// formed. We may want to split this into an abstract base container
  134. /// class, and a derived 'dyload' class, and perhaps then add non-dynamic
  135. /// derived classes as well. Currently, the class is actually derived in some
  136. /// of the tests, which is rather unclean (as this class as written is really
  137. /// intended to be used directly).
  138. class DataSourceClientContainer : boost::noncopyable {
  139. public:
  140. /// \brief Constructor
  141. ///
  142. /// \exception DataSourceLibraryError if there is an error loading the
  143. /// backend library
  144. /// \exception DataSourceLibrarySymbolError if the library does not have
  145. /// the needed symbols, or if there is an error reading them
  146. /// \exception DataError if the given config is not correct
  147. /// for the given type, or if there was a problem during
  148. /// initialization
  149. ///
  150. /// \param type The type of the datasource client. Based on the value of
  151. /// type, a specific backend library is used, by appending the
  152. /// string '_ds.so' to the given type, and loading that as the
  153. /// implementation library
  154. /// \param config Type-specific configuration data, see the documentation
  155. /// of the datasource backend type for information on what
  156. /// configuration data to pass.
  157. DataSourceClientContainer(const std::string& type,
  158. isc::data::ConstElementPtr config);
  159. /// \brief Destructor
  160. virtual ~DataSourceClientContainer();
  161. /// \brief Accessor to the instance
  162. ///
  163. /// \return Reference to the DataSourceClient instance contained in this
  164. /// container.
  165. virtual DataSourceClient& getInstance() { return (*instance_); }
  166. private:
  167. DataSourceClient* instance_;
  168. ds_destructor* destructor_;
  169. LibraryContainer ds_lib_;
  170. };
  171. ///
  172. /// Shared pointer type for datasource client containers
  173. ///
  174. typedef boost::shared_ptr<DataSourceClientContainer>
  175. DataSourceClientContainerPtr;
  176. } // end namespace datasrc
  177. } // end namespace isc
  178. #endif // DATA_SOURCE_FACTORY_H
  179. // Local Variables:
  180. // mode: c++
  181. // End: