| /******************************************************************** |
| * 2014 - |
| * open source under Apache License Version 2.0 |
| ********************************************************************/ |
| /** |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| #include "Exception.h" |
| #include "ExceptionInternal.h" |
| #include "XmlConfig.h" |
| #include "Hash.h" |
| |
| #include <cassert> |
| #include <errno.h> |
| #include <fstream> |
| #include <libxml/parser.h> |
| #include <libxml/tree.h> |
| #include <limits> |
| #include <string.h> |
| #include <unistd.h> |
| |
| using namespace Hdfs::Internal; |
| |
| namespace Hdfs { |
| |
| typedef std::map<std::string, std::string>::const_iterator Iterator; |
| typedef std::map<std::string, std::string> Map; |
| |
| static int32_t StrToInt32(const char * str) { |
| long retval; |
| char * end = NULL; |
| errno = 0; |
| retval = strtol(str, &end, 0); |
| |
| if (EINVAL == errno || 0 != *end) { |
| THROW(HdfsBadNumFoumat, "Invalid int32_t type: %s", str); |
| } |
| |
| if (ERANGE == errno || retval > std::numeric_limits<int32_t>::max() |
| || retval < std::numeric_limits<int32_t>::min()) { |
| THROW(HdfsBadNumFoumat, "Underflow/Overflow int32_t type: %s", str); |
| } |
| |
| return retval; |
| } |
| |
| static int64_t StrToInt64(const char * str) { |
| long long retval; |
| char * end = NULL; |
| errno = 0; |
| retval = strtoll(str, &end, 0); |
| |
| if (EINVAL == errno || 0 != *end) { |
| THROW(HdfsBadNumFoumat, "Invalid int64_t type: %s", str); |
| } |
| |
| if (ERANGE == errno || retval > std::numeric_limits<int64_t>::max() |
| || retval < std::numeric_limits<int64_t>::min()) { |
| THROW(HdfsBadNumFoumat, "Underflow/Overflow int64_t type: %s", str); |
| } |
| |
| return retval; |
| } |
| |
| static bool StrToBool(const char * str) { |
| bool retval = false; |
| |
| if (!strcasecmp(str, "true") || !strcmp(str, "1")) { |
| retval = true; |
| } else if (!strcasecmp(str, "false") || !strcmp(str, "0")) { |
| retval = false; |
| } else { |
| THROW(HdfsBadBoolFoumat, "Invalid bool type: %s", str); |
| } |
| |
| return retval; |
| } |
| |
| static double StrToDouble(const char * str) { |
| double retval; |
| char * end = NULL; |
| errno = 0; |
| retval = strtod(str, &end); |
| |
| if (EINVAL == errno || 0 != *end) { |
| THROW(HdfsBadNumFoumat, "Invalid double type: %s", str); |
| } |
| |
| if (ERANGE == errno || retval > std::numeric_limits<double>::max() |
| || retval < std::numeric_limits<double>::min()) { |
| THROW(HdfsBadNumFoumat, "Underflow/Overflow int64_t type: %s", str); |
| } |
| |
| return retval; |
| } |
| |
| static void readConfigItem(xmlNodePtr root, Map & kv, const char * path) { |
| std::string key, value; |
| xmlNodePtr curNode; |
| bool hasname = false, hasvalue = false; |
| |
| for (curNode = root; NULL != curNode; curNode = curNode->next) { |
| if (curNode->type != XML_ELEMENT_NODE) { |
| continue; |
| } |
| |
| if (!hasname && !strcmp((const char *) curNode->name, "name")) { |
| if (NULL != curNode->children |
| && XML_TEXT_NODE == curNode->children->type) { |
| key = (const char *) curNode->children->content; |
| hasname = true; |
| } |
| } else if (!hasvalue |
| && !strcmp((const char *) curNode->name, "value")) { |
| if (NULL != curNode->children |
| && XML_TEXT_NODE == curNode->children->type) { |
| value = (const char *) curNode->children->content; |
| hasvalue = true; |
| } |
| } else { |
| continue; |
| } |
| } |
| |
| if (hasname && hasvalue) { |
| kv[key] = value; |
| return; |
| } else if (hasname) { |
| kv[key] = ""; |
| return; |
| } |
| |
| THROW(HdfsBadConfigFoumat, "Config cannot parse configure file: \"%s\"", |
| path); |
| } |
| |
| static void readConfigItems(xmlDocPtr doc, Map & kv, const char * path) { |
| xmlNodePtr root, curNode; |
| root = xmlDocGetRootElement(doc); |
| |
| if (NULL == root || strcmp((const char *) root->name, "configuration")) { |
| THROW(HdfsBadConfigFoumat, "Config cannot parse configure file: \"%s\"", |
| path); |
| } |
| |
| /* |
| * for each property |
| */ |
| for (curNode = root->children; NULL != curNode; curNode = curNode->next) { |
| if (curNode->type != XML_ELEMENT_NODE) { |
| continue; |
| } |
| |
| if (strcmp((const char *) curNode->name, "property")) { |
| THROW(HdfsBadConfigFoumat, |
| "Config cannot parse configure file: \"%s\"", path); |
| } |
| |
| readConfigItem(curNode->children, kv, path); |
| } |
| } |
| |
| Config::Config(const char * p) : |
| path(p) { |
| update(p); |
| } |
| |
| void Config::update(const char * p) { |
| xmlDocPtr doc; /* the resulting document tree */ |
| LIBXML_TEST_VERSION |
| kv.clear(); |
| path = p; |
| |
| if (access(path.c_str(), R_OK)) { |
| THROW(HdfsBadConfigFoumat, "Cannot read configure file: \"%s\", %s", |
| path.c_str(), GetSystemErrorInfo(errno)); |
| } |
| |
| /* parse the file */ |
| doc = xmlReadFile(path.c_str(), NULL, 0); |
| |
| try { |
| /* check if parsing succeeded */ |
| if (doc == NULL) { |
| THROW(HdfsBadConfigFoumat, |
| "Config cannot parse configure file: \"%s\"", path.c_str()); |
| } else { |
| readConfigItems(doc, kv, path.c_str()); |
| /* free up the resulting document */ |
| xmlFreeDoc(doc); |
| } |
| } catch (...) { |
| xmlFreeDoc(doc); |
| throw; |
| } |
| } |
| |
| const char * Config::getString(const char * key) const { |
| Iterator it = kv.find(key); |
| |
| if (kv.end() == it) { |
| THROW(HdfsConfigNotFound, "Config key: %s not found", key); |
| } |
| |
| return it->second.c_str(); |
| } |
| |
| const char * Config::getString(const char * key, const char * def) const { |
| Iterator it = kv.find(key); |
| |
| if (kv.end() == it) { |
| return def; |
| } else { |
| return it->second.c_str(); |
| } |
| } |
| |
| const char * Config::getString(const std::string & key) const { |
| return getString(key.c_str()); |
| } |
| |
| const char * Config::getString(const std::string & key, |
| const std::string & def) const { |
| return getString(key.c_str(), def.c_str()); |
| } |
| |
| int64_t Config::getInt64(const char * key) const { |
| int64_t retval; |
| Iterator it = kv.find(key); |
| |
| if (kv.end() == it) { |
| THROW(HdfsConfigNotFound, "Config key: %s not found", key); |
| } |
| |
| try { |
| retval = StrToInt64(it->second.c_str()); |
| } catch (const HdfsBadNumFoumat & e) { |
| NESTED_THROW(HdfsConfigNotFound, "Config key: %s not found", key); |
| } |
| |
| return retval; |
| } |
| |
| int64_t Config::getInt64(const char * key, int64_t def) const { |
| int64_t retval; |
| Iterator it = kv.find(key); |
| |
| if (kv.end() == it) { |
| return def; |
| } |
| |
| try { |
| retval = StrToInt64(it->second.c_str()); |
| } catch (const HdfsBadNumFoumat & e) { |
| NESTED_THROW(HdfsConfigNotFound, "Config key: %s not found", key); |
| } |
| |
| return retval; |
| } |
| |
| int32_t Config::getInt32(const char * key) const { |
| int32_t retval; |
| Iterator it = kv.find(key); |
| |
| if (kv.end() == it) { |
| THROW(HdfsConfigNotFound, "Config key: %s not found", key); |
| } |
| |
| try { |
| retval = StrToInt32(it->second.c_str()); |
| } catch (const HdfsBadNumFoumat & e) { |
| NESTED_THROW(HdfsConfigNotFound, "Config key: %s not found", key); |
| } |
| |
| return retval; |
| } |
| |
| int32_t Config::getInt32(const char * key, int32_t def) const { |
| int32_t retval; |
| Iterator it = kv.find(key); |
| |
| if (kv.end() == it) { |
| return def; |
| } |
| |
| try { |
| retval = StrToInt32(it->second.c_str()); |
| } catch (const HdfsBadNumFoumat & e) { |
| NESTED_THROW(HdfsConfigNotFound, "Config key: %s not found", key); |
| } |
| |
| return retval; |
| } |
| |
| double Config::getDouble(const char * key) const { |
| double retval; |
| Iterator it = kv.find(key); |
| |
| if (kv.end() == it) { |
| THROW(HdfsConfigNotFound, "Config key: %s not found", key); |
| } |
| |
| try { |
| retval = StrToDouble(it->second.c_str()); |
| } catch (const HdfsBadNumFoumat & e) { |
| NESTED_THROW(HdfsConfigNotFound, "Config key: %s not found", key); |
| } |
| |
| return retval; |
| } |
| |
| double Config::getDouble(const char * key, double def) const { |
| double retval; |
| Iterator it = kv.find(key); |
| |
| if (kv.end() == it) { |
| return def; |
| } |
| |
| try { |
| retval = StrToDouble(it->second.c_str()); |
| } catch (const HdfsBadNumFoumat & e) { |
| NESTED_THROW(HdfsConfigNotFound, "Config key: %s not found", key); |
| } |
| |
| return retval; |
| } |
| |
| bool Config::getBool(const char * key) const { |
| bool retval; |
| Iterator it = kv.find(key); |
| |
| if (kv.end() == it) { |
| THROW(HdfsConfigNotFound, "Config key: %s not found", key); |
| } |
| |
| try { |
| retval = StrToBool(it->second.c_str()); |
| } catch (const HdfsBadBoolFoumat & e) { |
| NESTED_THROW(HdfsConfigNotFound, "Config key: %s not found", key); |
| } |
| |
| return retval; |
| } |
| |
| bool Config::getBool(const char * key, bool def) const { |
| bool retval; |
| Iterator it = kv.find(key); |
| |
| if (kv.end() == it) { |
| return def; |
| } |
| |
| try { |
| retval = StrToBool(it->second.c_str()); |
| } catch (const HdfsBadNumFoumat & e) { |
| NESTED_THROW(HdfsConfigNotFound, "Config key: %s not found", key); |
| } |
| |
| return retval; |
| } |
| |
| size_t Config::hash_value() const { |
| std::vector<size_t> values; |
| std::map<std::string, std::string>::const_iterator s, e; |
| e = kv.end(); |
| |
| for (s = kv.begin(); s != e; ++s) { |
| values.push_back(StringHasher(s->first)); |
| values.push_back(StringHasher(s->second)); |
| } |
| |
| return CombineHasher(&values[0], values.size()); |
| } |
| |
| } |
| |