Briefcase sample (desktop) (Delphi)
The Briefcase sample demonstrates using the TDAFolderBriefcase class to save and then load two Data Tables that may have changes that are waiting to be sent to the server. It also demonstrates using briefcase properties to ensure that the data in the briefcase is valid and if not delete the briefcase.
The Briefcase can be helpful for situations where there isn't a persistent connection to the server and the user needs to be able to quit your app or otherwise work in an offline fashion. Another use of a it might be to aid in the application start-up process, as you can load the data from disk without needing to rely on the server being available.
Getting Started
The sample is located in C:\Users\Public\Documents\RemObjects Samples\Data Abstract for Delphi\Briefcase
.
To build it, you will need Delphi Rad Studio, and like all the samples provided with Data Abstract for Delphi you will need to be running Relativity Server with the DASamples
Domain and the Simple
Schema available.
Running the Sample
The UI for the sample is split into three parts. A toolbar with various buttons, a table that displays data retrieved either from the server or from a briefcase, and finally a "console" like view where log data from the sample is displayed.
The toolbar has 4 buttons; "Reload", "Apply", "Reveal in Explorer" and "Invalidate" along with a drop down box which contains the default address used for an instance of Relativity Server running on a local machine; http://localhost:7099/bin
. The "Reload" button retrieves the data again from the server and saves it to a briefcase. The "Apply" button sends any changes to the server to be saved and then a fresh briefcase is saved to the filesystem which will remove the highlighting on the rows. The "Reveal in Explorer" button will open an Explorer window in the folder that contains the briefcase file. Finally the "Invalidate" button will set a boolean which will be checked next time the briefcase is saved to disk and display a information dialog.
When the sample is run, it immediately attempts to access an instance of Relativity Server running on the local machine at http://localhost:7099/bin
.
The sample checks to see if there is a Briefcase file available and if not then the data is freshly retrieved from the server. If on the other hand a Briefcase is available, then the BRIEFCASE_DATA_VERSION_KEY
stored in the briefcase as a property is tested to see if the data is valid. If it isn't valid then fresh data is retrieved from the server and the briefcase replaced with the new data. If the property is valid then the tables are retrieved from the briefcase. You will also see that the date property is also retrieved and logged to the console when the briefcase is being validated.
At this point the UI will be visible with a list of products, the product group they belong to and a minimum and maximum amount available. Unlike the figure above, when the sample is first run no rows will have a yellow highlight, which means that there are no changes compared to the server version of the data. (See below)
If you double click on a in the "Min Amount" column of a row, the field will become editable allowing you to change the value. If you make a change and press Enter, the row will have a yellow highlight to indicate that a change has been made compared to the DataTable
retrieved from the server.
If you quit the app at this point, those changes will be saved to the briefcase along with the information that the data is changed compared to the server, so that when you next run the app you will see those very same rows marked as changed. The highlighting will only be removed by either reloading the data from the server or by applying the changes to the server.
If you press the "Reveal in Explorer" button you will see the briefcase folder (Products.briefcase) that was written to disk when quitting the app, or after the data is retrieved from the server. If you open this folder, you will find three files, two with the extension .daBriefcase
which are the tables themselves, and a plist
file which has the data stored in any briefcase properties. If you double click on one of the .daBriefcase
files it will open in the Briefcase Explorer tool and display the contents of the briefcase for examination. The plist file is viewable in any text editor.
Examining the Code
The code for creating the connection to the server, retrieving and modifying the data are covered by other samples. In this section we will be focusing on the code needed to create the briefcase, store the tables & properties in it and load those tables & properties from disk.
The sample is built around two classes; ClientDataModule
and ClientForm
. The ClientDataModule
class handles everything related to interacting with the Data Abstract SDK; including retrieving data from an instance of Relativity Server, applying changes to the server and working with the briefcase. All of the code you are interested in is located in this class and will be discussed below. The ClientForm
handles everything related to the user interface.
Store the tables in a new briefcase
In this sample saving the briefcase to disk is handled over two procedures. SaveBriefcase
which handles the creation of the TDAFolderBriefcase object, recording some information as briefcase properties and writing the briefcase to disk, while the PutTablesToBriefcase
adds the data tables we are interested in into the briefcase.
As noted in the Briefcase Overview, briefcases can be stored in one of two formats; either as a single .daBriefcase
file which contains all of the tables and properties that you set or as a package (folder) where each table is stored in its own .daBriefcase
file and the properties are stored in a .plist
file. This sample uses the folder format, but if you wanted to use the other briefcase format you can replace the two instances of TDAFolderBriefcase with TDAFileBriefcase instead and alter the check to see if the briefcase folder exists in LoadData
.
If the fInvalidateBriefcase
property has been set to true then the value currently stored in briefcase for the BRIEFCASE_DATA_VERSION_KEY
property is retrieved and tested to see if it has already been set to INVALID
. If it hasn't, then the property is set to BRIEFCASE_DATA_VERSION_INVALID
and the briefcase is immediately written to disk using the WriteBriefcase procedure. No changes are saved to disk unless WriteBriefcase
is called.
Otherwise if fInvalidateBriefcase
is set to false, we call PutTablesToBriefcase
which adds the two tables, "Products" and "ProductGroups", to the briefcase using the AddTable procedure. If a table with the same name is already there, it will be replaced with this new table. The briefcase is then written to disk using the WriteBriefcase procedure. As noted, no changes to the briefcase are saved to disk unless WriteBriefcase
is called.
procedure TClientDataModule.PutTablesToBriefcase(briefcase: TDABaseBriefcase);
begin
AddToLog('Putting tables to the briefcase...');
briefcase.AddTable(tbl_ProductGroups, False);
briefcase.AddTable(tbl_Products, False);
end;
procedure TClientDataModule.SaveBriefcase;
var
lbriefcase: TDABaseBriefcase;
begin
lbriefcase := TDAFolderBriefcase.Create(GetBriefcaseFileName,False,False);
if fInvalidateBriefcase then begin
if AnsiSameText(BRIEFCASE_DATA_VERSION_INVALID, lbriefcase.PropValues[BRIEFCASE_DATA_VERSION_KEY]) then begin
AddToLog('Briefcase already marked as INVALID.')
end
else
begin
lbriefcase.PropValues[BRIEFCASE_DATA_VERSION_KEY] := BRIEFCASE_DATA_VERSION_INVALID;
AddToLog('Briefcase has been marked as INVALID.');
lbriefcase.WriteBriefcase;
end
end
else begin
PutTablesToBriefcase(lbriefcase);
lbriefcase.PropValues[BRIEFCASE_DATA_VERSION_KEY] := BRIEFCASE_DATA_VERSION;
lbriefcase.PropValues[BRIEFCASE_UPDATE_DATE_KEY] := DateTimeToStr(Now);
lbriefcase.WriteBriefcase;
AddToLog('Briefcase has been updated.')
end
end;
Loading the briefcase from disk and retrieving the tables
These three procedures handle loading the briefcase from disk and retrieving the tables from the briefcase based on the BRIEFCASE_DATA_VERSION_KEY
property stored inside the briefcase.
The LoadData
first tests to see if the briefcase folder exists, if not a fresh set of data is retrieved from the server. Otherwise a TDAFolderBriefcase object is created using Create procedure. The boolean values passed in indicate that the data should be pre-loaded into memory, and that the briefcase owns the tables.
The fully loaded briefcase is then passed to the ValidateBriefcase
function which checks the value of the BRIEFCASE_DATA_VERSION_KEY
property. If the briefcase is considered to be valid then the tables are retrieved with a call to GetTablesFromBriefcase:
which calls the Fill procedure with an array containing the tables to be filled.
procedure TClientDataModule.LoadData;
var
lbriefcaseName: string;
lbriefcase: TDAFolderBriefcase;
begin
AddToLog('Initial loading...');
AddToLog('Looking for the local briefcase first...');
lbriefcaseName := GetBriefcaseFileName;
AddToLog('Briefcase: '+ lbriefcaseName);
if not DirectoryExists(lbriefcaseName) then
begin
AddToLog('No briefcase found. Downloading fresh data...');
LoadFromServer;
end
else begin
AddToLog('Briefcase has been found.');
lbriefcase:= TDAFolderBriefcase.Create(lbriefcaseName,True,True);
if ValidateBriefcase(lbriefcase) then begin
GetTablesFromBriefcase(lbriefcase);
end
else begin
AddToLog('Clearing briefcase and downloading fresh data...');
LoadFromServer;
end
end;
AddToLog('Data is ready.')
end;
procedure TClientDataModule.GetTablesFromBriefcase(briefcase: TDABaseBriefcase);
begin
AddToLog('Loading tables from the briefcase...');
briefcase.Fill([tbl_ProductGroups,tbl_Products],True);
end;