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