Click or drag to resize


While the primary purpose of Tracking Library is the ability to perform analysis and visualization as data is received, it also contains a set of classes for archiving received data for later analysis and review.

Note Note

The functionality described in this topic requires a license for the Tracking Library.

Archiving Entities

TrackingArchive<TEntity> is an abstract base class that archives entities. The following implementations are provided:

You can create your own archiver by deriving from TrackingArchive<TEntity> and implementing the required methods. Data can be retrieved from an archive in several formats: raw property data, an entity, a DateMotionCollection1<T>, a DateMotionCollection2<T, TDerivative>, a Point, or an Axes.

Entity Schema

In order for an entity to be used by an archiver, an entity schema and set of archivers must be defined. These items are registered using the EntityDescriptor<TEntity> class, which is described in more detail in the Entities topic. By implementing the IEntityArchiveDescriptor<TEntity> interface, you control exactly what data gets written to and read from an archive.

The schema defines which properties are stored in the archive, and their names. The archivers define how to store a particular type of value in archive.

The following code sample defines an entity descriptor that implements IEntityArchiveDescriptor<TEntity>. The schema and archivers are configured in the constructor.

public static class ExampleEntityDescriptorWithArchive extends EntityDescriptor<ExampleEntity> implements IEntityPositionDescriptor, IEntityOrientationDescriptor, IEntityArchiveDescriptor<ExampleEntity> {
    public ExampleEntityDescriptorWithArchive() {
        m_schema = new EntitySchema<>(String.class);
        m_schema.addProperty(new TypeLiteral<String>() {}, "SymbolId", EntityTransactedPropertyGetter.of(entity -> entity.getSymbolId()));
        m_schema.addProperty(new TypeLiteral<Force>() {}, "Affiliation", EntityTransactedPropertyGetter.of(entity -> entity.getAffiliation()));

        m_archivers = new TrackingTypeArchiverCollection();
        m_archivers.addEnumeration(new TypeLiteral<Force>() {});

    public final ReferenceFrame getPositionReferenceFrame() {
        return CentralBodiesFacet.getFromContext().getEarth().getFixedFrame();

    public final Axes getOrientationAxes() {
        return getPositionReferenceFrame().getAxes();

    public final EntitySchema<ExampleEntity> getSchema() {
        return m_schema;

    public final TrackingTypeArchiverCollection getArchivers() {
        return m_archivers;

    public final ExampleEntity createEntity(TransactionContext context, Object entityIdentifier) {
        return new ExampleEntity(context, (String) entityIdentifier);

    private EntitySchema<ExampleEntity> m_schema;
    private TrackingTypeArchiverCollection m_archivers;

The schema is defined by constructing a EntitySchema<TEntity>, passing in the type of the EntityIdentifier (get) property. For each standard interface that the entity implements, addToSchema is called on the equivalent static class in CommonEntityInterfaces, in order to add the properties that correspond to that particular interface to the schema. Once the standard interfaces are defined in the schema, any remaining properties are then added by calling addProperty, passing the name of the property and a delegate that will get the value of the property from an entity. After the schema is defined, the set of TrackingTypeArchivers which can read and write entity data must also be defined. By default, TrackingTypeArchiverCollection already contains archivers which can handle all primitive types, as well as most Components immutable types and enums. In the above example, the Force enum is the only non-standard type, so it is added by calling the addEnumeration method. This will cause the enum to be treated as an integer. If a more complex type needs to be archived, you can implement a custom archiver by deriving from TrackingTypeArchiver.

In most cases, the default archivers simply read and write the underlying numeric properties from the data structure. For example, the Cartesian archiver produces three double values containing X (get), Y (get), and Z (get). Several archivers perform other transformations you may need to be aware of:

Writing to an Archive

After registering an EntityDescriptor<TEntity> for a given entity type, we can create an archive and start writing entities to that archive, as shown in the following code sample:

MemoryArchive<ExampleEntity> archive = new MemoryArchive<>(new TypeLiteral<ExampleEntity>() {}, context);

Any entity of the specified type that is created or modified using the specified TransactionContext will be written to the archive until stopWriting is called.

Retrieving Archived Data

Assuming an archive was created as in the above code sample, data can be retrieved in several ways. The most basic way is to retrieve RawEntityData<TEntity>, objects by calling the getArchivedData method. The following code sample takes an entity identifier, start time, stop time, maximum number of records, and list of properties to retrieve.

Object entityId = "Maverick";
JulianDate startTime = new JulianDate(new GregorianDate(2010, 5, 7, 0, 0, 0.0));
JulianDate stopTime = startTime.addDays(1.0);

MemoryArchive<ExampleEntity> archive = new MemoryArchive<>(new TypeLiteral<ExampleEntity>() {}, context);

RawEntityData<ExampleEntity> rawData =
        archive.getArchivedData(entityId, startTime, stopTime, Integer.MAX_VALUE,

for (int i = 0; i < rawData.getRecordCount(); i++) {
    Object[] values = rawData.getValues(i);
    JulianDate lastUpdate = (JulianDate) values[0];
    Cartesian position = (Cartesian) values[1];
    String symbolId = (String) values[2];

The original entity that was archived can then be reconstructed by calling the createEntity method. Note that only the properties which were retrieved from the archive when getArchivedData was called will be set on the entity. To create a complete entity, all properties must be specified.

RawEntityData<ExampleEntity> rawData =
        archive.getArchivedData(entityId, startTime, stopTime, Integer.MAX_VALUE,

context.doTransactionally(Action1.of(transaction -> {
    for (int j = 0; j < rawData.getRecordCount(); j++) {
        ExampleEntity entity = rawData.createEntity(j, transaction);

A DateMotionCollection1<T> can also be constructed from the archive, as shown in the following code sample:

DateMotionCollection1<Cartesian> motions =
        archive.getMotion1(entityId, startTime, stopTime,

Finally, PointFromArchive<TEntity> and AxesFromArchive<TEntity> are available, which implement Point and Axes, respectively. These classes access data directly from the archive on demand, allowing you to create Platforms and other objects that use archived data for analysis.

PointFromArchive<ExampleEntity> entityPoint = new PointFromArchive<>(new TypeLiteral<ExampleEntity>() {}, archive, entityId);
AxesFromArchive<ExampleEntity> entityAxes = new AxesFromArchive<>(new TypeLiteral<ExampleEntity>() {}, archive, entityId);

Platform platform = new Platform();