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_NON_BLOCKING_DATA_TYPE_CONTROLLER_H_
6#define COMPONENTS_SYNC_DRIVER_NON_BLOCKING_DATA_TYPE_CONTROLLER_H_
7
8#include "base/memory/scoped_ptr.h"
9#include "base/memory/weak_ptr.h"
10#include "base/sequenced_task_runner.h"
11#include "sync/internal_api/public/base/model_type.h"
12#include "sync/internal_api/public/sync_context_proxy.h"
13
14namespace syncer {
15class ModelTypeSyncProxy;
16}
17
18namespace sync_driver {
19
20// Lives on the UI thread and manages the interactions between many sync
21// components.
22//
23// There are three main parts to this controller:
24// - The SyncContextProxy, represening the sync thread.
25// - The ModelTypeSyncProxy, representing the model type thread.
26// - The user-set state for this type (prefs), which lives on the UI thread.
27//
28// The ModelTypeSyncProxy can exist in three different states.  Those
29// states are:
30// - Enabled: Changes are being synced.
31// - Disconnected: Changes would be synced, but there is no connection between
32//                 the sync thread and the model thread.
33// - Disabled: Syncing is intentionally disabled.  The type proxy may clear any
34//             of its local state associated with sync when this happens, since
35//             this is expected to last a while.
36//
37// This controller is responsible for transitioning the type proxy into and out
38// of these states.  It does this by posting tasks to the model type thread.
39//
40// The type proxy is enabled when the user has indicated a desire to sync this
41// type, and the ModelTypeSyncProxy and SyncContextProxy are available.
42//
43// The type proxy is disconnected during initialization, or when either the
44// NonBlockingDataTypeController or SyncContextProxy have not yet registered.
45// It can also be disconnected later on if the sync backend becomes
46// unavailable.
47//
48// The type proxy is disabled if the user has disabled sync for this type.  The
49// signal indicating this state will be sent to the type proxy when the pref is
50// first changed, or when the type proxy first connects to the controller.
51//
52// This class is structured using some state machine patterns.  It's a bit
53// awkward at times, but this seems to be the clearest way to express the
54// behaviors this class must implement.
55class NonBlockingDataTypeController {
56 public:
57  NonBlockingDataTypeController(syncer::ModelType type, bool is_preferred);
58  ~NonBlockingDataTypeController();
59
60  // Connects the ModelTypeSyncProxy to this controller.
61  //
62  // There is no "undo" for this operation.  The NonBlockingDataTypeController
63  // will only ever deal with a single type proxy.
64  void InitializeType(
65      const scoped_refptr<base::SequencedTaskRunner>& task_runner,
66      const base::WeakPtr<syncer::ModelTypeSyncProxyImpl>& type_sync_proxy);
67
68  // Initialize the connection to the SyncContextProxy.
69  //
70  // This process may be reversed with ClearSyncContextProxy().
71  void InitializeSyncContext(
72      scoped_ptr<syncer::SyncContextProxy> sync_context_proxy);
73
74  // Disconnect from the current SyncContextProxy.
75  void ClearSyncContext();
76
77  // Sets the current preferred state.
78  //
79  // Represents a choice to sync or not sync this type.  This is expected to
80  // last a long time, so local state may be deleted if this setting is toggled
81  // to false.
82  void SetIsPreferred(bool is_preferred);
83
84 private:
85  enum TypeState { ENABLED, DISABLED, DISCONNECTED };
86
87  // Figures out which signals need to be sent then send then sends them.
88  void UpdateState();
89
90  // Sends an enable signal to the ModelTypeSyncProxyImpl.
91  void SendEnableSignal();
92
93  // Sends a disable signal to the ModelTypeSyncProxyImpl.
94  void SendDisableSignal();
95
96  // Sends a disconnect signal to the ModelTypeSyncProxyImpl.
97  void SendDisconnectSignal();
98
99  // Returns true if this type should be synced.
100  bool IsPreferred() const;
101
102  // Returns true if this object has access to the ModelTypeSyncProxyImpl.
103  bool IsSyncProxyConnected() const;
104
105  // Returns true if this object has access to the SyncContextProxy.
106  bool IsSyncBackendConnected() const;
107
108  // Returns the state that the type sync proxy should be in.
109  TypeState GetDesiredState() const;
110
111  // The ModelType we're controlling.  Kept mainly for debugging.
112  const syncer::ModelType type_;
113
114  // Returns the state that the type sync proxy is actually in, from this
115  // class' point of view.
116  //
117  // This state is inferred based on the most recently sent signals, and is
118  // intended to represent the state the sync proxy will be in by the time any
119  // tasks we post to it now will be run.  Due to threading / queueing effects,
120  // this may or may not be the actual state at this point in time.
121  TypeState current_state_;
122
123  // Whether or not the user wants to sync this type.
124  bool is_preferred_;
125
126  // The ModelTypeSyncProxyImpl and its associated thread.  May be NULL.
127  scoped_refptr<base::SequencedTaskRunner> task_runner_;
128  base::WeakPtr<syncer::ModelTypeSyncProxyImpl> type_sync_proxy_;
129
130  // The SyncContextProxy that connects to the current sync backend.  May be
131  // NULL.
132  scoped_ptr<syncer::SyncContextProxy> sync_context_proxy_;
133
134  DISALLOW_COPY_AND_ASSIGN(NonBlockingDataTypeController);
135};
136
137}  // namespace sync_driver
138
139#endif  // COMPONENTS_SYNC_DRIVER_NON_BLOCKING_DATA_TYPE_CONTROLLER_H_
140