Streamline configuration.h
[ep-engine.git] / src / configuration.h
1 /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3  *     Copyright 2011 Couchbase, Inc
4  *
5  *   Licensed under the Apache License, Version 2.0 (the "License");
6  *   you may not use this file except in compliance with the License.
7  *   You may obtain a copy of the License at
8  *
9  *       http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *   Unless required by applicable law or agreed to in writing, software
12  *   distributed under the License is distributed on an "AS IS" BASIS,
13  *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *   See the License for the specific language governing permissions and
15  *   limitations under the License.
16  */
17 #ifndef SRC_CONFIGURATION_H_
18 #define SRC_CONFIGURATION_H_ 1
19
20 #include "config.h"
21
22 #include <memcached/engine.h>
23
24 #include <iostream>
25 #include <map>
26 #include <mutex>
27 #include <string>
28
29 #include "utility.h"
30
31 /**
32  * The value changed listeners runs _without_ the global mutex for
33  * the configuration class, so you may access other configuration
34  * members from the callback.
35  * The callback is fired <b>after</b> the value is set, so if you
36  * want to prevent the caller from setting specific values you should
37  * use the ValueChangedValidator instead.
38  */
39 class ValueChangedListener {
40 public:
41     void valueChanged(const std::string& key, bool value) {
42         booleanValueChanged(key, value);
43     }
44
45     void valueChanged(const std::string& key, size_t value) {
46         sizeValueChanged(key, value);
47     }
48
49     void valueChanged(const std::string& key, ssize_t value) {
50         ssizeValueChanged(key, value);
51     }
52
53     void valueChanged(const std::string& key, float value) {
54         floatValueChanged(key, value);
55     }
56
57     void valueChanged(const std::string& key, std::string value) {
58         stringValueChanged(key, value.c_str());
59     }
60
61     void valueChanged(const std::string& key, const char* value) {
62         stringValueChanged(key, value);
63     }
64
65     /**
66      * Callback if when a boolean configuration value changed
67      * @param key the key who changed
68      * @param value the new value for the key
69      */
70     virtual void booleanValueChanged(const std::string &key, bool) {
71         LOG(EXTENSION_LOG_DEBUG, "Configuration error.. %s does not expect"
72             " a boolean value", key.c_str());
73     }
74
75     /**
76      * Callback if when a numeric configuration value changed
77      * @param key the key who changed
78      * @param value the new value for the key
79      */
80     virtual void sizeValueChanged(const std::string &key, size_t) {
81         LOG(EXTENSION_LOG_DEBUG, "Configuration error.. %s does not expect"
82             " a size value", key.c_str());
83     }
84
85     /**
86      * Callback if when a numeric configuration value changed
87      * @param key the key who changed
88      * @param value the new value for the key
89      */
90     virtual void ssizeValueChanged(const std::string &key, ssize_t) {
91         LOG(EXTENSION_LOG_DEBUG, "Configuration error.. %s does not expect"
92             " a size value", key.c_str());
93     }
94
95     /**
96      * Callback if when a floatingpoint configuration value changed
97      * @param key the key who changed
98      * @param value the new value for the key
99      */
100     virtual void floatValueChanged(const std::string &key, float) {
101         LOG(EXTENSION_LOG_DEBUG, "Configuration error.. %s does not expect"
102             " a floating point value", key.c_str());
103     }
104     /**
105      * Callback if when a string configuration value changed
106      * @param key the key who changed
107      * @param value the new value for the key
108      */
109     virtual void stringValueChanged(const std::string &key, const char *) {
110         LOG(EXTENSION_LOG_DEBUG, "Configuration error.. %s does not expect"
111             " a string value", key.c_str());
112     }
113
114     virtual ~ValueChangedListener() { /* EMPTY */}
115 };
116
117 /**
118  * The validator for the values runs with the mutex held
119  * for the configuration class, so you can't try to access
120  * any other configuration variables from the callback
121  */
122 class ValueChangedValidator {
123 public:
124     void validate(const std::string& key, bool value) {
125         validateBool(key, value);
126     }
127
128     void validate(const std::string& key, size_t value) {
129         validateSize(key, value);
130     }
131
132     void validate(const std::string& key, ssize_t value) {
133         validateSSize(key, value);
134     }
135
136     void validate(const std::string& key, float value) {
137         validateFloat(key, value);
138     }
139
140     void validate(const std::string& key, const char* value) {
141         validateString(key, value);
142     }
143     void validate(const std::string& key, std::string value) {
144         validateString(key, value.c_str());
145     }
146
147     /**
148      * Validator for boolean values
149      * @param key the key that is about to change
150      * @param value the requested new value
151      * @throws runtime_error if the validation failed
152      */
153     virtual void validateBool(const std::string& key, bool) {
154         std::string error = "Configuration error.. " + key +
155                             " does not take a boolean parameter";
156         LOG(EXTENSION_LOG_DEBUG, "%s", error.c_str());
157         throw std::runtime_error(error);
158     }
159
160     /**
161      * Validator for a numeric value
162      * @param key the key that is about to change
163      * @param value the requested new value
164      * @throws runtime_error if the validation failed
165      */
166     virtual void validateSize(const std::string& key, size_t) {
167         std::string error = "Configuration error.. " + key +
168                             " does not take a size_t parameter";
169         LOG(EXTENSION_LOG_DEBUG, "%s", error.c_str());
170         throw std::runtime_error(error);
171     }
172
173     /**
174      * Validator for a signed numeric value
175      * @param key the key that is about to change
176      * @param value the requested new value
177      * @throws runtime_error if the validation failed
178      */
179     virtual void validateSSize(const std::string& key, ssize_t) {
180         std::string error = "Configuration error.. " + key +
181                             " does not take a ssize_t parameter";
182         LOG(EXTENSION_LOG_DEBUG, "%s", error.c_str());
183         throw std::runtime_error(error);
184     }
185
186     /**
187      * Validator for a floating point
188      * @param key the key that is about to change
189      * @param value the requested new value
190      * @throws runtime_error if the validation failed
191      */
192     virtual void validateFloat(const std::string& key, float) {
193         std::string error = "Configuration error.. " + key +
194                             " does not take a float parameter";
195         LOG(EXTENSION_LOG_DEBUG, "%s", error.c_str());
196         throw std::runtime_error(error);
197     }
198
199     /**
200      * Validator for a character string
201      * @param key the key that is about to change
202      * @param value the requested new value
203      * @throws runtime_error if the validation failed
204      */
205     virtual void validateString(const std::string& key, const char*) {
206         std::string error = "Configuration error.. " + key +
207                             " does not take a string parameter";
208         LOG(EXTENSION_LOG_DEBUG, "%s", error.c_str());
209         throw std::runtime_error(error);
210     }
211
212     virtual ~ValueChangedValidator() { }
213 };
214
215 class Requirement;
216
217 /**
218  * The configuration class represents and provides access to the
219  * entire configuration of the server.
220  */
221 class Configuration {
222 public:
223     struct value_t;
224
225     Configuration();
226     ~Configuration();
227
228     // Include the generated prototypes for the member functions
229 #include "generated_configuration.h" // NOLINT(*)
230
231     /**
232      * Parse a configuration string and set the local members
233      *
234      * @param str the string to parse
235      * @param sapi pointer to the server API
236      * @return true if success, false otherwise
237      */
238     bool parseConfiguration(const char *str, SERVER_HANDLE_V1* sapi);
239
240     /**
241      * Add all of the configuration variables as stats
242      * @param add_stat the callback to add statistics
243      * @param c the cookie for the connection who wants the stats
244      */
245     void addStats(ADD_STAT add_stat, const void *c) const;
246
247     /**
248      * Add a listener for changes for a key. The configuration class
249      * will release the memory for the ValueChangedListener by calling
250      * delete in it's destructor (so you have to allocate it by using
251      * new). There is no way to remove a ValueChangeListener.
252      *
253      * @param key the key to add the listener for
254      * @param val the listener that will receive all of the callbacks
255      *            when the value change.
256      */
257     void addValueChangedListener(const std::string &key,
258                                  ValueChangedListener *val);
259
260     /**
261      * Set a validator for a specific key. The configuration class
262      * will release the memory for the ValueChangedValidator by calling
263      * delete in its destructor (so you have to allocate it by using
264      * new). If a validator exists for the key, that will be returned
265      * (and it's up to the caller to release the memory for that
266      * validator).
267      *
268      * @param key the key to set the validator for
269      * @param validator the new validator
270      * @return the old validator (or NULL if there wasn't a validator)
271      */
272     ValueChangedValidator *setValueValidator(const std::string &key,
273                                              ValueChangedValidator *validator);
274     /**
275      * Adds an alias for a configuration. Values can be set in configuration
276      * under the original or aliased named, but setters/getters will only be
277      * generated for the main name.
278      *
279      * @param key the key to which the alias refers
280      * @param alias the new alias
281      */
282     void addAlias(const std::string& key, const std::string& alias);
283
284     /**
285      * Adds a prerequisite to a configuration option. This must be satisfied
286      * in order to set/get the config value or for it to appear in stats.
287      *
288      * @param key the key to set the requirement for
289      * @param requirement the requirement
290      */
291     Requirement* setRequirements(const std::string& key,
292                                  Requirement* requirement);
293
294     bool requirementsMet(const value_t& value) const;
295
296     void requirementsMetOrThrow(const std::string& key) const;
297
298 protected:
299     /**
300      * Set the configuration parameter for a given key to
301      * a new value (size_t, ssize_t, float, bool, string)
302      * @param key the key to specify
303      * @param value the new value
304      * @throws runtime_error if the validation failed
305      */
306     template <class T>
307     void setParameter(const std::string& key, T value);
308
309     /**
310      * Get the configuration parameter for a given key
311      * @param key the key to specify
312      * @return value the value
313      * @throws runtime_error if the validation failed
314      */
315     template <class T>
316     T getParameter(const std::string& key) const;
317
318 private:
319     void initialize();
320
321     // Access to the configuration variables is protected by the mutex
322     mutable std::mutex mutex;
323     std::map<std::string, std::shared_ptr<value_t>> attributes;
324
325     friend std::ostream& operator<< (std::ostream& out,
326                                      const Configuration &config);
327 };
328
329 // This specialisation is needed to convert char* to std::string to store in
330 // the variant.
331 template <>
332 void Configuration::setParameter<const char*>(const std::string& key,
333                                               const char* value);
334
335 #endif  // SRC_CONFIGURATION_H_