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#ifndef CHROME_BROWSER_AUTOCOMPLETE_SHORTCUTS_BACKEND_H_
6#define CHROME_BROWSER_AUTOCOMPLETE_SHORTCUTS_BACKEND_H_
7
8#include <map>
9#include <string>
10#include <vector>
11
12#include "base/files/file_path.h"
13#include "base/gtest_prod_util.h"
14#include "base/memory/ref_counted.h"
15#include "base/memory/scoped_ptr.h"
16#include "base/observer_list.h"
17#include "base/strings/string16.h"
18#include "base/synchronization/lock.h"
19#include "base/time/time.h"
20#include "chrome/browser/history/shortcuts_database.h"
21#include "components/keyed_service/content/refcounted_browser_context_keyed_service.h"
22#include "components/omnibox/autocomplete_match.h"
23#include "content/public/browser/notification_observer.h"
24#include "content/public/browser/notification_registrar.h"
25#include "url/gurl.h"
26
27class Profile;
28
29namespace history {
30class ShortcutsDatabase;
31};  // namespace history
32
33// This class manages the shortcut provider backend - access to database on the
34// db thread, etc.
35class ShortcutsBackend : public RefcountedBrowserContextKeyedService,
36                         public content::NotificationObserver {
37 public:
38  typedef std::multimap<base::string16,
39                        const history::ShortcutsDatabase::Shortcut> ShortcutMap;
40
41  // |profile| is necessary for profile notifications only and can be NULL in
42  // unit-tests. For unit testing, set |suppress_db| to true to prevent creation
43  // of the database, in which case all operations are performed in memory only.
44  ShortcutsBackend(Profile* profile, bool suppress_db);
45
46  // The interface is guaranteed to be called on the thread AddObserver()
47  // was called.
48  class ShortcutsBackendObserver {
49   public:
50    // Called after the database is loaded and Init() completed.
51    virtual void OnShortcutsLoaded() = 0;
52    // Called when shortcuts changed (added/updated/removed) in the database.
53    virtual void OnShortcutsChanged() {}
54
55   protected:
56    virtual ~ShortcutsBackendObserver() {}
57  };
58
59  // Asynchronously initializes the ShortcutsBackend, it is safe to call
60  // multiple times - only the first call will be processed.
61  bool Init();
62
63  // All of the public functions *must* be called on UI thread only!
64
65  bool initialized() const { return current_state_ == INITIALIZED; }
66  const ShortcutMap& shortcuts_map() const { return shortcuts_map_; }
67
68  // Deletes the Shortcuts with the url.
69  bool DeleteShortcutsWithURL(const GURL& shortcut_url);
70
71  void AddObserver(ShortcutsBackendObserver* obs);
72  void RemoveObserver(ShortcutsBackendObserver* obs);
73
74  // Looks for an existing shortcut to match.destination_url that starts with
75  // |text|.  Updates that shortcut if found, otherwise adds a new shortcut.
76  void AddOrUpdateShortcut(const base::string16& text,
77                           const AutocompleteMatch& match);
78
79 private:
80  friend class base::RefCountedThreadSafe<ShortcutsBackend>;
81  friend class ShortcutsProviderTest;
82  friend class ShortcutsBackendTest;
83  FRIEND_TEST_ALL_PREFIXES(ShortcutsBackendTest, EntitySuggestionTest);
84
85  enum CurrentState {
86    NOT_INITIALIZED,  // Backend created but not initialized.
87    INITIALIZING,     // Init() called, but not completed yet.
88    INITIALIZED,      // Initialization completed, all accessors can be safely
89                      // called.
90  };
91
92  typedef std::map<std::string, ShortcutMap::iterator> GuidMap;
93
94  virtual ~ShortcutsBackend();
95
96  static history::ShortcutsDatabase::Shortcut::MatchCore MatchToMatchCore(
97      const AutocompleteMatch& match, Profile* profile);
98
99  // RefcountedBrowserContextKeyedService:
100  virtual void ShutdownOnUIThread() OVERRIDE;
101
102  // content::NotificationObserver:
103  virtual void Observe(int type,
104                       const content::NotificationSource& source,
105                       const content::NotificationDetails& details) OVERRIDE;
106
107  // Internal initialization of the back-end. Posted by Init() to the DB thread.
108  // On completion posts InitCompleted() back to UI thread.
109  void InitInternal();
110
111  // Finishes initialization on UI thread, notifies all observers.
112  void InitCompleted();
113
114  // Adds the Shortcut to the database.
115  bool AddShortcut(const history::ShortcutsDatabase::Shortcut& shortcut);
116
117  // Updates timing and selection count for the Shortcut.
118  bool UpdateShortcut(const history::ShortcutsDatabase::Shortcut& shortcut);
119
120  // Deletes the Shortcuts with these IDs.
121  bool DeleteShortcutsWithIDs(
122      const history::ShortcutsDatabase::ShortcutIDs& shortcut_ids);
123
124  // Deletes all shortcuts whose URLs begin with |url|.  If |exact_match| is
125  // true, only shortcuts from exactly |url| are deleted.
126  bool DeleteShortcutsWithURL(const GURL& url, bool exact_match);
127
128  // Deletes all of the shortcuts.
129  bool DeleteAllShortcuts();
130
131  Profile* profile_;
132  CurrentState current_state_;
133  ObserverList<ShortcutsBackendObserver> observer_list_;
134  scoped_refptr<history::ShortcutsDatabase> db_;
135
136  // The |temp_shortcuts_map_| and |temp_guid_map_| used for temporary storage
137  // between InitInternal() and InitComplete() to avoid doing a potentially huge
138  // copy.
139  scoped_ptr<ShortcutMap> temp_shortcuts_map_;
140  scoped_ptr<GuidMap> temp_guid_map_;
141
142  ShortcutMap shortcuts_map_;
143  // This is a helper map for quick access to a shortcut by guid.
144  GuidMap guid_map_;
145
146  content::NotificationRegistrar notification_registrar_;
147
148  // For some unit-test only.
149  bool no_db_access_;
150
151  DISALLOW_COPY_AND_ASSIGN(ShortcutsBackend);
152};
153
154#endif  // CHROME_BROWSER_AUTOCOMPLETE_SHORTCUTS_BACKEND_H_
155