• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "third_party/libaddressinput/chromium/chrome_address_validator.h"
6 
7 #include <cmath>
8 
9 #include "base/bind.h"
10 #include "base/location.h"
11 #include "base/logging.h"
12 #include "base/message_loop/message_loop.h"
13 #include "third_party/libaddressinput/chromium/addressinput_util.h"
14 #include "third_party/libaddressinput/chromium/input_suggester.h"
15 #include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_data.h"
16 #include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_normalizer.h"
17 #include "third_party/libaddressinput/src/cpp/include/libaddressinput/source.h"
18 #include "third_party/libaddressinput/src/cpp/include/libaddressinput/storage.h"
19 
20 namespace autofill {
21 namespace {
22 
23 using ::i18n::addressinput::AddressData;
24 using ::i18n::addressinput::AddressField;
25 using ::i18n::addressinput::AddressNormalizer;
26 using ::i18n::addressinput::BuildCallback;
27 using ::i18n::addressinput::FieldProblemMap;
28 using ::i18n::addressinput::PreloadSupplier;
29 using ::i18n::addressinput::Source;
30 using ::i18n::addressinput::Storage;
31 
32 using ::i18n::addressinput::ADMIN_AREA;
33 using ::i18n::addressinput::DEPENDENT_LOCALITY;
34 using ::i18n::addressinput::POSTAL_CODE;
35 
36 // The maximum number attempts to load rules.
37 static const int kMaxAttemptsNumber = 8;
38 
39 }  // namespace
40 
AddressValidator(scoped_ptr<Source> source,scoped_ptr<Storage> storage,LoadRulesListener * load_rules_listener)41 AddressValidator::AddressValidator(scoped_ptr<Source> source,
42                                    scoped_ptr<Storage> storage,
43                                    LoadRulesListener* load_rules_listener)
44     : supplier_(new PreloadSupplier(source.release(),
45                                     storage.release())),
46       input_suggester_(new InputSuggester(supplier_.get())),
47       normalizer_(new AddressNormalizer(supplier_.get())),
48       validator_(new ::i18n::addressinput::AddressValidator(supplier_.get())),
49       validated_(BuildCallback(this, &AddressValidator::Validated)),
50       rules_loaded_(BuildCallback(this, &AddressValidator::RulesLoaded)),
51       load_rules_listener_(load_rules_listener),
52       weak_factory_(this) {}
53 
~AddressValidator()54 AddressValidator::~AddressValidator() {}
55 
LoadRules(const std::string & region_code)56 void AddressValidator::LoadRules(const std::string& region_code) {
57   attempts_number_[region_code] = 0;
58   supplier_->LoadRules(region_code, *rules_loaded_);
59 }
60 
ValidateAddress(const AddressData & address,const FieldProblemMap * filter,FieldProblemMap * problems) const61 AddressValidator::Status AddressValidator::ValidateAddress(
62     const AddressData& address,
63     const FieldProblemMap* filter,
64     FieldProblemMap* problems) const {
65   if (supplier_->IsPending(address.region_code)) {
66     if (problems)
67       addressinput::ValidateRequiredFields(address, filter, problems);
68     return RULES_NOT_READY;
69   }
70 
71   if (!supplier_->IsLoaded(address.region_code)) {
72     if (problems)
73       addressinput::ValidateRequiredFields(address, filter, problems);
74     return RULES_UNAVAILABLE;
75   }
76 
77   if (!problems)
78     return SUCCESS;
79 
80   validator_->Validate(address,
81                        true,  // Allow postal office boxes.
82                        true,  // Require recipient name.
83                        filter,
84                        problems,
85                        *validated_);
86 
87   return SUCCESS;
88 }
89 
GetSuggestions(const AddressData & user_input,AddressField focused_field,size_t suggestion_limit,std::vector<AddressData> * suggestions) const90 AddressValidator::Status AddressValidator::GetSuggestions(
91     const AddressData& user_input,
92     AddressField focused_field,
93     size_t suggestion_limit,
94     std::vector<AddressData>* suggestions) const {
95   if (supplier_->IsPending(user_input.region_code))
96     return RULES_NOT_READY;
97 
98   if (!supplier_->IsLoaded(user_input.region_code))
99     return RULES_UNAVAILABLE;
100 
101   if (!suggestions)
102     return SUCCESS;
103 
104   suggestions->clear();
105 
106   if (focused_field == POSTAL_CODE ||
107       (focused_field >= ADMIN_AREA && focused_field <= DEPENDENT_LOCALITY)) {
108     input_suggester_->GetSuggestions(
109         user_input, focused_field, suggestion_limit, suggestions);
110   }
111 
112   return SUCCESS;
113 }
114 
CanonicalizeAdministrativeArea(AddressData * address) const115 bool AddressValidator::CanonicalizeAdministrativeArea(
116     AddressData* address) const {
117   if (!supplier_->IsLoaded(address->region_code))
118     return false;
119 
120   // TODO: It would probably be beneficial to use the full canonicalization.
121   AddressData tmp(*address);
122   normalizer_->Normalize(&tmp);
123   address->administrative_area = tmp.administrative_area;
124 
125   return true;
126 }
127 
AddressValidator()128 AddressValidator::AddressValidator()
129     : load_rules_listener_(NULL), weak_factory_(this) {}
130 
GetBaseRetryPeriod() const131 base::TimeDelta AddressValidator::GetBaseRetryPeriod() const {
132   return base::TimeDelta::FromSeconds(8);
133 }
134 
Validated(bool success,const AddressData &,const FieldProblemMap &)135 void AddressValidator::Validated(bool success,
136                                  const AddressData&,
137                                  const FieldProblemMap&) {
138   DCHECK(success);
139 }
140 
RulesLoaded(bool success,const std::string & region_code,int)141 void AddressValidator::RulesLoaded(bool success,
142                                    const std::string& region_code,
143                                    int) {
144   if (load_rules_listener_)
145     load_rules_listener_->OnAddressValidationRulesLoaded(region_code, success);
146 
147   // Count the first failed attempt to load rules as well.
148   if (success || attempts_number_[region_code] + 1 >= kMaxAttemptsNumber)
149     return;
150 
151   base::MessageLoop::current()->PostDelayedTask(
152       FROM_HERE,
153       base::Bind(&AddressValidator::RetryLoadRules,
154                  weak_factory_.GetWeakPtr(),
155                  region_code),
156       GetBaseRetryPeriod() * pow(2, attempts_number_[region_code]++));
157 }
158 
RetryLoadRules(const std::string & region_code)159 void AddressValidator::RetryLoadRules(const std::string& region_code) {
160   // Do not reset retry count.
161   supplier_->LoadRules(region_code, *rules_loaded_);
162 }
163 
164 }  // namespace autofill
165