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

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: Fix debug build. 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) 2013 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 // CountryRulesRetriever uses Helper to download Rulesets (a tree of rules) for
16 // country codes. Helper builds a Ruleset and passes it to the
17 // CountryRulesRetriever::Callback in a scoped pointer. Helper uses a map of
18 // lookup keys (e.g. "data/CA/AB--fr") to RequestData objects to keep track of
19 // how the Ruleset should be built.
20
21 #include "country_rules_retriever.h"
22
23 #include <libaddressinput/address_field.h>
24 #include <libaddressinput/callback.h>
25 #include <libaddressinput/util/basictypes.h>
26 #include <libaddressinput/util/scoped_ptr.h>
27
28 #include <cassert>
29 #include <cstddef>
30 #include <string>
31
32 #include "retriever.h"
33 #include "rule.h"
34 #include "ruleset.h"
35
36 namespace i18n {
37 namespace addressinput {
38
39 namespace {
40
41 // Stores auxiliary information about data requests sent to Retriever. This data
42 // is not returned as part of the ruleset, but is useful in constructing the
43 // ruleset asynchronously.
44 struct RequestData {
45 // Does not take ownership of |parent|.
46 RequestData(Ruleset* parent,
47 AddressField level,
48 bool is_language_code,
49 const std::string& id)
50 : parent(parent),
51 level(level),
52 is_language_code(is_language_code),
53 id(id) {}
54 ~RequestData() {}
55
56 // The parent ruleset of the data being downloaded. If NULL, then this is the
57 // root ruleset at the COUNTRY level. The language-specific and sub-region
58 // rules are added to this ruleset. Owned by |Helper|.
59 Ruleset* parent;
60
61 // The level of the data being requested. Ranges from COUNTRY to
62 // DEPENDENT_LOCALITY. If COUNTRY, then the rule should use default rules from
63 // Rule::GetDefault().
64 AddressField level;
65
66 // If true, then |id| is a language. The data received for this request should
67 // be placed into a language-specific rule.
68 bool is_language_code;
69
70 // Can be a region name (e.g. "CA") or a language (e.g. "fr"). Used to add a
71 // sub-region or a language-specific rule to |parent|.
72 std::string id;
73 };
74
75 // Retrieves a ruleset for a single country code.
76 class Helper {
77 public:
78 // Uses |retriever| to recursively retrieve the ruleset for |country_code|.
79 // Invokes |rules_ready| callback when done.
80 Helper(const std::string& country_code,
81 scoped_ptr<CountryRulesRetriever::Callback> rules_ready,
82 const Retriever& retriever)
83 : country_code_(country_code),
84 rules_ready_(rules_ready.Pass()),
85 retriever_(retriever),
86 root_(),
87 num_requested_(1),
88 num_received_(0),
89 success_(true),
90 default_language_(),
91 languages_(),
92 requests_() {
93 // Key construction:
94 // https://code.google.com/p/libaddressinput/wiki/AddressValidationMetadata
95 // Example of a country-level key: "data/CA".
96 std::string key = "data/" + country_code_;
97 requests_.insert(std::make_pair(
98 key, RequestData(NULL, COUNTRY, false, std::string())));
99 retriever_.Retrieve(key, BuildCallback(this, &Helper::OnDataReady));
100 }
101
102 private:
103 ~Helper() {}
104
105 void OnDataReady(bool success,
106 const std::string& key,
107 const std::string& data) {
108 success_ &= success;
109 ++num_received_;
110
111 std::map<std::string, RequestData>::iterator request_it =
112 requests_.find(key);
113 assert(request_it != requests_.end());
114 RequestData& request = request_it->second;
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 // The default language and all supported languages for the country code are
125 // in the country-level rule without a language code identifier. For
126 // example: "data/CA".
127 if (request.level == COUNTRY && !request.is_language_code) {
128 default_language_ = rule->GetLanguage();
129 languages_ = rule->GetLanguages();
130 }
131
132 Ruleset* ruleset = NULL;
133 if (request.level == COUNTRY) {
134 root_.reset(new Ruleset(rule.Pass()));
135 ruleset = root_.get();
136 } else if (request.is_language_code) {
137 assert(request.parent != NULL);
138 request.parent->AddLanguageCode(request.id, rule.Pass());
139 // The |ruleset| is intentionally NULL.
140 } else {
141 assert(request.parent != NULL);
142 ruleset = request.parent->AddSubRegion(request.id, rule.Pass());
143 }
144
145 if (!request.is_language_code) {
146 // Retrieve the language-specific rules for this region.
147 for (std::vector<std::string>::const_iterator
148 lang_it = languages_.begin();
149 lang_it != languages_.end();
150 ++lang_it) {
151 if (*lang_it != default_language_) {
152 // Example of a language-specific key: "data/CA--fr".
153 std::string language_code_key = key + "--" + *lang_it;
154 requests_.insert(std::make_pair(
155 key, RequestData(ruleset, request.level, true, *lang_it)));
156 ++num_requested_;
157 retriever_.Retrieve(
158 language_code_key, BuildCallback(this, &Helper::OnDataReady));
159 }
160 }
161
162 if (request.level < DEPENDENT_LOCALITY) {
163 assert(ruleset->GetRule() != NULL);
164 // Retrieve the sub-region rules for this region.
165 for (std::vector<std::string>::const_iterator
166 subkey_it = ruleset->GetRule()->GetSubKeys().begin();
167 subkey_it != ruleset->GetRule()->GetSubKeys().end();
168 ++subkey_it) {
169 // Example of a sub-region key: "data/CA/AB".
170 std::string sub_region_key = key + "/" + *subkey_it;
171 requests_.insert(std::make_pair(
172 key,
173 RequestData(ruleset,
174 static_cast<AddressField>(request.level + 1),
175 false,
176 *subkey_it)));
177 ++num_requested_;
178 retriever_.Retrieve(
179 sub_region_key, BuildCallback(this, &Helper::OnDataReady));
180 }
181 }
182 }
183
184 if (num_received_ == num_requested_) {
185 (*rules_ready_)(success_, country_code_, root_.Pass());
186 delete this;
187 }
188 }
189
190 // The country code for which to retrieve the ruleset. Passed to the callback
191 // method to identify the ruleset. Examples: "US", "CA", "CH", etc.
192 const std::string country_code_;
193
194 // The callback to invoke when the ruleset has been retrieved.
195 scoped_ptr<CountryRulesRetriever::Callback> rules_ready_;
196
197 // The data retriever that can download serialized rules for one sub-region at
198 // a time.
199 const Retriever& retriever_;
200
201 // The top-level ruleset for the country code. Passed to the callback method
202 // as the result of the query.
203 scoped_ptr<Ruleset> root_;
204
205 // The number of requests sent to Retriever. Used to keep track of pending
206 // requests.
207 int num_requested_;
208
209 // The number of responses received from Retriever. Used to determine when the
210 // ruleset construction is finished, by comparing this number to
211 // |num_requested_|.
212 int num_received_;
213
214 // True if all requests to Retriever succeeded. Passed to the callback method
215 // as an indication of whether ruleset retrieval succeeded.
216 bool success_;
217
218 // The default language for the country code. This value is parsed from the
219 // country-level rule for the country code and is used to filter out the
220 // default language from the list of all supported languages for a country.
221 // For example, the list of supported languages for Canada is ["en", "fr"],
222 // but the default language is "en". Data requests for "data/CA/AB--fr" will
223 // succeed, but "data/CA/AB--en" will not return data.
224 std::string default_language_;
225
226 // The list of all supported languages for the country code. This value is
227 // parsed from the country-level rule for the country and is used to download
228 // language-specific rules.
229 std::vector<std::string> languages_;
230
231 // A map of data keys (e.g., "data/CA/AB--fr") to information that will help
232 // to parse the response data and place it in the correct location in the
233 // ruleset. For example, the RequestData for "data/CA/AB--fr" will specify
234 // that the retrieved rule is the "fr" language-specific rule for "data/CA/AB"
235 // ruleset.
236 std::map<std::string, RequestData> requests_;
237
238 DISALLOW_COPY_AND_ASSIGN(Helper);
239 };
240
241 } // namespace
242
243 CountryRulesRetriever::CountryRulesRetriever(
244 scoped_ptr<const Retriever> retriever)
245 : retriever_(retriever.Pass()) {
246 assert(retriever_ != NULL);
247 }
248
249 CountryRulesRetriever::~CountryRulesRetriever() {}
250
251 void CountryRulesRetriever::RetrieveRules(
252 const std::string& country_code,
253 scoped_ptr<Callback> rules_ready) const {
254 new Helper(country_code, rules_ready.Pass(), *retriever_);
Evan Stade 2014/01/06 22:54:19 this seems dangerous. How do you know Helper won't
please use gerrit instead 2014/01/06 23:44:35 This helper uses the same safety measure as all ot
Evan Stade 2014/01/07 00:03:15 Recall how I wanted to make it a rule that you onl
please use gerrit instead 2014/01/07 01:54:38 Done.
255 }
256
257 } // namespace addressinput
258 } // namespace i18n
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698