File/SyncML/SyncML/Backend.php

Description

A SyncML Backend provides the interface between the SyncML protocol as provided by the SyncML pear package and an actual calendar or address book application. This "actual application" is called the "data store" in this description.

The backend provides the following groups of functions:

1) Access to the datastore Reading, adding, replacing and deleting of entries. Also retrieve information about changes in data store. This is done via the retrieveEntry(), addEntry(), replaceEntry(), deleteEntry() and getServerChanges() methods.

2) User management functions This is the checkAuthentication() method to verify that a given user password combination is allowed to access the backend data store, and the setUser() method which does a "login" to the backend data store if required by the type of backend data store. Please note that the password is only transferred once in a sync session, so when handling the subsequent packets messages, the user may need to be "logged in" without a password. (Or the session management keeps the user "logged in").

3) Maintainig the client ID <-> server ID map The SyncML protocol does not require clients and servers to use the same primary keys for the data entries. So a map has to be in place to convert between client primary keys (called cuid's here) and server primary keys (called suid's). It's up to the server to maintain this map. Method for this is createUidMap().

4) Sync anchor handling After a successful initial sync, the client and server sync timestamps are stored. This allows to perform subsequent syncs as delta syncs, where only new changes are replicated. Servers as well as clients need to be able to store two sync anchors (the client's and the server's) for a sync. Methods for this are readSyncAnchors() and writeSyncAnchors().

5) Test supporting functions The SyncML module comes with its own testing framework. All you need to do is implement the two methods testSetup() and testTearDown() and you are able to test your backend with all the test cases that are part of the module.

6) Miscellaneous functions This involves session handling (sessionStart() and sessionClose()), logging (logMessage() and logFile()), timestamp creation (getCurrentTimeStamp()), charset handling (getCharset(), setCharset()) and database identification (isValidDatabaseURI()). For all of these functions, a default implementation is provided in SyncML_Backend.

If you want to create a backend for your own appliction, you can either derive from SyncML_Backend and implement everything in groups 1 to 5 or you derive from SyncML_Backend_Sql which implements an example backend based on direct database access using the PEAR MDB2 package. In this case you only need to implement groups 1 to 3 and can use the implementation from SyncML_Backend_Sql as a guideline for these functions.

Key Concepts ------------ In order to successfully create a backend, some understanding of a few key concepts in SyncML and the SyncML package are certainly helpful. So here's some stuff that should make some issues clear (or at lest less obfuscated):

1) DatabaseURIs and Databases The SyncML protocol itself is completly independant from the data that is replicated. Normally the data are calendar or address book entries but it may really be anything from browser bookmarks to comeplete database tables. An ID (string name) of the database you want to actually replicate has to be configured in the client. Typically that's something like 'calendar' or 'tasks'. Client and server must agree on these names. In addition this string may be used to provide additional arguments. These are provided in a HTTP GET query style: like tasks?ignorecompletedtasks to replicate only pending tasks. Such a "sync identifier" is called a DatabaseURI and is really a database name plus some additional options. The SyncML package completly ignores these options and simply passes them on to the backend. It's up to the backend to decide what to do with them. However when dealing with the internal maps (cuid<->suid and sync anchors), it's most likely to use the database name only rather than the full databaseURI. The map information saying that server entry 20070101203040xxa@mypc.org has id 768 in the client device is valid for the database "tasks", not for "tasks?somesillyoptions". So what you normally do is calling some kind of

  • author: Karsten Fourmont <karsten@horde.org>
  • todo:

    describe sync anchors Have a look at the SyncML spec http://www.openmobilealliance.org/tech/affiliates/syncml/syncmlindex.html to find out more.

    4) Changes and Timestamps

  • todo:

    description of Changes and Timestamps, "mirroring effect" This is real tricky stuff. First it's important to know, that the SyncML protocol requires the ending timestamp of the sync timeframe to be exchanged _before_ the actual syncing starts. So all changes made during a sync have timestamps that are in the timeframe for the next upcoming sync. Data exchange in a sync session works in two steps: 1st) the clients sends its changes to the server, 2nd) the server sends its changes to the client. So when in step 2, the backend datastore API is called with a request like "give me all changes in the server since the last sync". Thus you also get the changes induced by the client in step 1 as well. You have to somehow "tag" them to avoid echoing (and thus duplicating) them back to the client. Simply storing the guids in the session is not sufficient: the changes are made _after_ the end timestamp (see 1) of the current sync so you'll dupe them in the next sync. The current implementation deals with this as follows: whenever a client induced change is done in the backend, the timestamp for this change is stored in the cuid<->suid map in an additional field. That's the perfect place as the tagging needs to be done "per client device": when an add is received from the PDA it must not be sent back as an add to this device, but to mobile phone it must be sent. This is sorted out during the getServerChanges() process: if a server change has a timestamp that's the same as in the guid<->suid map, it came from the client and must not be added to the list of changes to be sent to this client. See the description of SyncML_Backend_Sql::_getChangeTS() for some more information.

    5) Messages and Packages A message is a single HTTP Request. A package is single "logical message", a sync step. Normally the two coincide. However due to message size restrictions one package may be transferred in multiple messages (HTTP requests).

    7) Server mode, client mode and test mode Per default, a backend is used for an SyncML server. Regarding the SyncML protocol, the working of client and server is similar, except that a) the client initiates the sync requests and the server respons to them, and b) the server must maintain the client id<->server id map.

    Currently the SyncML package is designed to create servers. But is's an obvious (and straightforward) extension to do it for clients as well. And as a client has actually less work to do than a server, the backend should work for servers _and_ clients. During the sessionStart(), the backend gets a parameter to let it know whether it's in client or server mode (or test, see below). When in client mode, it should behave slightly different: a) the client doesn't do suid<->cuid mapping, so all invokations to the map creation method createUidMap(). b) the client has only client ids, no server ids. So all arguments are considered cuids even when named suid. See the SyncML_Backend_Sql implementation, it's actually not that difficult.

    Finally there's the test mode. The test cases consist of replaying pre-recorded sessions. For that to work, the test script must "simulate" user entries in the server data store. To do so, it creates a backend in test mode. This behaves similar to a client: when an server entry is created (modified) using addEntry() (replaceEntry()), no map entry must be done. The test backend uses also the two methods testSetup() and testTearDown() to create a clean (empty) enviroment for the test user "syncmltest". See the SyncML_Backend_Sql implementation for details.

    $Horde: framework/SyncML/SyncML/Backend.php,v 1.8.2.21 2009/12/30 01:15:21 jan Exp $

    Copyright 2005-2009 The Horde Project (http://www.horde.org/)

    See the enclosed file COPYING for license information (LGPL). If you did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.

Classes
Class Description
 class SyncML_Backend
Constants
SYNCML_BACKENDMODE_CLIENT = 2 (line 187)
SYNCML_BACKENDMODE_SERVER = 1 (line 186)

Backend modes.

SYNCML_BACKENDMODE_TEST = 3 (line 188)
SYNCML_LOGFILE_CLIENTMESSAGE = 1 (line 180)

Types of logfiles. See logFile() method.

SYNCML_LOGFILE_DATA = 4 (line 183)
SYNCML_LOGFILE_DEVINF = 3 (line 182)
SYNCML_LOGFILE_SERVERMESSAGE = 2 (line 181)

Documentation generated on Sun, 30 Jan 2011 05:15:24 +0000 by phpDocumentor 1.4.3