bookmark_data_type_controller.cc revision c407dc5cd9bdc5668497f21b26b09d988ab439de
1// Copyright (c) 2009 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/histogram.h"
6#include "base/logging.h"
7#include "base/time.h"
8#include "chrome/browser/bookmarks/bookmark_model.h"
9#include "chrome/browser/chrome_thread.h"
10#include "chrome/browser/profile.h"
11#include "chrome/browser/sync/glue/bookmark_change_processor.h"
12#include "chrome/browser/sync/glue/bookmark_data_type_controller.h"
13#include "chrome/browser/sync/glue/bookmark_model_associator.h"
14#include "chrome/browser/sync/profile_sync_service.h"
15#include "chrome/browser/sync/profile_sync_factory.h"
16#include "chrome/common/notification_details.h"
17#include "chrome/common/notification_source.h"
18#include "chrome/common/notification_type.h"
19
20namespace browser_sync {
21
22BookmarkDataTypeController::BookmarkDataTypeController(
23    ProfileSyncFactory* profile_sync_factory,
24    Profile* profile,
25    ProfileSyncService* sync_service)
26    : profile_sync_factory_(profile_sync_factory),
27      profile_(profile),
28      sync_service_(sync_service),
29      state_(NOT_RUNNING) {
30  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
31  DCHECK(profile_sync_factory);
32  DCHECK(profile);
33  DCHECK(sync_service);
34}
35
36BookmarkDataTypeController::~BookmarkDataTypeController() {
37  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
38}
39
40void BookmarkDataTypeController::Start(StartCallback* start_callback) {
41  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
42  DCHECK(start_callback);
43  if (state_ != NOT_RUNNING) {
44    start_callback->Run(BUSY);
45    delete start_callback;
46    return;
47  }
48
49  start_callback_.reset(start_callback);
50
51  if (!enabled()) {
52    FinishStart(NOT_ENABLED);
53    return;
54  }
55
56  state_ = MODEL_STARTING;
57
58  // If the bookmarks model is loaded, continue with association.
59  BookmarkModel* bookmark_model = profile_->GetBookmarkModel();
60  if (bookmark_model && bookmark_model->IsLoaded()) {
61    Associate();
62    return;
63  }
64
65  // Add an observer and continue when the bookmarks model is loaded.
66  registrar_.Add(this, NotificationType::BOOKMARK_MODEL_LOADED,
67                 Source<Profile>(sync_service_->profile()));
68}
69
70void BookmarkDataTypeController::Stop() {
71  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
72  // If Stop() is called while Start() is waiting for the bookmark
73  // model to load, abort the start.
74  if (state_ == MODEL_STARTING)
75    FinishStart(ABORTED);
76
77  registrar_.RemoveAll();
78  if (change_processor_ != NULL)
79    sync_service_->DeactivateDataType(this, change_processor_.get());
80
81  if (model_associator_ != NULL)
82    model_associator_->DisassociateModels();
83
84  change_processor_.reset();
85  model_associator_.reset();
86
87  state_ = NOT_RUNNING;
88}
89
90void BookmarkDataTypeController::OnUnrecoverableError(
91    const tracked_objects::Location& from_here, const std::string& message) {
92  // The ProfileSyncService will invoke our Stop() method in response to this.
93  UMA_HISTOGRAM_COUNTS("Sync.BookmarkRunFailures", 1);
94  sync_service_->OnUnrecoverableError(from_here, message);
95}
96
97void BookmarkDataTypeController::Observe(NotificationType type,
98                                         const NotificationSource& source,
99                                         const NotificationDetails& details) {
100  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
101  DCHECK_EQ(NotificationType::BOOKMARK_MODEL_LOADED, type.value);
102  registrar_.RemoveAll();
103  Associate();
104}
105
106void BookmarkDataTypeController::Associate() {
107  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
108  DCHECK_EQ(state_, MODEL_STARTING);
109  state_ = ASSOCIATING;
110
111  ProfileSyncFactory::SyncComponents sync_components =
112      profile_sync_factory_->CreateBookmarkSyncComponents(sync_service_, this);
113  model_associator_.reset(sync_components.model_associator);
114  change_processor_.reset(sync_components.change_processor);
115
116  bool sync_has_nodes = false;
117  if (!model_associator_->SyncModelHasUserCreatedNodes(&sync_has_nodes)) {
118    StartFailed(UNRECOVERABLE_ERROR);
119    return;
120  }
121
122  base::TimeTicks start_time = base::TimeTicks::Now();
123  bool merge_success = model_associator_->AssociateModels();
124  UMA_HISTOGRAM_TIMES("Sync.BookmarkAssociationTime",
125                      base::TimeTicks::Now() - start_time);
126  if (!merge_success) {
127    StartFailed(ASSOCIATION_FAILED);
128    return;
129  }
130
131  sync_service_->ActivateDataType(this, change_processor_.get());
132  state_ = RUNNING;
133  FinishStart(!sync_has_nodes ? OK_FIRST_RUN : OK);
134}
135
136void BookmarkDataTypeController::FinishStart(StartResult result) {
137  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
138  start_callback_->Run(result);
139  start_callback_.reset();
140}
141
142void BookmarkDataTypeController::StartFailed(StartResult result) {
143  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
144  model_associator_.reset();
145  change_processor_.reset();
146  state_ = NOT_RUNNING;
147  start_callback_->Run(result);
148  start_callback_.reset();
149  UMA_HISTOGRAM_ENUMERATION("Sync.BookmarkStartFailures",
150                            result,
151                            MAX_START_RESULT);
152}
153
154}  // namespace browser_sync
155