123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328 |
- /**
- * 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 "configuration_loader.h"
- #include "common/logging.h"
- #include <fstream>
- #include <strings.h>
- #include <sstream>
- #include <map>
- #include <sys/stat.h>
- #include <rapidxml/rapidxml.hpp>
- #include <rapidxml/rapidxml_utils.hpp>
- namespace hdfs {
- /*
- * ConfigurationLoader class
- */
- #if defined(WIN32) || defined(_WIN32)
- static const char kFileSeparator = '\\';
- #else
- static const char kFileSeparator = '/';
- #endif
- static const char kSearchPathSeparator = ':';
- bool is_valid_bool(const std::string& raw) {
- if (raw.empty()) {
- return false;
- }
- if (!strcasecmp(raw.c_str(), "true")) {
- return true;
- }
- if (!strcasecmp(raw.c_str(), "false")) {
- return true;
- }
- return false;
- }
- bool str_to_bool(const std::string& raw) {
- if (!strcasecmp(raw.c_str(), "true")) {
- return true;
- }
- return false;
- }
- ConfigurationLoader::ConfigurationLoader() {
- //In order to creates a configuration loader with the default search path
- //("$HADOOP_CONF_DIR" or "/etc/hadoop/conf") we call SetDefaultSearchPath().
- ConfigurationLoader::SetDefaultSearchPath();
- }
- void ConfigurationLoader::SetDefaultSearchPath() {
- // Try (in order, taking the first valid one):
- // $HADOOP_CONF_DIR
- // /etc/hadoop/conf
- const char * hadoop_conf_dir_env = getenv("HADOOP_CONF_DIR");
- if (hadoop_conf_dir_env) {
- std::stringstream ss(hadoop_conf_dir_env);
- std::string path;
- while (std::getline(ss, path, kSearchPathSeparator)) {
- AddToSearchPath(path);
- }
- } else {
- AddToSearchPath("/etc/hadoop/conf");
- }
- }
- void ConfigurationLoader::ClearSearchPath()
- {
- search_path_.clear();
- }
- void ConfigurationLoader::SetSearchPath(const std::string & searchPath)
- {
- search_path_.clear();
- std::vector<std::string> paths;
- std::string::size_type start = 0;
- std::string::size_type end = searchPath.find(kSearchPathSeparator);
- while (end != std::string::npos) {
- paths.push_back(searchPath.substr(start, end-start));
- start = ++end;
- end = searchPath.find(kSearchPathSeparator, start);
- }
- paths.push_back(searchPath.substr(start, searchPath.length()));
- for (auto path: paths) {
- AddToSearchPath(path);
- }
- }
- void ConfigurationLoader::AddToSearchPath(const std::string & searchPath)
- {
- if (searchPath.empty())
- return;
- if (searchPath.back() != kFileSeparator) {
- std::string pathWithSlash(searchPath);
- pathWithSlash += kFileSeparator;
- search_path_.push_back(pathWithSlash);
- } else {
- search_path_.push_back(searchPath);
- }
- }
- std::string ConfigurationLoader::GetSearchPath()
- {
- std::stringstream result;
- bool first = true;
- for(std::string item: search_path_) {
- if (!first) {
- result << kSearchPathSeparator;
- }
- result << item;
- first = false;
- }
- return result.str();
- }
- Status validateStream(std::istream & stream) {
- std::streampos start = stream.tellg();
- stream.seekg(0, std::ios::end);
- std::streampos end = stream.tellg();
- stream.seekg(start, std::ios::beg);
- int length = end - start;
- if (length <= 0 || start == -1 || end == -1)
- return Status::Error("The configuration file is empty");
- LOG_DEBUG(kFileSystem, << "validateStream will read a config file of length " << length);
- std::vector<char> raw_bytes((int64_t)length + 1);
- stream.read(&raw_bytes[0], length);
- raw_bytes[length] = 0;
- try {
- rapidxml::xml_document<> dom;
- dom.parse<rapidxml::parse_trim_whitespace|rapidxml::parse_validate_closing_tags>(&raw_bytes[0]);
- /* File must contain a single <configuration> stanza */
- auto config_node = dom.first_node("configuration", 0, false);
- if (!config_node) {
- return Status::Error("The configuration file is missing a 'configuration' tag");
- }
- return Status::OK();
- } catch (const rapidxml::parse_error &e) {
- size_t location = e.where<char>() - &raw_bytes[0];
- std::string msg = "The configuration file has invalid xml around character " + std::to_string(location);
- return Status::Error(msg.c_str());
- }
- }
- std::vector<std::pair<std::string, Status> > ConfigurationLoader::ValidateResources(std::vector<std::string> filenames) const
- {
- std::vector<std::pair<std::string, Status> > stats;
- bool found;
- for(auto file: filenames) {
- found = false;
- for(auto dir: search_path_) {
- std::ifstream stream(dir + file);
- if ( stream.is_open() ) {
- found = true;
- stats.push_back(std::make_pair(file,validateStream(stream)));
- } else {
- LOG_DEBUG(kFileSystem, << dir << file << " was not found");
- }
- }
- if(!found) {
- std::string msg("No directory in the current search path contains the file [" + file + "]");
- stats.push_back(std::make_pair(file,Status::PathNotFound(msg.c_str())));
- }
- }
- return stats;
- }
- bool ConfigurationLoader::UpdateMapWithFile(ConfigMap & map, const std::string & path) const
- {
- if (path.front() == kFileSeparator) { // Absolute path
- std::ifstream stream(path, std::ifstream::in);
- if ( stream.is_open() ) {
- return UpdateMapWithStream(map, stream);
- } else {
- return false;
- }
- } else { // Use search path
- for(auto dir: search_path_) {
- std::ifstream stream(dir + path);
- if ( stream.is_open() ) {
- if (UpdateMapWithStream(map, stream))
- return true;
- }
- }
- }
- return false;
- }
- bool ConfigurationLoader::UpdateMapWithStream(ConfigMap & map,
- std::istream & stream) {
- std::streampos start = stream.tellg();
- stream.seekg(0, std::ios::end);
- std::streampos end = stream.tellg();
- stream.seekg(start, std::ios::beg);
- int length = end - start;
- if (length <= 0 || start == -1 || end == -1)
- return false;
- std::vector<char> raw_bytes((int64_t)length + 1);
- stream.read(&raw_bytes[0], length);
- raw_bytes[length] = 0;
- return UpdateMapWithBytes(map, raw_bytes);
- }
- bool ConfigurationLoader::UpdateMapWithString(ConfigMap & map,
- const std::string &xml_data) {
- if (xml_data.size() == 0) {
- return false;
- }
- std::vector<char> raw_bytes(xml_data.begin(), xml_data.end());
- raw_bytes.push_back('\0');
- bool success = UpdateMapWithBytes(map, raw_bytes);
- if (success) {
- return true;
- } else {
- return false;
- }
- }
- bool ConfigurationLoader::UpdateMapWithBytes(ConfigMap& map,
- std::vector<char>& raw_bytes) {
- try {
- rapidxml::xml_document<> dom;
- dom.parse<rapidxml::parse_trim_whitespace>(&raw_bytes[0]);
- /* File must contain a single <configuration> stanza */
- auto config_node = dom.first_node("configuration", 0, false);
- if (!config_node) {
- return false;
- }
- /* Walk all of the <property> nodes, ignoring the rest */
- for (auto property_node = config_node->first_node("property", 0, false);
- property_node;
- property_node = property_node->next_sibling("property", 0, false)) {
- auto name_node = property_node->first_node("name", 0, false);
- auto value_node = property_node->first_node("value", 0, false);
- if (name_node && value_node) {
- std::string final_value;
- auto final_node = property_node->first_node("final", 0, false);
- if (final_node) {
- final_value = final_node->value();
- }
- UpdateMapWithValue(map, name_node->value(), value_node->value(), final_value);
- }
- auto name_attr = property_node->first_attribute("name", 0, false);
- auto value_attr = property_node->first_attribute("value", 0, false);
- if (name_attr && value_attr) {
- std::string final_value;
- auto final_attr = property_node->first_attribute("final", 0, false);
- if (final_attr) {
- final_value = final_attr->value();
- }
- UpdateMapWithValue(map, name_attr->value(), value_attr->value(), final_value);
- }
- }
- return true;
- } catch (const rapidxml::parse_error &e) {
- // TODO: Capture the result in a Status object
- return false;
- }
- }
- bool ConfigurationLoader::UpdateMapWithValue(ConfigMap& map,
- const std::string& key, const std::string& value,
- const std::string& final_text)
- {
- std::string caseFixedKey = Configuration::fixCase(key);
- auto mapValue = map.find(caseFixedKey);
- if (mapValue != map.end() && mapValue->second.final) {
- return false;
- }
- bool final_value = false;
- if (is_valid_bool(final_text)) {
- final_value = str_to_bool(final_text);
- }
- map[caseFixedKey].value = value;
- map[caseFixedKey].final = final_value;
- return true;
- }
- }
|