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 <algorithm>
25#include <iostream>
26#include <limits>
27#include <map>
28#include <set>
29#include <string>
30#include <vector>
31
32#include "locks.h"
33
34/**
35 * The value changed listeners runs _without_ the global mutex for
36 * the configuration class, so you may access other configuration
37 * members from the callback.
38 * The callback is fired <b>after</b> the value is set, so if you
39 * want to prevent the caller from setting specific values you should
40 * use the ValueChangedValidator instead.
41 */
42class ValueChangedListener {
43public:
44    /**
45     * Callback if when a boolean configuration value changed
46     * @param key the key who changed
47     * @param value the new value for the key
48     */
49    virtual void booleanValueChanged(const std::string &key, bool) {
50        LOG(EXTENSION_LOG_DEBUG, "Configuration error.. %s does not expect"
51            " a boolean value", key.c_str());
52    }
53
54    /**
55     * Callback if when a numeric configuration value changed
56     * @param key the key who changed
57     * @param value the new value for the key
58     */
59    virtual void sizeValueChanged(const std::string &key, size_t) {
60        LOG(EXTENSION_LOG_DEBUG, "Configuration error.. %s does not expect"
61            " a size value", key.c_str());
62    }
63
64    /**
65     * Callback if when a numeric configuration value changed
66     * @param key the key who changed
67     * @param value the new value for the key
68     */
69    virtual void ssizeValueChanged(const std::string &key, ssize_t) {
70        LOG(EXTENSION_LOG_DEBUG, "Configuration error.. %s does not expect"
71            " a size value", key.c_str());
72    }
73
74    /**
75     * Callback if when a floatingpoint configuration value changed
76     * @param key the key who changed
77     * @param value the new value for the key
78     */
79    virtual void floatValueChanged(const std::string &key, float) {
80        LOG(EXTENSION_LOG_DEBUG, "Configuration error.. %s does not expect"
81            " a floating point value", key.c_str());
82    }
83    /**
84     * Callback if when a string configuration value changed
85     * @param key the key who changed
86     * @param value the new value for the key
87     */
88    virtual void stringValueChanged(const std::string &key, const char *) {
89        LOG(EXTENSION_LOG_DEBUG, "Configuration error.. %s does not expect"
90            " a string value", key.c_str());
91    }
92
93    virtual ~ValueChangedListener() { /* EMPTY */}
94};
95
96/**
97 * The validator for the values runs with the mutex held
98 * for the configuration class, so you can't try to access
99 * any other configuration variables from the callback
100 */
101class ValueChangedValidator {
102public:
103    /**
104     * Validator for boolean values
105     * @param key the key that is about to change
106     * @param value the requested new value
107     * @return true the value is ok, false the value is not ok
108     */
109    virtual bool validateBool(const std::string &key, bool) {
110        LOG(EXTENSION_LOG_DEBUG, "Configuration error.. %s does not take"
111            " a boolean parameter", key.c_str());
112        return false;
113    }
114
115    /**
116     * Validator for a numeric value
117     * @param key the key that is about to change
118     * @param value the requested new value
119     * @return true the value is ok, false the value is not ok
120     */
121    virtual bool validateSize(const std::string &key, size_t) {
122        LOG(EXTENSION_LOG_DEBUG, "Configuration error.. %s does not take"
123            " a size_t parameter", key.c_str());
124        return false;
125    }
126
127    /**
128     * Validator for a signed numeric value
129     * @param key the key that is about to change
130     * @param value the requested new value
131     * @return true the value is ok, false the value is not ok
132     */
133    virtual bool validateSSize(const std::string &key, ssize_t) {
134        LOG(EXTENSION_LOG_DEBUG, "Configuration error.. %s does not take"
135            " a ssize_t parameter", key.c_str());
136        return false;
137    }
138
139    /**
140     * Validator for a floating point
141     * @param key the key that is about to change
142     * @param value the requested new value
143     * @return true the value is ok, false the value is not ok
144     */
145    virtual bool validateFloat(const std::string &key, float) {
146        LOG(EXTENSION_LOG_DEBUG, "Configuration error.. %s does not take"
147            " a floating point parameter", key.c_str());
148        return false;
149    }
150
151    /**
152     * Validator for a character string
153     * @param key the key that is about to change
154     * @param value the requested new value
155     * @return true the value is ok, false the value is not ok
156     */
157    virtual bool validateString(const std::string &key, const char *) {
158        LOG(EXTENSION_LOG_DEBUG, "Configuration error.. %s does not take"
159            " a character string", key.c_str());
160        return false;
161    }
162
163    virtual ~ValueChangedValidator() { }
164};
165
166/**
167 * A configuration input validator that ensures a numeric (size_t)
168 * value falls between a specified upper and lower limit.
169 */
170class SizeRangeValidator : public ValueChangedValidator {
171public:
172    SizeRangeValidator() : lower(0), upper(0) {}
173
174    SizeRangeValidator *min(size_t v) {
175        lower = v;
176        return this;
177    }
178
179    SizeRangeValidator *max(size_t v) {
180        upper = v;
181        return this;
182    }
183
184    virtual bool validateSize(const std::string &key, size_t value) {
185        (void)key;
186        return (value >= lower && value <= upper);
187    }
188
189    virtual bool validateSSize(const std::string &key, ssize_t value) {
190        (void)key;
191        ssize_t s_lower = static_cast<ssize_t> (lower);
192        ssize_t s_upper = static_cast<ssize_t> (upper);
193        return (value >= s_lower && value <= s_upper);
194    }
195private:
196    size_t lower;
197    size_t upper;
198};
199
200/**
201 * A configuration input validator that ensures that a numeric (float)
202 * value falls between a specified upper and lower limit.
203 */
204class FloatRangeValidator : public ValueChangedValidator {
205public:
206    FloatRangeValidator() : lower(0), upper(0) {}
207
208    FloatRangeValidator *min(float v) {
209        lower = v;
210        return this;
211    }
212
213    FloatRangeValidator *max(float v) {
214        upper = v;
215        return this;
216    }
217
218    virtual bool validateFloat(const std::string &key, float value) {
219        (void)key;
220        return (value >= lower && value <= upper);
221    }
222private:
223    float lower;
224    float upper;
225};
226
227/**
228 * A configuration input validator that ensures that a value is one
229 * from a predefined set of acceptable values.
230 */
231class EnumValidator : public ValueChangedValidator {
232public:
233    EnumValidator() {}
234
235    EnumValidator *add(const char *s) {
236        acceptable.insert(std::string(s));
237        return this;
238    }
239
240    virtual bool validateString(const std::string &key, const char *value) {
241        (void)key;
242        return acceptable.find(std::string(value)) != acceptable.end();
243    }
244
245private:
246    std::set<std::string> acceptable;
247};
248
249/**
250 * The configuration class represents and provides access to the
251 * entire configuration of the server.
252 */
253class Configuration {
254public:
255    Configuration();
256    ~Configuration();
257
258    // Include the generated prototypes for the member functions
259#include "generated_configuration.h" // NOLINT(*)
260
261    /**
262     * Parse a configuration string and set the local members
263     *
264     * @param str the string to parse
265     * @param sapi pointer to the server API
266     * @return true if success, false otherwise
267     */
268    bool parseConfiguration(const char *str, SERVER_HANDLE_V1* sapi);
269
270    /**
271     * Add all of the configuration variables as stats
272     * @param add_stat the callback to add statistics
273     * @param c the cookie for the connection who wants the stats
274     */
275    void addStats(ADD_STAT add_stat, const void *c) const;
276
277    /**
278     * Add a listener for changes for a key. The configuration class
279     * will release the memory for the ValueChangedListner by calling
280     * delete in it's destructor (so you have to allocate it by using
281     * new). There is no way to remove a valueChangeListner.
282     *
283     * @param key the key to add the listener for
284     * @param val the listener that will receive all of the callbacks
285     *            when the value change.
286     */
287    void addValueChangedListener(const std::string &key,
288                                 ValueChangedListener *val);
289
290    /**
291     * Set a validator for a specific key. The configuration class
292     * will release the memory for the ValueChangedValidator by calling
293     * delete in its destructor (so you have to allocate it by using
294     * new). If a validator exists for the key, that will be returned
295     * (and it's up to the caller to release the memory for that
296     * validator).
297     *
298     * @param key the key to set the validator for
299     * @param validator the new validator
300     * @return the old validator (or NULL if there wasn't a validator)
301     */
302    ValueChangedValidator *setValueValidator(const std::string &key,
303                                             ValueChangedValidator *validator);
304
305protected:
306    /**
307     * Set the configuration parameter for a given key to
308     * a boolean value.
309     * @param key the key to specify
310     * @param value the new value
311     * @throws std::string if the value is refused by the validator
312     */
313    void setParameter(const std::string &key, bool value);
314    /**
315     * Set the configuration parameter for a given key to
316     * a size_t value.
317     * @param key the key to specify
318     * @param value the new value
319     * @throws std::string if the value is refused by the validator
320     */
321    void setParameter(const std::string &key, size_t value);
322    /**
323     * Set the configuration parameter for a given key to
324     * a ssize_t value.
325     * @param key the key to specify
326     * @param value the new value
327     * @throws std::string if the value is refused by the validator
328     */
329    void setParameter(const std::string &key, ssize_t value);
330    /**
331     * Set the configuration parameter for a given key to
332     * a floating value.
333     * @param key the key to specify
334     * @param value the new value
335     * @throws std::string if the value is refused by the validator
336     */
337    void setParameter(const std::string &key, float value);
338    /**
339     * Set the configuration parameter for a given key to
340     * a character string
341     * @param key the key to specify
342     * @param value the new value
343     * @throws std::string if the value is refused by the validator
344     */
345    void setParameter(const std::string &key, const char *value);
346    /**
347     * Set the configuration parameter for a given key to
348     * a string.
349     * @param key the key to specify
350     * @param value the new value
351     * @throws std::string if the value is refused by the validator
352     */
353    void setParameter(const std::string &key, const std::string &value);
354
355private:
356    void initialize();
357    std::string getString(const std::string &key) const;
358    bool getBool(const std::string &key) const;
359    float getFloat(const std::string &key) const;
360    size_t getInteger(const std::string &key) const;
361    ssize_t getSignedInteger(const std::string &key) const;
362
363    struct value_t {
364        value_t() : validator(NULL) { val.v_string = 0; }
365        std::vector<ValueChangedListener *> changeListener;
366        ValueChangedValidator *validator;
367        config_datatype datatype;
368        union {
369            size_t v_size;
370            ssize_t v_ssize;
371            float v_float;
372            bool v_bool;
373            const char *v_string;
374        } val;
375    };
376
377    // Access to the configuration variables is protected by the mutex
378    Mutex mutex;
379    std::map<std::string, value_t> attributes;
380
381    friend std::ostream& operator<< (std::ostream& out,
382                                     const Configuration &config);
383};
384
385#endif  // SRC_CONFIGURATION_H_
386