Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / libaddressinput / src / cpp / src / ondemand_supply_task.cc
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 "ondemand_supply_task.h"
16
17 #include <libaddressinput/address_field.h>
18 #include <libaddressinput/callback.h>
19 #include <libaddressinput/supplier.h>
20 #include <libaddressinput/util/basictypes.h>
21
22 #include <algorithm>
23 #include <cassert>
24 #include <cstddef>
25 #include <map>
26 #include <set>
27 #include <string>
28 #include <utility>
29
30 #include "lookup_key.h"
31 #include "retriever.h"
32 #include "rule.h"
33
34 namespace i18n {
35 namespace addressinput {
36
37 OndemandSupplyTask::OndemandSupplyTask(
38     const LookupKey& lookup_key,
39     std::map<std::string, const Rule*>* rules,
40     const Supplier::Callback& supplied)
41     : hierarchy_(),
42       pending_(),
43       lookup_key_(lookup_key),
44       rule_cache_(rules),
45       supplied_(supplied),
46       retrieved_(BuildCallback(this, &OndemandSupplyTask::Load)),
47       success_(true) {
48   assert(rule_cache_ != NULL);
49   assert(retrieved_ != NULL);
50 }
51
52 OndemandSupplyTask::~OndemandSupplyTask() {
53 }
54
55 void OndemandSupplyTask::Queue(const std::string& key) {
56   assert(pending_.find(key) == pending_.end());
57   pending_.insert(key);
58 }
59
60 void OndemandSupplyTask::Retrieve(const Retriever& retriever) {
61   if (pending_.empty()) {
62     Loaded();
63   } else {
64     // When the final pending rule has been retrieved, the retrieved_ callback,
65     // implemented by Load(), will finish by calling Loaded(), which will finish
66     // by delete'ing this OndemandSupplyTask object. So after the final call to
67     // retriever.Retrieve() no attributes of this object can be accessed (as the
68     // object then no longer will exist, if the final callback has finished by
69     // then), and the condition statement of the loop must therefore not use the
70     // otherwise obvious it != pending_.end() but instead test a local variable
71     // that isn't affected by the object being deleted.
72     bool done = false;
73     for (std::set<std::string>::const_iterator it = pending_.begin(); !done; ) {
74       const std::string& key = *it++;
75       done = it == pending_.end();
76       retriever.Retrieve(key, *retrieved_);
77     }
78   }
79 }
80
81 void OndemandSupplyTask::Load(bool success,
82                               const std::string& key,
83                               const std::string& data) {
84   size_t depth = std::count(key.begin(), key.end(), '/') - 1;
85   assert(depth < arraysize(LookupKey::kHierarchy));
86
87   // Sanity check: This key should be present in the set of pending requests.
88   size_t status = pending_.erase(key);
89   assert(status == 1);  // There will always be one item erased from the set.
90   (void)status;  // Prevent unused variable if assert() is optimized away.
91
92   if (success) {
93     // The address metadata server will return the empty JSON "{}" when it
94     // successfully performed a lookup, but didn't find any data for that key.
95     if (data != "{}") {
96       Rule* rule = new Rule;
97       if (LookupKey::kHierarchy[depth] == COUNTRY) {
98         // All rules on the COUNTRY level inherit from the default rule.
99         rule->CopyFrom(Rule::GetDefault());
100       }
101       if (rule->ParseSerializedRule(data)) {
102         // Try inserting the Rule object into the rule_cache_ map, or else find
103         // the already existing Rule object with the same ID already in the map.
104         // It is possible that a key was queued even though the corresponding
105         // Rule object is already in the cache, as the data server is free to do
106         // advanced normalization and aliasing so that the ID of the data
107         // returned is different from the key requested. (It would be possible
108         // to cache such aliases, to increase performance in the case where a
109         // certain alias is requested repeatedly, but such a cache would then
110         // have to be kept to some limited size to not grow indefinitely with
111         // every possible permutation of a name recognized by the data server.)
112         std::pair<std::map<std::string, const Rule*>::iterator, bool> result =
113             rule_cache_->insert(std::make_pair(rule->GetId(), rule));
114         if (!result.second) {  // There was already an entry with this ID.
115           delete rule;
116         }
117         // Pointer to object in the map.
118         hierarchy_.rule[depth] = result.first->second;
119       } else {
120         delete rule;
121         success_ = false;
122       }
123     }
124   } else {
125     success_ = false;
126   }
127
128   if (pending_.empty()) {
129     Loaded();
130   }
131 }
132
133 void OndemandSupplyTask::Loaded() {
134   supplied_(success_, lookup_key_, hierarchy_);
135   delete this;
136 }
137
138 }  // namespace addressinput
139 }  // namespace i18n