Introduction | MI Multi-user Concept | Smart Sync Javadoc
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:
The classes and interfaces of the Smart Sync API have the following structure:
The Smart Sync API structure in detail.
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. |
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:
mySyncBo = SyncBoDataFacade.createEmptySyncBo (SyncBoDescriptor);
Get the top row and set header fields.
myHeaderRow = mySyncBo.getTopRow; myHeaderRow.setFieldValue (<field
descriptor>, <value>);
Optionally create and save item rows.
myNewRow = mySyncBo.createEmptyRow (<row descriptor>);... <set
fields>mySyncBO.insertRow( myNewRow);
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:
mySyncBo = SyncBoDataFacade.getSyncBo(<id>);
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
)
mySyncBo.deleteRow(<row descriptor or query>);
mSyncBoDataFacade.replaceSyncBo(mySyncBo);
Example how to delete a SyncBO instance:
SyncBoDataFacade.deleteSyncBo(<syncbo instance>);
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);
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).
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:
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.
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
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); }