history_data_store.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
1// Copyright 2013 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 "chrome/browser/ui/app_list/search/history_data_store.h" 6 7#include "base/callback.h" 8#include "base/json/json_file_value_serializer.h" 9#include "base/json/json_string_value_serializer.h" 10#include "base/strings/string_number_conversions.h" 11#include "base/values.h" 12 13namespace app_list { 14 15namespace { 16 17const char kKeyVersion[] = "version"; 18const char kCurrentVersion[] = "1"; 19 20const char kKeyAssociations[] = "associations"; 21const char kKeyPrimary[] = "p"; 22const char kKeySecondary[] = "s"; 23const char kKeyUpdateTime[] = "t"; 24 25// Extracts strings from ListValue. 26void GetSecondary(const base::ListValue* list, 27 HistoryData::SecondaryDeque* secondary) { 28 HistoryData::SecondaryDeque results; 29 for (base::ListValue::const_iterator it = list->begin(); 30 it != list->end(); ++it) { 31 std::string str; 32 if (!(*it)->GetAsString(&str)) 33 return; 34 35 results.push_back(str); 36 } 37 38 secondary->swap(results); 39} 40 41// V1 format json dictionary: 42// { 43// "version": "1", 44// "associations": { 45// "user typed query": { 46// "p" : "result id of primary association", 47// "s" : [ 48// "result id of 1st (oldest) secondary association", 49// ... 50// "result id of the newest secondary association" 51// ], 52// "t" : "last_update_timestamp" 53// }, 54// ... 55// } 56// } 57scoped_ptr<HistoryData::Associations> Parse( 58 scoped_ptr<base::DictionaryValue> dict) { 59 std::string version; 60 if (!dict->GetStringWithoutPathExpansion(kKeyVersion, &version) || 61 version != kCurrentVersion) { 62 return scoped_ptr<HistoryData::Associations>(); 63 } 64 65 const base::DictionaryValue* assoc_dict = NULL; 66 if (!dict->GetDictionaryWithoutPathExpansion(kKeyAssociations, 67 &assoc_dict) || 68 !assoc_dict) { 69 return scoped_ptr<HistoryData::Associations>(); 70 } 71 72 scoped_ptr<HistoryData::Associations> data(new HistoryData::Associations); 73 for (base::DictionaryValue::Iterator it(*assoc_dict); 74 !it.IsAtEnd(); it.Advance()) { 75 const base::DictionaryValue* entry_dict = NULL; 76 if (!it.value().GetAsDictionary(&entry_dict)) 77 continue; 78 79 std::string primary; 80 std::string update_time_string; 81 if (!entry_dict->GetStringWithoutPathExpansion(kKeyPrimary, &primary) || 82 !entry_dict->GetStringWithoutPathExpansion(kKeyUpdateTime, 83 &update_time_string)) { 84 continue; 85 } 86 87 const base::ListValue* secondary_list = NULL; 88 HistoryData::SecondaryDeque secondary; 89 if (entry_dict->GetListWithoutPathExpansion(kKeySecondary, &secondary_list)) 90 GetSecondary(secondary_list, &secondary); 91 92 const std::string& query = it.key(); 93 HistoryData::Data& association_data = (*data.get())[query]; 94 association_data.primary = primary; 95 association_data.secondary.swap(secondary); 96 97 int64 update_time_val; 98 base::StringToInt64(update_time_string, &update_time_val); 99 association_data.update_time = 100 base::Time::FromInternalValue(update_time_val); 101 } 102 103 return data.Pass(); 104} 105 106} // namespace 107 108HistoryDataStore::HistoryDataStore() 109 : cached_dict_(new base::DictionaryValue()) { 110 Init(cached_dict_.get()); 111} 112 113HistoryDataStore::HistoryDataStore( 114 scoped_refptr<DictionaryDataStore> data_store) 115 : data_store_(data_store) { 116 Init(data_store_->cached_dict()); 117} 118 119HistoryDataStore::~HistoryDataStore() { 120} 121 122void HistoryDataStore::Init(base::DictionaryValue* cached_dict) { 123 DCHECK(cached_dict); 124 cached_dict->SetString(kKeyVersion, kCurrentVersion); 125 cached_dict->Set(kKeyAssociations, new base::DictionaryValue); 126} 127 128void HistoryDataStore::Flush( 129 const DictionaryDataStore::OnFlushedCallback& on_flushed) { 130 if (data_store_.get()) 131 data_store_->Flush(on_flushed); 132 else 133 on_flushed.Run(); 134} 135 136void HistoryDataStore::Load( 137 const HistoryDataStore::OnLoadedCallback& on_loaded) { 138 if (data_store_.get()) { 139 data_store_->Load(base::Bind(&HistoryDataStore::OnDictionaryLoadedCallback, 140 this, 141 on_loaded)); 142 } else { 143 OnDictionaryLoadedCallback( 144 on_loaded, make_scoped_ptr(cached_dict_->DeepCopy())); 145 } 146} 147 148void HistoryDataStore::SetPrimary(const std::string& query, 149 const std::string& result) { 150 base::DictionaryValue* entry_dict = GetEntryDict(query); 151 entry_dict->SetWithoutPathExpansion(kKeyPrimary, 152 new base::StringValue(result)); 153 if (data_store_.get()) 154 data_store_->ScheduleWrite(); 155} 156 157void HistoryDataStore::SetSecondary( 158 const std::string& query, 159 const HistoryData::SecondaryDeque& results) { 160 scoped_ptr<base::ListValue> results_list(new base::ListValue); 161 for (size_t i = 0; i< results.size(); ++i) 162 results_list->AppendString(results[i]); 163 164 base::DictionaryValue* entry_dict = GetEntryDict(query); 165 entry_dict->SetWithoutPathExpansion(kKeySecondary, results_list.release()); 166 if (data_store_.get()) 167 data_store_->ScheduleWrite(); 168} 169 170void HistoryDataStore::SetUpdateTime(const std::string& query, 171 const base::Time& update_time) { 172 base::DictionaryValue* entry_dict = GetEntryDict(query); 173 entry_dict->SetWithoutPathExpansion(kKeyUpdateTime, 174 new base::StringValue(base::Int64ToString( 175 update_time.ToInternalValue()))); 176 if (data_store_.get()) 177 data_store_->ScheduleWrite(); 178} 179 180void HistoryDataStore::Delete(const std::string& query) { 181 base::DictionaryValue* assoc_dict = GetAssociationDict(); 182 assoc_dict->RemoveWithoutPathExpansion(query, NULL); 183 if (data_store_.get()) 184 data_store_->ScheduleWrite(); 185} 186 187base::DictionaryValue* HistoryDataStore::GetAssociationDict() { 188 base::DictionaryValue* cached_dict = 189 cached_dict_ ? cached_dict_.get() : data_store_->cached_dict(); 190 DCHECK(cached_dict); 191 192 base::DictionaryValue* assoc_dict = NULL; 193 CHECK(cached_dict->GetDictionary(kKeyAssociations, &assoc_dict) && 194 assoc_dict); 195 196 return assoc_dict; 197} 198 199base::DictionaryValue* HistoryDataStore::GetEntryDict( 200 const std::string& query) { 201 base::DictionaryValue* assoc_dict = GetAssociationDict(); 202 203 base::DictionaryValue* entry_dict = NULL; 204 if (!assoc_dict->GetDictionaryWithoutPathExpansion(query, &entry_dict)) { 205 // Creates one if none exists. Ownership is taken in the set call after. 206 entry_dict = new base::DictionaryValue; 207 assoc_dict->SetWithoutPathExpansion(query, entry_dict); 208 } 209 210 return entry_dict; 211} 212 213void HistoryDataStore::OnDictionaryLoadedCallback( 214 OnLoadedCallback callback, scoped_ptr<base::DictionaryValue> dict) { 215 if (!dict) { 216 callback.Run(scoped_ptr<HistoryData::Associations>()); 217 } else { 218 callback.Run(Parse(dict.Pass()).Pass()); 219 } 220} 221 222} // namespace app_list 223