Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(837)

Unified Diff: third_party/libaddressinput/chromium/cpp/src/country_rules_retriever.cc

Issue 109323011: [rac] Download all rules for a country code in libaddressinput. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Address comments. Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/libaddressinput/chromium/cpp/src/country_rules_retriever.cc
diff --git a/third_party/libaddressinput/chromium/cpp/src/country_rules_retriever.cc b/third_party/libaddressinput/chromium/cpp/src/country_rules_retriever.cc
new file mode 100644
index 0000000000000000000000000000000000000000..d0128766bc6b96da4fbef74a78e2fd1f30fc21af
--- /dev/null
+++ b/third_party/libaddressinput/chromium/cpp/src/country_rules_retriever.cc
@@ -0,0 +1,262 @@
+// Copyright (C) 2014 Google Inc.
+//
+// Licensed 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 "country_rules_retriever.h"
+
+#include <libaddressinput/address_field.h>
+#include <libaddressinput/callback.h>
+#include <libaddressinput/util/basictypes.h>
+#include <libaddressinput/util/scoped_ptr.h>
+
+#include <cassert>
+#include <cstddef>
+#include <map>
+#include <string>
+#include <utility>
+
+#include "retriever.h"
+#include "rule.h"
+#include "ruleset.h"
+#include "util/stl_util.h"
+
+namespace i18n {
+namespace addressinput {
+
+// Information about data requests sent to Retriever. This data is not returned
+// as part of the ruleset, but is useful in constructing the ruleset
+// asynchronously.
+struct CountryRulesRetriever::RequestData {
+ // Does not take ownership of |parent|.
+ RequestData(RulesetData* ruleset_data,
+ Ruleset* parent,
+ AddressField level,
+ bool is_language_code,
+ const std::string& id)
+ : ruleset_data(ruleset_data),
+ parent(parent),
+ level(level),
+ is_language_code(is_language_code),
+ id(id) {}
+
+ ~RequestData() {}
+
+ // Information about the ruleset being downloaded.
+ RulesetData* ruleset_data;
+
+ // The parent ruleset of the data being downloaded. If NULL, then this is the
+ // root ruleset at the COUNTRY level. The language-specific and sub-region
+ // rules are added to this ruleset. Owned by |RulesetData|.
+ Ruleset* parent;
+
+ // The level of the data being requested. Ranges from COUNTRY to
+ // DEPENDENT_LOCALITY. If COUNTRY, then the rule should use default rules from
+ // Rule::GetDefault().
+ AddressField level;
+
+ // If true, then |id| is a language. The data received for this request should
+ // be placed into a language-specific rule.
+ bool is_language_code;
+
+ // Can be a region name (e.g. "CA") or a language (e.g. "fr"). Used to add a
+ // sub-region or a language-specific rule to |parent|.
+ std::string id;
+};
+
+// Stores information about a ruleset that is being retrieved for a country
+// code.
+class CountryRulesRetriever::RulesetData {
+ public:
+ RulesetData(const std::string& country_code,
+ scoped_ptr<CountryRulesRetriever::Callback> rules_ready)
+ : country_code_(country_code),
+ rules_ready_(rules_ready.Pass()),
+ root_(),
+ num_requested_(0),
+ num_received_(0),
+ success_(true),
+ default_language_(),
+ languages_() {}
+
+ ~RulesetData() {}
+
+ // Sends the |root_| ruleset to |rules_ready_| callback.
+ void InvokeRulesReadyCallback() {
+ (*rules_ready_)(success_, country_code_, root_.Pass());
+ }
+
+ // The country code for which to retrieve the ruleset. Passed to the callback
+ // method to identify the ruleset. Examples: "US", "CA", "CH", etc.
+ const std::string country_code_;
+
+ // The callback to invoke when the ruleset has been retrieved.
+ scoped_ptr<CountryRulesRetriever::Callback> rules_ready_;
+
+ // The top-level ruleset for the country code. Passed to the callback method
+ // as the result of the query.
+ scoped_ptr<Ruleset> root_;
+
+ // The number of requests sent to Retriever. Used to keep track of pending
+ // requests.
+ int num_requested_;
+
+ // The number of responses received from Retriever. Used to determine when the
+ // ruleset construction is finished, by comparing this number to
+ // |num_requested_|.
+ int num_received_;
+
+ // True if all requests to Retriever succeeded. Passed to the callback method
+ // as an indication of whether ruleset retrieval succeeded.
+ bool success_;
+
+ // The default language for the country code. This value is parsed from the
+ // country-level rule for the country code and is used to filter out the
+ // default language from the list of all supported languages for a country.
+ // For example, the list of supported languages for Canada is ["en", "fr"],
+ // but the default language is "en". Data requests for "data/CA/AB--fr" will
+ // succeed, but "data/CA/AB--en" will not return data.
+ std::string default_language_;
+
+ // The list of all supported languages for the country code. This value is
+ // parsed from the country-level rule for the country and is used to download
+ // language-specific rules.
+ std::vector<std::string> languages_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(RulesetData);
+};
+
+CountryRulesRetriever::CountryRulesRetriever(scoped_ptr<Retriever> retriever)
+ : retriever_(retriever.Pass()) {
+ assert(retriever_ != NULL);
+}
+
+CountryRulesRetriever::~CountryRulesRetriever() {
+ STLDeleteContainerPointers(rulesets_.begin(), rulesets_.end());
+}
+
+void CountryRulesRetriever::RetrieveRules(
+ const std::string& country_code,
+ scoped_ptr<Callback> rules_ready) {
+ RulesetData* ruleset_data = new RulesetData(country_code, rules_ready.Pass());
+ rulesets_.push_back(ruleset_data);
Evan Stade 2014/01/07 20:09:58 why would you need to retrieve rules for more than
please use gerrit instead 2014/01/07 22:11:08 The user might rapidly switch the country combobox
Evan Stade 2014/01/07 22:13:13 in which case you could/should probably abandon th
please use gerrit instead 2014/01/07 22:57:09 Done.
+
+ // Key construction:
+ // https://code.google.com/p/libaddressinput/wiki/AddressValidationMetadata
+ // Example of a country-level key: "data/CA".
+ std::string key = "data/" + ruleset_data->country_code_;
+ requests_.insert(std::make_pair(
+ key, RequestData(ruleset_data, NULL, COUNTRY, false, std::string())));
+
+ ++ruleset_data->num_requested_;
+ retriever_->Retrieve(
+ key, BuildCallback(this, &CountryRulesRetriever::OnDataReady));
+}
+
+void CountryRulesRetriever::OnDataReady(bool success,
+ const std::string& key,
+ const std::string& data) {
+ std::map<std::string, RequestData>::iterator request_it =
+ requests_.find(key);
Evan Stade 2014/01/07 20:09:58 remove request_it now that you're done with it aft
please use gerrit instead 2014/01/07 22:11:08 Done.
+ assert(request_it != requests_.end());
+ RequestData& request = request_it->second;
+
+ RulesetData* ruleset_data = request.ruleset_data;
+ assert(ruleset_data != NULL);
+
+ ruleset_data->success_ &= success;
+ ++ruleset_data->num_received_;
+
+ // All country-level rules are based on the default rule.
+ scoped_ptr<Rule> rule(new Rule);
+ if (request.level == COUNTRY) {
+ rule->CopyFrom(Rule::GetDefault());
+ }
+
+ ruleset_data->success_ &= rule->ParseSerializedRule(data);
+
+ // Place the rule in the correct location in the ruleset.
+ Ruleset* ruleset = NULL;
+ if (request.is_language_code) {
+ assert(request.parent != NULL);
+ request.parent->AddLanguageCode(request.id, rule.Pass());
+ ruleset = request.parent;
+ } else if (request.level == COUNTRY) {
+ // The default language and all supported languages for the country code are
+ // in the country-level rule without a language code identifier. For
+ // example: "data/CA".
+ ruleset_data->default_language_ = rule->GetLanguage();
+ ruleset_data->languages_ = rule->GetLanguages();
+
+ ruleset_data->root_.reset(new Ruleset(rule.Pass()));
+ ruleset = ruleset_data->root_.get();
+ } else {
+ assert(request.parent != NULL);
+ ruleset = request.parent->AddSubRegion(request.id, rule.Pass());
+ }
+
+ if (!request.is_language_code) {
+ // Retrieve the language-specific rules for this region.
+ for (std::vector<std::string>::const_iterator
+ lang_it = ruleset_data->languages_.begin();
+ lang_it != ruleset_data->languages_.end();
+ ++lang_it) {
+ if (*lang_it == ruleset_data->default_language_) {
+ continue;
+ }
+ // Example of a language-specific key: "data/CA--fr".
+ std::string language_code_key = key + "--" + *lang_it;
+ requests_.insert(std::make_pair(
+ key,
+ RequestData(ruleset_data, ruleset, request.level, true, *lang_it)));
+ ++ruleset_data->num_requested_;
+ retriever_->Retrieve(
+ language_code_key,
+ BuildCallback(this, &CountryRulesRetriever::OnDataReady));
+ }
+
+ if (request.level < DEPENDENT_LOCALITY) {
+ // Retrieve the sub-region rules for this region.
+ for (std::vector<std::string>::const_iterator
+ subkey_it = ruleset->rule().GetSubKeys().begin();
+ subkey_it != ruleset->rule().GetSubKeys().end();
+ ++subkey_it) {
+ // Example of a sub-region key: "data/CA/AB".
+ std::string sub_region_key = key + "/" + *subkey_it;
+ requests_.insert(std::make_pair(
+ key,
+ RequestData(ruleset_data,
+ ruleset,
+ static_cast<AddressField>(request.level + 1),
+ false,
+ *subkey_it)));
+ ++ruleset_data->num_requested_;
+ retriever_->Retrieve(
+ sub_region_key,
+ BuildCallback(this, &CountryRulesRetriever::OnDataReady));
+ }
+ }
+ }
+
+ if (ruleset_data->num_received_ == ruleset_data->num_requested_) {
+ ruleset_data->InvokeRulesReadyCallback();
+ std::vector<RulesetData*>::iterator ruleset_it =
+ std::find(rulesets_.begin(), rulesets_.end(), ruleset_data);
+ assert(ruleset_it != rulesets_.end());
+ rulesets_.erase(ruleset_it);
+ delete ruleset_data;
+ }
+}
+
+} // namespace addressinput
+} // namespace i18n

Powered by Google App Engine
This is Rietveld 408576698