platform/include/pion/platform/ConfigManager.hpp

00001 // ------------------------------------------------------------------------
00002 // Pion is a development platform for building Reactors that process Events
00003 // ------------------------------------------------------------------------
00004 // Copyright (C) 2007-2008 Atomic Labs, Inc.  (http://www.atomiclabs.com)
00005 //
00006 // Pion is free software: you can redistribute it and/or modify it under the
00007 // terms of the GNU Affero General Public License as published by the Free
00008 // Software Foundation, either version 3 of the License, or (at your option)
00009 // any later version.
00010 //
00011 // Pion is distributed in the hope that it will be useful, but WITHOUT ANY
00012 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00013 // FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for
00014 // more details.
00015 //
00016 // You should have received a copy of the GNU Affero General Public License
00017 // along with Pion.  If not, see <http://www.gnu.org/licenses/>.
00018 //
00019 
00020 #ifndef __PION_CONFIGMANAGER_HEADER__
00021 #define __PION_CONFIGMANAGER_HEADER__
00022 
00023 #include <string>
00024 #include <libxml/tree.h>
00025 #include <boost/noncopyable.hpp>
00026 #include <boost/lexical_cast.hpp>
00027 #include <pion/PionConfig.hpp>
00028 #include <pion/PionException.hpp>
00029 #include <pion/PionLogger.hpp>
00030 #include <pion/PionId.hpp>
00031 
00032 
00033 namespace pion {        // begin namespace pion
00034 namespace platform {    // begin namespace platform (Pion Platform Library)
00035 
00036 
00040 class PION_PLATFORM_API ConfigManager
00041     : public boost::noncopyable
00042 {
00043 public:
00044 
00046     class ConfigNotOpenException : public PionException {
00047     public:
00048         ConfigNotOpenException(const std::string& config_file)
00049             : PionException("Configuration file must be opened before making changes: ", config_file) {}
00050     };
00051     
00053     class ConfigAlreadyOpenException : public PionException {
00054     public:
00055         ConfigAlreadyOpenException(const std::string& file_name)
00056             : PionException("Configuration file is already open: ", file_name) {}
00057     };
00058 
00060     class ConfigFileExistsException : public PionException {
00061     public:
00062         ConfigFileExistsException(const std::string& file_name)
00063             : PionException("Configuration file already exists: ", file_name) {}
00064     };
00065     
00067     class MissingConfigFileException : public PionException {
00068     public:
00069         MissingConfigFileException(const std::string& file_name)
00070             : PionException("Unable to find configuration file: ", file_name) {}
00071     };
00072 
00074     class MissingRootElementException : public PionException {
00075     public:
00076         MissingRootElementException(const std::string& config_file)
00077         : PionException("Configuration file is missing the root config element: ", config_file) {}
00078 
00079         MissingRootElementException(const char* buffer)
00080         : PionException("Root config element not found in buffer: ", buffer) {}
00081     };
00082 
00084     class MissingResourceElementException : public PionException {
00085     public:
00086         MissingResourceElementException(const std::string& resource_name)
00087         : PionException("Could not find element for specified resource: ", resource_name) {}
00088     };
00089 
00091     class InitializeRootConfigException : public PionException {
00092     public:
00093         InitializeRootConfigException(const std::string& file_name)
00094             : PionException("Unable to initialize configuration file: ", file_name) {}
00095     };
00096 
00098     class ConfigFileVersionException : public PionException {
00099     public:
00100         ConfigFileVersionException(const std::string& file_name)
00101             : PionException("Incompatible configuration file (run pupgrade.py): ", file_name) {}
00102     };
00103 
00105     class WriteConfigException : public PionException {
00106     public:
00107         WriteConfigException(const std::string& file_name)
00108             : PionException("Unable to write config to file: ", file_name) {}
00109     };
00110 
00112     class UpdateConfigException : public PionException {
00113     public:
00114         UpdateConfigException(const std::string& element_name)
00115             : PionException("Unable to update configuration.  Element name: ", element_name) {}
00116     };
00117 
00119     class ReadConfigException : public PionException {
00120     public:
00121         ReadConfigException(const std::string& config_file)
00122         : PionException("Unable to read config file: ", config_file) {}
00123     };
00124 
00126     class BadXMLBufferException : public PionException {
00127     public:
00128         BadXMLBufferException(void)
00129         : PionException("NULL buffer pointer or buffer length is zero") {}
00130     };
00131 
00133     class XMLBufferParsingException : public PionException {
00134     public:
00135         XMLBufferParsingException(const char* buffer)
00136         : PionException("Unable to parse buffer: ", buffer) {}
00137     };
00138 
00140     class AddPluginConfigException : public PionException {
00141     public:
00142         AddPluginConfigException(const std::string& plugin_type)
00143             : PionException("Unable to add a plug-in to the configuration file: ", plugin_type) {}
00144     };
00145     
00147     class UpdatePluginConfigException : public PionException {
00148     public:
00149         UpdatePluginConfigException(const std::string& plugin_id)
00150             : PionException("Unable to update a plug-in in the configuration file: ", plugin_id) {}
00151     };
00152     
00154     class RemovePluginConfigException : public PionException {
00155     public:
00156         RemovePluginConfigException(const std::string& plugin_id)
00157             : PionException("Unable to remove a plug-in from the configuration file: ", plugin_id) {}
00158     };
00159     
00161     class EmptyPluginIdException : public PionException {
00162     public:
00163         EmptyPluginIdException(const std::string& config_file)
00164         : PionException("Configuration file includes a plug-in with an empty identifier: ", config_file) {}
00165     };
00166     
00168     class EmptyPluginElementException : public PionException {
00169     public:
00170         EmptyPluginElementException(const std::string& plugin_id)
00171             : PionException("Plug-in configuration does not contain a \"plugin\" element: ", plugin_id) {}
00172     };
00173     
00174     
00176     virtual ~ConfigManager() { closeConfigFile(); }
00177     
00179     virtual void createConfigFile(void);
00180     
00182     virtual void openConfigFile(void);
00183 
00184     static xmlDocPtr getConfigFromFile(const std::string& config_file, const std::string& root_element_name, xmlNodePtr& config_ptr, PionLogger& logger);
00185 
00187     inline void setConfigFile(const std::string& config_file) {
00188         m_config_file = config_file;
00189         resetDataDirectory();
00190     }
00191     
00193     inline const std::string& getConfigFile(void) const { return m_config_file; }
00194 
00196     inline bool configIsOpen(void) const { return m_config_doc_ptr != NULL; }
00197     
00199     inline void setLogger(PionLogger log_ptr) { m_logger = log_ptr; }
00200     
00202     inline PionLogger getLogger(void) { return m_logger; }
00203     
00205     inline void setDataDirectory(const std::string& dir) { m_data_directory = dir; }
00206 
00208     inline const std::string& getDataDirectory(void) const { return m_data_directory; }
00209 
00211     inline void resetDataDirectory(void) {
00212         m_data_directory = resolveRelativePath(m_config_file, "./");
00213     }
00214 
00216     inline void setDebugMode(bool b) { m_debug_mode = b; }
00217 
00219     inline bool getDebugMode(void) const { return m_debug_mode; }
00220 
00222     void removeConfigFile(void);
00223     
00229     virtual void writeConfigXML(std::ostream& out) const {
00230         writeConfigXML(out, m_config_node_ptr, true);
00231     }
00232     
00240     static void writeConfigXML(std::ostream& out,
00241                                xmlNodePtr config_node,
00242                                bool include_siblings = false);
00243     
00249     static void writeConfigXMLHeader(std::ostream& out);
00250     
00256     static void writeBeginPionConfigXML(std::ostream& out);
00257     
00263     static void writeEndPionConfigXML(std::ostream& out);
00264     
00270     static void writeBeginPionStatsXML(std::ostream& out);
00271     
00277     static void writeEndPionStatsXML(std::ostream& out);
00278     
00280     static std::string xml_encode(const std::string& str);
00281     
00283     inline std::string createUUID(void) { return m_id_gen().to_string(); }
00284 
00286     std::string createFilename(void);
00287 
00295     std::string createFilename(const std::string& file_path);
00296     
00304     static xmlNodePtr createPluginConfig(const std::string& plugin_type);
00305     
00315     static xmlNodePtr createResourceConfig(const std::string& resource_name,
00316                                            const char *buf, std::size_t len);
00317     
00326     static bool getNodeId(xmlNodePtr config_node, std::string& node_id);
00327     
00337     static xmlNodePtr findConfigNodeByName(const std::string& element_name,
00338                                            xmlNodePtr starting_node);
00339     
00351     static xmlNodePtr findConfigNodeByContent(const std::string& element_name,
00352                                               const std::string& content_value,
00353                                               xmlNodePtr starting_node);
00354     
00367     static xmlNodePtr findConfigNodeByAttr(const std::string& element_name,
00368                                            const std::string& attr_name,
00369                                            const std::string& attr_value,
00370                                            xmlNodePtr starting_node);
00371     
00383     static bool getConfigOption(const std::string& option_name,
00384                                 std::string& option_value,
00385                                 const xmlNodePtr starting_node);
00386 
00387 
00400     static bool getConfigOptionEmptyOk(const std::string& option_name,
00401                                 std::string& option_value,
00402                                 const xmlNodePtr starting_node);
00403 
00411     static std::string getAttribute(const char *name, const xmlNodePtr ptr);
00412 
00420     static std::string getAttribute(const std::string& name, const xmlNodePtr ptr)
00421     {
00422         return getAttribute(name.c_str(), ptr);
00423     }
00424 
00436     template <typename ValueType>
00437     static bool getConfigOption(const std::string& option_name,
00438                                 ValueType& option_value,
00439                                 const xmlNodePtr starting_node)
00440     {
00441         std::string value_str;
00442         if (getConfigOption(option_name, value_str, starting_node)) {
00443             option_value = boost::lexical_cast<ValueType>(value_str);
00444             return true;
00445         }
00446         return false;
00447     }
00448 
00461     template <typename ValueType>
00462     static bool getConfigOption(const std::string& option_name,
00463                                 ValueType& option_value,
00464                                 const ValueType& default_value,
00465                                 const xmlNodePtr starting_node)
00466     {
00467         if (getConfigOption(option_name, option_value, starting_node))
00468             return true;
00469         option_value = default_value;
00470         return false;
00471     }
00472     
00484     static bool updateConfigOption(const std::string& option_name,
00485                                    const std::string& option_value,
00486                                    xmlNodePtr parent_node);
00487 
00496     static std::string resolveRelativePath(const std::string& base_path_to_file,
00497                                            const std::string& orig_path);
00498     
00506     inline std::string resolveRelativePath(const std::string& orig_path) const {
00507         return resolveRelativePath(getConfigFile(), orig_path);
00508     }
00509 
00517     std::string resolveRelativeDataPath(const std::string& orig_path);
00518 
00528     virtual bool creationAllowed(xmlNodePtr permission_config_ptr, xmlNodePtr config_ptr) const {
00529         // By default, permission is granted solely based on whether a Permission node of the appropriate type was found.
00530         return permission_config_ptr != NULL;
00531     }
00532 
00543     virtual bool updateAllowed(xmlNodePtr permission_config_ptr, const std::string& id, xmlNodePtr config_ptr) const {
00544         // By default, permission is granted solely based on whether a Permission node of the appropriate type was found.
00545         return permission_config_ptr != NULL;
00546     }
00547 
00556     virtual bool removalAllowed(xmlNodePtr permission_config_ptr, const std::string& id) const {
00557         // By default, permission is granted solely based on whether a Permission node of the appropriate type was found.
00558         return permission_config_ptr != NULL;
00559     }
00560 
00569     virtual bool accessAllowed(xmlNodePtr permission_config_ptr, const std::string& plugin_id) const {
00570         // By default, permission is granted solely based on whether a Permission node of the appropriate type was found.
00571         return permission_config_ptr != NULL;
00572     }
00573 
00575     virtual std::string getPermissionType(void) const { 
00576         // Returning an empty string means that UserManager::getPermissionNode() will always return NULL.
00577         // So, if this method is not overridden for a particular ConfigManager, then permission for that
00578         // ConfigManager will only be granted if the User has "Admin" permission.
00579         return "";
00580     }
00581 
00582 
00583 protected:
00584     
00590     ConfigManager(const std::string& default_config_file)
00591         : m_logger(PION_GET_LOGGER("pion.platform.ConfigManager")),
00592         m_config_file(default_config_file), m_debug_mode(false),
00593         m_config_doc_ptr(NULL), m_config_node_ptr(NULL)
00594     {
00595         resetDataDirectory();
00596     }
00597     
00599     void closeConfigFile(void);
00600     
00602     void saveConfigFile(void);
00603     
00605     void backupConfigFile(void);
00606     
00613     void openPluginConfig(const std::string& plugin_name);
00614     
00623     bool setPluginConfig(xmlNodePtr plugin_node_ptr, xmlNodePtr config_ptr);
00624     
00633     void setPluginConfig(const std::string& plugin_name,
00634                          const std::string& plugin_id,
00635                          const xmlNodePtr config_ptr);
00636     
00647     void addPluginConfig(const std::string& plugin_name,
00648                          const std::string& plugin_id,
00649                          const std::string& plugin_type,
00650                          const xmlNodePtr config_ptr = NULL);
00651         
00658     void removePluginConfig(const std::string& plugin_name,
00659                             const std::string& plugin_id);
00660 
00672     virtual void addPluginNoLock(const std::string& plugin_id,
00673                                  const std::string& plugin_name,
00674                                  const xmlNodePtr config_ptr) {}
00675 
00676     
00678     static const std::string        XML_FILE_EXTENSION;
00679     
00681     static const std::string        BACKUP_FILE_EXTENSION;
00682     
00684     static const std::string        CONFIG_NAMESPACE_URL;
00685 
00687     static const std::string        ROOT_ELEMENT_NAME;
00688     
00690     static const std::string        STATS_ELEMENT_NAME;
00691     
00693     static const std::string        PLUGIN_ELEMENT_NAME;
00694     
00696     static const std::string        NAME_ELEMENT_NAME;
00697     
00699     static const std::string        COMMENT_ELEMENT_NAME;
00700 
00702     static const std::string        PION_VERSION_ATTRIBUTE_NAME;
00703 
00705     static const std::string        ID_ATTRIBUTE_NAME;
00706 
00707     
00709     PionLogger                      m_logger;
00710     
00712     PionIdGenerator                 m_id_gen;
00713     
00715     std::string                     m_config_file;
00716     
00718     std::string                     m_data_directory;
00719 
00721     bool                            m_debug_mode;
00722 
00724     xmlDocPtr                       m_config_doc_ptr;
00725     
00727     xmlNodePtr                      m_config_node_ptr;
00728 };
00729 
00730 
00731 }   // end namespace platform
00732 }   // end namespace pion
00733 
00734 #endif

Generated on Wed Apr 13 16:38:34 2011 for pion-platform by  doxygen 1.4.7