lib: fixed iterator start bug in DeviceBuilder, which skipped first DB added
[barry.git] / src / m_desktop.h
blobb5610f8b4221aa1b67fcbaeda472766fabf852ef
1 ///
2 /// \file m_desktop.h
3 /// Mode class for the Desktop mode
4 ///
6 /*
7 Copyright (C) 2005-2010, Net Direct Inc. (http://www.netdirect.ca/)
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18 See the GNU General Public License in the COPYING file at the
19 root directory of this project for more details.
22 #ifndef __BARRY_M_DESKTOP_H__
23 #define __BARRY_M_DESKTOP_H__
25 #include "dll.h"
26 #include "m_mode_base.h"
27 #include "data.h"
28 #include "socket.h"
29 #include "record.h"
30 #include "builder.h"
32 namespace Barry {
34 // forward declarations
35 class Parser;
36 class IConverter;
38 namespace Mode {
40 class DBLoader;
43 // Desktop class
45 /// The main interface class to the device databases.
46 ///
47 /// To use this class, use the following steps:
48 ///
49 /// - Create a Controller object (see Controller class for more details)
50 /// - Create this Mode::Desktop object, passing in the Controller
51 /// object during construction
52 /// - Call Open() to open database socket and finish constructing.
53 /// - Call GetDBDB() to get the device's database database
54 /// - Call GetDBID() to get a database ID by name
55 /// - Call LoadDatabase() to retrieve and store a database
56 ///
57 class BXEXPORT Desktop : public Mode
59 friend class DBLoader;
61 public:
62 enum CommandType { Unknown, DatabaseAccess };
64 private:
65 // packet data
66 Data m_command, m_response;
68 CommandTable m_commandTable;
69 DatabaseDatabase m_dbdb;
71 // external objects (optional, can be null)
72 const IConverter *m_ic;
74 protected:
75 void LoadCommandTable();
76 void LoadDBDB();
78 //////////////////////////////////
79 // overrides
81 virtual void OnOpen();
83 public:
84 Desktop(Controller &con);
85 Desktop(Controller &con, const IConverter &ic);
86 ~Desktop();
88 //////////////////////////////////
89 // meta access
91 /// Returns DatabaseDatabase object for this connection.
92 /// Must call Open() first, which loads the DBDB.
93 const DatabaseDatabase& GetDBDB() const { return m_dbdb; }
94 unsigned int GetDBID(const std::string &name) const;
95 unsigned int GetDBCommand(CommandType ct);
97 void SetIConverter(const IConverter &ic);
99 //////////////////////////////////
100 // Desktop mode - database specific
102 // dirty flag related functions, for sync operations
103 void GetRecordStateTable(unsigned int dbId, RecordStateTable &result);
104 void AddRecord(unsigned int dbId, Builder &build); // RecordId is
105 // retrieved from build, and duplicate IDs are allowed,
106 // but *not* recommended!
107 void GetRecord(unsigned int dbId, unsigned int stateTableIndex, Parser &parser);
108 void SetRecord(unsigned int dbId, unsigned int stateTableIndex, Builder &build);
109 void ClearDirty(unsigned int dbId, unsigned int stateTableIndex);
110 void DeleteRecord(unsigned int dbId, unsigned int stateTableIndex);
112 // pure load/save operations
113 void LoadDatabase(unsigned int dbId, Parser &parser);
114 void ClearDatabase(unsigned int dbId);
115 void SaveDatabase(unsigned int dbId, Builder &builder);
117 template <class RecordT, class StorageT> void LoadDatabaseByType(StorageT &store);
118 template <class RecordT, class StorageT> void SaveDatabaseByType(StorageT &store);
120 template <class StorageT> void LoadDatabaseByName(const std::string &name, StorageT &store);
121 template <class StorageT> void SaveDatabaseByName(const std::string &name, StorageT &store);
123 template <class RecordT> void AddRecordByType(uint32_t recordId, const RecordT &rec);
127 // used to hold internal-only state
128 struct DBLoaderData;
131 // DBLoader
133 /// Database Loader operation class. Encapsulates the load / save
134 /// logic of Desktop::LoadDatabase() and someday Desktop::SaveDatabase()
135 /// in such a way that the loading of individual records is
136 /// controllable by the user, instead of using the parser callback mechanism.
138 /// This class can be reused to load / save multiple databases, but
139 /// do not call Desktop members while a load operation is in progress.
141 class BXEXPORT DBLoader
143 Desktop &m_desktop;
144 Data m_send;
145 bool m_loading;
146 std::string m_dbName;
147 DBLoaderData *m_loader;
149 public:
150 explicit DBLoader(Desktop &desktop);
151 ~DBLoader();
153 /// Do not call Desktop members if this is true.
154 bool IsBusy() const { return m_loading; }
156 // caller-controllable load/save operations... if
157 // these functions return true, then new data has
158 // just been loaded into the data object passed to
159 // the constructor
161 // Both of these functions use a DBData object in order
162 // to pass buffers from application code all the way down
163 // to the socket level, to avoid copies wherever possible.
164 bool StartDBLoad(unsigned int dbId, DBData &data);
165 bool GetNextRecord(DBData &data);
168 } // namespace Barry::Mode
175 // DeviceBuilder
177 /// Takes a list of database dbId's and behaves like a Builder,
178 /// trying to avoid copies where possible on the device loading end.
180 class BXEXPORT DeviceBuilder : public Builder
182 typedef unsigned int dbid_type;
184 struct DBLabel
186 dbid_type id;
187 std::string name;
189 DBLabel(dbid_type id, const std::string &name)
190 : id(id)
191 , name(name)
196 typedef std::vector<DBLabel> list_type;
198 // list of databases to fetch during build
199 list_type m_dbIds;
200 list_type::iterator m_current;
201 bool m_started;
203 Mode::Desktop &m_desktop;
205 // loader object to use optimized batch loading while
206 // giving per-record control
207 Mode::DBLoader m_loader;
209 public:
210 explicit DeviceBuilder(Mode::Desktop &desktop);
212 // searches the dbdb from the desktop to find the dbId,
213 // returns false if not found, and adds it to the list of
214 // databases to retrieve if found
215 bool Add(const std::string &dbname);
217 /// sets the internal iterator to the start of the list
218 /// in order to perform a fresh run
219 void Restart() { m_current = m_dbIds.begin(); m_started = false; }
222 // Builder overrides
225 // has both BuildRecord() and Retrieve() functionality,
226 // and uses data all the way down to the socket level copy
227 virtual bool BuildRecord(DBData &data, size_t &offset,
228 const IConverter *ic);
229 virtual bool FetchRecord(DBData &data, const IConverter *ic);
230 virtual bool EndOfFile() const;
235 // DeviceParser
237 /// A parser class that "parses" raw data into a device. Basically this
238 /// is a pipe-oriented way to call SaveDatabase().
240 /// Note that this is a multi-record parser. For each incoming DBData
241 /// that has a new DBName, a new save will be started. There is no
242 /// way to filter out records, except via the callback, so the easiest
243 /// way to filter out records by database name is on the Builder side.
245 class BXEXPORT DeviceParser
247 public:
248 enum WriteMode {
249 /// Similar to SaveDatabase(). Erases all records from
250 /// the existing database and then uploads all new records.
251 ERASE_ALL_WRITE_ALL,
253 /// Adds any new records, and for records with Unique IDs
254 /// that already exist, overwrite them.
255 INDIVIDUAL_OVERWRITE,
257 /// Adds any new records, but if a record exists with the
258 /// current Unique ID, skip that record and don't write it
259 /// to the device.
260 ADD_BUT_NO_OVERWRITE,
262 /// Adds all incoming records as brand new records, generating
263 /// a new Unique ID for each one, and leaving any existing
264 /// records intact.
265 ADD_WITH_NEW_ID,
267 /// Calls the virtual function DecideWrite(...) for each
268 /// record, passing in the data. DecideWrite() returns one
269 /// of these WriteMode values.
270 DECIDE_BY_CALLBACK,
272 /// Primarily used by DecideWrite(), and causes the current
273 /// record to not be written.
274 DROP_RECORD
277 private:
278 Mode::Desktop &m_desktop;
279 WriteMode m_mode;
281 std::string m_current_db;
282 unsigned int m_current_dbid;
283 RecordStateTable m_rstate;
285 protected:
286 void StartDB(const DBData &data, const IConverter *ic);
287 void WriteNext(const DBData &data, const IConverter *ic);
289 public:
290 DeviceParser(Mode::Desktop &desktop, WriteMode mode);
291 virtual ~DeviceParser();
293 /// Callback... you must derive and override this if you use
294 /// the DECIDE_BY_CALLBACK mode.
295 /// May be called multiple times per record.
296 virtual WriteMode DecideWrite(const DBData &record) const
298 return DROP_RECORD;
301 /// Parser overrides
302 virtual void ParseRecord(const DBData &data, const IConverter *ic);
306 } // namespace Barry
308 #endif