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