Introduction  |   MI Multi-user Concept  |   Smart Sync Javadoc

 

Smart Sync API

Introduction

The Smart Sync API offers access to the SyncBO that has been replicated to the MI Client. The application can choose if the Smart Sync API keeps track of changes and is capable to perform a "merged delta" transmit (the changed entity in final state only is transmitted) or "delta-history" transmit (all changes of an entity are recorded and are transmitted in the correct order).

Do not use the Persistence API in addition to the SmartSync API. Please also check the latest SAP Note 717510 for restrictions.

Environment of a Smart Sync application:

 

API Overview

The classes and interfaces of the Smart Sync API have the following structure:

The Smart Sync API structure in detail.

Entry Points

Class / Interface

Purpose
SmartSyncRuntime Accessor methods for the SmartSync facade, factory and notifier classes.
SyncBoDataFacade
Data access.
SyncBoDescriptorFacade Meta-data access.
SmartSyncQueryFactory Query creation
InboxNotifier Inbound data handling.
SyncBoOutDeltaNotifier Outbound data handling. Notifies about changes.
SyncBoDeltaRequestFacade

Delta handling of outbound messages.

SyncBoOutDeltaFacade Delta handling of outbound data.

Data Access

Class / Interface

Purpose
SyncBo Read/write operations for a SyncBO instance.
Row
Read/write operations for an item of a given SyncBO instance.
Field Read/write operations for a field in a row of a given SyncBO instance.
SyncBOCollection
SyncBOList
RowCollection
RowList
Collections and lists of SyncBOs and rows. Collections and lists are usually returned from a hierarchically higher object and queries.

Meta-data access

Class / Interface

Purpose
SyncBoDescriptor
Read operation for a SyncBO type.
RowDescriptor
Read operation for an item type of a given SyncBo type.
FieldDescriptor Read operation on a field type in an item type of a given SyncBo type.
RelationDescriptor
Read on foreign-key relation ships between field values to item keys in other SyncBos.
SyncBoCollection
SyncBoList
RowCollection
RowList
ObjectIterator
SyncBoDescriptorIterator
RowDescriptorIterator
FieldDescriptorIterator
RelationDescriptorIterator

Collections, lists and iterators of SyncBOs, rows and fields. Collections and lists are usually returned from a hierarchically higher object and queries.


The SyncBoDescriptor instance provides read-access to:

Because a SyncBO must have one header row, every SyncBO type has one header row type. Therefore every SyncBoDescriptor is also a RowDescriptor. In Java terminology, the SyncBoDescriptor class extends the RowDescriptor class.


The RowDescriptor instance provides read access to:


The FieldDescriptor instance provides read access to:


The RelationDescriptor instance provides read access to:



Example how to create a SyncBO instance:

  1. Create an empty SyncBO instance for a given SyncBO type.

    mySyncBo = SyncBoDataFacade.createEmptySyncBo (SyncBoDescriptor);

  2. Get the top row and set header fields.
    myHeaderRow = mySyncBo.getTopRow; myHeaderRow.setFieldValue (<field descriptor>, <value>);

  3. Optionally create and save item rows.
    myNewRow = mySyncBo.createEmptyRow (<row descriptor>); ... <set fields> mySyncBO.insertRow( myNewRow);

  4. Save SyncBO locally (this will check SyncBO consistency like mandatory fields, field types and so on)
    SyncBoDataFacade.insertSyncBo(mySyncBo);

Example how to modify a SyncBO instance:

  1. Get a SyncBO instance from SyncBoDataFacade via one of its getter methods.

    mySyncBo = SyncBoDataFacade.getSyncBo(<id>);

  2. Replace a row.

    myChangedRow = mySyncBo.getRow(<row descriptor or query>);
    myChangedRow.setFieldValue(<field descriptor>, <value>);
    mySyncBo.replaceRow(myChangedRow);

    Changes are recorded. To increase the performance, work on a copy of a SyncBO or row (method: createUnlinkedCopy or createInitialCopy)

  3. Delete a row.

    mySyncBo.deleteRow(<row descriptor or query>);

  4. Save SyncBO locally to make changes permanent. This will check SyncBO consistency like mandatory fields, field types, ..) .

    mSyncBoDataFacade.replaceSyncBo(mySyncBo);

Example how to delete a SyncBO instance:

  1. Delete a SyncBO instance with the SyncBoDataFacade.

    SyncBoDataFacade.deleteSyncBo(<syncbo instance>);


Queries

Queries are used to get all SyncBo or row instances that match a certain condition. Queries are executed by passing them to SyncBoDataFacade. Query over joins are not supported.

Class / Interface

Purpose
SmartSyncQueryFactory
Factory to create queries.
Query
Object representing a query for data or meta-data. The object contains a condition and the sort order.
Condition Definition of a condition composed out of the field descriptor + operator (condition) + value.
SortOrder
Definition of a condition composed out of the field descriptor and an attribute (ascending/descending).


Examples:

Create a Condition

//SYNC_KEY > '10000000001
Condition singleCondition = queryFactory.createCondition(syncKeyFieldDescriptor, RelationalOperatorType.GREATER_THAN,"10000000001");

Create a Sort Order

//sort in SYNC_KEY field in ascending order
Condition singleSortOrder = queryFactory.createSortOrder(syncKeyFieldDescriptor, true);

Create the Query

syncBoQuery = queryFactory.createQuery(syncBoDescriptor, singleCondition, singleSortOrder);


In/Outbound handling

Class / Interface

Purpose
InboxNotifier
Observers can be registered for inbound messages or inbound data.
SyncBoInDeltaObserver
Observes inbound data and SyncReplys and serves as entry point for delta management.
MessageReplyObserver
Observes inbound messages on communication status.
SyncBoOutDeltaNotifier
Definition of a condition composed out of the field descriptor and an attribute (ascending/descending).
SyncBoOutDeltaObserver Observes outbound data and its send type.


A Mobile application can subscribe to inbound & outbound data. Whenever data of a given SyncBo type is handled, the registered observer class in the application is notified and can, for example, send types and resolve conflicts (Delta Management).

Error handling of synched data

Class / Interface

Purpose
MessageReplyServer
Called when a MessageReply arrives. Registered by InboxNotifier.
MessageReply
Actual message describing the communication status.
MessageReplyType
Communication status. Error/success, sync started/ended and so on.
SyncReply
Message describing the response to uploaded data or download request.
SyncReplyType Backend handling information on uploaded data (for example, conflict, error, success).


A Mobile application can subscribe to synchronization messages. Applications use the message to decide if reaction to inbound datais needed. There are two types of messages:

Delta management

Class / Interface

Purpose
SyncBoInDelta
Inbound data set and SyncReply (subinterface of SyncBoChange).
SyncBoOutDelta Outbound data set and SendType (subinterface of SyncBoChange).
SyncBoChange
In-/Outbound data set. Access to action type and row changes.
RowChange
In-/Outbound data set. Access to action type and field changes.
SyncBoChangeActionType
RowChangeActionType
Action to be performed on a SyncBO or row (Insert, modify, delete, no operation, replace).


Observers have read access to delta messages that are exchanged between the MI client and the server. In case of conflicts, observers can save a copy of the conflicting object and merge it later with the new original from the server.


Constants and types

All constants used in Smart Sync are defined as static variables of the following classes:

DependencyType
DependencyType
FieldGroupType
FieldInputQualifyType
FieldModifiabilityType
GlobalResetProcessing
MessageReplyType
StatusType
SyncBoChangeActionType
SyncBoDeltaRequestType
SyncBoOutDeltaMergeType
SyncProcessingType
SyncReplyType
SyncBoStatusType


Basic Coding Examples

This demonstrates to use the Smart Sync API for basic operations.

How to set up a SyncBoDescriptorFacade:
Getting the SyncBoDescriptorFacade with the SmartSyncRuntime and getting the descriptors.

 public AppAccess() {
   this.syncBoDescriptorFacade = SmartSyncRuntime.getInstance().getSyncBoDescriptorFacade();
   this.customerOrderD = this.syncBoDescriptorFacade.getSyncBoDescriptor("Customer Order");
   this.customerOrderHeadD = this.customerOrderD.getTopRowDescriptor();
   this.orderValueD = this.customerOrderHeadD.getFieldDescriptor("Order value");
   this.salesRegionD = this.customerOrderHeadD.getFieldDescriptor("Sales region");
   this.customerNumberD = this.customerOrderHeadD.getFieldDescriptor("Customer number");

   this.syncBoQueryFactory = SmartSyncRuntime.getInstance().getQueryFactory();

   this.inboxNotifier = SmartSyncRuntime.getInstance().getInboxNotifier();
}
 

Insert a new SyncBo:
Using the SyncBoDataFacade to create an empty SyncBO and fill it with data.

 public void insertNewSyncBo() {
     SyncBo newCustomerOrder = this.syncBoDataFacade.createEmptySyncBo(this.customerOrderD);

     Row customerOrderHead = newCustomerOrder.getTopRow();
     customerOrderHead.setFieldValue(this.customerNumberD, "987");
     customerOrderHead.setFieldValue(this.orderValueD, new FixedDecimal("1234,25"));
     customerOrderHead.setFieldValue(this.salesRegion, "Walldorf");

     Row customerOrderItem = newCustomerOrder.createEmptyRow(customerOrderItemD);
     customerOrderItem.setFieldValue(this.productNumberD, new Integer(1241294));
     customerOrderItem.setQuantity(this.productNumberD, new Integer(3));

     this.syncBoDataFacade.insertSyncBo(newCustomerOrder);
}
     

Queries:
Setup query conditions.

public void createQuery() {
     Condition cond1 = this.syncBoQueryFactory.createCondition
                 (this.orderValueD, RelationalOperatorType.GREATER_THAN, "125469");
     Condition cond2 = this.syncBoQueryFactory.createCondition
                 (this.salesRegionD, RelationalOperatorType.EQUALS, "Walldorf");
     Condition cond3 = this.syncBoQueryFactory.createCondition
                 (new Condition[]{cond1, cond2},LogicalOperatorType.AND);

     SortOrder sort = this.syncBoQueryFactory.createSortOrder(this.customerNumberD, true);

     Query query = this.syncBoQueryFactory.createQuery(this.customerOrderD, cond3, sort, 10);

     SyncBoList result = this.syncBoDataFacade.getSyncBos(query);
}

Notification:
Set up an event handler

public void notifyOnInDelta() {
   SyncBoInDeltaObserver myObserver = new SyncBoInDeltaObserver() {
     public void observeSyncBoTypes() {
       return new SyncBoDescriptor[] {this.customerOrderD};
     }
     public void receivedSyncBoInDelta(SyncBoInDelta syncBoInDelta) {
       if (syncBoInDelta.getAction() == SyncBoChangeActionType.DELETE) {
         String key = syncBoInDelta.getSyncKey();
         SyncBo toBeDeleted = ZTstAppAccessDemo.this.syncBoDataFacade.getSyncBo(key);
         SyncBo copyThatWontBeDeleted = toBeDeleted.createUnlinkedCopy();
         ZTstAppAccessDemo.this.syncBoDataFacade.insertSyncBo(copyThatWontBeDeleted);
       }
     }
   };
   ZTstAppAccessDemo.this.inboxNotifier.registerSyncBoInDeltaObserver(myObserver);
}