Chapter 9

Generic Data Synchronization: Project Migrate and the WebData API

WHAT’S IN THIS CHAPTER?

  • Understanding the common problems that Android developers encounter when interacting with network data
  • Solving common mobile data problems in a generic way with project Migrate and the WebData API
  • Looking at the WebData protocol in detail
  • Noting advantages of a WebData API–based system

WROX.COM CODE DOWNLOADS FOR THIS CHAPTER

Please note that all the code examples in this chapter are available at https://github.com/wileyenterpriseandroid/Examples.git and as a part of the book’s code download at www.wrox.com on the Download Code tab.

As you’ve read in this book, mobile developers face similar problems on many platforms when writing applications that use network services to store data. Developers getting started with Android face problems associated with network data loading right off the bat. A typical first application for many developers will include a list of items loaded from a network service. The items will use thumbnails that require lazy loading. Developers with a bit more experience will start to use more sophisticated techniques like paging schemes that avoid the need to load all the results of a query over the network — large queries are loaded in pieces. Developers will also need a RESTful protocol for communicating with a backend service, and that protocol is likely to need synchronization support to deal with multiple hosts changing the same state. Developers often want offline data editing that allows an app to remain useful if the network becomes unavailable. Ideally, developers won’t have to reinvent the wheel to address concerns such as these, but Android out of the box could do more to help developers solve these problems correctly.

As noted in earlier chapters, when implementing these functions, developers are likely to create similar bugs such as long-running UI events, hanging UI threads, or inflexible code that requires frequent application updates. Developers often write inefficient network protocols that rely on polling to update application data.

Why not create a system that solves all of these problems in a generic way that can be reused for many applications?

Of all the expressive web services and built-in content providers available on mobile platforms today, we see a gap in the available features — a generic data service explicitly designed to plug into a mobile MVC client in a way that extracts the redundantly implemented chores of handling data from the user interface of a mobile application.

This chapter introduces a new and simple RESTful network API that leverages the Android content provider system to facilitate seamless custom data integration into the Android platform. It covers a service implementation of that API and a mobile client for the API that communicates directly with user interface components. The chapter ends by summarizing advantages of deploying applications around an architecture that uses this technology. The next chapter digs into writing some real applications using this system.

INTRODUCING WEBDATA AND PROJECT MIGRATE

The WebData API and an open source implementation of it called, project Migrate provide a solution in this space. These technologies relieve Android developers from the need to write their own SQL tables, create their own synchronized and RESTful protocol, and integrate with the Android view components in a way that is resilient to all of the problems described in this and previous chapters. At the time of writing of this book, Migrate and WebData represent a fledgling open source effort. Consequently, you should expect to see significant changes in the project in the coming months. The Migrate feature set currently just puts “meat on the bones” of a compelling set of ideas and in terms of features that can make this system convenient for developers, the project has room to grow. For this reason, this chapter delves into both the existing Migrate implementation and important future enhancements for the project.


NOTE You can find more information about the Migrate project, including future architectural directions, on the following github wiki:

How Project Migrate Works

We’ve focused on the third pattern from Chapter 5, content providers used with sync adapters, and created a specific RESTful protocol that supports robust Android network communication for custom data with synchronization support. The Migrate project provides a generic data binding framework that links standard Android UIs to backend service persistence on a remote host. The API is geared toward a persistent key/value interface like that of android.content.Cursor that enables WebData service implementations to easily leverage web-scale databases like DataStore, MongoDb, DynamoDb, etc.

With WebData, developers use a schema format to define custom data in a backend service. The Migrate client, an Android-based content provider and sync adapter, can synchronize this data to a device and bind it into UI components. An Android application UI only needs to communicate with an Android-based API to store and access data (for example, a provider contract). Project Migrate handles the REST (pun intended). The Migrate provider API shares characteristics of built-in Android content providers, like the calendar and contacts providers, but also enables applications to define their own types of data and reuse a generic framework to create data that can serve a diverse range of applications.

The WebData API enables developers to define and synchronize persistent “objects” or map oriented key/value pairs (like JavaScript objects). The Migrate system takes care of persisting and synchronizing changes in these objects between a backend service with scalable storage, and mobile clients using SQLite over time. The API is event oriented, so it fits seamlessly into the network-oriented MVC pattern discussed in Chapter 5.

Figure 9-1 provides an illustration of the Migrate and WebData architecture with an Android client.

How Project Migrate Streamlines the Mobile Connection to the Enterprise

The following characteristics of the WebData API and project Migrate drastically reduce the amount of overhead required to create robust Android network applications:

  • The WebData protocol replaces many transactions that would normally require the development of a custom RESTful web protocol.
  • Migrate provides a seamless connection from a backend service to the Android UI using Android content providers and cursors.
  • Migrate also provides streamlined synchronization built into the central Android provider sync adapter framework.
  • The WebData API provides an event-oriented, reusable, and scalable synchronization protocol.
  • The Migrate client creates and manages SQL tables on behalf of client applications.
  • The Migrate service maintains a managed data connection that supports service managed data evolution.
  • Developers do not need to “know” the correct way to program the handset and service — the Migrate framework enforces correct programming techniques (for example, correct synchronization, proper use of the UI event thread, and efficient network programming).
  • Migrate supports a transparent and flexible data paging scheme for efficient use of system resources.
  • Migrate enables support for UI component validation that leverages the same schema that defines data.

The WebData API in Detail

The WebData API reuses standard web services concepts wherever possible in order to permit as wide a range for integration as possible (we currently support an Android client, foresee an iPhone client, and may eventually provide HTML5 integration). The API stipulates a serialization format based on JSON, which is both widely deployed and efficient, and on JSON schema, a simple object schema format. The API also requires RESTful URL-based protocol requests. Here’s a complete list of the components of the WebData API specification:

  • Schema-based definition of objects to define the structure of objects (for creation of SQLite tables)
  • A RESTful request protocol for modifying and transmitting objects
  • An object serialization format based on JSON; see:
  • Paging parameters that enable client- and server-side specification of the size of data “windows” that clients will use to transmit collections of data
  • An integrated synchronization scheme
  • A notification system that enables event-based interaction between a WebData instance and mobile clients to support MVC-style client architectures
  • Application of schema data for user interface component validation

The next sections provide detailed descriptions of relevant aspects of the WebData API protocol. As you read, keep in mind that the Migrate WebData client API relies on the standard content provider API CRUD operations and sync adapter synchronization to access and update WebData objects.

The following explanations of protocol operations only serve as an overview for developers who want to understand the details of the Migrate client and synchronization protocol. In explicit terms, the Migrate client directly uses these operations; UI developers do not. Note also that we have structured the design of protocol operations to preserve the standard sequence of the built-in providers — the CRUD operations operate on local SQLite state, and the synchronization operation is the only time that the provider communicates with the backend service.

The WebData API RESTful Protocol

The WebData API specifies a REST-based synchronization protocol. The API revolves around schema that define data, REST operations that modify persistent objects, and a synchronization system that uses those operations to keep data consistent between a service and multiple clients.

Using Schema to Define Data

Before a client can use a WebData service to store domain objects, the service must have schema information that defines those objects. WebData uses JSON schema, http://json-schema.org/, as an object schema format, and a WebData JSON envelope to support synchronization. JSON schema is an extremely simple object definition language that supports the declaration of an array of domain objects with corresponding <key, type> properties that define fields of those objects.

Applications that need to define new schema, simply POST JSON schema to WebData service instances. The POSTing entity will typically be a backend service itself, rather than a mobile client. Using a third party program to define schema allows the schema to change in backward-compatible ways (for example, fields used by clients are not removed, and so forth) after an application is deployed.


NOTE It’s a general architectural theme of Migrate to enable post-deployment configuration of handset applications.

The schema in Listing 9-1 defines a domain object for a contact usable in a hypothetical contacts application. To define this contact type, you’ll need a utility that POSTs the schema and Sync envelope into the following WebData service URL:

http://host:port/contacts/scheme/com.enterpriseandroid.webDataContacts.dataModel.Contact

Figure 9-2 shows a web application posting a schema into a WebData service implementation. After the web app POSTs this schema, clients can read and write objects with fields that conform to the schema.

The schema payload includes the synchronization envelope and the schema itself. Listing 9-1 shows the contact POST.

LISTING 9-1: A WebData schema creation POST payload

1 POST
    http://host:port/context/schema/com.enterpriseandroid.webDataContacts.Contact
2 {
3      "wd_version":1,
4      "wd_id":"com.enterpriseandroid.webDataContacts.Contact",
5      "wd_classname":"com.migrate.webData.model.PersistentSchema",
6      "wd_namespace":"__schema",
7      "wd_deleted":false,
8      "wd_status":0
9      "jsonSchema":{
10         "properties":{
11             "status":{
12                 "type":"string"
13             },
14             "lastname":{
15                 "type":"string"
16             },
17             "email":{
18                 "type":"string"
19             },
20             "age":{
21                 "type":"integer"
22             },
23             "birthDate":{
24                 "type":"integer"
25             },
26             "phoneNumber":{
27                 "type":"string"
28             },
29             "wd_id":{
30                 "required":true,
31                 "type":"string"
32             },
33             "firstname":{
34                 "type":"string"
35             },
36             "wd_namespace":{
37                 "type":"string"
38             },
39             "wd_classname":{
40                 "type":"string"
41             },
42             "wd_updateTime":{
43                 "required":true,
44                 "type":"long"
45             },
46             "wd_version":{
47                 "required":true,
48                 "type":"integer"
49             },
50             "wd_deleted":{
51                 "required":true,
52                 "type":"integer"
53             },
54         },
55         "type":"object"
56     },
57 }

We want to take a minute to point out some interesting details about this code:

  • Lines 3-8 — Specify envelope information that enables synchronization of the schema itself whenever the POSTing application needs to modify the schema to support new versions of the application. The fields work as follows:
    • wd_id — Defines the JSON schema ID that the Migrate project uses as the name of the domain object in reverse domain name format. This name can be used to create names of tables for client or service SQL storage.
    • This is the first version of the schema, so the value of wd_version: is 1; the version will increment on subsequent POSTs to this URL.
    • The wd_namespace field specifies that this payload pertains to "__schema" and not to "__data".
    • The wd_deleted field indicates that this schema has not been deleted.
  • Line 9 — Starts the listing of JSON that conforms to the JSON schema specification. The JSON schema is the largest part of the schema payload — it defines the typed fields of each WebData object.
  • Lines 29-53 — Show the definition of fields that Migrate requires in the domain object itself to enable synchronization in instances of the type — the WebData fields will be part of the data object itself. Migrate won’t directly show these fields to UI code; they assist with internal bookkeeping.
  • Lines 20-22 — A declaration of a domain field, age. The declaration has a type of integer, and note that type is contained in a map of its own — thus allowing the possibility of other metadata associated with the age field, such as UI validation information (for example, the format of the field, if the field is required, etc.).

Referencing Data

WebData supports both CRUD and Sync based access to schema and domain data. For example, the following URI format provides access to contact objects with fields defined by the schema in the previous section:

http://host:port/contacts/classes/com.enterpriseandroid.webDataContacts.api.Contact/{id}

The general form of WebData data URIs follows:

http://host:port/context/classes/{class}/{id}

where class denotes the schema id of the requested object, and id indicates the UUID of the object. GET, PUT, POST, and DELETE operations on URIs like the one shown here have the standard RESTful effect — POST creates an object, PUT updates it, GET returns it, and DELETE removes the object. Requests select specific object instances using the UUID. The next few code listings show significant example protocol requests, to give you a sense of how WebData works.

Listing 9-2 shows an example POST payload that creates a new contact instance.

LISTING 9-2: An example domain object POST request

1 POST
   http://host:port/context/classes/com.enterpriseandroid.webdataContacts.Contact/
   b83296c4-2bdb-438e-a789-57536431026c
2
3 {
4      "wd_version":1,
5      "wd_namespace":"__data",
6      "wd_deleted":0
7      "firstname":"John",
8      "lastname":"Smith",
9      "birthDate":136194847583,
10     "email":"[email protected]",
11     "age":23,
12     "phoneNumber":"978-123-4567",
13     "status":"some status",
14 } 

This POST creates a new WebData object with data and envelope fields described as follows:

  • Line 1 — Specifies the complete RESTful URL for the object, including a client created UUID that allows the WebData service to create new data, or correlate the POST with pre-existing persistent storage. The class, or type of the object is com.enterpriseandroid.webdataContacts.Contact.
  • Line 4-6 — WebData synchronization support fields:
    • On creation, the WebData object version is 1.
    • The wd_namespace is "__data", since this is object information, not schema related.
    • The object is new and not deleted, wd_deleted is 0.
  • Line 7-12 — Actual data field values for the POSTed object.

Listing 9-3 shows a WebData GET request for the object posted in Listing 9-2. Such a request would return a JSON-formatted WebData object, as listed.

LISTING 9-3: An example WebData GET response

1  GET 
http://host:port/context/classes/com.enterpriseandroid.webDataContacts.Contact/
    b83296c4-2bdb-438e-a789-57536431026c
2  {
3     "wd_id":"b83296c4-2bdb-438e-a789-57536431026c",
4     "wd_version":1,
5     "wd_classname":"com.enterpriseandroid.webDataContacts.Contact",
6     "wd_namespace":"__data",
7     "wd_updateTime":1369022907831,
8     "wd_deleted":0
9     "firstname":"John",
10    "lastname":"Smith",
11    "birthDate":136194847583,
12    "email":"[email protected]",
13    "age":23,
14    "phoneNumber":"978-123-4567",
15    "status":"some status",
16 } 

The response retrieves the formerly POSTed contact object. The following highlights the lines that should catch your interest:

  • Line 1 — The URI is the same as that in Listing 9-2, but the operation is GET.
  • Lines 3-8 — Contain the WebData envelope information.
  • Lines 9-14 — Show the same contact data as that from Listing 9-2.

Searching

The WebData API supports CRUD-based queries; however, the typical usage pattern for Migrate at the time of writing of this book is to rely on synchronization and local content provider operations. A future edition of this book may cover more detail on Migrate CRUD operations, such as remote search. For now, Migrate relies on the ContentProvider.query method to enable searching for data in content provider managed SQLite tables.

Notifications

WebData specifies support for push messaging notification to prevent clients from needing to poll a WebData implementation service for data changes. The WebData payload for push messages merely contains a list of schema identifiers that indicate the data that has changed since the last client update. Once the client has received this list from the push notification, it should engage in the synchronization protocol outlined in the next section for each modified schema identifier. Listing 9-4 shows an example WebData schema modification notification, where lines 4 and 5 list the schema ids for which data has changed.

LISTING 9-4: An example WebData schema modification notification

1 {
2     "modified": 
3         [
4             "com.enterpriseandroid.webDataContacts.Contact",        
5             "com.enterpriseandroid.webDataAutomobile.Automobile"
6         ]
7  }

Synchronization

Data travels or “migrates” between a WebData client and a WebData service instance during a synchronization operation. Such operations are central to the concept of the WebData API. These exchanges of data allow clients to merge local changes with remote changes in a service host, and also represent the mode of transport of the objects between the client and the service. The WebData API specifies synchronization support according to the following protocol:

1. WebData clients persistently maintain a timestamp of the last synchronization operation with a particular service host. The synchronization time is recorded on the service host, and then passed to clients at synchronization time.
2. During any synchronization operation between a WebData client and a service, the client will first send changes it has made locally since it last updated with the service, to the service host. The client should maintain a “dirty” flag to know which elements it has changed. The service host will attempt to resolve the client’s changes against any changes that may have taken place in the service since the last update.
3. When the service is ready, it will send back to the client all changes that took place since the client’s last update. The client updates its timestamp from the service accordingly to reflect that the synchronization operation has completed successfully.
4. Synchronization operations can originate from the client (a “pull” or “poll”) or from the service host (a “push”). The WebData content provider makes use of local Android network APIs to poll the service. Push operations will use one of several commercially available mobile push services such as Google Cloud Message for Android, Apple Push Technology, or a commercially available push technology aggregator.
5. If a client application knows that it needs new data, it can request a sync operation to take place. Application developers should use such requests judiciously given that polling-based applications can place a great strain on network resources.

Conflict Resolution

Because the WebData API permits concurrent changes on multiple devices, it’s possible for conflicts to arise between data modifications from different sources. The WebData API specifies the transmission of version information to enable the resolution of versioning conflicts when data is modified between the backend service and multiple clients. WebData objects must always contain a version field that is incremented every time the client or service succeeds in changing a given object. When a client updates an object, the server checks the version against the one stored on the server. The update operation succeeds only when the version numbers match.

WebData implementations should resolve conflicts as follows:

  • The service first attempts to resolve changes sent from clients.
  • The service sends conflicts it cannot resolve to the client for resolution.
  • A client can request all conflicts since the last synchronization.
  • The Migrate client attempts to resolve the conflicts. If the Migrate client cannot resolve a change automatically, the client delegates to the end user to resolve it.
  • If a client is unable to resolve the conflict, the server keeps its own version of the data and ignores the version of the data sent by the client.

These operations should look similar to the ones outlined in Chapter 6, which intentionally built a foundation for WebData synchronization as discussed earlier in this chapter.

An Example Synchronization and Conflict Resolution Scenario

To help you understand how synchronization and conflict resolution works in practice, we’ve created a simple scenario in which:

1. A client makes changes to a contact object.
2. The server has a change to the same contact, creating a conflict for id a7329678-4bdc-536a-b234-78236431026a.
3. A different client has also added a new contact to the service (not in conflict).

The client will need to sync the server contact that is not in conflict (that is, make its own copy locally) and will need to resolve differences between its own version of the conflicted contact and the server’s version. Listings 9-5, 9-6, and 9-7 show these changes and Figure 9-3 illustrates the interaction. Changes are flowing in and out of the local SQLite cache on the client. Changes from the client and service are selected based on timestamp, similar to what you saw in Chapter 6.

The scenario begins with Listing 9-5, when a client initiates a sync request.

LISTING 9-5: A client initiates sync with objects changed since last sync time

1 POST http://host:port/migrate/context/classes/
   com.enterpriseAndroid.webDataContacts.dataModel.Contact?syncTime=13423220558251
2 
3  {
4      "modified":[
5          {
6              "firstname":"Mark",
7              "lastname":"Johnson",
8              "birthDate":135579679583,
9              "email":"[email protected]",
10             "age":43,
11             "phoneNumber":"781-201-4567",
12             "status":"some status",
13             "wd_id":"a7329678-4bdc-536a-b234-78236431026a",
14             "wd_version":1,
15             "wd_classname":"com.enterpriseandroid.webDataContacts.Contact",
16             "wd_namespace":"__data",
17             "wd_updateTime":1369010208846,
18             "wd_deleted":0
19         }
20     ],
21     "resolved" : []
22 }

The sync request shows the client has changed a contact “Mark Johnson”. The following points explain the payload:

  • Line 1 — Shows a POST from a Migrate client to sync changes it has made since the last time it sync’ed, syncTime. The client has made one change provided in the modified list, and has no conflict resolutions to send; the resolved list is empty.
  • Lines 6, 7 — The modified contact name is “Mark Johnson.”
  • Line 13 — Shows the unique identifier for this contact object.
  • Line 14 — This is still version 1 of the contact object. It will be up to the server to increment the version if it accepts the change.

The service responds to the sync request with the payload in Listing 9-6.

LISTING 9-6: The service response — the service has changed two contacts and one modification has resulted in a conflict

1  {
2      "syncTime":13690102023423,
3      "modified":[
4          {
5              "firstname":"Andrew",
6              "lastname":"Smith",
7              "birthDate":135579679583,
8              "email":"[email protected]",
9              "age":12,
10             "phoneNumber":"781-201-4567",
11             "status":"some status",
12             "wd_id":"d7894563-9edf-378w-u907-94675342378d",
13             "wd_version":1,
14             "wd_classname":"com.enterpriseandroid.webDataContacts.Contact",
15             "wd_namespace":"__data",
16             "wd_updateTime":1369010208846,
17             "wd_deleted":0
18         }
19     ],
20     "conflict":[
21         {
22             "firstname":"Mark",
23             "lastname":"Johnson",
24             "birthDate":135579679583,
25             "email":"[email protected]",
26             "age":43,
27             "phoneNumber":"781-223-1234",
28             "status":"some status",
29             "wd_id":"a7329678-4bdc-536a-b234-78236431026a",
30             "wd_version":2,
31             "wd_classname":"com.enterpriseandroid.webDataContacts.Contact",
32             "wd_namespace":"__data",
33             "wd_updateTime":1369010208846,
34             "wd_deleted":0
35         }
36     ]
37 }

The server response contains a new contact for “Andrew Smith” that the client can simply add locally. However, the contact with an id "a7329678-4bdc-536a-b234-78236431026a" for “Mark Johnson” is in conflict. The version of this contact from Listing 9-5 has a phone number of 781-201-4567, and the server has a version of the contact with phone number 781-223-1234. The Migrate client will call back to the relevant Android UI to ask the application user to pick the right phone number. Points to note in the payload include:

  • Line 2 — The server sends the time of sync, that the client will store persistently. The client will send this sync time the next time it syncs, so the server can send back any changes the client has missed in the interim.
  • Lines 10, 27 — As noted, the phone number for “Mark Johnson” is changed to different values by both the client and backend.
  • Line 30 — Since the server already accepted a change for “Mark Johnson” the value of wd_version is now 2.

To resolve the conflict in the service, the client needs to POST the resolved object back with the new version in another sync request as follows (Listing 9-7).

LISTING 9-7: The client resolves the conflicting phone number

1 POST 
    http://host:port/migrate/contact/classes/
    com.enterpriseAndroid.webDataContacts.Contact?syncTime=1342322066851
2  {
3      "modified":[],
4      "resolved":[
5          {
6              "firstname":"Mark",
7              "lastname":"Johnson",
8              "birthDate":135579679583,
9              "email":"[email protected]",
10             "age":43,
11             "phoneNumber":"781-223-1234",
12             "status":"some status",
13             "wd_id":"a7329678-4bdc-536a-b234-78236431026a",
14             "wd_version":2,
15             "wd_classname":"com.enterpriseandroid.webDataContacts.Contact",
16             "wd_namespace":"__data",
17             "wd_updateTime":1369010208846,
18             "wd_deleted":0
19         }
20     ]
21}

With the sync request in Listing 9-7, the client has selected the desired phone number on line 11, and used the same version as was sent to it as a conflict from the service, on line 14. The service will see that this is a resolution request, from line 4, and apply the change from the client to increment the object to version 3, assuming no other conflicting changes happen in the interim — which demonstrates optimistic concurrency control as applied to WebData.

Now that you understand WebData synchronization, it’s time to take a look at some other features.

Polling

Polling for changes in data goes somewhat against the grain of the design of the WebData API. In the absence of a push notification system, a WebData client should periodically invoke synchronization to ensure data stays current for a particular schema identifier. In Android, polling should be invoked using the Android sync adapter API ContentResolver.requestSync.

Paging

The WebData API provides parameters for paging that enable a client to download subsets of results when a query would return a large number of objects. The client can use these paging controls to conserve memory and storage space as needed. The following URL query parameters provide paging controls to a WebData client:

  • maxSize — Specifies the maximum number of results that should be present in the response to a given query
  • startPosition — Specifies the start position in a given query

The following GET request shows an example query with paging parameters:

GET http://host:port/context/classes/{classname}?startPosition=30&maxSize=10

The WebData Specification

Now that you’ve learned a bit about the components of the WebData API, it’s a good time to look at the complete WebData specification, which is available at the following location:

https://github.com/wileyenterpriseandroid/migrate/wiki/WebData

PROJECT MIGRATE IN DETAIL

The project Migrate client currently provides a complete implementation of the WebData API and supports an API for UI integration on the Android platform. Future versions of Migrate may provide iPhone and Objective C support, and potentially support for JavaScript. However, this book focuses on Migrate support for Android. As of the time of writing of this book, the Migrate open source project supports a working Android client implementation.

The Migrate Project Android WebData Client

The Migrate project supports an Android client that leverages the Android content provider framework. Although the WebData API may be useful on IOS and on other platforms, it’s not an exaggeration to say that the API was designed to take advantage of the Android content provider infrastructure. Recall that with project Migrate, developers can create their own synchronized data services that offer the convenience of the built-in Android content providers, but allow application-defined data types. The project Migrate Android client uses the service schema definition to create local SQLite tables as needed to store synchronization data. The client also uses the WebData versioning protocol to update data and schema information as directed by the WebData service host.

Project Migrate Android Features

The bulk of the Migrate WebData client on Android resides inside a custom Android content provider. This provider supports the following features that help developers manage data for Android mobile applications:

  • Semantics similar to the built-in providers — The Migrate project maintains the goal of keeping the semantics of its provider as similar to the built-in Android content providers as possible. In most cases, developers use the Migrate content provider just as they use the built-in content providers, using URIs, Cursors, and ContentObservers to track data.
  • Integrated synchronization — When an application modifies local Migrate content provider data, the Migrate client leverages the Android synchronization system to upload the changes to the Migrate backend service. Specifically, the Migrate client uses a custom synchronization adapter, as described in Chapter 5, to initiate synchronization. Developers can use the standard android.content.SyncStatusObserver to check on synchronization operations in progress.

As mentioned, there are a couple of ways in which the Migrate content provider differs from the built-in providers, specifically:

  • Access to WebData schema — The Migrate content provider API provides access to the data schema using a simple content provider URI.
  • Service-side configurability — It’s possible to use Migrate schema to evolve a client SQLite database schema in a deployed Migrate-based application. By invoking versioned PUTs of a Migrate schema, it’s possible for a web app to drive schema evolution on a Migrate service, and consequently when synchronization happens, also on Migrate clients. When the Migrate client updates schema from the service, it will automatically update SQL tables to reflect the changed schema.

Synchronization

The project Migrate Android client uses the WebData synchronization protocol to maintain a local persistent SQLite-based data cache that tracks changes from the client and service, updating and replacing elements that change in the service host. The Migrate WebData Android client implements the WebData synchronization protocol using a sync adapter implementation, using the standard onPerformSync method, as shown in the pseudo-code in Listing 9-8:

LISTING 9-8: Illustrating sync from onPerformSync

1 onPerformSync(Account account, Bundle extras, String authority,
2       ContentProviderClient provider, SyncResult syncResult) 
3 {
4   // The Migrate client synchronizes with its service host
5   Map serverData = 
6       WebDataClient.syncData(className, values, lastUpdateTime);
7     . . .
8 }

Searching

A client that needs to query Migrate data should just use the standard ContentProvider.query method.

Notification

The Migrate client implementation can use Google Cloud messaging for Android to avoid polling the Migrate service. In the absence of push notification support, the Migrate client can use a polling system that operates out of band of the normal WebData synchronization protocol. The implementation can periodically invoke a WebData synchronization operation.

Google has made documentation available on its website:

http://developer.android.com/google/gcm/index.html

THE WEBDATA CONTENT PROVIDER ANDROID API

Now that you have seen the features offered in the Migrate client and its content provider, this section explains how to access Migrate data in an Android UI. Currently, the Migrate project supports a slightly modified version of the API style used by the built-in Android content providers.

Android Built-In Provider APIs

The APIs of built-in Android content providers each revolve around a contract class, like the one for the contacts provider, ContactsContract:

http://developer.android.com/reference/android/provider/ContactsContract.html

The central purpose of the Android built-in content provider APIs is to host constant fields in classes like ContactsContract.Email.DATA, which can be used to index the Cursor results of invoking a query method as follows:

Cursor email = ContentResolver.query();
final Cursor email = ... // use of LoaderManager to access an email query cursor
final int contactEmailColumnIndex = email.getColumnIndex(Email.DATA);
String emailData = email.getString(contactEmailColumnIndex);

The last two lines show the indexing of a cursor to obtain its e-mail data.

These fields — in combination with content provider URIs as discussed in Chapter 4 — compose the APIs that developers use to access the Android contacts data and that of other built-in providers. These column classes (ContactsContract.Email, ContactsContract.Settings, ContactsContract.StatusUpdates, and so on) map to SQLite database tables that provide content provider persistence. This API approach relies on a set of hard-coded constants to access the central Android key/value-oriented data structure, Cursor. These constants must be “well known” to the application developer in order to load cursor data.

The Migrate Provider API

The Migrate provider API uses the same style of contract API as discussed in the previous section; however, the usage model has a significant difference: Migrate provides a utility in its SDK that generates the code for a contract class given a service POJO with Migrate annotations as input. The same tool also creates a WebData schema for POSTing to a WebData service instance. The next chapter demonstrates how this works in a detailed example.

SUMMARY

This chapter has covered the WebData protocol and its application in the Migrate Android open source project. Migrate has significant potential for Enterprise Android application development. Much of this book has built a foundation in technical understanding that enables you to appreciate the benefits of using Migrate to bridge the gap between enterprise Android applications and scalable cloud infrastructure.

Now that you have learned about the operation of the WebData API, the Migrate backend service, and the Migrate Android client, the chapter concludes with a discussion of the benefits of deploying a mobile infrastructure based on a WebData style architecture.

Service-Side Advantages

The WebData API encourages efficient network communication that reduces service load and enhances application protocols in the following ways:

  • WebData includes a push-oriented lightweight synchronization protocol out of the box. Pushing data reduces the need to poll to detect service-side data changes, thus reducing service load.
  • WebData and Migrate enforces a data transmission format based on JSON and JSON schema. This required structure enables you to create service management tools that can interpret, manage, and create analytics for applications that use the WebData API.
  • The WebData protocol can stand as a generic replacement for many custom-developed RESTful protocols.
  • Clients maintain an intelligent cache that precludes the need for redundant requests to retrieve data, again reducing service load. Clients request new data only when notified that their current set is out of date.
  • Clients use paging size and have the opportunity to select only the data that they need to see, rather than having to preconfigure a one-size-fits-all data window. Clients only request data they need, which also reduces service load.
  • It’s easy to implement the key/value-oriented WebData API on highly scalable columnar style databases, like DynamoDB or App Engine.

Client Advantages

Properties of WebData and the Migrate client that benefit handset applications include the following:

  • The Migrate framework has the potential to move applications from the mode of static configuration, which can be changed only at deployment time, to a flexible deployment environment in which a backend service can change the behavior and configuration of a client on the fly. Such flexibility arises from supporting schema that can be pushed and synchronized to clients.
  • The Migrate client can function as a secure proxy for applications that do not have to request Internet permission.
  • You will see a decrease in the size and development cost of applications that do not need to reinvent the wheel to access and synchronize network data with local SQLite tables.

Now that you’ve looked at the WebData and Migrate Android APIs in detail, you’ll jump into building an actual application with project Migrate in the next chapter.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset