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_DOWNLOAD_DOWNLOAD_HISTORY_H_
6#define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_HISTORY_H_
7
8#include <set>
9#include <vector>
10
11#include "base/basictypes.h"
12#include "base/callback.h"
13#include "base/memory/weak_ptr.h"
14#include "base/observer_list.h"
15#include "chrome/browser/download/all_download_item_notifier.h"
16#include "chrome/browser/history/history_service.h"
17#include "content/public/browser/download_item.h"
18#include "content/public/browser/download_manager.h"
19
20namespace history {
21struct DownloadRow;
22}  // namespace history
23
24// Observes a single DownloadManager and all its DownloadItems, keeping the
25// DownloadDatabase up to date.
26class DownloadHistory : public AllDownloadItemNotifier::Observer {
27 public:
28  typedef std::set<uint32> IdSet;
29
30  // Caller must guarantee that HistoryService outlives HistoryAdapter.
31  class HistoryAdapter {
32   public:
33    explicit HistoryAdapter(HistoryService* history);
34    virtual ~HistoryAdapter();
35
36    virtual void QueryDownloads(
37        const HistoryService::DownloadQueryCallback& callback);
38
39    virtual void CreateDownload(
40        const history::DownloadRow& info,
41        const HistoryService::DownloadCreateCallback& callback);
42
43    virtual void UpdateDownload(const history::DownloadRow& data);
44
45    virtual void RemoveDownloads(const std::set<uint32>& ids);
46
47   private:
48    HistoryService* history_;
49    DISALLOW_COPY_AND_ASSIGN(HistoryAdapter);
50  };
51
52  class Observer {
53   public:
54    Observer();
55    virtual ~Observer();
56
57    // Fires when a download is added to or updated in the database, just after
58    // the task is posted to the history thread.
59    virtual void OnDownloadStored(content::DownloadItem* item,
60                                  const history::DownloadRow& info) {}
61
62    // Fires when RemoveDownloads messages are sent to the DB thread.
63    virtual void OnDownloadsRemoved(const IdSet& ids) {}
64
65    // Fires when the DownloadHistory is being destroyed so that implementors
66    // can RemoveObserver() and nullify their DownloadHistory*s.
67    virtual void OnDownloadHistoryDestroyed() {}
68  };
69
70  // Returns true if the download is persisted. Not reliable when called from
71  // within a DownloadManager::Observer::OnDownloadCreated handler since the
72  // persisted state may not yet have been updated for a download that was
73  // restored from history.
74  static bool IsPersisted(const content::DownloadItem* item);
75
76  // Neither |manager| nor |history| may be NULL.
77  // DownloadService creates DownloadHistory some time after DownloadManager is
78  // created and destroys DownloadHistory as DownloadManager is shutting down.
79  DownloadHistory(
80      content::DownloadManager* manager,
81      scoped_ptr<HistoryAdapter> history);
82
83  virtual ~DownloadHistory();
84
85  void AddObserver(Observer* observer);
86  void RemoveObserver(Observer* observer);
87
88  // Returns true if the download was restored from history. Safe to call from
89  // within a DownloadManager::Observer::OnDownloadCreated handler and can be
90  // used to distinguish between downloads that were created due to new requests
91  // vs. downloads that were created due to being restored from history. Note
92  // that the return value is only reliable for downloads that were restored by
93  // this specific DownloadHistory instance.
94  bool WasRestoredFromHistory(const content::DownloadItem* item) const;
95
96 private:
97  typedef std::set<content::DownloadItem*> ItemSet;
98
99  // Callback from |history_| containing all entries in the downloads database
100  // table.
101  void QueryCallback(
102      scoped_ptr<std::vector<history::DownloadRow> > infos);
103
104  // May add |item| to |history_|.
105  void MaybeAddToHistory(content::DownloadItem* item);
106
107  // Callback from |history_| when an item was successfully inserted into the
108  // database.
109  void ItemAdded(uint32 id, bool success);
110
111  // AllDownloadItemNotifier::Observer
112  virtual void OnDownloadCreated(
113      content::DownloadManager* manager, content::DownloadItem* item) OVERRIDE;
114  virtual void OnDownloadUpdated(
115      content::DownloadManager* manager, content::DownloadItem* item) OVERRIDE;
116  virtual void OnDownloadOpened(
117      content::DownloadManager* manager, content::DownloadItem* item) OVERRIDE;
118  virtual void OnDownloadRemoved(
119      content::DownloadManager* manager, content::DownloadItem* item) OVERRIDE;
120
121  // Schedule a record to be removed from |history_| the next time
122  // RemoveDownloadsBatch() runs. Schedule RemoveDownloadsBatch() to be run soon
123  // if it isn't already scheduled.
124  void ScheduleRemoveDownload(uint32 download_id);
125
126  // Removes all |removing_ids_| from |history_|.
127  void RemoveDownloadsBatch();
128
129  AllDownloadItemNotifier notifier_;
130
131  scoped_ptr<HistoryAdapter> history_;
132
133  // Identifier of the item being created in QueryCallback(), matched up with
134  // created items in OnDownloadCreated() so that the item is not re-added to
135  // the database.
136  uint32 loading_id_;
137
138  // Identifiers of items that are scheduled for removal from history, to
139  // facilitate batching removals together for database efficiency.
140  IdSet removing_ids_;
141
142  // |GetId()|s of items that were removed while they were being added, so that
143  // they can be removed when the database finishes adding them.
144  // TODO(benjhayden) Can this be removed now that it doesn't need to wait for
145  // the db_handle, and can rely on PostTask sequentiality?
146  IdSet removed_while_adding_;
147
148  // Count the number of items in the history for UMA.
149  int64 history_size_;
150
151  ObserverList<Observer> observers_;
152
153  base::WeakPtrFactory<DownloadHistory> weak_ptr_factory_;
154
155  DISALLOW_COPY_AND_ASSIGN(DownloadHistory);
156};
157
158#endif  // CHROME_BROWSER_DOWNLOAD_DOWNLOAD_HISTORY_H_
159