/* * Copyright 2009, 2010 Free Software Foundation, Inc. * Copyright 2010 Kestrel Signal Processing, Inc. * Copyright 2011, 2012 Range Networks, Inc. * * This software is distributed under the terms of the GNU Affero Public License. * See the COPYING file in the main directory for details. * * This use of this software may be subject to additional restrictions. * See the LEGAL file in the main directory for details. This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #ifndef CONFIGURATION_H #define CONFIGURATION_H #include "sqlite3util.h" #include #include #include #include #include #include #include #include #include #include #include #include /** A class for configuration file errors. */ class ConfigurationTableError {}; extern char gCmdName[]; // Gotta be global, gotta be char*, gotta love it. /** An exception thrown when a given config key isn't found. */ class ConfigurationTableKeyNotFound : public ConfigurationTableError { private: std::string mKey; public: ConfigurationTableKeyNotFound(const std::string& wKey) :mKey(wKey) { } const std::string& key() const { return mKey; } }; class ConfigurationRecord { private: std::string mValue; long mNumber; bool mDefined; public: ConfigurationRecord(bool wDefined=true): mDefined(wDefined) { } ConfigurationRecord(const std::string& wValue): mValue(wValue), mNumber(strtol(wValue.c_str(),NULL,0)), mDefined(true) { } ConfigurationRecord(const char* wValue): mValue(std::string(wValue)), mNumber(strtol(wValue,NULL,0)), mDefined(true) { } const std::string& value() const { return mValue; } long number() const { return mNumber; } bool defined() const { return mDefined; } float floatNumber() const; }; /** A string class that uses a hash function for comparison. */ class HashString : public std::string { protected: uint64_t mHash; void computeHash(); public: HashString(const char* src) :std::string(src) { computeHash(); } HashString(const std::string& src) :std::string(src) { computeHash(); } HashString() { mHash=0; } HashString& operator=(std::string& src) { std::string::operator=(src); computeHash(); return *this; } HashString& operator=(const char* src) { std::string::operator=(src); computeHash(); return *this; } bool operator==(const HashString& other) { return mHash==other.mHash; } bool operator<(const HashString& other) { return mHash(const HashString& other) { return mHash ConfigurationRecordMap; typedef std::map ConfigurationMap; class ConfigurationKey; typedef std::map ConfigurationKeyMap; /** A class for maintaining a configuration key-value table, based on sqlite3 and a local map-based cache. Thread-safe, too. */ class ConfigurationTable { private: sqlite3* mDB; ///< database connection ConfigurationMap mCache; ///< cache of recently access configuration values mutable Mutex mLock; ///< control for multithreaded access to the cache std::vector (*mCrossCheck)(const std::string&); ///< cross check callback pointer public: ConfigurationKeyMap mSchema;///< definition of configuration default values and validation logic ConfigurationTable(const char* filename = ":memory:", const char *wCmdName = 0, ConfigurationKeyMap wSchema = ConfigurationKeyMap()); /** Generate an up-to-date example sql file for new installs. */ std::string getDefaultSQL(const std::string& program, const std::string& version); /** Generate an up-to-date TeX snippet. */ std::string getTeX(const std::string& program, const std::string& version); /** Return true if the key is used in the table. */ bool defines(const std::string& key); /** Return true if the application's schema knows about this key. */ bool keyDefinedInSchema(const std::string& name); /** Return true if the provided value validates correctly against the defined schema. */ bool isValidValue(const std::string& name, const std::string& val); /** Return true if the provided value validates correctly against the defined schema. */ bool isValidValue(const std::string& name, const int val) { std::stringstream ss; ss << val; return isValidValue(name, ss.str()); } /** Return a map of all similar keys in the defined schema. */ ConfigurationKeyMap getSimilarKeys(const std::string& snippet); /** Return true if this key is identified as static. */ bool isStatic(const std::string& key); /** Get a string parameter from the table. Throw ConfigurationTableKeyNotFound if not found. */ std::string getStr(const std::string& key); /** Get a boolean from the table. Return false if NULL or 0, true otherwise. */ bool getBool(const std::string& key); /** Get a numeric parameter from the table. Throw ConfigurationTableKeyNotFound if not found. */ long getNum(const std::string& key); /** Get a vector of strings from the table. */ std::vector getVectorOfStrings(const std::string& key); /** Get a float from the table. Throw ConfigurationTableKeyNotFound if not found. */ float getFloat(const std::string& key); /** Get a numeric vector from the table. */ std::vector getVector(const std::string& key); /** Get length of a vector */ unsigned getVectorLength(const std::string &key) { return getVector(key).size(); } /** Set or change a value in the table. */ bool set(const std::string& key, const std::string& value); /** Set or change a value in the table. */ bool set(const std::string& key, long value); /** Create an entry in the table, no value though. */ bool set(const std::string& key); /** Remove an entry from the table. Will not alter required values. @param key The key of the item to be removed. @return true if anything was actually removed. */ bool remove(const std::string& key); /** Search the table, dumping to a stream. */ void find(const std::string& pattern, std::ostream&) const; /** Return all key/value pairs stored in the ConfigurationTable */ ConfigurationRecordMap getAllPairs() const; /** Define the callback to purge the cache whenever the database changes. */ void setUpdateHook(void(*)(void *,int ,char const *,char const *,sqlite3_int64)); /** Define the callback for cross checking. */ void setCrossCheckHook(std::vector (*wCrossCheck)(const std::string&)); /** Execute the application specific value cross checking logic. */ std::vector crossCheck(const std::string& key); /** purege cache if it exceeds a certain age */ void checkCacheAge(); /** Delete all records from the cache. */ void purge(); private: /** Attempt to lookup a record, cache if needed. Throw ConfigurationTableKeyNotFound if not found. Caller should hold mLock because the returned reference points into the cache. */ const ConfigurationRecord& lookup(const std::string& key); }; typedef std::map HashStringMap; class SimpleKeyValue { protected: HashStringMap mMap; public: /** Take a C string "A=B" and set map["A"]="B". */ void addItem(const char*); /** Take a C string "A=B C=D E=F ..." and add all of the pairs to the map. */ void addItems(const char*s); /** Return a reference to the string at map["key"]. */ const char* get(const char*) const; }; class ConfigurationKey { public: enum VisibilityLevel { CUSTOMER, CUSTOMERSITE, CUSTOMERTUNE, CUSTOMERWARN, DEVELOPER, FACTORY }; enum Type { BOOLEAN, CHOICE_OPT, CHOICE, CIDR_OPT, CIDR, FILEPATH_OPT, FILEPATH, IPADDRESS_OPT, IPADDRESS, IPANDPORT, MIPADDRESS_OPT, MIPADDRESS, PORT_OPT, PORT, REGEX_OPT, REGEX, STRING_OPT, STRING, VALRANGE }; private: std::string mName; std::string mDefaultValue; std::string mUnits; VisibilityLevel mVisibility; Type mType; std::string mValidValues; bool mIsStatic; std::string mDescription; public: ConfigurationKey(const std::string& wName, const std::string& wDefaultValue, const std::string& wUnits, const VisibilityLevel wVisibility, const Type wType, const std::string& wValidValues, bool wIsStatic, const std::string& wDescription): mName(wName), mDefaultValue(wDefaultValue), mUnits(wUnits), mVisibility(wVisibility), mType(wType), mValidValues(wValidValues), mIsStatic(wIsStatic), mDescription(wDescription) { } ConfigurationKey() { } const std::string& getName() const { return mName; } const std::string& getDefaultValue() const { return mDefaultValue; } void updateDefaultValue(const std::string& newValue) { mDefaultValue = newValue; } void updateDefaultValue(const int newValue) { std::stringstream ss; ss << newValue; updateDefaultValue(ss.str()); } const std::string& getUnits() const { return mUnits; } const VisibilityLevel& getVisibility() const { return mVisibility; } const Type& getType() const { return mType; } const std::string& getValidValues() const { return mValidValues; } bool isStatic() const { return mIsStatic; } const std::string& getDescription() const { return mDescription; } static bool isValidIP(const std::string& ip); static void getMinMaxStepping(const ConfigurationKey &key, std::string &min, std::string &max, std::string &stepping); template static bool isInValRange(const ConfigurationKey &key, const std::string& val, const bool isInteger); static const std::string visibilityLevelToString(const VisibilityLevel& visibility); static const std::string typeToString(const ConfigurationKey::Type& type); static void printKey(const ConfigurationKey &key, const std::string& currentValue, std::ostream& os); static void printDescription(const ConfigurationKey &key, std::ostream& os); static const std::string getARFCNsString(); }; #endif // vim: ts=4 sw=4