HistoryService Developer Documentation

In two words

The HistoryService may be described as a “simple database”. However due to the specific requirements it is highly customized. The main design goal was to define a simple, independent programming interface that would allow functionality like message history, call logs or any other feature that requires persistence.

In four words

Data is stored in HistoryRecords. A HistoryRecord always belongs to a group of records. Such group is simply a History. It is identified by a HistoryID. Each History has a HistoryRecordStructure. You can add records to a History by using a HistoryWriter, or search through the existing records by using a HistoryReader.

The main idea: to be able to simply call addRecord( id, String[] ); or findByStartDate( id, startDate );

Database analogy
In order to better understand the different entities one can make an analogy with standard databases: A database (HistoryService) consists of tables (History). Each table has a name (HistoryID) and contains records (HistoryRecord). Each table has a fixed structure (HistoryRecordStructure).
Of course there are many differences. A history is considered as ‘append-only’. That is - once created, the structure of a history cannot be changed. The same is valid for single records - once added, a record cannot be deleted or changed. Another major difference is that the HistoryRecordStructure can be overriden for individual records.
An important feature is that all HistoryRecords are timestamped.

In Integer.MAX_VALUE words

The HistoryID is a wrapper of a String[], where the elements should contain only letters, numbers or _ (underscore). In order to create one you can use one of the two static functions:

  • createFromRawID by providing a String[] whose elements are arbitrary strings
  • createFromID by providing a String[] whose elements contain only letters, numbers or _

The HistoryRecordStructure is wrapper of a String[]. Each of its elements is the name in a name-value mapping. A name may appear several times, which corresponds to a one-to-many relationship.

The HistoryRecord is a HistoryRecordStructure AND values for each of the elements in this structure.

After obtaining a HistoryService you can use the following methods:

  • getExistingIDs
  • getHistory for a given HistoryID
  • check if isHistoryExisting for a given HistoryID
  • createHistory with specified HistoryID and HistoryRecordStructure

Then, after creating or obtaining an existing History, you can:

  • getReader
  • getWriter
  • getID
  • getHistoryRecordsStructure

If you need to query the existing records, after obtaining a HistoryReader, you can search:

  • findByStartDate by providing a start date
  • findByEndDate by providing an end date
  • findByPeriod by providing a start date and an end date
  • findByKeyword by providing a keyword
  • findByKeywords by providing a list of keywords
  • findByText by providing a start date, an end date and a list of keywords

However if you want to add records, you should obtain a HistoryWriter, and afterwards:

  • addRecord by providing a HistoryRecord
  • addRecord by providing a String[] corresponding to the HistoryRecordStructure

And of course.. the example..

// Obtain the service
ServiceReference historyServiceRef =
            context.getServiceReference(
                HistoryService.class.getName());
HistoryService historyService =
    (HistoryService)context.getService(historyServiceRef);

HistoryID id = HistoryID.createFromRawID(
            new String[] {"this", "is", "a simple", "id, yeah!!"});

// If there is no such history - create it.
// Otherwise just get the existing one
History history;
if(!historyService.isHistoryExisting(id)) {
    HistoryRecordStructure recordStructure = 
            new HistoryRecordStructure(new String[]{"name", "age", "gender"});
    history = historyService.createHistory(id, recordStructure);
} else {
    history = historyService.getHistory(id);
}

// Add some records
HistoryWriter writer = this.history.getWriter();
writer.addRecord(new String[] {"Monica", "32", "female"});
writer.addRecord(new String[] {"John", "64", "male"});
writer.addRecord(new String[] {"Santa Claus", "1024", "declines to state"});

// Then search through all records and print the results
HistoryReader reader = this.history.getReader();
QueryResultSet result = reader.findByKeyword("state");
while(result.hasNext()) {
    HistoryRecord record = result.nextRecord();
    String[] vals = record.getPropertyValues();

    System.out.println(   "Found! Name: " + vals[0]
                        + " Age:" + vals[1]
                        + " Gender:" + vals[2]);
}

Author: Alexander Pelov