BREW Scheduler Supporting vCalendar - 3 / 7 -
Data Structure
The VCalendarFile class is basically the VCalendar class with added file I/O capabilities. VCalendarFile class inherits from VCalendar and has member variables for file name and status flag, in addition to member functions for file I/O.
class VCalendarFile : public VCalendar { private: SFXPath _fileName; // for file name SFXAnsiString _flag; // "n " : create new, "m " : modify, "d " : delete public: Void SetFileName(SFXPathConstRef fileName);// Sets file name Void SetFlag(SFXAnsiStringConstRef flag);// Sets the flag SFXPath GetFileName(Void) const; // Returns the file name SFXAnsiString GetFlag(Void) const;// Returns flag status SFCError SaveToFile(Void) const; // Write onto file SFCError LoadFromFile(Void); // Read from file // ... };
A file is necessary to contain the data of VCalendar.
In addition, the VCalCollection class manages the instance variables of the VCalendarFile class. This class is declared as a memmber variable of its application class.
class VCalCollection { private: // Manage VCalendarFile variab // This list should be always ordered by date ( _startDT ) SFXList<VCalendarFilePtr> _list; SFXAnsiString _lastSyncTime; // The last synchronized time with server public: SFCError ReadIndexFile(Void); // Read from file SFCError WriteIndexFile(Void); // Write to file // ... }
SFXList is used for saving instance variables of VCalendarFile.
When an element is inserted into this list, it should be ordered by the value of _startDate.
If the elements are sorted, it is useful to display a series of dates on the calendar, and mark the number of data items that were entered on that day.
Inserting an Element
// add an element onto VCalCollection Void VCalCollection::Append(VCalendarFilePtr vcalendar) { SFXDateConst date1(vcalendar->GetStartDate()); Bool isInsert = false; SIntN i; // The flag that indicates a new creation is set. vcalendar->SetFlag("n"); // Search for the position where the element is to be inserted // Data must be sorted. for (i = 0; i < _list.GetSize(); ++i) { // Get the startDate of i th element SFXDate date2 = _list.Get(i)->GetStartDate(); if (date1 <= date2) { // Compare the StartDates _list.Insert(i, vcalendar); // Insert an element isInsert = true; break; } } // If the insertion position is not found if (!isInsert) { _list.Append(vcalendar); // Append it to the end } vcalendar->SaveToFile(); // Save data to file WriteIndexFile(); // Update index return; }
The above procedure is as follows.
- Search for the positon where an element is to be inserted by comparing it with each other element included in the _list. The criteria being compared here is ( startDate ).
- Insert an element into _list with Insert() when the position is found
- Append an element at the end of _list with Append() if the position is not found
- Save the data with an inserted element as a file by using the SaveToFile() function of VCalendar
- Update an index file by using WriteIndexFile()
Dates are compared by using comparison operators like "date1 <= date2".
Implement SaveToFile () of VCalendarFile
// save data as file SFCError VCalendarFile::SaveToFile(Void) const { SFCError error; SFXFile file; SFXAnsiStringStreamWriter writer; SFXPath fileName(DIR_NAME + _fileName.Get()); SFXPath temp; SFXAnsiString content; // Get temporary file name error = SFXFile::GetTemporaryPath(SFXPath(DIR_NAME), &temp); if (error == SFERR_NO_ERROR) { // Make temporary file error = file.OpenReadWrite(temp); if (error == SFERR_NO_ERROR) { // Convert from VCalendar class into string in vCalendar format Export(&content); // Get stream for writing error = file.GetStreamWriter(content.GetLength(), &writer); if (error == SFERR_NO_ERROR) { // Write to file writer << content; writer.Flush(); } // Close file file.Close(); } } if (error == SFERR_NO_ERROR) { // Delete old file SFXFile::Remove(fileName); // Rename temporary file to original name error = SFXFile::Rename(temp, fileName); } return error; }
WriteIndexFile() is the function that saves the file names of VCalendar data as index files with the following format.
20080324T031654Z // Last updated time filename1 - // Filename, tab(\t), flag filename2 d filename3 f ...
Implement WriteIndexFile() of VCalCollection
// write onto file SFCError VCalCollection::WriteIndexFile(Void) { SFCError error; SFXFile file; SFXAnsiStringStreamWriter writer; SFXPath fileName(DIR_NAME INDEX_FILE_NAME); SFXPath temp; SFXAnsiString content; // Get temporary file name error = SFXFile::GetTemporaryPath(SFXPath(DIR_NAME), &temp); if (error == SFERR_NO_ERROR) { // Make temporary file error = file.OpenReadWrite(temp); if (error == SFERR_NO_ERROR) { // Get stream for writing error = file.GetStreamWriter(1024, &writer); if (error == SFERR_NO_ERROR) { // Write to file writer << _lastSyncTime << "\r\n"; writer.Flush(); SFXList<VCalendarFilePtr>::Enumerator etor = _list.GetEnumerator(); while(etor.HasNext()) { VCalendarFilePtr vcal = etor.GetNext(); writer << vcal->GetFileName().Get() << " " << vcal->GetFlag() << "\r\n"; writer.Flush(); } } // Close file file.Close(); } } if (error == SFERR_NO_ERROR) { // Delete old file SFXFile::Remove(fileName); // Rename temporary file to original name error = SFXFile::Rename(temp, fileName); } return error; }
Enumrator is used for processing each element of SFXList. The HasNext() function is used to check whether the next element exists and GetNext() returns that element.
Instance of VCalCollection
There is the only one instance of VCalCollection in this apllication, and it will be referred to by a variety of other classess.
In general, variables available at any part of an application like this are placed in an application class, which is automatically generated by SophiaFramework Application Wizard when creating new project.
SyncScheduler Application Class
class SyncScheduler : public SFRApplication { private: VCalCollection _vcalCollection; // ... public: static VCalCollectionPtr GetVCalCollection(Void); // ... }; // get instance of VCalCollection VCalCollectionPtr SyncScheduler::GetVCalCollection(Void) { return &static_cast<SyncSchedulerPtr>(GetInstance()) ->_vcalCollection; }
Thanks to the preceding code, the instance of VCalCollection is available at any point in the program, and is accessed as follows:
VCalCollectionPtr collection = SyncScheduler::GetVCalCollection();
Load Data
Data is loaded from file when the application starts.
// Constructor SyncScheduler::SyncScheduler(Void) static_throws { .... _vcalCollection.ReadIndexFile(); ... }
ReadIndexFile() to read data from index file
// load all the data from file // 1st, read index file // 2nd, analyze index file // 3rd, read data into VCalCollection from each file SFCError VCalCollection::ReadIndexFile(Void) { SFCError error; SFXFile file; SFXAnsiStringStreamReader reader; UInt32 size; SFXAnsiString string; // Get file size error = SFXFile::GetSize(SFXPath(DIR_NAME INDEX_FILE_NAME), &size); if (error == SFERR_NO_ERROR) { // Open file error = file.OpenReadOnly(SFXPath(DIR_NAME INDEX_FILE_NAME)); if (error == SFERR_NO_ERROR) { // Get stream for reading error = file.GetStreamReader(size, &reader); if (error == SFERR_NO_ERROR) { reader.Fetch(); // Read from file reader >> string; } file.Close(); } } if (error == SFERR_NO_ERROR) { SInt32 c1 = 0; SInt32 c2 = 0; // Search for end of line c2 = string.IndexOf('\n'); // Trim blank characters _lastSyncTime = string.Substring(0, c2).Trim(); ++c2; while ((c1 = string.IndexOf(' ', c2)) > -1) { SFXPath filename(string.Substring(c2, c1)); c2 = string.IndexOf("\r\n", c1); SFXAnsiString flag(string.Substring(c1 + 1, c2)); c2 += 2; // size of "\r\n" VCalendarFilePtr vcal = ::new VCalendarFile(filename, flag); vcal->LoadFromFile(); // Read vCalendar data from file _list.Append(vcal); } } return error; }
LoadFromFile() to Read one VCalendar File
// read data from file SFCError VCalendarFile::LoadFromFile(Void) { SFCError error; SFXFile file; SFXAnsiStringStreamReader reader; UInt32 size; SFXAnsiString string; SFXPath filename(SFXPath(DIR_NAME + _fileName.Get())); // Get file size error = SFXFile::GetSize(filename, &size); if (error == SFERR_NO_ERROR) { // Open file error = file.OpenReadOnly(filename); if (error == SFERR_NO_ERROR) { // Get stream for reading error = file.GetStreamReader(size, &reader); if (error == SFERR_NO_ERROR) { reader.Fetch(); // Read from file reader >> string; } file.Close(); } } if (error == SFERR_NO_ERROR) { Import(string); // Analyze data in vCalendar format // Subsutitute each element into member variable } return error; }