Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (C) 2014 Google Inc. | |
| 2 // | |
| 3 // Licensed under the Apache License, Version 2.0 (the "License"); | |
| 4 // you may not use this file except in compliance with the License. | |
| 5 // You may obtain a copy of the License at | |
| 6 // | |
| 7 // http://www.apache.org/licenses/LICENSE-2.0 | |
| 8 // | |
| 9 // Unless required by applicable law or agreed to in writing, software | |
| 10 // distributed under the License is distributed on an "AS IS" BASIS, | |
| 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 12 // See the License for the specific language governing permissions and | |
| 13 // limitations under the License. | |
| 14 | |
| 15 #include "country_rules_retriever.h" | |
| 16 | |
| 17 #include <libaddressinput/address_field.h> | |
| 18 #include <libaddressinput/callback.h> | |
| 19 #include <libaddressinput/util/basictypes.h> | |
| 20 #include <libaddressinput/util/scoped_ptr.h> | |
| 21 | |
| 22 #include <cassert> | |
| 23 #include <cstddef> | |
| 24 #include <map> | |
| 25 #include <string> | |
| 26 #include <utility> | |
| 27 | |
| 28 #include "retriever.h" | |
| 29 #include "rule.h" | |
| 30 #include "ruleset.h" | |
| 31 #include "util/stl_util.h" | |
| 32 | |
| 33 namespace i18n { | |
| 34 namespace addressinput { | |
| 35 | |
| 36 // Information about data requests sent to Retriever. This data is not returned | |
| 37 // as part of the ruleset, but is useful in constructing the ruleset | |
| 38 // asynchronously. | |
| 39 struct CountryRulesRetriever::RequestData { | |
| 40 // Does not take ownership of |parent|. | |
| 41 RequestData(Ruleset* parent, | |
| 42 AddressField level, | |
| 43 bool is_language_code, | |
| 44 const std::string& id) | |
| 45 : parent(parent), | |
| 46 level(level), | |
| 47 is_language_code(is_language_code), | |
| 48 id(id) {} | |
| 49 | |
| 50 ~RequestData() {} | |
| 51 | |
| 52 // The parent ruleset of the data being downloaded. If NULL, then this is the | |
| 53 // root ruleset at the COUNTRY level. The language-specific and sub-region | |
| 54 // rules are added to this ruleset. Owned by |CountryRulesRetriever|. | |
| 55 Ruleset* parent; | |
| 56 | |
| 57 // The level of the data being requested. Ranges from COUNTRY to | |
| 58 // DEPENDENT_LOCALITY. If COUNTRY, then the rule should use default rules from | |
| 59 // Rule::GetDefault(). | |
| 60 AddressField level; | |
| 61 | |
| 62 // If true, then |id| is a language. The data received for this request should | |
| 63 // be placed into a language-specific rule. | |
| 64 bool is_language_code; | |
| 65 | |
| 66 // Can be a region name (e.g. "CA") or a language (e.g. "fr"). Used to add a | |
| 67 // sub-region or a language-specific rule to |parent|. | |
| 68 std::string id; | |
| 69 }; | |
| 70 | |
| 71 CountryRulesRetriever::CountryRulesRetriever(scoped_ptr<Retriever> retriever) | |
| 72 : retriever_(retriever.Pass()), | |
| 73 requests_(), | |
| 74 country_code_(), | |
| 75 rules_ready_(), | |
| 76 root_(), | |
| 77 success_(true), | |
| 78 default_language_(), | |
| 79 languages_() { | |
| 80 assert(retriever_ != NULL); | |
| 81 } | |
| 82 | |
| 83 CountryRulesRetriever::~CountryRulesRetriever() {} | |
| 84 | |
| 85 void CountryRulesRetriever::RetrieveRules(const std::string& country_code, | |
| 86 scoped_ptr<Callback> rules_ready) { | |
| 87 Reset(); | |
| 88 country_code_ = country_code; | |
| 89 rules_ready_.reset(rules_ready.release()); | |
| 90 | |
| 91 // Key construction: | |
| 92 // https://code.google.com/p/libaddressinput/wiki/AddressValidationMetadata | |
| 93 // Example of a country-level key: "data/CA". | |
| 94 std::string key = "data/" + country_code_; | |
| 95 requests_.insert(std::make_pair( | |
| 96 key, RequestData(NULL, COUNTRY, false, std::string()))); | |
| 97 | |
| 98 retriever_->Retrieve( | |
| 99 key, BuildCallback(this, &CountryRulesRetriever::OnDataReady)); | |
| 100 } | |
| 101 | |
| 102 void CountryRulesRetriever::OnDataReady(bool success, | |
| 103 const std::string& key, | |
| 104 const std::string& data) { | |
| 105 std::map<std::string, RequestData>::iterator request_it = | |
| 106 requests_.find(key); | |
| 107 if (request_it == requests_.end()) { | |
| 108 return; // An abandoned request. | |
| 109 } | |
| 110 | |
| 111 RequestData request = request_it->second; | |
| 112 requests_.erase(request_it); | |
| 113 | |
| 114 success_ &= success; | |
|
Evan Stade
2014/01/08 01:22:46
it seems that if success is false, we should aband
please use gerrit instead
2014/01/08 02:04:40
Done.
| |
| 115 | |
| 116 // All country-level rules are based on the default rule. | |
| 117 scoped_ptr<Rule> rule(new Rule); | |
| 118 if (request.level == COUNTRY) { | |
| 119 rule->CopyFrom(Rule::GetDefault()); | |
| 120 } | |
| 121 | |
| 122 success_ &= rule->ParseSerializedRule(data); | |
| 123 | |
| 124 // Place the rule in the correct location in the ruleset. | |
| 125 Ruleset* ruleset = NULL; | |
| 126 if (request.is_language_code) { | |
| 127 assert(request.parent != NULL); | |
| 128 request.parent->AddLanguageCode(request.id, rule.Pass()); | |
| 129 ruleset = request.parent; | |
| 130 } else if (request.level == COUNTRY) { | |
| 131 // The default language and all supported languages for the country code are | |
| 132 // in the country-level rule without a language code identifier. For | |
| 133 // example: "data/CA". | |
| 134 default_language_ = rule->GetLanguage(); | |
| 135 languages_ = rule->GetLanguages(); | |
| 136 | |
| 137 root_.reset(new Ruleset(rule.Pass())); | |
| 138 ruleset = root_.get(); | |
| 139 } else { | |
| 140 assert(request.parent != NULL); | |
| 141 ruleset = request.parent->AddSubRegion(request.id, rule.Pass()); | |
| 142 } | |
| 143 | |
| 144 if (!request.is_language_code) { | |
| 145 // Retrieve the language-specific rules for this region. | |
| 146 for (std::vector<std::string>::const_iterator | |
| 147 lang_it = languages_.begin(); | |
| 148 lang_it != languages_.end(); | |
| 149 ++lang_it) { | |
| 150 if (*lang_it == default_language_) { | |
| 151 continue; | |
| 152 } | |
| 153 // Example of a language-specific key: "data/CA--fr". | |
| 154 std::string language_code_key = key + "--" + *lang_it; | |
| 155 requests_.insert(std::make_pair( | |
| 156 key, RequestData(ruleset, request.level, true, *lang_it))); | |
| 157 retriever_->Retrieve( | |
| 158 language_code_key, | |
| 159 BuildCallback(this, &CountryRulesRetriever::OnDataReady)); | |
| 160 } | |
| 161 | |
| 162 if (request.level < DEPENDENT_LOCALITY) { | |
| 163 // Retrieve the sub-region rules for this region. | |
| 164 for (std::vector<std::string>::const_iterator | |
| 165 subkey_it = ruleset->rule().GetSubKeys().begin(); | |
| 166 subkey_it != ruleset->rule().GetSubKeys().end(); | |
| 167 ++subkey_it) { | |
| 168 // Example of a sub-region key: "data/CA/AB". | |
| 169 std::string sub_region_key = key + "/" + *subkey_it; | |
| 170 requests_.insert(std::make_pair( | |
| 171 key, | |
| 172 RequestData(ruleset, | |
| 173 static_cast<AddressField>(request.level + 1), | |
| 174 false, | |
| 175 *subkey_it))); | |
| 176 retriever_->Retrieve( | |
| 177 sub_region_key, | |
| 178 BuildCallback(this, &CountryRulesRetriever::OnDataReady)); | |
| 179 } | |
| 180 } | |
| 181 } | |
| 182 | |
| 183 if (requests_.empty()) { | |
| 184 (*rules_ready_)(success_, country_code_, root_.Pass()); | |
| 185 Reset(); | |
| 186 } | |
| 187 } | |
| 188 | |
| 189 void CountryRulesRetriever::Reset() { | |
| 190 requests_.clear(); | |
| 191 country_code_.clear(); | |
| 192 rules_ready_.reset(); | |
| 193 root_.reset(); | |
| 194 success_ = true; | |
|
Evan Stade
2014/01/08 01:22:46
this is surprising.
please use gerrit instead
2014/01/08 02:04:40
Changed the variable description to "False if at l
| |
| 195 default_language_.clear(); | |
| 196 languages_.clear(); | |
| 197 } | |
| 198 | |
| 199 } // namespace addressinput | |
| 200 } // namespace i18n | |
| OLD | NEW |