Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / components / sync_driver / ui_data_type_controller.cc
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/ui_data_type_controller.h"
6
7 #include "base/logging.h"
8 #include "base/memory/weak_ptr.h"
9 #include "components/sync_driver/generic_change_processor_factory.h"
10 #include "components/sync_driver/shared_change_processor_ref.h"
11 #include "sync/api/sync_error.h"
12 #include "sync/api/syncable_service.h"
13 #include "sync/internal_api/public/base/model_type.h"
14 #include "sync/util/data_type_histogram.h"
15
16 namespace sync_driver {
17
18 UIDataTypeController::UIDataTypeController()
19     : DataTypeController(base::MessageLoopProxy::current(),
20                          base::Closure()),
21       sync_factory_(NULL),
22       state_(NOT_RUNNING),
23       type_(syncer::UNSPECIFIED) {
24 }
25
26 UIDataTypeController::UIDataTypeController(
27     scoped_refptr<base::MessageLoopProxy> ui_thread,
28     const base::Closure& error_callback,
29     syncer::ModelType type,
30     SyncApiComponentFactory* sync_factory)
31     : DataTypeController(ui_thread, error_callback),
32       sync_factory_(sync_factory),
33       state_(NOT_RUNNING),
34       type_(type),
35       processor_factory_(new GenericChangeProcessorFactory()),
36       ui_thread_(ui_thread) {
37   DCHECK(ui_thread_->BelongsToCurrentThread());
38   DCHECK(sync_factory);
39   DCHECK(syncer::IsRealDataType(type_));
40 }
41
42 void UIDataTypeController::SetGenericChangeProcessorFactoryForTest(
43       scoped_ptr<GenericChangeProcessorFactory> factory) {
44   DCHECK_EQ(state_, NOT_RUNNING);
45   processor_factory_ = factory.Pass();
46 }
47
48 UIDataTypeController::~UIDataTypeController() {
49   DCHECK(ui_thread_->BelongsToCurrentThread());
50 }
51
52 void UIDataTypeController::LoadModels(
53     const ModelLoadCallback& model_load_callback) {
54   DCHECK(ui_thread_->BelongsToCurrentThread());
55   DCHECK(syncer::IsRealDataType(type_));
56   model_load_callback_ = model_load_callback;
57   if (state_ != NOT_RUNNING) {
58     model_load_callback.Run(type(),
59                             syncer::SyncError(FROM_HERE,
60                                               syncer::SyncError::DATATYPE_ERROR,
61                                               "Model already loaded",
62                                               type()));
63     return;
64   }
65   // Since we can't be called multiple times before Stop() is called,
66   // |shared_change_processor_| must be NULL here.
67   DCHECK(!shared_change_processor_.get());
68   shared_change_processor_ = new SharedChangeProcessor();
69
70   state_ = MODEL_STARTING;
71   if (!StartModels()) {
72     // If we are waiting for some external service to load before associating
73     // or we failed to start the models, we exit early. state_ will control
74     // what we perform next.
75     DCHECK(state_ == NOT_RUNNING || state_ == MODEL_STARTING);
76     return;
77   }
78
79   state_ = MODEL_LOADED;
80   model_load_callback_.Run(type(), syncer::SyncError());
81 }
82
83 void UIDataTypeController::OnModelLoaded() {
84   DCHECK(ui_thread_->BelongsToCurrentThread());
85   DCHECK_EQ(state_, MODEL_STARTING);
86
87   state_ = MODEL_LOADED;
88   model_load_callback_.Run(type(), syncer::SyncError());
89 }
90
91 void UIDataTypeController::StartAssociating(
92     const StartCallback& start_callback) {
93   DCHECK(ui_thread_->BelongsToCurrentThread());
94   DCHECK(!start_callback.is_null());
95   DCHECK_EQ(state_, MODEL_LOADED);
96
97   start_callback_ = start_callback;
98   state_ = ASSOCIATING;
99   Associate();
100   // It's possible StartDone(..) resulted in a Stop() call, or that association
101   // failed, so we just verify that the state has moved foward.
102   DCHECK_NE(state_, ASSOCIATING);
103 }
104
105 bool UIDataTypeController::StartModels() {
106   DCHECK_EQ(state_, MODEL_STARTING);
107   // By default, no additional services need to be started before we can proceed
108   // with model association.
109   return true;
110 }
111
112 void UIDataTypeController::Associate() {
113   DCHECK_EQ(state_, ASSOCIATING);
114   syncer::SyncMergeResult local_merge_result(type());
115   syncer::SyncMergeResult syncer_merge_result(type());
116   base::WeakPtrFactory<syncer::SyncMergeResult> weak_ptr_factory(
117       &syncer_merge_result);
118
119   // Connect |shared_change_processor_| to the syncer and get the
120   // syncer::SyncableService associated with type().
121   local_service_ = shared_change_processor_->Connect(
122       sync_factory_,
123       processor_factory_.get(),
124       user_share(),
125       this,
126       type(),
127       weak_ptr_factory.GetWeakPtr());
128   if (!local_service_.get()) {
129     syncer::SyncError error(FROM_HERE,
130                             syncer::SyncError::DATATYPE_ERROR,
131                             "Failed to connect to syncer.",
132                             type());
133     local_merge_result.set_error(error);
134     StartDone(ASSOCIATION_FAILED,
135               local_merge_result,
136               syncer_merge_result);
137     return;
138   }
139
140   if (!shared_change_processor_->CryptoReadyIfNecessary()) {
141     syncer::SyncError error(FROM_HERE,
142                             syncer::SyncError::CRYPTO_ERROR,
143                             "",
144                             type());
145     local_merge_result.set_error(error);
146     StartDone(NEEDS_CRYPTO,
147               local_merge_result,
148               syncer_merge_result);
149     return;
150   }
151
152   bool sync_has_nodes = false;
153   if (!shared_change_processor_->SyncModelHasUserCreatedNodes(
154           &sync_has_nodes)) {
155     syncer::SyncError error(FROM_HERE,
156                             syncer::SyncError::UNRECOVERABLE_ERROR,
157                             "Failed to load sync nodes",
158                             type());
159     local_merge_result.set_error(error);
160     StartDone(UNRECOVERABLE_ERROR,
161               local_merge_result,
162               syncer_merge_result);
163     return;
164   }
165
166   base::TimeTicks start_time = base::TimeTicks::Now();
167   syncer::SyncDataList initial_sync_data;
168   syncer::SyncError error =
169       shared_change_processor_->GetAllSyncDataReturnError(
170           type(), &initial_sync_data);
171   if (error.IsSet()) {
172     local_merge_result.set_error(error);
173     StartDone(ASSOCIATION_FAILED,
174               local_merge_result,
175               syncer_merge_result);
176     return;
177   }
178
179   std::string datatype_context;
180   if (shared_change_processor_->GetDataTypeContext(&datatype_context)) {
181     local_service_->UpdateDataTypeContext(
182         type(), syncer::SyncChangeProcessor::NO_REFRESH, datatype_context);
183   }
184
185   syncer_merge_result.set_num_items_before_association(
186       initial_sync_data.size());
187   // Passes a reference to |shared_change_processor_|.
188   local_merge_result = local_service_->MergeDataAndStartSyncing(
189       type(),
190       initial_sync_data,
191       scoped_ptr<syncer::SyncChangeProcessor>(
192           new SharedChangeProcessorRef(shared_change_processor_)),
193       scoped_ptr<syncer::SyncErrorFactory>(
194           new SharedChangeProcessorRef(shared_change_processor_)));
195   RecordAssociationTime(base::TimeTicks::Now() - start_time);
196   if (local_merge_result.error().IsSet()) {
197     StartDone(ASSOCIATION_FAILED,
198               local_merge_result,
199               syncer_merge_result);
200     return;
201   }
202
203   syncer_merge_result.set_num_items_after_association(
204       shared_change_processor_->GetSyncCount());
205
206   state_ = RUNNING;
207   StartDone(sync_has_nodes ? OK : OK_FIRST_RUN,
208             local_merge_result,
209             syncer_merge_result);
210 }
211
212 ChangeProcessor* UIDataTypeController::GetChangeProcessor() const {
213   DCHECK_EQ(state_, RUNNING);
214   return shared_change_processor_->generic_change_processor();
215 }
216
217 void UIDataTypeController::AbortModelLoad() {
218   DCHECK(ui_thread_->BelongsToCurrentThread());
219   state_ = NOT_RUNNING;
220
221   if (shared_change_processor_.get()) {
222     shared_change_processor_ = NULL;
223   }
224
225   model_load_callback_.Run(
226       type(),
227       syncer::SyncError(
228           FROM_HERE, syncer::SyncError::DATATYPE_ERROR, "Aborted", type()));
229   // We don't want to continue loading models (e.g OnModelLoaded should never be
230   // called after we've decided to abort).
231   StopModels();
232 }
233
234 void UIDataTypeController::StartDone(
235     ConfigureResult start_result,
236     const syncer::SyncMergeResult& local_merge_result,
237     const syncer::SyncMergeResult& syncer_merge_result) {
238   DCHECK(ui_thread_->BelongsToCurrentThread());
239
240   if (!IsSuccessfulResult(start_result)) {
241     StopModels();
242     if (start_result == ASSOCIATION_FAILED) {
243       state_ = DISABLED;
244     } else {
245       state_ = NOT_RUNNING;
246     }
247     RecordStartFailure(start_result);
248
249     if (shared_change_processor_.get()) {
250       shared_change_processor_->Disconnect();
251       shared_change_processor_ = NULL;
252     }
253   }
254
255   start_callback_.Run(start_result, local_merge_result, syncer_merge_result);
256 }
257
258 void UIDataTypeController::Stop() {
259   DCHECK(ui_thread_->BelongsToCurrentThread());
260   DCHECK(syncer::IsRealDataType(type_));
261
262   if (state_ == NOT_RUNNING)
263     return;
264
265   State prev_state = state_;
266   state_ = STOPPING;
267
268   if (shared_change_processor_.get()) {
269     shared_change_processor_->Disconnect();
270     shared_change_processor_ = NULL;
271   }
272
273   // If Stop() is called while Start() is waiting for the datatype model to
274   // load, abort the start.
275   if (prev_state == MODEL_STARTING) {
276     AbortModelLoad();
277     // We can just return here since we haven't performed association if we're
278     // still in MODEL_STARTING.
279     return;
280   }
281
282   StopModels();
283
284   if (local_service_.get()) {
285     local_service_->StopSyncing(type());
286   }
287
288   state_ = NOT_RUNNING;
289 }
290
291 syncer::ModelType UIDataTypeController::type() const {
292   DCHECK(syncer::IsRealDataType(type_));
293   return type_;
294 }
295
296 void UIDataTypeController::StopModels() {
297   // Do nothing by default.
298 }
299
300 syncer::ModelSafeGroup UIDataTypeController::model_safe_group() const {
301   DCHECK(syncer::IsRealDataType(type_));
302   return syncer::GROUP_UI;
303 }
304
305 std::string UIDataTypeController::name() const {
306   // For logging only.
307   return syncer::ModelTypeToString(type());
308 }
309
310 DataTypeController::State UIDataTypeController::state() const {
311   return state_;
312 }
313
314 void UIDataTypeController::OnSingleDataTypeUnrecoverableError(
315     const syncer::SyncError& error) {
316   DCHECK_EQ(type(), error.model_type());
317   UMA_HISTOGRAM_ENUMERATION("Sync.DataTypeRunFailures",
318                             ModelTypeToHistogramInt(type()),
319                             syncer::MODEL_TYPE_COUNT);
320   // TODO(tim): We double-upload some errors.  See bug 383480.
321   if (!error_callback_.is_null())
322     error_callback_.Run();
323   if (!model_load_callback_.is_null()) {
324     base::MessageLoop::current()->PostTask(
325         FROM_HERE, base::Bind(model_load_callback_, type(), error));
326   }
327 }
328
329 void UIDataTypeController::RecordAssociationTime(base::TimeDelta time) {
330   DCHECK(ui_thread_->BelongsToCurrentThread());
331 #define PER_DATA_TYPE_MACRO(type_str) \
332     UMA_HISTOGRAM_TIMES("Sync." type_str "AssociationTime", time);
333   SYNC_DATA_TYPE_HISTOGRAM(type());
334 #undef PER_DATA_TYPE_MACRO
335 }
336
337 void UIDataTypeController::RecordStartFailure(ConfigureResult result) {
338   DCHECK(ui_thread_->BelongsToCurrentThread());
339   UMA_HISTOGRAM_ENUMERATION("Sync.DataTypeStartFailures",
340                             ModelTypeToHistogramInt(type()),
341                             syncer::MODEL_TYPE_COUNT);
342 #define PER_DATA_TYPE_MACRO(type_str) \
343     UMA_HISTOGRAM_ENUMERATION("Sync." type_str "StartFailure", result, \
344                               MAX_START_RESULT);
345   SYNC_DATA_TYPE_HISTOGRAM(type());
346 #undef PER_DATA_TYPE_MACRO
347 }
348
349 }  // namespace sync_driver