Home | History | Annotate | Download | only in glue
      1 // Copyright (c) 2011 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 "chrome/browser/sync/glue/frontend_data_type_controller.h"
      6 
      7 #include "base/logging.h"
      8 #include "chrome/browser/profiles/profile.h"
      9 #include "chrome/browser/sync/glue/change_processor.h"
     10 #include "chrome/browser/sync/glue/model_associator.h"
     11 #include "chrome/browser/sync/profile_sync_factory.h"
     12 #include "chrome/browser/sync/profile_sync_service.h"
     13 #include "chrome/browser/sync/syncable/model_type.h"
     14 #include "content/browser/browser_thread.h"
     15 
     16 namespace browser_sync {
     17 
     18 FrontendDataTypeController::FrontendDataTypeController()
     19     : profile_sync_factory_(NULL),
     20       profile_(NULL),
     21       sync_service_(NULL) {}
     22 
     23 FrontendDataTypeController::FrontendDataTypeController(
     24     ProfileSyncFactory* profile_sync_factory,
     25     Profile* profile,
     26     ProfileSyncService* sync_service)
     27     : profile_sync_factory_(profile_sync_factory),
     28       profile_(profile),
     29       sync_service_(sync_service),
     30       state_(NOT_RUNNING) {
     31   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     32   DCHECK(profile_sync_factory);
     33   DCHECK(profile);
     34   DCHECK(sync_service);
     35 }
     36 
     37 FrontendDataTypeController::~FrontendDataTypeController() {
     38   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     39 }
     40 
     41 void FrontendDataTypeController::Start(StartCallback* start_callback) {
     42   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     43   DCHECK(start_callback);
     44   if (state_ != NOT_RUNNING) {
     45     start_callback->Run(BUSY, FROM_HERE);
     46     delete start_callback;
     47     return;
     48   }
     49 
     50   start_callback_.reset(start_callback);
     51 
     52   state_ = MODEL_STARTING;
     53   if (!StartModels()) {
     54     // If we are waiting for some external service to load before associating
     55     // or we failed to start the models, we exit early. state_ will control
     56     // what we perform next.
     57     DCHECK(state_ == NOT_RUNNING || state_ == MODEL_STARTING);
     58     return;
     59   }
     60 
     61   state_ = ASSOCIATING;
     62   if (!Associate()) {
     63     // We failed to associate and are aborting.
     64     DCHECK_EQ(state_, NOT_RUNNING);
     65     return;
     66   }
     67   DCHECK_EQ(state_, RUNNING);
     68 }
     69 
     70 bool FrontendDataTypeController::StartModels() {
     71   DCHECK_EQ(state_, MODEL_STARTING);
     72   // By default, no additional services need to be started before we can proceed
     73   // with model association.
     74   return true;
     75 }
     76 
     77 bool FrontendDataTypeController::Associate() {
     78   DCHECK_EQ(state_, ASSOCIATING);
     79   CreateSyncComponents();
     80 
     81   if (!model_associator_->CryptoReadyIfNecessary()) {
     82     StartFailed(NEEDS_CRYPTO, FROM_HERE);
     83     return false;
     84   }
     85 
     86   bool sync_has_nodes = false;
     87   if (!model_associator_->SyncModelHasUserCreatedNodes(&sync_has_nodes)) {
     88     StartFailed(UNRECOVERABLE_ERROR, FROM_HERE);
     89     return false;
     90   }
     91 
     92   base::TimeTicks start_time = base::TimeTicks::Now();
     93   bool merge_success = model_associator_->AssociateModels();
     94   RecordAssociationTime(base::TimeTicks::Now() - start_time);
     95   if (!merge_success) {
     96     StartFailed(ASSOCIATION_FAILED, FROM_HERE);
     97     return false;
     98   }
     99 
    100   sync_service_->ActivateDataType(this, change_processor_.get());
    101   state_ = RUNNING;
    102   FinishStart(!sync_has_nodes ? OK_FIRST_RUN : OK, FROM_HERE);
    103   return true;
    104 }
    105 
    106 void FrontendDataTypeController::Stop() {
    107   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    108   // If Stop() is called while Start() is waiting for the datatype model to
    109   // load, abort the start.
    110   if (state_ == MODEL_STARTING)
    111     FinishStart(ABORTED, FROM_HERE);
    112   DCHECK(!start_callback_.get());
    113 
    114   CleanupState();
    115 
    116   if (change_processor_ != NULL)
    117     sync_service_->DeactivateDataType(this, change_processor_.get());
    118 
    119   if (model_associator_ != NULL)
    120     model_associator_->DisassociateModels();
    121 
    122   change_processor_.reset();
    123   model_associator_.reset();
    124 
    125   state_ = NOT_RUNNING;
    126 }
    127 
    128 void FrontendDataTypeController::CleanupState() {
    129   // Do nothing by default.
    130 }
    131 
    132 browser_sync::ModelSafeGroup FrontendDataTypeController::model_safe_group()
    133     const {
    134   return browser_sync::GROUP_UI;
    135 }
    136 
    137 std::string FrontendDataTypeController::name() const {
    138   // For logging only.
    139   return syncable::ModelTypeToString(type());
    140 }
    141 
    142 DataTypeController::State FrontendDataTypeController::state() const {
    143   return state_;
    144 }
    145 
    146 void FrontendDataTypeController::OnUnrecoverableError(
    147     const tracked_objects::Location& from_here, const std::string& message) {
    148   // The ProfileSyncService will invoke our Stop() method in response to this.
    149   RecordUnrecoverableError(from_here, message);
    150   sync_service_->OnUnrecoverableError(from_here, message);
    151 }
    152 
    153 void FrontendDataTypeController::FinishStart(StartResult result,
    154     const tracked_objects::Location& location) {
    155   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    156   start_callback_->Run(result, location);
    157   start_callback_.reset();
    158 }
    159 
    160 void FrontendDataTypeController::StartFailed(StartResult result,
    161     const tracked_objects::Location& location) {
    162   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    163   CleanupState();
    164   model_associator_.reset();
    165   change_processor_.reset();
    166   state_ = NOT_RUNNING;
    167   start_callback_->Run(result, location);
    168   start_callback_.reset();
    169   RecordStartFailure(result);
    170 }
    171 
    172 }  // namespace browser_sync
    173