3 /// Mode class for the Desktop mode
7 Copyright (C) 2005-2011, 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__
26 #include "m_mode_base.h"
35 // forward declarations
46 /// The main interface class to the device databases.
48 /// To use this class, use the following steps:
50 /// - Create a Controller object (see Controller class for more details)
51 /// - Create this Mode::Desktop object, passing in the Controller
52 /// object during construction
53 /// - Call Open() to open database socket and finish constructing.
54 /// - Call GetDBDB() to get the device's database database
55 /// - Call GetDBID() to get a database ID by name
56 /// - Call LoadDatabase() to retrieve and store a database
58 class BXEXPORT Desktop
: public Mode
60 friend class DBLoader
;
63 enum CommandType
{ Unknown
, DatabaseAccess
};
67 Data m_command
, m_response
;
69 CommandTable m_commandTable
;
70 DatabaseDatabase m_dbdb
;
72 // external objects (optional, can be null)
73 const IConverter
*m_ic
;
76 void LoadCommandTable();
79 //////////////////////////////////
82 virtual void OnOpen();
85 Desktop(Controller
&con
);
86 Desktop(Controller
&con
, const IConverter
&ic
);
89 //////////////////////////////////
92 /// Returns DatabaseDatabase object for this connection.
93 /// Must call Open() first, which loads the DBDB.
94 const DatabaseDatabase
& GetDBDB() const { return m_dbdb
; }
95 unsigned int GetDBID(const std::string
&name
) const;
96 unsigned int GetDBCommand(CommandType ct
);
98 void SetIConverter(const IConverter
&ic
);
100 //////////////////////////////////
101 // Desktop mode - database specific
103 // dirty flag related functions, for sync operations
104 void GetRecordStateTable(unsigned int dbId
, RecordStateTable
&result
);
105 void AddRecord(unsigned int dbId
, Builder
&build
); // RecordId is
106 // retrieved from build, and duplicate IDs are allowed,
107 // but *not* recommended!
108 void GetRecord(unsigned int dbId
, unsigned int stateTableIndex
, Parser
&parser
);
109 void SetRecord(unsigned int dbId
, unsigned int stateTableIndex
, Builder
&build
);
110 void ClearDirty(unsigned int dbId
, unsigned int stateTableIndex
);
111 void DeleteRecord(unsigned int dbId
, unsigned int stateTableIndex
);
113 // pure load/save operations
114 void LoadDatabase(unsigned int dbId
, Parser
&parser
);
115 void ClearDatabase(unsigned int dbId
);
116 void SaveDatabase(unsigned int dbId
, Builder
&builder
);
118 template <class RecordT
, class StorageT
> void LoadDatabaseByType(StorageT
&store
);
119 template <class RecordT
, class StorageT
> void SaveDatabaseByType(StorageT
&store
);
121 template <class StorageT
> void LoadDatabaseByName(const std::string
&name
, StorageT
&store
);
122 template <class StorageT
> void SaveDatabaseByName(const std::string
&name
, StorageT
&store
);
124 template <class RecordT
> void AddRecordByType(uint32_t recordId
, const RecordT
&rec
);
128 // used to hold internal-only state
134 /// Database Loader operation class. Encapsulates the load / save
135 /// logic of Desktop::LoadDatabase() and someday Desktop::SaveDatabase()
136 /// in such a way that the loading of individual records is
137 /// controllable by the user, instead of using the parser callback mechanism.
139 /// This class can be reused to load / save multiple databases, but
140 /// do not call Desktop members while a load operation is in progress.
142 class BXEXPORT DBLoader
147 std::string m_dbName
;
148 DBLoaderData
*m_loader
;
151 explicit DBLoader(Desktop
&desktop
);
154 /// Do not call Desktop members if this is true.
155 bool IsBusy() const { return m_loading
; }
157 // caller-controllable load/save operations... if
158 // these functions return true, then new data has
159 // just been loaded into the data object passed to
162 // Both of these functions use a DBData object in order
163 // to pass buffers from application code all the way down
164 // to the socket level, to avoid copies wherever possible.
165 bool StartDBLoad(unsigned int dbId
, DBData
&data
);
166 bool GetNextRecord(DBData
&data
);
169 } // namespace Barry::Mode
178 /// Takes a list of database dbId's and behaves like a Builder,
179 /// trying to avoid copies where possible on the device loading end.
181 class BXEXPORT DeviceBuilder
: public Builder
183 typedef unsigned int dbid_type
;
190 DBLabel(dbid_type id
, const std::string
&name
)
197 typedef std::vector
<DBLabel
> list_type
;
199 // list of databases to fetch during build
201 list_type::iterator m_current
;
204 Mode::Desktop
&m_desktop
;
206 // loader object to use optimized batch loading while
207 // giving per-record control
208 Mode::DBLoader m_loader
;
211 explicit DeviceBuilder(Mode::Desktop
&desktop
);
213 // searches the dbdb from the desktop to find the dbId,
214 // returns false if not found, and adds it to the list of
215 // databases to retrieve if found
216 bool Add(const std::string
&dbname
);
218 // adds all databases found in the given dbdb
219 void Add(const Barry::DatabaseDatabase
&dbdb
);
221 /// sets the internal iterator to the start of the list
222 /// in order to perform a fresh run
223 void Restart() { m_current
= m_dbIds
.begin(); m_started
= false; }
229 // has both BuildRecord() and Retrieve() functionality,
230 // and uses data all the way down to the socket level copy
231 virtual bool BuildRecord(DBData
&data
, size_t &offset
,
232 const IConverter
*ic
);
233 virtual bool FetchRecord(DBData
&data
, const IConverter
*ic
);
234 virtual bool EndOfFile() const;
241 /// A parser class that "parses" raw data into a device. Basically this
242 /// is a pipe-oriented way to call SaveDatabase().
244 /// Note that this is a multi-record parser. For each incoming DBData
245 /// that has a new DBName, a new save will be started. There is no
246 /// way to filter out records, except via the callback, so the easiest
247 /// way to filter out records by database name is on the Builder side.
249 class BXEXPORT DeviceParser
: public Barry::Parser
253 /// Similar to SaveDatabase(). Erases all records from
254 /// the existing database and then uploads all new records.
257 /// Adds any new records, and for records with Unique IDs
258 /// that already exist, overwrite them.
259 INDIVIDUAL_OVERWRITE
,
261 /// Adds any new records, but if a record exists with the
262 /// current Unique ID, skip that record and don't write it
264 ADD_BUT_NO_OVERWRITE
,
266 /// Adds all incoming records as brand new records, generating
267 /// a new Unique ID for each one, and leaving any existing
271 /// Calls the virtual function DecideWrite(...) for each
272 /// record, passing in the data. DecideWrite() returns one
273 /// of these WriteMode values.
276 /// Primarily used by DecideWrite(), and causes the current
277 /// record to not be written.
282 Mode::Desktop
&m_desktop
;
285 std::string m_current_db
;
286 unsigned int m_current_dbid
;
287 RecordStateTable m_rstate
;
290 void StartDB(const DBData
&data
, const IConverter
*ic
);
291 void WriteNext(const DBData
&data
, const IConverter
*ic
);
294 DeviceParser(Mode::Desktop
&desktop
, WriteMode mode
);
295 virtual ~DeviceParser();
297 /// Callback... you must derive and override this if you use
298 /// the DECIDE_BY_CALLBACK mode.
299 /// May be called multiple times per record.
300 virtual WriteMode
DecideWrite(const DBData
&record
) const
306 virtual void ParseRecord(const DBData
&data
, const IConverter
*ic
);