1// Copyright 2014 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 "components/sync_driver/shared_change_processor.h"
6
7#include "base/message_loop/message_loop_proxy.h"
8#include "components/sync_driver/generic_change_processor.h"
9#include "components/sync_driver/generic_change_processor_factory.h"
10#include "components/sync_driver/sync_api_component_factory.h"
11#include "sync/api/sync_change.h"
12
13using base::AutoLock;
14
15namespace browser_sync {
16
17SharedChangeProcessor::SharedChangeProcessor()
18    : disconnected_(false),
19      type_(syncer::UNSPECIFIED),
20      frontend_loop_(base::MessageLoopProxy::current()),
21      generic_change_processor_(NULL),
22      error_handler_(NULL) {
23}
24
25SharedChangeProcessor::~SharedChangeProcessor() {
26  // We can either be deleted when the DTC is destroyed (on UI
27  // thread), or when the syncer::SyncableService stop's syncing (datatype
28  // thread).  |generic_change_processor_|, if non-NULL, must be
29  // deleted on |backend_loop_|.
30  if (frontend_loop_->BelongsToCurrentThread()) {
31    if (backend_loop_.get()) {
32      if (!backend_loop_->DeleteSoon(FROM_HERE, generic_change_processor_)) {
33        NOTREACHED();
34      }
35    } else {
36      DCHECK(!generic_change_processor_);
37    }
38  } else {
39    DCHECK(backend_loop_.get());
40    DCHECK(backend_loop_->BelongsToCurrentThread());
41    delete generic_change_processor_;
42  }
43}
44
45base::WeakPtr<syncer::SyncableService> SharedChangeProcessor::Connect(
46    browser_sync::SyncApiComponentFactory* sync_factory,
47    GenericChangeProcessorFactory* processor_factory,
48    syncer::UserShare* user_share,
49    DataTypeErrorHandler* error_handler,
50    syncer::ModelType type,
51    const base::WeakPtr<syncer::SyncMergeResult>& merge_result) {
52  DCHECK(sync_factory);
53  DCHECK(error_handler);
54  DCHECK_NE(type, syncer::UNSPECIFIED);
55  backend_loop_ = base::MessageLoopProxy::current();
56  AutoLock lock(monitor_lock_);
57  if (disconnected_)
58    return base::WeakPtr<syncer::SyncableService>();
59  type_ = type;
60  error_handler_ = error_handler;
61  base::WeakPtr<syncer::SyncableService> local_service =
62      sync_factory->GetSyncableServiceForType(type);
63  if (!local_service.get()) {
64    LOG(WARNING) << "SyncableService destroyed before DTC was stopped.";
65    disconnected_ = true;
66    return base::WeakPtr<syncer::SyncableService>();
67  }
68
69  generic_change_processor_ =
70      processor_factory->CreateGenericChangeProcessor(user_share,
71                                                      error_handler,
72                                                      local_service,
73                                                      merge_result,
74                                                      sync_factory).release();
75  return local_service;
76}
77
78bool SharedChangeProcessor::Disconnect() {
79  // May be called from any thread.
80  DVLOG(1) << "Disconnecting change processor.";
81  AutoLock lock(monitor_lock_);
82  bool was_connected = !disconnected_;
83  disconnected_ = true;
84  error_handler_ = NULL;
85  return was_connected;
86}
87
88ChangeProcessor* SharedChangeProcessor::generic_change_processor() {
89  return generic_change_processor_;
90}
91
92int SharedChangeProcessor::GetSyncCount() {
93  DCHECK(backend_loop_.get());
94  DCHECK(backend_loop_->BelongsToCurrentThread());
95  AutoLock lock(monitor_lock_);
96  if (disconnected_) {
97    LOG(ERROR) << "Change processor disconnected.";
98    return 0;
99  }
100  return generic_change_processor_->GetSyncCountForType(type_);
101}
102
103syncer::SyncError SharedChangeProcessor::ProcessSyncChanges(
104    const tracked_objects::Location& from_here,
105    const syncer::SyncChangeList& list_of_changes) {
106  DCHECK(backend_loop_.get());
107  DCHECK(backend_loop_->BelongsToCurrentThread());
108  AutoLock lock(monitor_lock_);
109  if (disconnected_) {
110    // The DTC that disconnects us must ensure it posts a StopSyncing task.
111    // If we reach this, it means it just hasn't executed yet.
112    syncer::SyncError error(FROM_HERE,
113                            syncer::SyncError::DATATYPE_ERROR,
114                            "Change processor disconnected.",
115                            type_);
116    return error;
117  }
118  return generic_change_processor_->ProcessSyncChanges(
119      from_here, list_of_changes);
120}
121
122syncer::SyncDataList SharedChangeProcessor::GetAllSyncData(
123    syncer::ModelType type) const {
124  syncer::SyncDataList data;
125  GetAllSyncDataReturnError(type, &data);  // Handles the disconnect case.
126  return data;
127}
128
129syncer::SyncError SharedChangeProcessor::GetAllSyncDataReturnError(
130    syncer::ModelType type,
131    syncer::SyncDataList* data) const {
132  DCHECK(backend_loop_.get());
133  DCHECK(backend_loop_->BelongsToCurrentThread());
134  AutoLock lock(monitor_lock_);
135  if (disconnected_) {
136    syncer::SyncError error(FROM_HERE,
137                            syncer::SyncError::DATATYPE_ERROR,
138                            "Change processor disconnected.",
139                            type_);
140    return error;
141  }
142  return generic_change_processor_->GetAllSyncDataReturnError(type, data);
143}
144
145syncer::SyncError SharedChangeProcessor::UpdateDataTypeContext(
146    syncer::ModelType type,
147    syncer::SyncChangeProcessor::ContextRefreshStatus refresh_status,
148    const std::string& context) {
149  DCHECK(backend_loop_.get());
150  DCHECK(backend_loop_->BelongsToCurrentThread());
151  AutoLock lock(monitor_lock_);
152  if (disconnected_) {
153    syncer::SyncError error(FROM_HERE,
154                            syncer::SyncError::DATATYPE_ERROR,
155                            "Change processor disconnected.",
156                            type_);
157    return error;
158  }
159  return generic_change_processor_->UpdateDataTypeContext(
160      type, refresh_status, context);
161}
162
163bool SharedChangeProcessor::SyncModelHasUserCreatedNodes(bool* has_nodes) {
164  DCHECK(backend_loop_.get());
165  DCHECK(backend_loop_->BelongsToCurrentThread());
166  AutoLock lock(monitor_lock_);
167  if (disconnected_) {
168    LOG(ERROR) << "Change processor disconnected.";
169    return false;
170  }
171  return generic_change_processor_->SyncModelHasUserCreatedNodes(
172      type_, has_nodes);
173}
174
175bool SharedChangeProcessor::CryptoReadyIfNecessary() {
176  DCHECK(backend_loop_.get());
177  DCHECK(backend_loop_->BelongsToCurrentThread());
178  AutoLock lock(monitor_lock_);
179  if (disconnected_) {
180    LOG(ERROR) << "Change processor disconnected.";
181    return true;  // Otherwise we get into infinite spin waiting.
182  }
183  return generic_change_processor_->CryptoReadyIfNecessary(type_);
184}
185
186bool SharedChangeProcessor::GetDataTypeContext(std::string* context) const {
187  DCHECK(backend_loop_.get());
188  DCHECK(backend_loop_->BelongsToCurrentThread());
189  AutoLock lock(monitor_lock_);
190  if (disconnected_) {
191    LOG(ERROR) << "Change processor disconnected.";
192    return false;
193  }
194  return generic_change_processor_->GetDataTypeContext(type_, context);
195}
196
197syncer::SyncError SharedChangeProcessor::CreateAndUploadError(
198    const tracked_objects::Location& location,
199    const std::string& message) {
200  AutoLock lock(monitor_lock_);
201  if (!disconnected_) {
202    return error_handler_->CreateAndUploadError(location, message, type_);
203  } else {
204    return syncer::SyncError(location,
205                             syncer::SyncError::DATATYPE_ERROR,
206                             message,
207                             type_);
208  }
209}
210
211}  // namespace browser_sync
212