platform/src/ConfigManager.cpp

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 #include <pion/platform/ConfigManager.hpp>
00021 #include <boost/filesystem/operations.hpp>
00022 
00023 
00024 namespace pion {        // begin namespace pion
00025 namespace platform {    // begin namespace platform (Pion Platform Library)
00026 
00027 
00028 // static members of ConfigManager
00029 
00030 const std::string       ConfigManager::XML_FILE_EXTENSION = ".xml";
00031 const std::string       ConfigManager::BACKUP_FILE_EXTENSION = ".bak";
00032 const std::string       ConfigManager::CONFIG_NAMESPACE_URL = "http://purl.org/pion/config";
00033 const std::string       ConfigManager::ROOT_ELEMENT_NAME = "PionConfig";
00034 const std::string       ConfigManager::STATS_ELEMENT_NAME = "PionStats";
00035 const std::string       ConfigManager::PLUGIN_ELEMENT_NAME = "Plugin";
00036 const std::string       ConfigManager::NAME_ELEMENT_NAME = "Name";
00037 const std::string       ConfigManager::COMMENT_ELEMENT_NAME = "Comment";
00038 const std::string       ConfigManager::PION_VERSION_ATTRIBUTE_NAME = "pion_version";
00039 const std::string       ConfigManager::ID_ATTRIBUTE_NAME = "id";
00040 
00041         
00042 // ConfigManager member functions
00043 
00044 void ConfigManager::createConfigFile(void)
00045 {
00046     // make sure the config file is not already open
00047     if (m_config_doc_ptr != NULL)
00048         throw ConfigAlreadyOpenException(m_config_file);
00049 
00050     // make sure the config file does not already exist
00051     if (boost::filesystem::exists(m_config_file))
00052         throw ConfigFileExistsException(m_config_file);
00053 
00054     // create a new (empty) XML config tree
00055     if ((m_config_doc_ptr = xmlNewDoc(reinterpret_cast<const xmlChar*>("1.0"))) == NULL)
00056         throw InitializeRootConfigException(m_config_file);
00057     
00058     // add the root Pion "config" element
00059     if ((m_config_node_ptr = xmlNewNode(NULL, reinterpret_cast<const xmlChar*>(ROOT_ELEMENT_NAME.c_str()))) == NULL)
00060         throw InitializeRootConfigException(m_config_file);
00061     xmlDocSetRootElement(m_config_doc_ptr, m_config_node_ptr);
00062 
00063     // add the namespace for the "config" element
00064     if (xmlNewProp(m_config_node_ptr,
00065                    reinterpret_cast<const xmlChar*>("xmlns"),
00066                    reinterpret_cast<const xmlChar*>(CONFIG_NAMESPACE_URL.c_str())) == NULL)
00067         throw InitializeRootConfigException(m_config_file);
00068 
00069     // add the version for the "config" element
00070     if (xmlNewProp(m_config_node_ptr,
00071                    reinterpret_cast<const xmlChar*>(PION_VERSION_ATTRIBUTE_NAME.c_str()),
00072                    reinterpret_cast<const xmlChar*>(PION_VERSION)) == NULL)
00073         throw InitializeRootConfigException(m_config_file);
00074 
00075     // save the new config file
00076     saveConfigFile();
00077 }
00078 
00079 void ConfigManager::openConfigFile(void)
00080 {
00081     // make sure the config file is not already open
00082     if (m_config_doc_ptr != NULL)
00083         throw ConfigAlreadyOpenException(m_config_file);
00084 
00085     m_config_doc_ptr = getConfigFromFile(m_config_file, ROOT_ELEMENT_NAME, m_config_node_ptr, m_logger);
00086     if (m_config_doc_ptr == NULL)
00087         throw ConfigManager::ReadConfigException(m_config_file);
00088 }
00089 
00090 xmlDocPtr ConfigManager::getConfigFromFile(const std::string& config_file, const std::string& root_element_name, xmlNodePtr& config_ptr, PionLogger& logger)
00091 {
00092     // make sure the config file exists
00093     if (! boost::filesystem::exists(config_file))
00094         throw MissingConfigFileException(config_file);
00095 
00096     // read the existing config file
00097     xmlDocPtr xml_doc_ptr = xmlReadFile(config_file.c_str(), NULL, XML_PARSE_NOBLANKS);
00098     if (xml_doc_ptr == NULL)
00099         throw ReadConfigException(config_file);
00100 
00101     // make sure that the root element is what it should be
00102     if ( (config_ptr = xmlDocGetRootElement(xml_doc_ptr)) == NULL
00103         || xmlStrcmp(config_ptr->name,
00104                      reinterpret_cast<const xmlChar*>(root_element_name.c_str())) )
00105     {
00106         // config file is missing the expected root element
00107         throw MissingRootElementException(config_file);
00108     }
00109 
00110     // If the version number in the file is different than the current one:
00111     // a) if major or minor is different, throw fatal exception and refuse to run
00112     // b) if build number is different, update the version attribute in memory and in the file
00113     xmlChar* xml_char_ptr = xmlGetProp(config_ptr,
00114                                        reinterpret_cast<const xmlChar*>(PION_VERSION_ATTRIBUTE_NAME.c_str()));
00115     if (xml_char_ptr == NULL)
00116         throw ConfigFileVersionException(config_file);
00117     std::string cfg_file_version = reinterpret_cast<char*>(xml_char_ptr);
00118     xmlFree(xml_char_ptr);
00119     if (cfg_file_version != PION_VERSION && cfg_file_version != "tests") {  // use "tests" to disregard check for unit tests
00120         // incrementally compare version number in config file to PION_VERSION
00121         unsigned int num_dots = 0;
00122         for (size_t pos = 0; pos < cfg_file_version.size() && num_dots < 2; ++pos) {
00123             if (cfg_file_version[pos] == '.') ++num_dots;   // count dots
00124             if (cfg_file_version[pos] != PION_VERSION[pos]) // compare chars
00125                 throw ConfigFileVersionException(config_file);
00126         }
00127         if (num_dots != 2)  // check if stopped prematurely
00128             throw ConfigFileVersionException(config_file);
00129         // major and minor match, but build number does not
00130         if (xmlSetProp(config_ptr,
00131                        reinterpret_cast<const xmlChar*>(PION_VERSION_ATTRIBUTE_NAME.c_str()),
00132                        reinterpret_cast<const xmlChar*>(PION_VERSION)) == NULL)
00133             throw UpdateConfigException(root_element_name);
00134         if (xmlSaveFormatFileEnc(config_file.c_str(), xml_doc_ptr, "UTF-8", 1) == -1)
00135             throw WriteConfigException(config_file);
00136     }
00137 
00138     return xml_doc_ptr;
00139 }
00140 
00141 void ConfigManager::closeConfigFile(void)
00142 {
00143     xmlFreeDoc(m_config_doc_ptr);
00144     m_config_doc_ptr = NULL;
00145     m_config_node_ptr = NULL;
00146 }
00147 
00148 void ConfigManager::saveConfigFile(void)
00149 {
00150     // always create a backup copy of the config file first
00151     backupConfigFile();
00152     
00153     // save the latest XML config document to the file
00154     if (xmlSaveFormatFileEnc(m_config_file.c_str(), m_config_doc_ptr, "UTF-8", 1) == -1)
00155         throw WriteConfigException(m_config_file);
00156 }
00157     
00158 void ConfigManager::removeConfigFile(void)
00159 {
00160     backupConfigFile();
00161     boost::filesystem::remove(m_config_file);
00162 }
00163 
00164 void ConfigManager::backupConfigFile(void)
00165 {
00166     try {
00167 
00168         // make sure that the config file exists
00169         if (boost::filesystem::exists(m_config_file)) {
00170             const std::string backup_filename(m_config_file + BACKUP_FILE_EXTENSION);
00171             if (boost::filesystem::exists(backup_filename))
00172                 boost::filesystem::remove(backup_filename);
00173             boost::filesystem::copy_file(m_config_file, backup_filename);
00174         }
00175     } catch (...) {
00176         PION_LOG_WARN(m_logger, "Failed to backup configuration file: " << m_config_file);
00177     }
00178 }
00179 
00180 void ConfigManager::writeConfigXML(std::ostream& out,
00181                                    xmlNodePtr config_node,
00182                                    bool include_siblings)
00183 {
00184     // this should not be so hard!
00185     // there has to be a better way to do this....
00186     
00187     while (config_node != NULL) {
00188         
00189         // write data for the current node
00190         if (config_node->type == XML_ELEMENT_NODE) {
00191             
00192             // write new element tag (begin)
00193             out << '<' << xml_encode(reinterpret_cast<const char*>(config_node->name));
00194             
00195             // write attribute properties
00196             for (_xmlAttr *attr_ptr = config_node->properties;
00197                  attr_ptr != NULL; attr_ptr = attr_ptr->next)
00198             {
00199                 xmlChar *xml_char_ptr = xmlGetProp(config_node, attr_ptr->name);
00200                 if (xml_char_ptr != NULL) {
00201                     out << ' ' << xml_encode(reinterpret_cast<const char*>(attr_ptr->name))
00202                         << "=\"" << xml_encode(reinterpret_cast<const char*>(xml_char_ptr)) << '"';
00203                     xmlFree(xml_char_ptr);
00204                 }
00205             }
00206 
00207             // write new XML element node
00208             if (config_node->children != NULL) {
00209                 // write new element tag (end)
00210                 out << '>';
00211 
00212                 // recursive into children nodes
00213                 writeConfigXML(out, config_node->children, true);
00214                 
00215                 // write close element tag (end)
00216                 out << "</" << xml_encode(reinterpret_cast<const char*>(config_node->name)) << '>';
00217             } else {
00218                 // write new element tag (end, no children)
00219                 out << "/>";
00220             }
00221             
00222             // break if siblings should not be included
00223             if (! include_siblings)
00224                 break;
00225             
00226         } else if (config_node->type == XML_TEXT_NODE) {
00227 
00228             // write contents of text node
00229             out << xml_encode(reinterpret_cast<const char*>(config_node->content));
00230         }
00231 
00232         // step to the next sibling of config_node
00233         config_node = config_node->next;
00234     }
00235 }
00236 
00237 void ConfigManager::writeConfigXMLHeader(std::ostream& out)
00238 {
00239     out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl;
00240 }
00241     
00242 void ConfigManager::writeBeginPionConfigXML(std::ostream& out)
00243 {
00244     writeConfigXMLHeader(out);
00245     out << '<' << ROOT_ELEMENT_NAME << " xmlns=\"" << CONFIG_NAMESPACE_URL << "\" "
00246         << PION_VERSION_ATTRIBUTE_NAME << "=\"" << PION_VERSION << "\">" << std::endl;
00247 }
00248 
00249 void ConfigManager::writeEndPionConfigXML(std::ostream& out)
00250 {
00251     out << "</" << ROOT_ELEMENT_NAME << '>' << std::endl;
00252 }
00253     
00254 void ConfigManager::writeBeginPionStatsXML(std::ostream& out)
00255 {
00256     writeConfigXMLHeader(out);
00257     out << '<' << STATS_ELEMENT_NAME << " xmlns=\""
00258         << CONFIG_NAMESPACE_URL << "\">" << std::endl;
00259 }
00260 
00261 void ConfigManager::writeEndPionStatsXML(std::ostream& out)
00262 {
00263     out << "</" << STATS_ELEMENT_NAME << '>' << std::endl;
00264 }
00265     
00266 std::string ConfigManager::xml_encode(const std::string& str)
00267 {
00268     std::string result;
00269     result.reserve(str.size() + 20);    // Assume ~5 characters converted (length increases)
00270     const unsigned char *ptr = reinterpret_cast<const unsigned char*>(str.c_str());
00271     const unsigned char *end_ptr = ptr + str.size();
00272     while (ptr < end_ptr) {
00273         // check byte ranges for valid UTF-8
00274         // see http://en.wikipedia.org/wiki/UTF-8
00275         // also, see http://www.w3.org/TR/REC-xml/#charsets
00276         // this implementation is the strictest subset of both
00277         if ((*ptr >= 0x20 && *ptr <= 0x7F) || *ptr == 0x9 || *ptr == 0xa || *ptr == 0xd) {
00278             // regular ASCII character
00279             switch(*ptr) {
00280             // Escape special XML characters.
00281             case '&':
00282                 result += "&amp;";
00283                 break;
00284             case '<':
00285                 result += "&lt;";
00286                 break;
00287             case '>':
00288                 result += "&gt;";
00289                 break;
00290             case '\"':
00291                 result += "&quot;";
00292                 break;
00293             case '\'':
00294                 result += "&apos;";
00295                 break;
00296             default:
00297                 result += *ptr;
00298             }
00299         } else if (*ptr >= 0xC2 && *ptr <= 0xDF) {
00300             // two-byte sequence
00301             if (*(ptr+1) >= 0x80 && *(ptr+1) <= 0xBF) {
00302                 result += *ptr;
00303                 result += *(++ptr);
00304             } else {
00305                 // insert replacement char
00306                 result += 0xef;
00307                 result += 0xbf;
00308                 result += 0xbd;
00309             }
00310         } else if (*ptr >= 0xE0 && *ptr <= 0xEF) {
00311             // three-byte sequence
00312             if (*(ptr+1) >= 0x80 && *(ptr+1) <= 0xBF
00313                 && *(ptr+2) >= 0x80 && *(ptr+2) <= 0xBF) {
00314                 result += *ptr;
00315                 result += *(++ptr);
00316                 result += *(++ptr);
00317             } else {
00318                 // insert replacement char
00319                 result += 0xef;
00320                 result += 0xbf;
00321                 result += 0xbd;
00322             }
00323         } else if (*ptr >= 0xF0 && *ptr <= 0xF4) {
00324             // four-byte sequence
00325             if (*(ptr+1) >= 0x80 && *(ptr+1) <= 0xBF
00326                 && *(ptr+2) >= 0x80 && *(ptr+2) <= 0xBF
00327                 && *(ptr+3) >= 0x80 && *(ptr+3) <= 0xBF) {
00328                 result += *ptr;
00329                 result += *(++ptr);
00330                 result += *(++ptr);
00331                 result += *(++ptr);
00332             } else {
00333                 // insert replacement char
00334                 result += 0xef;
00335                 result += 0xbf;
00336                 result += 0xbd;
00337             }
00338         } else {
00339             // insert replacement char
00340             result += 0xef;
00341             result += 0xbf;
00342             result += 0xbd;
00343         }
00344         ++ptr;
00345     }
00346     
00347     return result;
00348 }
00349 
00350 std::string ConfigManager::createFilename(void)
00351 {
00352     std::string file_name(createUUID());
00353     file_name += XML_FILE_EXTENSION;
00354     return file_name;
00355 }
00356     
00357 xmlNodePtr ConfigManager::createPluginConfig(const std::string& plugin_type)
00358 {
00359     xmlNodePtr config_ptr = xmlNewNode(NULL, reinterpret_cast<const xmlChar*>(PLUGIN_ELEMENT_NAME.c_str()));
00360     xmlNodeSetContent(config_ptr,  reinterpret_cast<const xmlChar*>(plugin_type.c_str()));
00361     return config_ptr;
00362 }
00363 
00364 xmlNodePtr ConfigManager::createResourceConfig(const std::string& resource_name,
00365                                                const char *buf, std::size_t len)
00366 {
00367     // sanity check
00368     if (buf == NULL || len == 0)
00369         throw BadXMLBufferException();
00370     
00371     // parse request payload content as XML
00372     xmlNodePtr node_ptr = NULL;
00373     xmlDocPtr doc_ptr = xmlParseMemory(buf, len);
00374     if (doc_ptr == NULL)
00375         throw XMLBufferParsingException(buf);
00376 
00377     // find the ROOT element
00378     if ( (node_ptr = xmlDocGetRootElement(doc_ptr)) == NULL
00379         || xmlStrcmp(node_ptr->name,
00380                      reinterpret_cast<const xmlChar*>(ROOT_ELEMENT_NAME.c_str())) )
00381     {
00382         xmlFreeDoc(doc_ptr);
00383         // buf is missing the root "PionConfig" element 
00384         throw MissingRootElementException(buf);
00385     }
00386     // find the resource element
00387     node_ptr = findConfigNodeByName(resource_name, node_ptr->children);
00388     if (node_ptr == NULL) {
00389         xmlFreeDoc(doc_ptr);
00390         throw MissingResourceElementException(resource_name);
00391     }
00392 
00393     // found the resource config -> make a copy of it
00394     node_ptr = xmlCopyNodeList(node_ptr->children);
00395     
00396     // free the temporary document
00397     xmlFreeDoc(doc_ptr);
00398     
00399     // return the copied configuration info
00400     return node_ptr;
00401 }
00402     
00403 std::string ConfigManager::createFilename(const std::string& file_path)
00404 {
00405     boost::filesystem::path new_path(file_path);
00406     new_path /= createFilename();
00407     return boost::filesystem::system_complete(new_path).file_string();
00408 }
00409     
00410 std::string ConfigManager::resolveRelativePath(const std::string& base_path_to_file,
00411                                                const std::string& orig_path)
00412 {
00413     // return the original if it is not relative
00414     if (boost::filesystem::path(orig_path).is_complete())
00415         return orig_path;
00416     
00417     // build a new path using the config file location as a starting point
00418     boost::filesystem::path new_path(boost::filesystem::system_complete(base_path_to_file));
00419     new_path.remove_leaf();
00420     new_path /= orig_path;
00421     new_path.normalize();
00422     return new_path.file_string();
00423 }
00424 
00425 std::string ConfigManager::resolveRelativeDataPath(const std::string& orig_path)
00426 {
00427     // return the original if it is not relative
00428     if (boost::filesystem::path(orig_path).is_complete())
00429         return orig_path;
00430     
00431     boost::filesystem::path new_path(boost::filesystem::system_complete(getDataDirectory()));
00432     new_path /= orig_path;
00433     new_path.normalize();
00434     return new_path.file_string();
00435 }
00436 
00437 bool ConfigManager::getNodeId(xmlNodePtr config_node, std::string& node_id)
00438 {
00439     node_id = "";
00440     xmlChar *xml_char_ptr = xmlGetProp(config_node,
00441                                        reinterpret_cast<const xmlChar*>(ID_ATTRIBUTE_NAME.c_str()));
00442     if (xml_char_ptr != NULL && xml_char_ptr[0]!='\0')
00443         node_id = reinterpret_cast<char*>(xml_char_ptr);
00444     xmlFree(xml_char_ptr);
00445     return(! node_id.empty());
00446 }
00447     
00448 xmlNodePtr ConfigManager::findConfigNodeByName(const std::string& element_name,
00449                                                xmlNodePtr starting_node)
00450 {
00451     xmlNodePtr matching_node = NULL;
00452     
00453     // find the element node in the XML config document
00454     for (xmlNodePtr cur_node = starting_node;
00455          cur_node != NULL; cur_node = cur_node->next)
00456     {
00457         if (cur_node->type == XML_ELEMENT_NODE
00458             && xmlStrcmp(cur_node->name, reinterpret_cast<const xmlChar*>(element_name.c_str()))==0)
00459         {
00460             // found it!
00461             matching_node = cur_node;
00462             break;
00463         }
00464     }
00465     
00466     return matching_node;
00467 }
00468     
00469 xmlNodePtr ConfigManager::findConfigNodeByContent(const std::string& element_name,
00470                                                   const std::string& content_value,
00471                                                   xmlNodePtr starting_node)
00472 {
00473     xmlNodePtr matching_node = NULL;
00474 
00475     // find the element node in the XML config document
00476     for (xmlNodePtr cur_node = starting_node;
00477          cur_node != NULL; cur_node = cur_node->next)
00478     {
00479         if (cur_node->type == XML_ELEMENT_NODE
00480             && xmlStrcmp(cur_node->name, reinterpret_cast<const xmlChar*>(element_name.c_str()))==0)
00481         {
00482             // found an element with matching name
00483             xmlChar *xml_char_ptr = xmlNodeGetContent(cur_node);
00484             if (xml_char_ptr != NULL) {
00485                 if (content_value == reinterpret_cast<char*>(xml_char_ptr)) {
00486                     // found it!
00487                     matching_node = cur_node;
00488                     break;
00489                 }
00490                 xmlFree(xml_char_ptr);
00491             }
00492         }
00493     }
00494         
00495     return matching_node;
00496 }
00497     
00498 xmlNodePtr ConfigManager::findConfigNodeByAttr(const std::string& element_name,
00499                                                const std::string& attr_name,
00500                                                const std::string& attr_value,
00501                                                xmlNodePtr starting_node)
00502 {
00503     xmlNodePtr matching_node = NULL;
00504     
00505     // find the element node in the XML config document
00506     for (xmlNodePtr cur_node = starting_node;
00507          cur_node != NULL; cur_node = cur_node->next)
00508     {
00509         if (cur_node->type == XML_ELEMENT_NODE
00510             && xmlStrcmp(cur_node->name, reinterpret_cast<const xmlChar*>(element_name.c_str()))==0)
00511         {
00512             // found an element with matching name
00513             xmlChar *xml_char_ptr = xmlGetProp(cur_node, reinterpret_cast<const xmlChar*>(attr_name.c_str()));
00514             if (xml_char_ptr != NULL) {
00515                 if (attr_value == reinterpret_cast<char*>(xml_char_ptr)) {
00516                     // found it!
00517                     matching_node = cur_node;
00518                     break;
00519                 }
00520                 xmlFree(xml_char_ptr);
00521             }
00522         }
00523     }
00524     
00525     return matching_node;
00526 }
00527     
00528 bool ConfigManager::getConfigOption(const std::string& option_name,
00529                                     std::string& option_value,
00530                                     const xmlNodePtr starting_node)
00531 {
00532     // find the option's element
00533     xmlNodePtr option_node = findConfigNodeByName(option_name, starting_node);
00534     if (option_node != NULL) {
00535         xmlChar *xml_char_ptr = xmlNodeGetContent(option_node);
00536         if (xml_char_ptr != NULL) {
00537             // found it
00538             if (xml_char_ptr[0] != '\0') {
00539                 // it is not empty
00540                 option_value = reinterpret_cast<char*>(xml_char_ptr);
00541                 xmlFree(xml_char_ptr);
00542                 return true;
00543             }
00544             xmlFree(xml_char_ptr);
00545         }
00546     }
00547 
00548     // option was not found or it had an empty value
00549     option_value.clear();
00550     return false;
00551 }
00552 
00553 bool ConfigManager::getConfigOptionEmptyOk(const std::string& option_name,
00554                             std::string& option_value,
00555                             const xmlNodePtr starting_node)
00556 {
00557     if (findConfigNodeByName(option_name, starting_node)) {
00558         option_value.clear();
00559         getConfigOption(option_name, option_value, starting_node);
00560         return true;
00561     } else
00562         return false;
00563 }
00564 
00565 std::string ConfigManager::getAttribute(const char *name, const xmlNodePtr ptr)
00566 {
00567     std::string id_str;
00568     xmlChar *xml_char_ptr = xmlGetProp(ptr, reinterpret_cast<const xmlChar*>(name));
00569     if (xml_char_ptr != NULL) {
00570         if (xml_char_ptr[0] != '\0')
00571             id_str = reinterpret_cast<char*>(xml_char_ptr);
00572         xmlFree(xml_char_ptr);
00573     }
00574     return id_str;
00575 }
00576 
00577 bool ConfigManager::updateConfigOption(const std::string& option_name,
00578                                        const std::string& option_value,
00579                                        xmlNodePtr parent_node)
00580 {
00581     // find the option's element
00582     xmlNodePtr option_node = findConfigNodeByName(option_name, parent_node->children);
00583     if (option_node != NULL) {
00584         // an existing value is assigned to the option
00585         if (option_value.empty()) {
00586             // changing to an empty value -> remove the element node
00587             xmlUnlinkNode(option_node);
00588             xmlFreeNodeList(option_node);
00589         } else {
00590             // change the value of an existing element
00591             xmlNodeSetContent(option_node, reinterpret_cast<const xmlChar*>(xml_encode(option_value).c_str()));
00592         }
00593     } else {
00594         // no value is currently set for the option
00595         // only add an element if the new value is not empty
00596         if (! option_value.empty()) {
00597             if (xmlNewTextChild(parent_node, NULL,
00598                                 reinterpret_cast<const xmlChar*>(option_name.c_str()),
00599                                 reinterpret_cast<const xmlChar*>(option_value.c_str())) == NULL)
00600                 return false;
00601         }
00602     }
00603     
00604     return true;
00605 }
00606 
00607 void ConfigManager::openPluginConfig(const std::string& plugin_name)
00608 {
00609     // open the file and find the "config" root element
00610     ConfigManager::openConfigFile();
00611     
00612     xmlNodePtr plugin_node = m_config_node_ptr->children;
00613     while ( (plugin_node = findConfigNodeByName(plugin_name, plugin_node)) != NULL)
00614     {
00615         // parse new plug-in definition
00616         std::string new_plugin_id;
00617         if (! getNodeId(plugin_node, new_plugin_id))
00618             throw EmptyPluginIdException(getConfigFile());
00619         
00620         // find plug-in type
00621         std::string new_plugin_type;
00622         if (! getConfigOption(PLUGIN_ELEMENT_NAME, new_plugin_type, plugin_node->children))
00623             throw EmptyPluginElementException(new_plugin_id);
00624 
00625         // execute callback to actually add the plug-in
00626         addPluginNoLock(new_plugin_id, new_plugin_type, plugin_node->children);
00627 
00628         // look for more plug-in nodes
00629         plugin_node = plugin_node->next;
00630     }
00631 }
00632     
00633 bool ConfigManager::setPluginConfig(xmlNodePtr plugin_node_ptr, xmlNodePtr config_ptr)
00634 {
00635     xmlNodePtr plugin_config_copy = xmlCopyNodeList(config_ptr);
00636     if (plugin_config_copy == NULL)
00637         return false;
00638     
00639     // remove the plugin type element, if it exists in the new config
00640     xmlNodePtr plugin_type_node = findConfigNodeByName(PLUGIN_ELEMENT_NAME,
00641                                                        plugin_config_copy);
00642     if (plugin_type_node != NULL) {
00643         // check if we are removing the first node in the list
00644         if (plugin_config_copy == plugin_type_node)
00645             plugin_config_copy = plugin_type_node->next;
00646 
00647         // remove the Plugin type node (this cannot be changed)
00648         xmlUnlinkNode(plugin_type_node);
00649         xmlFreeNode(plugin_type_node);
00650         
00651         // stop early if this is the only node in the configuration
00652         if (plugin_config_copy == NULL)
00653             return true;
00654     }
00655     
00656     // clean namespaces in config nodes: work-around for libxml namespace bugs
00657     for (xmlNodePtr tmp_node = plugin_config_copy; tmp_node != NULL;
00658          tmp_node = tmp_node->next)
00659     {
00660         tmp_node->ns = tmp_node->nsDef = NULL;
00661     }
00662     
00663     // add the plugin config to the config file
00664     if (xmlAddChildList(plugin_node_ptr, plugin_config_copy) == NULL) {
00665         xmlFreeNodeList(plugin_config_copy);
00666         return false;
00667     }
00668 
00669     return true;
00670 }
00671     
00672 void ConfigManager::setPluginConfig(const std::string& plugin_name,
00673                                     const std::string& plugin_id,
00674                                     const xmlNodePtr config_ptr)
00675 {
00676     // find the plug-in element in the XML config document
00677     xmlNodePtr plugin_node = findConfigNodeByAttr(plugin_name,
00678                                                   ID_ATTRIBUTE_NAME,
00679                                                   plugin_id,
00680                                                   m_config_node_ptr->children);
00681     if (plugin_node == NULL)
00682         throw UpdatePluginConfigException(plugin_id);
00683     
00684     // remove all children except the plugin type node
00685     xmlNodePtr cur_node;
00686     xmlNodePtr next_node = plugin_node->children;
00687     while (next_node != NULL) {
00688         cur_node = next_node;
00689         next_node = next_node->next;
00690         
00691         if (cur_node->type != XML_ELEMENT_NODE
00692             || xmlStrcmp(cur_node->name, reinterpret_cast<const xmlChar*>(PLUGIN_ELEMENT_NAME.c_str()))!=0)
00693         {
00694             xmlUnlinkNode(cur_node);
00695             xmlFreeNode(cur_node);
00696         }
00697     }
00698     
00699     // update the plugin configuration parameters (if any)
00700     if (config_ptr != NULL) {
00701         if (! setPluginConfig(plugin_node, config_ptr))
00702             throw UpdatePluginConfigException(plugin_id);
00703     }
00704     
00705     // save the new XML config file
00706     saveConfigFile();
00707 }
00708 
00709 void ConfigManager::addPluginConfig(const std::string& plugin_name,
00710                                     const std::string& plugin_id,
00711                                     const std::string& plugin_type,
00712                                     const xmlNodePtr config_ptr)
00713 {
00714     // create a new node for the plug-in and add it to the XML config document
00715     xmlNodePtr new_plugin_node = xmlNewNode(NULL, reinterpret_cast<const xmlChar*>(plugin_name.c_str()));
00716     if (new_plugin_node == NULL)
00717         throw AddPluginConfigException(plugin_type);
00718     if ((new_plugin_node=xmlAddChild(m_config_node_ptr, new_plugin_node)) == NULL) {
00719         xmlFreeNode(new_plugin_node);
00720         throw AddPluginConfigException(plugin_type);
00721     }
00722     
00723     // set the id attribute for the plug-in element
00724     if (xmlNewProp(new_plugin_node, reinterpret_cast<const xmlChar*>(ID_ATTRIBUTE_NAME.c_str()),
00725                    reinterpret_cast<const xmlChar*>(plugin_id.c_str())) == NULL)
00726         throw AddPluginConfigException(plugin_type);
00727     
00728     // add a plugin type child element to the plug-in element
00729     if (xmlNewTextChild(new_plugin_node, NULL,
00730                         reinterpret_cast<const xmlChar*>(PLUGIN_ELEMENT_NAME.c_str()),
00731                         reinterpret_cast<const xmlChar*>(plugin_type.c_str())) == NULL)
00732         throw AddPluginConfigException(plugin_type);
00733     
00734     // update the plug-in configuration parameters (if any)
00735     if (config_ptr != NULL) {
00736         if (! setPluginConfig(new_plugin_node, config_ptr))
00737             throw AddPluginConfigException(plugin_type);
00738     }
00739     
00740     // save the new XML config file
00741     saveConfigFile();
00742 }
00743         
00744 void ConfigManager::removePluginConfig(const std::string& plugin_name,
00745                                        const std::string& plugin_id)
00746 {
00747     // find the plug-in node to remove
00748     xmlNodePtr plugin_node = findConfigNodeByAttr(plugin_name,
00749                                                   ID_ATTRIBUTE_NAME,
00750                                                   plugin_id,
00751                                                   m_config_node_ptr->children);
00752     if (plugin_node == NULL)
00753         throw RemovePluginConfigException(plugin_id);
00754     
00755     // remove the plug-in element (and all of its children)
00756     xmlUnlinkNode(plugin_node);
00757     xmlFreeNode(plugin_node);
00758     
00759     // save the new XML config file
00760     saveConfigFile();
00761 }
00762 
00763     
00764 }   // end namespace platform
00765 }   // end namespace pion

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