Pending State Pattern

When a create, update, delete, or save operation is called on an entity, the requested change becomes pending. To apply the pending change, call SubmitPending on the entity, or SubmitPendingOperations on the MBO class:

Customer e = new Customer();
e.Name = "Fred";
e.Address = "123 Four St.";
e.Create(); // create as pending
e.SubmitPending(); // submit to server

Customer.SubmitPendingOperations(); // submit all pending Customer rows to server

SubmitPendingOperations submits all the pending records for the entity to the Unwired Server. This method internally invokes the SubmitPending method on each of the pending records.

For message-based sychronization, the call to SubmitPending causes a JSON message to be sent to the Unwired Server with the Replay method, containing the data for the rows to be created, updated, or deleted. The Unwired Server processes the message and responds with a JSON message with the ReplayResult method (the Unwired Server accepts the requested operation) or the ReplayFailure method (the server rejects the requested operation).

If the Unwired Server accepts the requested change, it also sends one or more Import messages to the client, containing data for any created, updated, or deleted row that has changed on the Unwired Server as a result of the Replay request. These changes are written to the client database and marked as rows that are not pending. When the ReplayResult message is received, the pending row is removed, and the row remaining in the client database now contains data that has been imported from and validated by the Unwired Server. The Unwired Server may optionally send a log record to the client indicating a successful operation.

If the Unwired Server rejects the requested change, the client receives a ReplayFailed message, and the entity remains in the pending state, with its ReplayFailed attribute set to indicate that the change was rejected.

For replication-based synchronization, the call to SubmitPending creates a replay record in local database. When the DBClass.Synchronize() method is called, the replay records are uploaded to Unwired Server. Unwired Server processes the replay records one by one and either accepts or rejects it.

At the end of the synchronization, the replay results are downloaded to client along with any created, updated or deleted rows that have changed on the Unwired Server as a result of the Replay requests. These changes are written to the client database and marked as rows that are not pending.

When the operation is successful, the pending row is removed, and the row remaining in the client database now contains data that has been imported from and validated by the Unwired Server. If the Unwired Server rejects the requested change, the entity remains in the pending state, with its ReplayFailed attribute set to indicate that the change was rejected. The Unwired Server may optionally send a log record to the client.

The LogRecord interface for both message-based synchronization and replication-based synchronization has the following getter methods to access information about the log record:

Method Name C# Type Description
Component string Name of the MBO for the row for which this log record was written.
EntityKey string String representation of the primary key of the row for which this log record was written.
Code int One of several possible HTTP error codes:
  • 200 indicates success.
  • 401 indicates that the client request had invalid credentials, or that authentication failed for some other reason.
  • 403 indicates that the client request had valid credentials, but that the user does not have permission to access the requested resource (package, MBO, or operation).
  • 404 indicates that the client tried to access a nonexistent package or MBO.
  • 405 indicates that there is no valid license to check out for the client.
  • 500 to indicate an unexpected (unspecified) server failure.
Message string Descriptive message from the server with the reason for the log record.
Operation string The operation (create, update, or delete) that caused the log record to be written.
RequestId string The id of the replay message sent by the client that caused this log record to be written.
Timestamp System.DateTime? Date and time of the log record.

If a rejection is received, the application can use the entity method GetLogRecords or the database class method SampleDB.GetLogRecords(query) to access the log records and get the reason:

Sybase.Collections.GenericList<Sybase.Persistence.ILogRecord> logs = e.GetLogRecords();
for(int i=0; i<logs.Size(); i++)
{
Console.WriteLine("Entity has a log record:");
Console.WriteLine("Code = {0}",logs[i].Code);
Console.WriteLine("Component = {0}",logs[i].Component);
Console.WriteLine("EntityKey = {0}",logs[i].EntityKey);
Console.WriteLine("Level = {0}",logs[i].Level);
Console.WriteLine("Message = {0}",logs[i].Message);
Console.WriteLine("Operation = {0}",logs[i].Operation);
Console.WriteLine("RequestId = {0}",logs[i].RequestId);
Console.WriteLine("Timestamp = {0}",logs[i].Timestamp);
}

CancelPendingOperations cancels all the pending records for an entity. This method internally invokes the CancelPending method on each of the pending records.