- add sources.
[platform/framework/web/crosswalk.git] / src / base / prefs / json_pref_store.cc
1 // Copyright (c) 2012 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 "base/prefs/json_pref_store.h"
6
7 #include <algorithm>
8
9 #include "base/bind.h"
10 #include "base/callback.h"
11 #include "base/file_util.h"
12 #include "base/json/json_file_value_serializer.h"
13 #include "base/json/json_string_value_serializer.h"
14 #include "base/memory/ref_counted.h"
15 #include "base/message_loop/message_loop_proxy.h"
16 #include "base/sequenced_task_runner.h"
17 #include "base/threading/sequenced_worker_pool.h"
18 #include "base/values.h"
19
20 namespace {
21
22 // Some extensions we'll tack on to copies of the Preferences files.
23 const base::FilePath::CharType* kBadExtension = FILE_PATH_LITERAL("bad");
24
25 // Differentiates file loading between origin thread and passed
26 // (aka file) thread.
27 class FileThreadDeserializer
28     : public base::RefCountedThreadSafe<FileThreadDeserializer> {
29  public:
30   FileThreadDeserializer(JsonPrefStore* delegate,
31                          base::SequencedTaskRunner* sequenced_task_runner)
32       : no_dir_(false),
33         error_(PersistentPrefStore::PREF_READ_ERROR_NONE),
34         delegate_(delegate),
35         sequenced_task_runner_(sequenced_task_runner),
36         origin_loop_proxy_(base::MessageLoopProxy::current()) {
37   }
38
39   void Start(const base::FilePath& path) {
40     DCHECK(origin_loop_proxy_->BelongsToCurrentThread());
41     sequenced_task_runner_->PostTask(
42         FROM_HERE,
43         base::Bind(&FileThreadDeserializer::ReadFileAndReport,
44                    this, path));
45   }
46
47   // Deserializes JSON on the sequenced task runner.
48   void ReadFileAndReport(const base::FilePath& path) {
49     DCHECK(sequenced_task_runner_->RunsTasksOnCurrentThread());
50
51     value_.reset(DoReading(path, &error_, &no_dir_));
52
53     origin_loop_proxy_->PostTask(
54         FROM_HERE,
55         base::Bind(&FileThreadDeserializer::ReportOnOriginThread, this));
56   }
57
58   // Reports deserialization result on the origin thread.
59   void ReportOnOriginThread() {
60     DCHECK(origin_loop_proxy_->BelongsToCurrentThread());
61     delegate_->OnFileRead(value_.release(), error_, no_dir_);
62   }
63
64   static base::Value* DoReading(const base::FilePath& path,
65                                 PersistentPrefStore::PrefReadError* error,
66                                 bool* no_dir) {
67     int error_code;
68     std::string error_msg;
69     JSONFileValueSerializer serializer(path);
70     base::Value* value = serializer.Deserialize(&error_code, &error_msg);
71     HandleErrors(value, path, error_code, error_msg, error);
72     *no_dir = !base::PathExists(path.DirName());
73     return value;
74   }
75
76   static void HandleErrors(const base::Value* value,
77                            const base::FilePath& path,
78                            int error_code,
79                            const std::string& error_msg,
80                            PersistentPrefStore::PrefReadError* error);
81
82  private:
83   friend class base::RefCountedThreadSafe<FileThreadDeserializer>;
84   ~FileThreadDeserializer() {}
85
86   bool no_dir_;
87   PersistentPrefStore::PrefReadError error_;
88   scoped_ptr<base::Value> value_;
89   const scoped_refptr<JsonPrefStore> delegate_;
90   const scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner_;
91   const scoped_refptr<base::MessageLoopProxy> origin_loop_proxy_;
92 };
93
94 // static
95 void FileThreadDeserializer::HandleErrors(
96     const base::Value* value,
97     const base::FilePath& path,
98     int error_code,
99     const std::string& error_msg,
100     PersistentPrefStore::PrefReadError* error) {
101   *error = PersistentPrefStore::PREF_READ_ERROR_NONE;
102   if (!value) {
103     DVLOG(1) << "Error while loading JSON file: " << error_msg
104              << ", file: " << path.value();
105     switch (error_code) {
106       case JSONFileValueSerializer::JSON_ACCESS_DENIED:
107         *error = PersistentPrefStore::PREF_READ_ERROR_ACCESS_DENIED;
108         break;
109       case JSONFileValueSerializer::JSON_CANNOT_READ_FILE:
110         *error = PersistentPrefStore::PREF_READ_ERROR_FILE_OTHER;
111         break;
112       case JSONFileValueSerializer::JSON_FILE_LOCKED:
113         *error = PersistentPrefStore::PREF_READ_ERROR_FILE_LOCKED;
114         break;
115       case JSONFileValueSerializer::JSON_NO_SUCH_FILE:
116         *error = PersistentPrefStore::PREF_READ_ERROR_NO_FILE;
117         break;
118       default:
119         *error = PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE;
120         // JSON errors indicate file corruption of some sort.
121         // Since the file is corrupt, move it to the side and continue with
122         // empty preferences.  This will result in them losing their settings.
123         // We keep the old file for possible support and debugging assistance
124         // as well as to detect if they're seeing these errors repeatedly.
125         // TODO(erikkay) Instead, use the last known good file.
126         base::FilePath bad = path.ReplaceExtension(kBadExtension);
127
128         // If they've ever had a parse error before, put them in another bucket.
129         // TODO(erikkay) if we keep this error checking for very long, we may
130         // want to differentiate between recent and long ago errors.
131         if (base::PathExists(bad))
132           *error = PersistentPrefStore::PREF_READ_ERROR_JSON_REPEAT;
133         base::Move(path, bad);
134         break;
135     }
136   } else if (!value->IsType(base::Value::TYPE_DICTIONARY)) {
137     *error = PersistentPrefStore::PREF_READ_ERROR_JSON_TYPE;
138   }
139 }
140
141 }  // namespace
142
143 scoped_refptr<base::SequencedTaskRunner> JsonPrefStore::GetTaskRunnerForFile(
144     const base::FilePath& filename,
145     base::SequencedWorkerPool* worker_pool) {
146   std::string token("json_pref_store-");
147   token.append(filename.AsUTF8Unsafe());
148   return worker_pool->GetSequencedTaskRunnerWithShutdownBehavior(
149       worker_pool->GetNamedSequenceToken(token),
150       base::SequencedWorkerPool::BLOCK_SHUTDOWN);
151 }
152
153 JsonPrefStore::JsonPrefStore(const base::FilePath& filename,
154                              base::SequencedTaskRunner* sequenced_task_runner)
155     : path_(filename),
156       sequenced_task_runner_(sequenced_task_runner),
157       prefs_(new base::DictionaryValue()),
158       read_only_(false),
159       writer_(filename, sequenced_task_runner),
160       initialized_(false),
161       read_error_(PREF_READ_ERROR_OTHER) {}
162
163 bool JsonPrefStore::GetValue(const std::string& key,
164                              const base::Value** result) const {
165   base::Value* tmp = NULL;
166   if (!prefs_->Get(key, &tmp))
167     return false;
168
169   if (result)
170     *result = tmp;
171   return true;
172 }
173
174 void JsonPrefStore::AddObserver(PrefStore::Observer* observer) {
175   observers_.AddObserver(observer);
176 }
177
178 void JsonPrefStore::RemoveObserver(PrefStore::Observer* observer) {
179   observers_.RemoveObserver(observer);
180 }
181
182 bool JsonPrefStore::HasObservers() const {
183   return observers_.might_have_observers();
184 }
185
186 bool JsonPrefStore::IsInitializationComplete() const {
187   return initialized_;
188 }
189
190 bool JsonPrefStore::GetMutableValue(const std::string& key,
191                                     base::Value** result) {
192   return prefs_->Get(key, result);
193 }
194
195 void JsonPrefStore::SetValue(const std::string& key, base::Value* value) {
196   DCHECK(value);
197   scoped_ptr<base::Value> new_value(value);
198   base::Value* old_value = NULL;
199   prefs_->Get(key, &old_value);
200   if (!old_value || !value->Equals(old_value)) {
201     prefs_->Set(key, new_value.release());
202     ReportValueChanged(key);
203   }
204 }
205
206 void JsonPrefStore::SetValueSilently(const std::string& key,
207                                      base::Value* value) {
208   DCHECK(value);
209   scoped_ptr<base::Value> new_value(value);
210   base::Value* old_value = NULL;
211   prefs_->Get(key, &old_value);
212   if (!old_value || !value->Equals(old_value)) {
213     prefs_->Set(key, new_value.release());
214     if (!read_only_)
215       writer_.ScheduleWrite(this);
216   }
217 }
218
219 void JsonPrefStore::RemoveValue(const std::string& key) {
220   if (prefs_->Remove(key, NULL))
221     ReportValueChanged(key);
222 }
223
224 void JsonPrefStore::MarkNeedsEmptyValue(const std::string& key) {
225   keys_need_empty_value_.insert(key);
226 }
227
228 bool JsonPrefStore::ReadOnly() const {
229   return read_only_;
230 }
231
232 PersistentPrefStore::PrefReadError JsonPrefStore::GetReadError() const {
233   return read_error_;
234 }
235
236 PersistentPrefStore::PrefReadError JsonPrefStore::ReadPrefs() {
237   if (path_.empty()) {
238     OnFileRead(NULL, PREF_READ_ERROR_FILE_NOT_SPECIFIED, false);
239     return PREF_READ_ERROR_FILE_NOT_SPECIFIED;
240   }
241
242   PrefReadError error;
243   bool no_dir;
244   base::Value* value =
245       FileThreadDeserializer::DoReading(path_, &error, &no_dir);
246   OnFileRead(value, error, no_dir);
247   return error;
248 }
249
250 void JsonPrefStore::ReadPrefsAsync(ReadErrorDelegate *error_delegate) {
251   initialized_ = false;
252   error_delegate_.reset(error_delegate);
253   if (path_.empty()) {
254     OnFileRead(NULL, PREF_READ_ERROR_FILE_NOT_SPECIFIED, false);
255     return;
256   }
257
258   // Start async reading of the preferences file. It will delete itself
259   // in the end.
260   scoped_refptr<FileThreadDeserializer> deserializer(
261       new FileThreadDeserializer(this, sequenced_task_runner_.get()));
262   deserializer->Start(path_);
263 }
264
265 void JsonPrefStore::CommitPendingWrite() {
266   if (writer_.HasPendingWrite() && !read_only_)
267     writer_.DoScheduledWrite();
268 }
269
270 void JsonPrefStore::ReportValueChanged(const std::string& key) {
271   FOR_EACH_OBSERVER(PrefStore::Observer, observers_, OnPrefValueChanged(key));
272   if (!read_only_)
273     writer_.ScheduleWrite(this);
274 }
275
276 void JsonPrefStore::OnFileRead(base::Value* value_owned,
277                                PersistentPrefStore::PrefReadError error,
278                                bool no_dir) {
279   scoped_ptr<base::Value> value(value_owned);
280   read_error_ = error;
281
282   if (no_dir) {
283     FOR_EACH_OBSERVER(PrefStore::Observer,
284                       observers_,
285                       OnInitializationCompleted(false));
286     return;
287   }
288
289   initialized_ = true;
290
291   switch (error) {
292     case PREF_READ_ERROR_ACCESS_DENIED:
293     case PREF_READ_ERROR_FILE_OTHER:
294     case PREF_READ_ERROR_FILE_LOCKED:
295     case PREF_READ_ERROR_JSON_TYPE:
296     case PREF_READ_ERROR_FILE_NOT_SPECIFIED:
297       read_only_ = true;
298       break;
299     case PREF_READ_ERROR_NONE:
300       DCHECK(value.get());
301       prefs_.reset(static_cast<base::DictionaryValue*>(value.release()));
302       break;
303     case PREF_READ_ERROR_NO_FILE:
304       // If the file just doesn't exist, maybe this is first run.  In any case
305       // there's no harm in writing out default prefs in this case.
306       break;
307     case PREF_READ_ERROR_JSON_PARSE:
308     case PREF_READ_ERROR_JSON_REPEAT:
309       break;
310     default:
311       NOTREACHED() << "Unknown error: " << error;
312   }
313
314   if (error_delegate_.get() && error != PREF_READ_ERROR_NONE)
315     error_delegate_->OnError(error);
316
317   FOR_EACH_OBSERVER(PrefStore::Observer,
318                     observers_,
319                     OnInitializationCompleted(true));
320 }
321
322 JsonPrefStore::~JsonPrefStore() {
323   CommitPendingWrite();
324 }
325
326 bool JsonPrefStore::SerializeData(std::string* output) {
327   // TODO(tc): Do we want to prune webkit preferences that match the default
328   // value?
329   JSONStringValueSerializer serializer(output);
330   serializer.set_pretty_print(true);
331   scoped_ptr<base::DictionaryValue> copy(
332       prefs_->DeepCopyWithoutEmptyChildren());
333
334   // Iterates |keys_need_empty_value_| and if the key exists in |prefs_|,
335   // ensure its empty ListValue or DictonaryValue is preserved.
336   for (std::set<std::string>::const_iterator
337        it = keys_need_empty_value_.begin();
338        it != keys_need_empty_value_.end();
339        ++it) {
340     const std::string& key = *it;
341
342     base::Value* value = NULL;
343     if (!prefs_->Get(key, &value))
344       continue;
345
346     if (value->IsType(base::Value::TYPE_LIST)) {
347       const base::ListValue* list = NULL;
348       if (value->GetAsList(&list) && list->empty())
349         copy->Set(key, new base::ListValue);
350     } else if (value->IsType(base::Value::TYPE_DICTIONARY)) {
351       const base::DictionaryValue* dict = NULL;
352       if (value->GetAsDictionary(&dict) && dict->empty())
353         copy->Set(key, new base::DictionaryValue);
354     }
355   }
356
357   return serializer.Serialize(*(copy.get()));
358 }