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