Transactions and Operations - STARIONGROUP/COMET-SDK-Community-Edition GitHub Wiki

Introduction

[Annex C]] specifies the protocol that is to be used to read and write from an ECSS-E-TM-10-25 compliant data-source. The part of the protocol that deals with write operations is designed so that only properties of objects that have been updated need to be sent to the data-source. This is applicable to both value properties, and reference properties, including reference properties that represent [COMET-Data-Model Containment relationships.

The CDP4-COMET-SDK provides an API that makes it straightforward to perform writes to an Annex C data-source using the ThingTransaction, the OperationContainer and Operation classes. The ThingTransaction works with POCO classes and the Cache; the OperationContainer and Operation classes work on the basis of DTO classes.

ThingTransaction

The ThingTransaction is used to make a record of all the updates that need to be made to existing Things, for the creation of new Things or the deletion of existing Things. The ThingTransaction, in combination with the OperationContaier and Operation, is the COMET-SDK implementation of the Unit of Work design pattern that is geared towards compliance with Annex C.

Multiple Things can be added, updated and deleted using a single ThingTransaction, but it is also possible to stack multiple ThingTransactions on top of eachother.

Stacked ThingTransactions are used in the COMET-IME to allow a user to open multiple dialogs to create, edit and delete objects. When a user presses the Ok button on a dialog, the ThingTransaction associated to that dialog is kept, when the user presses the Cancel button the ThingTransaction associated to that dialog is discarded.

TransactionContext and TransactionContextResolver

[Annex C]] specifies that write operations, in case of the JSON REST API by means of an HTTP POST request, are only allowed on 2 different routes: The SiteDirectory route and the Iteration route. This means that all data that is somehow a part of the SiteDirectory [CDP4-COMET Data Model Containment hierarchy is written to the SiteDirectory route. Data that is in the containment hierarchy of an EngineeringModel (the other TopContainer) is written to one of the Iteration routes contained by the EngineeringModel.

Even though the ThingTransaction is used to perform create, update and deletes on multiple Things, these things may not be from a combination of SiteDirectory and an Iteration CDP4-COMET Data Model Containment tree. In COMET-SDK terms this is called the TransactionContext.

The TransactionContextResolver class is used resolve the TransactionContext of a specific Thing, the context is used to initialize a ThingTransaction.

The sample code on this page is constructed around updating an existing Person object.

    // assume we have a Person object from the Cache
    var context = TransactionContextResolver.ResolveContext(person);
    var transaction = new ThingTransaction(context);

Add, Upadate and Delete Things

The ThingTransaction class is used to register Things that need to be added, updated or deleted. The CDP4-COMET Data Model Containment hierarchy plays an important role when adding or deleting Things. All objects, with the exception of the SiteDirectory and EngineeringModel are contained by another object. The consequence of this is that when an object is added or deleted, this also means that the container object is updated. The ThingTransaction class takes care of these aspects and exposes methods that allow an API developer to easily add, update and delete objects.

An Add and Delete operation of a Thing mean an Update of its container.

The following sample code demonstrates how to register the addittion of an EmailAddress object with a Person object in the ThingTransaction.

    // create a new EmailAddress object
    var emailAddress = new EmailAddress();
    emailAddress.VcardType = VcardEmailAddressKind.WORK;
    emailAddress.Value = "[email protected]";

    // create a clone of the Person object that we want to add the EmailAddres to
    var personClone = person.Clone(false);

    // register the EmailAddres and clone of the Person object with the ThingTransaction
    transaction.Create(emailAddress, personClone);

Lets assume that the Person object already contains a TelephoneNumber, the following sample code demonstrates how to register that TelephoneNumber for deletion.

    var telephoneNumber = person.TelephoneNumber.First();
    var telephoneNumberClone = telephoneNumber.Clone(false);

    transaction.Delete(telephoneNumberClone, personClone);

At the same time we can also update some value properties of the Person object. Since the Person object is already registered with the ThingTransaction we do not need to register it again.

    personClone.Organization = "Starion";

OperationContainer and Operation

Once all the Added, Updated and Deleted POCO Things are registered with the ThingTransaction, the ThingTransaction needs to be finalized. The FinalizeTransaction function returns an OperationContainer that contains the Operations that need to be executed on an Annex C data-source.

As mentioned before, the Operation class works with DTOs, not with POCOs. An Operation contains the DTO representation of the original POCO and the updated cloned POCO, as well as the OperationKind which states what kind of operation it is: Create, Update, Delete, or Copy.

To execute the operations on an Annex C data-source, the OperationContainer is provided to the write function of a Dal that implements IDal. An IDal makes use of the Operation in an OperationContainer to compute the differences between the original and updated DTO instances to construct the proper command to send to the data-source. An API developer should make use of the Session class to write to a data-source.

An Annex C data-source will always return the updated objects as a response to write operation. The advantage of using the Session class is that the Cache is updated with the returned results coming from the data-source.

    var uri = new Uri("https://cdp4services-public.cdp4.org");
    var credentrials = new Credentials("some-user-name", "some-password", uri);
    var dal = new CdpServicesDal();

    var session = new Session(dal, credentials);
    await session.Open();

    var operationContainer = transaction.FinalizeTransaction();
    await session.Write(operationContainer);

A lower level Dal implementation is of course also possible.

    var uri = new Uri("https://cdp4services-public.cdp4.org");
    var credentrials = new Credentials("some-user-name", "some-password", uri);
    var dal = new CdpServicesDal();

    var cancelationTokenSource = new CancellationTokenSource();
    await dal.Open(credentrials, cancelationTokenSource.Token);

    var operationContainer = transaction.FinalizeTransaction();
    var updatedDtos = await dal.Write(operationContainer);