borland Packages  Class Hierarchy  datastore Package  Index 

DataStore component

java.lang.Object
   +----borland.datastore.SaveListener
           +----borland.datastore.CacheOwner
                   +----borland.datastore.DataStore

About the DataStore component

Variables  Constructors  Properties  Methods  Event Listeners

Implements Store

The DataStore component provides the main access point to high performance data caching and compact persistence. It uses a simple hierarchical file system which allows it to contain DataExpress DataSets and arbitrary files (including Java Objects).

Use a DataStore to

To cache and persist a StorageDataSet in a DataStore, set the store and storeName properties of the StorageDataSet.By default, all StorageDataSets (and its subclasses) use a MemoryStore component. Currently MemoryStore and DataStore are the only implementations for the store property. The storeName property is the name associated with this StorageDataSet in the DataStore directory; it must be unique. The value specified for storeName is case insensitive, though it is stored internally in upper case. To force a storeName to be case insensitive, enclose it in quotes, for example

 "\"name\""
Adding a DataStore component to your application

To add a DataStore component to your application using the JBuilder UI design tools:

If you prefer, you may also create your DataStore manually (programmatically). Call the DataStore's create() method after setting the desired properties. Note that some properties cannot be changes after the call to the create() method.

DataStore directory structure

The directory structure of the DataStore associates a name and various directory status with a particular data stream. DataStore currently has these public data stream categories:

  1. DataSet: Provides data caching and persistence for any DataExpress DataSet that extends from StorageDataSet (for example, QueryDataSet, ProcedureDataSet, and TableDataSet). All StorageDataSet features are supported including master detail, picklists, constraints, calc fields, sorting, filtering, and aggregation.

  2. File: DataStore component provides methods to create and open arbitrary file streams (createFileStream and openFileStream). These methods return a FileStream that extends the Java InputStream class with additional seek() and write() methods.

    Data of type Object can be stored in the DataStore as a file stream. The DataStore component provides convenience methods to serialize and deserialize them through the readObject() and writeObject() methods. If these Objects are not serialized using Java serialization, an Exception is raised when the DataStore attempts to save the Object. Also, the class must exist on the classpath when the DataStore attempts to read an Object. (You can also persist Java Objects in a DataStore by using a DataSet with a Column that has an Object data type.)

You can access a DataStore's directory structure by calling its openDirectory() method. This returns a TableDataSet with several columns for the name, data stream category, modification time, size, delete status, and so on. The directory structure for the DataStore's file system typically contains multiple levels that you can traverse using this TableDataSet.

You delete streams in a DataStore by marking their directory entries as deleted. The contents of these streams are reallocated as new storage is needed for existing streams. Although streams can be undeleted, the entire contents may not be present if space was already used for new allocations.

Time values stored in the DataStore's directory DataSet and in Time, Date, and TimeStamp columns are recorded in UTC time.

See the openDirectory() method for more information on the directory DataSet.

Designing and debugging a DataStore application

Changing the store property of a DataSet from its default of MemoryStore to DataStore component is transparent to the DataSet as well as to any data-aware controls that are connected to the DataSet. The storage mechanism of DataStore or MemoryStore is seamlessly integrated into the JBuilder design tools. Object persistence, however, is evident when you shut down your application and reload it: the DataStore component has a "memory" and retains the data (and associated property settings) from the time the application was closed. Therefore, an application that uses a DataStore where the QueryDescriptor or ProcedureDescriptor's executeOnOpen property is enabled should empty the DataSet before re-executing the data provide phase (re-executing the query or stored procedure).

When designing an application that uses a DataStore, it is strongly recommended that:

Because of possible discrepancies that can emerge from object persistence, including your DataStore component in the DataModule ensures that all properties of the DataSet are persisted with the DataStore and are therefore applicable. When discrepancies arise, JBuilder sets the DataSet to read-only. You need to restructure the DataSet and perform a save operation so that the persisted DataSet object is updated with any variables, properties, methods, and events that were added since the object was originally persisted.

References to the StorageDataSets in the DataStore should be made through DataModule accessor methods such as "myBusinessModule.getCustomer()". This is because much of the functionality being surfaced through StorageDataSets is driven by property and event settings. Although most of the important structural StorageDataSet properties are persisted in the DataStore directory, the classes that implement the event listener interfaces are not. By instantiating the StorageDataSet with all event listener settings, constraints, calc fields, and filters implemented with events are properly maintained at run time and design time.

A daemon thread for all open DataStore instances saves modified cache data, by default, every 100 milliseconds. Although the DataStore daemon is very good at saving DataStore modifications, the following precautions should be taken:

If you use a RowFilter in an application using DataStore, the filter is persisted as a secondary index stream. This means that when you reopen the DataSet, the RowFilter will still be in affect.

You can restructure DataStore StorageDataSets using the Column Designer JBuilder UI. The Column Designer supports moving, deleting, and inserting columns and changing Column data types. To open the Column Designer, right-click any StorageDataSet in your application or DataModule and select the Activate Designer option from the context menu. For more information on the Column Designer, see the Column component.

When restructuring a DataStore, the move, insert, delete, and change type operations are not performed on the StorageDataSet immediately. The structural change is noted inside the DataStore directory as a "pending" operation (see StorageDataSet.getNeedsRestructure() and the StorageDataSet property needsRestructure). To commit the restructure, click the Restructure button from the Column Designer's toolbar, or call the restructure method of the StorageDataSet.

If a DataStore is busy whan an application loads (for example, it is in use by another application), a response event is sent and the application receiving the notification can decide how to respond rather than throw an Exception. If there is no response, the attempt to load the DataStore eventually times out.

The DataStore component differs from TableDataSet in that TableDataSet is intended for file-based import and export of data; there is little persistence except for the actual data. Also, the TableDataSet does not have any default resolver capabilities: the data is simply exported. With the DataStore component, data and property settings persist, under version control, between different runs of an application.

Note: The DataStore component is not intended for use as a database. It does not have multi-user or query capabilities, nor many other features required of a database management system.

Data type coercions

When the data type of a Column component in a StorageDataSet that is bound to a DataStore is changed, type coercions occur when going from one type to another. The following table describes what happens when a data type is coerced to another data type. The data types on the left indicate the original data type of the Column with the data types listed along the top of the table indicating the new data type of the Column.

From\To Big Decimal Double Float Long int Short boolean Time Date Time stamp String Input Stream Object
BigDecimal None Prec Prec Prec Prec Prec Prec Prec Prec Prec Ok Loss Loss
Double Prec None Prec Prec Prec Prec Prec Prec Prec Prec Ok Loss Loss
Float Prec Ok None Prec Prec Prec Prec Prec Prec Prec Ok Loss Loss
Long Ok Prec Prec None Prec Prec Prec Prec Prec Prec Ok Loss Loss
int Ok Ok Prec Ok None Prec Prec Prec Prec Prec Ok Loss Loss
Short Ok Ok Ok Ok Ok None Prec Prec Prec Prec Ok Loss Loss
boolean Ok Ok Ok Ok Ok Ok None Prec Prec Prec Ok Loss Loss
Time Prec Prec Prec Prec Prec Prec Prec None Prec Prec Ok Loss Loss
Date Prec Prec Prec Prec Prec Prec Prec Prec None Prec Ok Loss Loss
Timestamp Prec Prec Prec Prec Prec Prec Prec Prec Prec None Ok Loss Loss

Where the table values represent the following: