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 #include "retriever.h" 16 17 #include <libaddressinput/callback.h> 18 #include <libaddressinput/downloader.h> 19 #include <libaddressinput/storage.h> 20 #include <libaddressinput/util/basictypes.h> 21 #include <libaddressinput/util/scoped_ptr.h> 22 23 #include <cassert> 24 #include <cstddef> 25 #include <string> 26 27 #include "lookup_key_util.h" 28 #include "validating_storage.h" 29 30 namespace i18n { 31 namespace addressinput { 32 33 namespace { 34 35 class Helper { 36 public: 37 // Does not take ownership of its parameters. 38 Helper(const std::string& key, 39 const Retriever::Callback& retrieved, 40 const LookupKeyUtil& lookup_key_util, 41 const Downloader& downloader, 42 ValidatingStorage* storage) 43 : retrieved_(retrieved), 44 lookup_key_util_(lookup_key_util), 45 downloader_(downloader), 46 storage_(storage), 47 downloaded_(BuildCallback(this, &Helper::OnDownloaded)), 48 validated_data_ready_( 49 BuildCallback(this, &Helper::OnValidatedDataReady)), 50 stale_data_() { 51 assert(storage_ != NULL); 52 storage_->Get(key, *validated_data_ready_); 53 } 54 55 private: 56 ~Helper() {} 57 58 void OnValidatedDataReady(bool success, 59 const std::string& key, 60 std::string* data) { 61 if (success) { 62 assert(data != NULL); 63 retrieved_(success, key, *data); 64 delete this; 65 } else { 66 // Validating storage returns (false, key, stale-data) for valid but stale 67 // data. If |data| is empty, however, then it's either missing or invalid. 68 if (data != NULL && !data->empty()) { 69 stale_data_ = *data; 70 } 71 downloader_.Download(lookup_key_util_.GetUrlForKey(key), *downloaded_); 72 } 73 delete data; 74 } 75 76 void OnDownloaded(bool success, const std::string& url, std::string* data) { 77 const std::string& key = lookup_key_util_.GetKeyForUrl(url); 78 if (success) { 79 assert(data != NULL); 80 retrieved_(true, key, *data); 81 storage_->Put(key, data); 82 data = NULL; // Deleted by Storage::Put(). 83 } else if (!stale_data_.empty()) { 84 // Reuse the stale data if a download fails. It's better to have slightly 85 // outdated validation rules than to suddenly lose validation ability. 86 retrieved_(true, key, stale_data_); 87 } else { 88 retrieved_(false, key, std::string()); 89 } 90 delete data; 91 delete this; 92 } 93 94 const Retriever::Callback& retrieved_; 95 const LookupKeyUtil& lookup_key_util_; 96 const Downloader& downloader_; 97 ValidatingStorage* storage_; 98 scoped_ptr<Downloader::Callback> downloaded_; 99 scoped_ptr<Storage::Callback> validated_data_ready_; 100 std::string stale_data_; 101 102 DISALLOW_COPY_AND_ASSIGN(Helper); 103 }; 104 105 } // namespace 106 107 Retriever::Retriever(const std::string& validation_data_url, 108 const Downloader* downloader, 109 Storage* storage) 110 : lookup_key_util_(validation_data_url), 111 downloader_(downloader), 112 storage_(new ValidatingStorage(storage)) { 113 assert(storage_ != NULL); 114 assert(downloader_ != NULL); 115 } 116 117 Retriever::~Retriever() {} 118 119 void Retriever::Retrieve(const std::string& key, 120 const Callback& retrieved) const { 121 new Helper(key, retrieved, lookup_key_util_, *downloader_, storage_.get()); 122 } 123 124 } // namespace addressinput 125 } // namespace i18n 126