My Account

MAX Protocol Reference - Developer Site

  1. Targeted Audience
  2. Overview
  3. How to define the web service url
  4. Implementing the GET Request
  5. Implementing the POST Request
  6. Impact on server SQL Database tables
  7. Encoding of Date Field Values
  8. Sessions State & Cookies
  9. GZIP compression for the XML Response

Targeted Audience

You need to read this section only if you want to develop your own web services hosted on your own servers connected to a custom MAX application, which runs inside the Upvise mobile client. This basically allows you to host yourselves the persistant data used by your custom MAX Application.

Upvise servers implements the server part of this protocol and offer a cloud-based persistant data storage and sync.  The Upvise mobie client implement the client part of the protocol.
It you want to create custom applications where persistant data us stored and sychronized with the Upvise servers, you can skip this section and learn how to write Upvise MAX Applications.

Overview

the MAX Protocol is used to synchronize data sources between the Upvise mobile client and a server storing the persistant data.

The MAX Protocol is basically a super set of HTTP + RSS. It allows a 2 way synchronization of any data source specified in the Upvise MAX Application. It supports 2 key features:

  • authorization
  • delta synchronization, using a time stamp value issued by your server and passed back by the Upvise client

For a given data source, you must implement a corresponding web service URL. This URL can be called in 2 different ways by the Upvise mobile cliemt:

  1. a GET Query Request , asking the web service to return an XML response containing all modified records on the server since the last timestamp value returned by a previous call
  2. a POST Request, to inform the web service that a single record had been created, updated or deleted by the mobile client.

How to define the web service url associated with a MAX local data source

For each data source described in a MAX Application, there is a webservice tag which defines the assocated web service URL responsible to synchronize the data locally.
Note that if there is no webservice tag, the data source is not synchronized with the server.

<max>
...
<datasrc id="[MyDataSourceId]">
     <webservice>http://myurl</webservice>
     <field type="primarykey">id</field>
     <field type="string">[FieldName1]</field>
     <field type="string">[FieldName2]</field>
     ..... more fields here...
</datasrc> 
....
</max>

Implementing the GET Query Request

This query is responsible to send to the Upvise mobile client all newly created, modified and deleted records on the server, since the last time.

This query is sent by the Upvise mobile client when the local data cache has expired. It performs an HTTP  GET request using the url specified in the webservice tag of the data source.

Two GET parameters are added in the URL:

  • lbd, which stands for Last Build Date. Its value is a string in Epoch Format (number of milliseconds since Jan 1st 1970). It is the value sent by the server during the last reponse.
  • auth , which stands for authorization. It contains the user token obtained by the Upvise logon web service.
    http://mywebservice?lbd=[SomeDate]&auth=[SomeToken]

When the web service receive this request, it must:

  1. Identify the user by checking the authorization token is correct. If it is not, it should return an Error Response.
  2. Decode the last build date parameter if present. If this is the first time the web service is called, this parameter value is empty.
  3. Retrieve from the server storage all records which has been modified, created or deleted since this lastBuildDate.
  4. Return an XML formatted reponse, containing these records. The response is a super set of RSS format.

The XML Response must contain one root <rss> node and under it one <channel> node. Under it, you must have the follwoing nodes:

  • <title> : containing te data source name as defined in the MAX dtaa source file
  • <lastBuildDate> : it must contains the current server date and time, format in Epoch time. This value is then reused by the Upvise mobile client to perform the same request later on.
  • <ttl> : This is the time to live for the response, which defines when it is a number in minutes For example, 20
  • zero or more <item> nodes, each for a record that has been created, modified or deleted since the last build date value found in the GET parameter of the URL

Each <item> node must contain sub nodes who names must match the field names defined in the MAX data source.

A special case is for DELETED items. In this case, only the id sub node identifiying the record and a special sub node <_deleted>1<_deleted> must be set.

    <rss>
    <channel>
         <title>[MyDataSourceId]</title>
     <lastBuildDate>[CURRENT SERVER DATE in EPOCH FORMAT]</lastBuildDate>
     <tt>20</ttl>
<!-- This corresponds to a created or modified record -->      <item>   
          <id>...</id>   <!-- This is the primary key field -->
          <[fieldName1]>value1</[fieldName1]>
          <[fieldName2]>value2</[fieldName2]>
          .... more fields here
    
</item>
.... more items here
<!-- This corresponds to a deleted item -->
     <item>           <id>...</id>
          <_deleted>1</_deleted>
     </item>
</channel>
</rss>
Note:
  • all node names in XML are case sensitive. Be aware of it, in particular of the case of <lastBuildDate>
  • it is valid and expect to return zero item node, but you still neeed to return a valid XML document. In particular it must contains the lastBuildDate containing the current server time.

XML Response Details

  • The resulting document is a valid XML document. It must be in UTF-8 format.
  • The HTTP Reponse type must be "text/xml".
  • standard HTTP 1.1 compression using "gzip" is supported by the Upvise client and recommended in order to improve performance. See GZIP Compression section 

Note : it is recommended to use a class or library which generates correctly formatted XML document, so that the output document will be valid, and correctly encoded.

For example, with ASP.NET, use theXmlTextWriter class with the following declaration:

	XmlTextWriter myWriter = new XmlTextWriter(new MemoryStream(),
					new UTF8Encoding(false));

Implementing the POST request (INSERT, UPDATE and DELETE)

When data are created, updated or deleted locally on the device, the Upvise mobile clients performs a HTTP POST request on the web service URL.
The POST DATA contains all fields name and values which has been created or modified.

There is one HTTP POST request for each created, modified or deleted record.
Note: in all cases the id paramter, which is the primary key for the the record is always set.

URL POST Data
INSERT or UPDATE http://mywebservice?auth=[SomeToken] id=[PrimaryKeyValue]
fieldName1=....
fieldName2=...]
DELETE http://mywebservice?auth=[SomeToken]&meth=delete id=[PrimaryKeyValue]

Server responsability:

  1. Identify the user by checking the authroization token is correct. If it is not, it should return an Error Response.
  2. Get the id POST paramter corresponding to the record primary key. If no id is present, regurn an Error Response
  3. Check the meth (Method) GET parameter.
  4. If the method is 'delete', flag the record as deleted in the server storage and update the record last modified date.  (Do not delete the record as Query request needs the information that a record has been deleted)
  5. if the meth GET parameter is not present, this is an insert / update request. Obtain all other POST Parameters and perform an INSERT or UPDATE in the local storage, make sure your set the modified date of this record.
  6. Return an empty response string with an HTTP 200 OK Response code.

 

Impact on server SQL Database tables

If the server storage is going to be a SQL Database, you will need to keep track of 2 important pieces of data for each record you intend you synchronize:

  • the last time the data was modified or created or flagged as deleted. It is basically a timestamp
  • if the record is deleted or not

The timestamp information for each record is essential because it enable your GET Query Request to return only the modifed data since the last query.
Also when records are deleted, they must be flagged as deleted and not actually deleted from the SQL Table (ie do not use a DELETE statement). The GET Query Request needs to output the list of deleted record since the last query date.

One simple way to do this is to add 2 system fields to each SQL table : a _date field of type Date and a _deleted field of type integer with a default value of 0

  • When we record is created or modified, update the _date field to the current date.
  • When a record has to be deleted set the _deletedFlag to 1.

Encoding of Date Field Values

Date values must always be in Epoch format, ie te number of milliseconds from Jn 1st 1970. It applies to:

  • the <lastBuildDate> node value sent by the server in the GET request XML response to the Upvise mobile client
  • the field values for the records sent by the server in the XML response to the Upvise mobile client
  • the lbd (LastBuildDate) GET Parameter part of the GET request sent by the Upvise mobile client to the server
  • POST request parameters sent by the Upvise mobile client to the server in case of an UPDATE, INSERT or DELETE

Note . if you are using  Microsft ASP.NET, you can convert a .NET DateTime object to and from a Epoch time string with the following code:

public static long ToEpochTime(DateTime aDate) {
    DateTime start = new DateTime(1970, 1, 1);
    TimeSpan ts = aDate.Subtract(start);
    return Convert.ToInt64(ts.TotalMilliseconds);
}

public static DateTime fromEpochTime(string aDate) {
    long date = Convert.ToInt64(aDate);
    DateTime start = new DateTime(1970, 1, 1);
    return start.AddMilliseconds(date);
}

public static long EpochTimeNow() {
    return ToEpochTime(DateTime.UtcNow);
}
Note:
  • Use the ToEpochTime() function to convert field of type=date coming from your database before your output them in the XML Response
  • Use the fromEpochTime() function to convert the lbd (LastBuildDate) parameter received the GET Request to then perform your SQL request request
  • Also use fromEpochTime() when reading the POST Parameter field values of type=date in the POST Request (for UPDATE, INSERT or flag as DELETE SQL Request)
  • Use EpochTimeNow() function to return the current date in the LastBuildDate node in the XML Response for the GET request

Sessions State & Cookies

The MAX protocol does not support cookies. No cookies are sent by the Upvise client during the HTTP requests to the server web service.

It means that all sessions state manangement based on cookies like ASP.NET or JSP session variable MUST NOT be used.

For each request, the server is responsible to authenticate the client using the auth token each time.

GZIP compression for the XML Response

Web server implements HTTP 1.1 compression in a standard way for  dynamic or static pages. But you usually need to implement it manually for web services.

Here is how to do it simply:

  1. Check if the "Accept-Encoding" HTTP Request header is contains "gzip"
  2. If this is the case, compression the XML response string using GZIP standard libraries
  3. Set the "Content-Encoding" HTTP Response header to "gzip"
  4. Set the "Content-Length" HTTP Response header to the length of the compressed data
  5. Return the compressed string

For example, with ASP.NET, use the following code:

// data is supposeed to have been filled correctly with the XML Response
public writeResponse(byte[] data) {
	// if the Upvise client accepts gzip encoding 
	//and the plain data is bigger than 1KB, gzip the data first
	string acceptEncoding = Request.Headers["Accept-Encoding"];
	if (!string.IsNullOrEmpty(acceptEncoding) && 
	    acceptEncoding.Contains("gzip") && data.Length> 1024) {
		// compress the data
		data = Compress(data);
	
		// set the gzip flag in the HTTP Response 
		Response.AppendHeader("Content-Encoding", "gzip");
	}

	// VERY IMPORTANT: set the No Transform flag in the HTTP Response Header
	// to avoid intermediate gateways to re transform the response
	Response.Cache.SetNoTransforms();

	// Set Content Length HTTP Response header
	Response.AppendHeader("Content-Length", data.Length.ToString());

	// output the data to the Http Response stream
	Response.BinaryWrite(data);
	Response.Flush();
 	// NB : putting Response.End() instead or .Flush generates an Exception
 }

private static byte[] Compress(byte[] plainData) {
	// create a new MemoryStream to contain the zipped data
	MemoryStream memzip = new MemoryStream();
	
	// Create a GZIP compression stream on top of it 
	GZipStream zip = new GZipStream(memzip, CompressionMode.Compress);
	
	// write and flush the plain data into it
	zip.Write(plainData, 0, plainData.Length);
	zip.Flush();
	// close the GZIP Stream to read from underlying stream
	//if not, the zip footer will not be written!!!!
	zip.Close();
	
	// get the compressed data
	byte[] zippedData = memzip.ToArray();
	memzip.Close();
	return zippedData;
}