Table of Contents
This document describes the plugin API supported by zXSync. Plugins are the sole means of reading and writing data, both on supported devices and on the host computer.
Every plugin must provide the following global functions called by zXSync.
probe
(
settings, context)
;
zXSync calls this function to find connected devices. The return value must be a list of objects derived from (or otherwise providing the methods of) zxsync.pluginbase.Device. The list can be empty if no connected device is found.
The settings parameter contains a list of dictionaries with device settings (for example, the IP address of a device). The supported keys in such a dictionary are currently completely plugin-specific, and the user must specifiy the key/value pairs manually. However, future versions of zXSync will likely define several "well-known keys" for things like IP addresses or DNS names.
A common way of implementing probe is to return at most as many devices as there are settings dictionaries. For example, the Zaurus plugin expects to find an IP address of a Zaurus in each settings dictionary. If there really is a Zaurus with this address, a virtual device for it will be included in the returned list.
The context parameter references a zxsync.engine.SyncContext object that can be used to communicate with zXSync.
Every plugin must support one or more virtual devices, where the term "device" is used in a rather broad way. For example, the OS X plugin provides a "device" class with the ability to read from and write to Address Book and iCal.
The plugin should use sub classes of zxsync.pluginbase.Device for its devices. However, this is not strictly necessary as long as all devices provide the methods described here.
init
(
context)
;
Called by zXSync to initialize the device. Implementing this method is optional if the device class inherits from zxsync.pluginbase.Device.
init is guaranteed to be the first method call made by zXSync, and it's always balanced by a call to free (except when init raises an exception). init will not be called more than once before calling free (again, except calling init raises an exception).
The context parameter references a zxsync.engine.SyncContext object that can be used to communicate with zXSync. It should be used by a device instead of the context passed to probe. This allows zXSync to configure contexts for different devices in different ways.
free
(
void)
;
Called by zXSync when this device is no longer needed. However, init may be called again on the same device later on. Implementing this method is optional if the device class inherits from zxsync.pluginbase.Device.
getApplications
(
void)
;
Called by zXSync to retrieve the applications supported by a device (e. g. one for contacts and one for calendar entries). The return value must be a list of objects derived from (or otherwise providing the methods of) zxsync.pluginbase.DeviceApplication. The list can be empty if no supported application is found on the device.
Every virtual device can contain support for one or more "applications". These can be counterparts of real applications or something more abstract.
The plugin should use sub classes of zxsync.pluginbase.DeviceApplication for its applications. However, this is not strictly necessary as long as all applications provide the methods described here.
getId
(
void)
;
Called by zXSync to get the id of the application. This must be one of the constants defined in zxsync/syncbase.py or - for custom extensions - start with "X-". Matching applications during a sync operation is solely based on this id.
getDataFormat
(
void)
;
Called by zXSync to determine the data format of the application. This must be one of the constants defined in zxsync/syncbase.py or - for custom extensions - start with "X-".
Currently, the return value is simply ignored, and the semantics of this method will likely change in the future.
beginSync
(
void)
;
Called by zXSync before reading or writing any entries in this application. This call is always balanced by a call to endSync (except when beginSync raises an exception). beginSync will not be called more than once before calling endSync (again, except calling beginSync raises an exception).
If at all possible, beginSync should put the device in a locked state. This means that the user should not be able to change data on the device until endSync is called.
The return value must be one of the following:
zxsync.syncbase.WRITE_SINGLE
zxsync.syncbase.WRITE_ALL
endSync
(
void)
;
Called by zXSync after syncing is complete. endSync is called whether the sync was successful or not. However, an aborted or unsuccessful sync will not have added/changed/deleted any entries (except when a problem occured during adding/changing/deleting of course).
readAllEntries
(
void)
;
Called by zXSync to read all entries present for the application. The return value must be a list of objects derived from (or otherwise providing the methods of) zxsync.syncbase.Entry. The list can be empty if no entry is found for this application.
addEntry
(
entry)
;
Called by zXSync to add an entry to the application. This method is only called if a previous call to beginSync returned zxsync.syncbase.WRITE_SINGLE. Otherwise, implementation of this method is optional.
The entry parameter is an instance returned by a call to readAllEntries on another application.
changeEntry
(
entry)
;
Called by zXSync to change an entry of the application. This method is only called if a previous call to beginSync returned zxsync.syncbase.WRITE_SINGLE. Otherwise, implementation of this method is optional.
The entry parameter is gueranteed to be one of the instances returned by a previous call to readAllEntries on this application.
deleteEntry
(
entry)
;
Called by zXSync to delete an entry of the application. This method is only called if a previous call to beginSync returned zxsync.syncbase.WRITE_SINGLE. Otherwise, implementation of this method is optional.
The entry parameter is gueranteed to be one of the instances returned by a previous call to readAllEntries on this application.
writeAllEntries
(
entries)
;
Called by zXSync to write all entries of the application. This method is only called if a previous call to beginSync returned zxsync.syncbase.WRITE_ALL. Otherwise, implementation of this method is optional.
The entries parameter is a sequence of zxsync.syncbase.Entry instances or equivalent objects. The plugin must overwrite all previously existing entries with these.
zxsync.engine.SyncContext is an interface for plugins to communicate with zXSync. Currently, its only purpose is handling errors.
handleError
(
fatal, message, ...)
;
The purpose of this method is to deal with errors that occur within a plugin. While a plugin is free to just raise an exception if something goes wrong, using handleError has the advantage that errors don't have to be fatal. For example, reading a single entry from a device might fail, but the user might still want the other entries to be read. If an exception was raised from readAllEntries, this would not be possible.
In addition to allowing non-fatal errors, handleError will probably include support for internationalization in the future.
The fatal parameter determines whether the error should be considered fatal (1), non-fatal (0), or its severity depends on the circumstances/user preferences. A fatal error causes handleError to abort the method from which it is called (simply by rethrowing the exception) while a non-fatal error causes the method to continue. When None is passed for fatal, zXSync determines whether to continue or not. This is the preferred way of dealing with non-fatal errors.
The message parameter contains an error message with embedded place holders (%1, %2, ..., %n). The place holders are replaced by the values contained in the variable argument list following fatal and message.
zxsync.syncbase.HierarchyElement is the base class for a number of internal data representations in zXSync. Most importantly, it's the base for zxsync.syncbase.Entry and zxsync.syncbase.Field.
Plugins only have to care for the methods described here if they handle non-standard data (i. e. data for which zXSync does not (yet) provide a standard representation). In this case, specialized versions of Entry and Field must be provided, and they must properly override the methods mentioned below.
Not all methods are described here. For detailed method documentation, import zxsync.syncbase.HierarchyElement in an interactive Python shell and use help(HierarchyElement).
clone
(
void)
;
Called by zXSync to clone a hierarchy element. This is used, for example, when adding an entry or field present on one device to another. This method must perform a "deep clone" operation, i. e. all children must also be cloned. For example, cloning an Entry must also clone all its fields.
For convenience, you can additionally override the doClone method (see zxsync/syncbase.py for how this works).
matches
(
other)
;
Called by zXSync to determine if two elements match. This doesn't mean they have to be identical, only that they carry information about the same entity. For example, two contact entries are considered matching if they refer to the same person (which might not always be easy to determine).
The return value must be 1 if the elements match and 0 if the elements don't match.
Sub classes must be written in a way that instanceA.matches(instanceB) yields the same result as instanceB.matches(instanceA) for two instances of the same class.
isValid
(
void)
;
Called by zXSync to determine if an element is valid. The validity is determined in terms of matching: An invalid element is one that can never possibly match another element. For example, a completely empty contact entry does not match any other entry (not even another empty one) since there is no identifying information present in it at all.
Invalid elements should not be filtered out during readAllEntries. This gives zXSync the chance to alert the user about such entries (or fields) or to take other measures.
zxsync.syncbase.Entry provides a base class for entries.
An entry is the name for units of data handled by an application (in the sense of the DeviceApplication class explained above). For example, an addressbook application deals with contact entries.
It is important that the entry class used by an application always matches its id. For example, if the application returns zxsync.syncbase.CONTACTS_APP_ID from its getId method, it must return VCard instances from its readAllEntries method. Likewise, a plugin dealing with non-standard data will only be able to sync with other plugins if they use the same id and the same Entry sub class (or at least sub classes that implement the HierarchyElement methods in the same way).
zxsync.syncbase.Field provides a base class for fields.
A field is a child element of an entry. For example, the VCard class uses a VCardField instance with id "N" to store the name of a person.
For internally handling contact information, zXSync uses a Python representation of vCards (described in RFC 2426). zxsync.vcard.VCard is an Entry sub class for VCards, and zxsync.vcard.VCardField is a specialized version of Field.
For detailed documentation of these classes, import them in an interactive Python shell and use help(<classname>).
For internally handling calendar information, zXSync uses a Python representation of iCalendar events (described in RFC 2445). zxsync.vevent.VEvent is an Entry sub class for events, and zxsync.vevent.VEventField is a specialized version of Field.
For detailed documentation of these classes, import them in an interactive Python shell and use help(<classname>).