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#ifndef COMPONENTS_SYNC_DRIVER_DATA_TYPE_CONTROLLER_H__
6#define COMPONENTS_SYNC_DRIVER_DATA_TYPE_CONTROLLER_H__
7
8#include <map>
9#include <string>
10
11#include "base/callback.h"
12#include "base/location.h"
13#include "base/memory/ref_counted.h"
14#include "base/memory/ref_counted_delete_on_message_loop.h"
15#include "base/sequenced_task_runner_helpers.h"
16#include "components/sync_driver/data_type_error_handler.h"
17#include "sync/api/sync_merge_result.h"
18#include "sync/internal_api/public/base/model_type.h"
19#include "sync/internal_api/public/engine/model_safe_worker.h"
20#include "sync/internal_api/public/util/unrecoverable_error_handler.h"
21
22namespace syncer {
23class SyncError;
24struct UserShare;
25}
26
27namespace sync_driver {
28
29class ChangeProcessor;
30
31// Data type controllers need to be refcounted threadsafe, as they may
32// need to run model associator or change processor on other threads.
33class DataTypeController
34    : public base::RefCountedDeleteOnMessageLoop<DataTypeController>,
35      public DataTypeErrorHandler {
36 public:
37  enum State {
38    NOT_RUNNING,    // The controller has never been started or has
39                    // previously been stopped.  Must be in this state to start.
40    MODEL_STARTING, // The controller is waiting on dependent services
41                    // that need to be available before model
42                    // association.
43    MODEL_LOADED,   // The model has finished loading and can start
44                    // associating now.
45    ASSOCIATING,    // Model association is in progress.
46    RUNNING,        // The controller is running and the data type is
47                    // in sync with the cloud.
48    STOPPING,       // The controller is in the process of stopping
49                    // and is waiting for dependent services to stop.
50    DISABLED        // The controller was started but encountered an error
51                    // so it is disabled waiting for it to be stopped.
52  };
53
54  enum ConfigureResult {
55    OK,                   // The data type has started normally.
56    OK_FIRST_RUN,         // Same as OK, but sent on first successful
57                          // start for this type for this user as
58                          // determined by cloud state.
59    ASSOCIATION_FAILED,   // An error occurred during model association.
60    ABORTED,              // Start was aborted by calling Stop().
61    UNRECOVERABLE_ERROR,  // An unrecoverable error occured.
62    NEEDS_CRYPTO,         // The data type cannot be started yet because it
63                          // depends on the cryptographer.
64    RUNTIME_ERROR,        // After starting, a runtime error was encountered.
65    MAX_START_RESULT
66  };
67
68  typedef base::Callback<void(ConfigureResult,
69                              const syncer::SyncMergeResult&,
70                              const syncer::SyncMergeResult&)> StartCallback;
71
72  typedef base::Callback<void(syncer::ModelType,
73                              syncer::SyncError)> ModelLoadCallback;
74
75  typedef base::Callback<void(const tracked_objects::Location& location,
76                              const std::string&)> DisableTypeCallback;
77
78  typedef std::map<syncer::ModelType,
79                   scoped_refptr<DataTypeController> > TypeMap;
80  typedef std::map<syncer::ModelType, DataTypeController::State> StateMap;
81
82  // Returns true if the start result should trigger an unrecoverable error.
83  // Public so unit tests can use this function as well.
84  static bool IsUnrecoverableResult(ConfigureResult result);
85
86  // Returns true if the datatype started successfully.
87  static bool IsSuccessfulResult(ConfigureResult result);
88
89  // Begins asynchronous operation of loading the model to get it ready for
90  // model association. Once the models are loaded the callback will be invoked
91  // with the result. If the models are already loaded it is safe to call the
92  // callback right away. Else the callback needs to be stored and called when
93  // the models are ready.
94  virtual void LoadModels(const ModelLoadCallback& model_load_callback) = 0;
95
96  // Will start a potentially asynchronous operation to perform the
97  // model association. Once the model association is done the callback will
98  // be invoked.
99  virtual void StartAssociating(const StartCallback& start_callback) = 0;
100
101  // Synchronously stops the data type. If StartAssociating has already been
102  // called but is not done yet it will be aborted. Similarly if LoadModels
103  // has not completed it will also be aborted.
104  // NOTE: Stop() should be called after sync backend machinery has stopped
105  // routing changes to this data type. Stop() should ensure the data type
106  // logic shuts down gracefully by flushing remaining changes and calling
107  // StopSyncing on the SyncableService. This assumes no changes will ever
108  // propagate from sync again from point where Stop() is called.
109  virtual void Stop() = 0;
110
111  // Unique model type for this data type controller.
112  virtual syncer::ModelType type() const = 0;
113
114  // Name of this data type.  For logging purposes only.
115  virtual std::string name() const = 0;
116
117  // The model safe group of this data type.  This should reflect the
118  // thread that should be used to modify the data type's native
119  // model.
120  virtual syncer::ModelSafeGroup model_safe_group() const = 0;
121
122  // Access to the ChangeProcessor for the type being controlled by |this|.
123  // Returns NULL if the ChangeProcessor isn't created or connected.
124  virtual ChangeProcessor* GetChangeProcessor() const = 0;
125
126  // Current state of the data type controller.
127  virtual State state() const = 0;
128
129  // Partial implementation of DataTypeErrorHandler.
130  // This is thread safe.
131  virtual syncer::SyncError CreateAndUploadError(
132      const tracked_objects::Location& location,
133      const std::string& message,
134      syncer::ModelType type) OVERRIDE;
135
136  // Called when the sync backend has initialized. |share| is the
137  // UserShare handle to associate model data with.
138  void OnUserShareReady(syncer::UserShare* share);
139
140  // Whether the DataTypeController is ready to start. This is useful if the
141  // datatype itself must make the decision about whether it should be enabled
142  // at all (and therefore whether the initial download of the sync data for
143  // the type should be performed).
144  // Returns true by default.
145  virtual bool ReadyForStart() const;
146
147 protected:
148  friend class base::RefCountedDeleteOnMessageLoop<DataTypeController>;
149  friend class base::DeleteHelper<DataTypeController>;
150
151  DataTypeController(scoped_refptr<base::MessageLoopProxy> ui_thread,
152                     const base::Closure& error_callback);
153
154  // If the DTC is waiting for models to load, once the models are
155  // loaded the datatype service will call this function on DTC to let
156  // us know that it is safe to start associating.
157  virtual void OnModelLoaded() = 0;
158
159  virtual ~DataTypeController();
160
161  syncer::UserShare* user_share() const;
162
163  // The callback that will be invoked when an unrecoverable error occurs.
164  // TODO(sync): protected for use by legacy controllers.
165  base::Closure error_callback_;
166
167 private:
168  syncer::UserShare* user_share_;
169};
170
171}  // namespace sync_driver
172
173#endif  // COMPONENTS_SYNC_DRIVER_DATA_TYPE_CONTROLLER_H__
174