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

Side by Side 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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(RulesetData* ruleset_data,
42 Ruleset* parent,
43 AddressField level,
44 bool is_language_code,
45 const std::string& id)
46 : ruleset_data(ruleset_data),
47 parent(parent),
48 level(level),
49 is_language_code(is_language_code),
50 id(id) {}
51
52 ~RequestData() {}
53
54 // Information about the ruleset being downloaded.
55 RulesetData* ruleset_data;
56
57 // The parent ruleset of the data being downloaded. If NULL, then this is the
58 // root ruleset at the COUNTRY level. The language-specific and sub-region
59 // rules are added to this ruleset. Owned by |RulesetData|.
60 Ruleset* parent;
61
62 // The level of the data being requested. Ranges from COUNTRY to
63 // DEPENDENT_LOCALITY. If COUNTRY, then the rule should use default rules from
64 // Rule::GetDefault().
65 AddressField level;
66
67 // If true, then |id| is a language. The data received for this request should
68 // be placed into a language-specific rule.
69 bool is_language_code;
70
71 // Can be a region name (e.g. "CA") or a language (e.g. "fr"). Used to add a
72 // sub-region or a language-specific rule to |parent|.
73 std::string id;
74 };
75
76 // Stores information about a ruleset that is being retrieved for a country
77 // code.
78 class CountryRulesRetriever::RulesetData {
79 public:
80 RulesetData(const std::string& country_code,
81 scoped_ptr<CountryRulesRetriever::Callback> rules_ready)
82 : country_code_(country_code),
83 rules_ready_(rules_ready.Pass()),
84 root_(),
85 num_requested_(0),
86 num_received_(0),
87 success_(true),
88 default_language_(),
89 languages_() {}
90
91 ~RulesetData() {}
92
93 // Sends the |root_| ruleset to |rules_ready_| callback.
94 void InvokeRulesReadyCallback() {
95 (*rules_ready_)(success_, country_code_, root_.Pass());
96 }
97
98 // The country code for which to retrieve the ruleset. Passed to the callback
99 // method to identify the ruleset. Examples: "US", "CA", "CH", etc.
100 const std::string country_code_;
101
102 // The callback to invoke when the ruleset has been retrieved.
103 scoped_ptr<CountryRulesRetriever::Callback> rules_ready_;
104
105 // The top-level ruleset for the country code. Passed to the callback method
106 // as the result of the query.
107 scoped_ptr<Ruleset> root_;
108
109 // The number of requests sent to Retriever. Used to keep track of pending
110 // requests.
111 int num_requested_;
112
113 // The number of responses received from Retriever. Used to determine when the
114 // ruleset construction is finished, by comparing this number to
115 // |num_requested_|.
116 int num_received_;
117
118 // True if all requests to Retriever succeeded. Passed to the callback method
119 // as an indication of whether ruleset retrieval succeeded.
120 bool success_;
121
122 // The default language for the country code. This value is parsed from the
123 // country-level rule for the country code and is used to filter out the
124 // default language from the list of all supported languages for a country.
125 // For example, the list of supported languages for Canada is ["en", "fr"],
126 // but the default language is "en". Data requests for "data/CA/AB--fr" will
127 // succeed, but "data/CA/AB--en" will not return data.
128 std::string default_language_;
129
130 // The list of all supported languages for the country code. This value is
131 // parsed from the country-level rule for the country and is used to download
132 // language-specific rules.
133 std::vector<std::string> languages_;
134
135 private:
136 DISALLOW_COPY_AND_ASSIGN(RulesetData);
137 };
138
139 CountryRulesRetriever::CountryRulesRetriever(scoped_ptr<Retriever> retriever)
140 : retriever_(retriever.Pass()) {
141 assert(retriever_ != NULL);
142 }
143
144 CountryRulesRetriever::~CountryRulesRetriever() {
145 STLDeleteContainerPointers(rulesets_.begin(), rulesets_.end());
146 }
147
148 void CountryRulesRetriever::RetrieveRules(
149 const std::string& country_code,
150 scoped_ptr<Callback> rules_ready) {
151 RulesetData* ruleset_data = new RulesetData(country_code, rules_ready.Pass());
152 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.
153
154 // Key construction:
155 // https://code.google.com/p/libaddressinput/wiki/AddressValidationMetadata
156 // Example of a country-level key: "data/CA".
157 std::string key = "data/" + ruleset_data->country_code_;
158 requests_.insert(std::make_pair(
159 key, RequestData(ruleset_data, NULL, COUNTRY, false, std::string())));
160
161 ++ruleset_data->num_requested_;
162 retriever_->Retrieve(
163 key, BuildCallback(this, &CountryRulesRetriever::OnDataReady));
164 }
165
166 void CountryRulesRetriever::OnDataReady(bool success,
167 const std::string& key,
168 const std::string& data) {
169 std::map<std::string, RequestData>::iterator request_it =
170 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.
171 assert(request_it != requests_.end());
172 RequestData& request = request_it->second;
173
174 RulesetData* ruleset_data = request.ruleset_data;
175 assert(ruleset_data != NULL);
176
177 ruleset_data->success_ &= success;
178 ++ruleset_data->num_received_;
179
180 // All country-level rules are based on the default rule.
181 scoped_ptr<Rule> rule(new Rule);
182 if (request.level == COUNTRY) {
183 rule->CopyFrom(Rule::GetDefault());
184 }
185
186 ruleset_data->success_ &= rule->ParseSerializedRule(data);
187
188 // Place the rule in the correct location in the ruleset.
189 Ruleset* ruleset = NULL;
190 if (request.is_language_code) {
191 assert(request.parent != NULL);
192 request.parent->AddLanguageCode(request.id, rule.Pass());
193 ruleset = request.parent;
194 } else if (request.level == COUNTRY) {
195 // The default language and all supported languages for the country code are
196 // in the country-level rule without a language code identifier. For
197 // example: "data/CA".
198 ruleset_data->default_language_ = rule->GetLanguage();
199 ruleset_data->languages_ = rule->GetLanguages();
200
201 ruleset_data->root_.reset(new Ruleset(rule.Pass()));
202 ruleset = ruleset_data->root_.get();
203 } else {
204 assert(request.parent != NULL);
205 ruleset = request.parent->AddSubRegion(request.id, rule.Pass());
206 }
207
208 if (!request.is_language_code) {
209 // Retrieve the language-specific rules for this region.
210 for (std::vector<std::string>::const_iterator
211 lang_it = ruleset_data->languages_.begin();
212 lang_it != ruleset_data->languages_.end();
213 ++lang_it) {
214 if (*lang_it == ruleset_data->default_language_) {
215 continue;
216 }
217 // Example of a language-specific key: "data/CA--fr".
218 std::string language_code_key = key + "--" + *lang_it;
219 requests_.insert(std::make_pair(
220 key,
221 RequestData(ruleset_data, ruleset, request.level, true, *lang_it)));
222 ++ruleset_data->num_requested_;
223 retriever_->Retrieve(
224 language_code_key,
225 BuildCallback(this, &CountryRulesRetriever::OnDataReady));
226 }
227
228 if (request.level < DEPENDENT_LOCALITY) {
229 // Retrieve the sub-region rules for this region.
230 for (std::vector<std::string>::const_iterator
231 subkey_it = ruleset->rule().GetSubKeys().begin();
232 subkey_it != ruleset->rule().GetSubKeys().end();
233 ++subkey_it) {
234 // Example of a sub-region key: "data/CA/AB".
235 std::string sub_region_key = key + "/" + *subkey_it;
236 requests_.insert(std::make_pair(
237 key,
238 RequestData(ruleset_data,
239 ruleset,
240 static_cast<AddressField>(request.level + 1),
241 false,
242 *subkey_it)));
243 ++ruleset_data->num_requested_;
244 retriever_->Retrieve(
245 sub_region_key,
246 BuildCallback(this, &CountryRulesRetriever::OnDataReady));
247 }
248 }
249 }
250
251 if (ruleset_data->num_received_ == ruleset_data->num_requested_) {
252 ruleset_data->InvokeRulesReadyCallback();
253 std::vector<RulesetData*>::iterator ruleset_it =
254 std::find(rulesets_.begin(), rulesets_.end(), ruleset_data);
255 assert(ruleset_it != rulesets_.end());
256 rulesets_.erase(ruleset_it);
257 delete ruleset_data;
258 }
259 }
260
261 } // namespace addressinput
262 } // namespace i18n
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698