OLD | NEW |
| (Empty) |
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/extension_sync.h" | |
6 | |
7 #include <utility> | |
8 | |
9 #include "base/logging.h" | |
10 #include "base/tracked.h" | |
11 #include "chrome/browser/extensions/extension_service.h" | |
12 #include "chrome/browser/extensions/extension_sync_data.h" | |
13 #include "chrome/browser/sync/engine/syncapi.h" | |
14 #include "chrome/browser/sync/glue/extension_sync_traits.h" | |
15 #include "chrome/browser/sync/glue/extension_util.h" | |
16 #include "chrome/browser/sync/protocol/extension_specifics.pb.h" | |
17 | |
18 namespace browser_sync { | |
19 | |
20 bool RootNodeHasChildren(const char* tag, | |
21 sync_api::UserShare* user_share, | |
22 bool* has_children) { | |
23 CHECK(has_children); | |
24 *has_children = false; | |
25 sync_api::ReadTransaction trans(FROM_HERE, user_share); | |
26 sync_api::ReadNode node(&trans); | |
27 if (!node.InitByTagLookup(tag)) { | |
28 LOG(ERROR) << "Root node with tag " << tag << " does not exist"; | |
29 return false; | |
30 } | |
31 *has_children = node.GetFirstChildId() != sync_api::kInvalidId; | |
32 return true; | |
33 } | |
34 | |
35 namespace { | |
36 | |
37 // Fills in |extension_data_map| with data from | |
38 // extension_service.GetSyncDataList(). | |
39 void SlurpClientData( | |
40 IsValidAndSyncablePredicate is_valid_and_syncable, | |
41 const ExtensionServiceInterface& extension_service, | |
42 ExtensionDataMap* extension_data_map) { | |
43 std::vector<ExtensionSyncData> sync_data_list = | |
44 extension_service.GetSyncDataList(is_valid_and_syncable); | |
45 for (std::vector<ExtensionSyncData>::const_iterator it = | |
46 sync_data_list.begin(); | |
47 it != sync_data_list.end(); ++it) { | |
48 std::pair<ExtensionDataMap::iterator, bool> result = | |
49 extension_data_map->insert(std::make_pair(it->id, *it)); | |
50 if (!result.second) { | |
51 // The value wasn't inserted, so merge it in. | |
52 result.first->second.Merge(*it); | |
53 } | |
54 } | |
55 } | |
56 | |
57 // Gets the boilerplate error message for not being able to find a | |
58 // root node. | |
59 // | |
60 // TODO(akalin): Put this somewhere where all data types can use it. | |
61 std::string GetRootNodeDoesNotExistError(const char* root_node_tag) { | |
62 return | |
63 std::string("Server did not create the top-level ") + | |
64 root_node_tag + | |
65 " node. We might be running against an out-of-date server."; | |
66 } | |
67 | |
68 // Gets the data from the server for extensions to be synced and | |
69 // updates |extension_data_map|. | |
70 bool SlurpServerData( | |
71 const char* root_node_tag, | |
72 const ExtensionSpecificsGetter extension_specifics_getter, | |
73 sync_api::UserShare* user_share, | |
74 ExtensionDataMap* extension_data_map) { | |
75 sync_api::WriteTransaction trans(FROM_HERE, user_share); | |
76 sync_api::ReadNode root(&trans); | |
77 if (!root.InitByTagLookup(root_node_tag)) { | |
78 LOG(ERROR) << GetRootNodeDoesNotExistError(root_node_tag); | |
79 return false; | |
80 } | |
81 | |
82 int64 id = root.GetFirstChildId(); | |
83 while (id != sync_api::kInvalidId) { | |
84 sync_api::ReadNode sync_node(&trans); | |
85 if (!sync_node.InitByIdLookup(id)) { | |
86 LOG(ERROR) << "Failed to fetch sync node for id " << id; | |
87 return false; | |
88 } | |
89 const sync_pb::ExtensionSpecifics& server_data = | |
90 (*extension_specifics_getter)(sync_node); | |
91 ExtensionSyncData sync_data; | |
92 if (!SpecificsToSyncData(server_data, &sync_data)) { | |
93 LOG(ERROR) << "Invalid extensions specifics for id " << id; | |
94 return false; | |
95 } | |
96 (*extension_data_map)[sync_data.id] = sync_data; | |
97 id = sync_node.GetSuccessorId(); | |
98 } | |
99 return true; | |
100 } | |
101 | |
102 } // namespace | |
103 | |
104 bool SlurpExtensionData(const ExtensionSyncTraits& traits, | |
105 const ExtensionServiceInterface& extension_service, | |
106 sync_api::UserShare* user_share, | |
107 ExtensionDataMap* extension_data_map) { | |
108 // Read server-side data first so client user settings take | |
109 // precedence. | |
110 if (!SlurpServerData( | |
111 traits.root_node_tag, traits.extension_specifics_getter, | |
112 user_share, extension_data_map)) { | |
113 return false; | |
114 } | |
115 | |
116 SlurpClientData( | |
117 traits.is_valid_and_syncable, extension_service, | |
118 extension_data_map); | |
119 return true; | |
120 } | |
121 | |
122 namespace { | |
123 | |
124 // Updates the server data from the given extension data. Returns | |
125 // whether or not the update was successful. | |
126 bool UpdateServer( | |
127 const ExtensionSyncTraits& traits, | |
128 const ExtensionSyncData& data, | |
129 sync_api::WriteTransaction* trans) { | |
130 sync_pb::ExtensionSpecifics specifics; | |
131 SyncDataToSpecifics(data, &specifics); | |
132 const std::string& id = data.id; | |
133 sync_api::WriteNode write_node(trans); | |
134 if (write_node.InitByClientTagLookup(traits.model_type, id)) { | |
135 (*traits.extension_specifics_setter)(specifics, &write_node); | |
136 } else { | |
137 sync_api::ReadNode root(trans); | |
138 if (!root.InitByTagLookup(traits.root_node_tag)) { | |
139 LOG(ERROR) << GetRootNodeDoesNotExistError(traits.root_node_tag); | |
140 return false; | |
141 } | |
142 sync_api::WriteNode create_node(trans); | |
143 if (!create_node.InitUniqueByCreation(traits.model_type, root, id)) { | |
144 LOG(ERROR) << "Could not create node for extension " << id; | |
145 return false; | |
146 } | |
147 (*traits.extension_specifics_setter)(specifics, &create_node); | |
148 } | |
149 return true; | |
150 } | |
151 | |
152 } // namespace | |
153 | |
154 bool FlushExtensionData(const ExtensionSyncTraits& traits, | |
155 const ExtensionDataMap& extension_data_map, | |
156 ExtensionServiceInterface* extension_service, | |
157 sync_api::UserShare* user_share) { | |
158 sync_api::WriteTransaction trans(FROM_HERE, user_share); | |
159 sync_api::ReadNode root(&trans); | |
160 if (!root.InitByTagLookup(traits.root_node_tag)) { | |
161 LOG(ERROR) << GetRootNodeDoesNotExistError(traits.root_node_tag); | |
162 return false; | |
163 } | |
164 | |
165 // Update server and client as necessary. | |
166 for (ExtensionDataMap::const_iterator it = extension_data_map.begin(); | |
167 it != extension_data_map.end(); ++it) { | |
168 const ExtensionSyncData& extension_data = it->second; | |
169 if (!UpdateServer(traits, extension_data, &trans)) { | |
170 LOG(ERROR) << "Could not update server data for extension " | |
171 << it->first; | |
172 return false; | |
173 } | |
174 extension_service->ProcessSyncData(extension_data, | |
175 traits.is_valid_and_syncable); | |
176 } | |
177 return true; | |
178 } | |
179 | |
180 bool UpdateServerData(const ExtensionSyncTraits& traits, | |
181 const Extension& extension, | |
182 const ExtensionServiceInterface& extension_service, | |
183 sync_api::UserShare* user_share, | |
184 std::string* error) { | |
185 const std::string& id = extension.id(); | |
186 ExtensionSyncData data; | |
187 if (!extension_service.GetSyncData( | |
188 extension, traits.is_valid_and_syncable, &data)) { | |
189 *error = | |
190 std::string("UpdateServerData() called for invalid or " | |
191 "unsyncable extension ") + id; | |
192 LOG(DFATAL) << *error; | |
193 return false; | |
194 } | |
195 | |
196 sync_api::WriteTransaction trans(FROM_HERE, user_share); | |
197 if (!UpdateServer(traits, data, &trans)) { | |
198 *error = | |
199 std::string("Could not update server data for extension ") + id; | |
200 LOG(ERROR) << *error; | |
201 return false; | |
202 } | |
203 return true; | |
204 } | |
205 | |
206 void RemoveServerData(const ExtensionSyncTraits& traits, | |
207 const std::string& id, | |
208 sync_api::UserShare* user_share) { | |
209 sync_api::WriteTransaction trans(FROM_HERE, user_share); | |
210 sync_api::WriteNode write_node(&trans); | |
211 if (write_node.InitByClientTagLookup(traits.model_type, id)) { | |
212 write_node.Remove(); | |
213 } else { | |
214 LOG(ERROR) << "Server data does not exist for extension " << id; | |
215 } | |
216 } | |
217 | |
218 } // namespace browser_sync | |
OLD | NEW |