Development  »  Libraries  »  Kolab_Storage

Kolab_Storage structure and API

Introduction

Kolab_Storage is a PHP library that provides access to the user data stored in a Kolab Server backend. The data is usually accessed via IMAP which is not cheap. Hence the primary purpose of the library is to reduce the IMAP traffic to a minimal amount. This is achieved by caching the parsed Kolab groupware data after retrieving it from the IMAP account and only updating the cache incrementally whenever possible.

Core Elements

The library divides the data access into three conceptual elements:

  • The "List"
  • The "Folder"
  • The "Data"
  1. Rationale

First and foremost this structure intends to provide simple Kolab data access for the developer using the API. In addition this structure does at least to some degree follow structures that one would choose when representing the data available in the Kolab server backend in a relational database. But it also reflects specific constraints imposed by the IMAP protocol.

The following sections will - among other things - try to highlight the reasons for the specific boundaries between the different elements.

  1. Querying

Each of the elements mentioned above is able to handle a defined set of data. While handling this information efficiently is important it is often even more important to allow quick access ("queries") into the data set. How these queries are made quick is left to the implementation but the library strives to clearly separate data management and querying the data to allow optimizing both independantly.

Wherever applicable the following sections will also highlight the most common queries.

  1. Caching

It was initially mentioned that caching is a central aspect of the library. It is however equally important to point out that caching is totally irrelevant to the API itself. The three elements mentioned above always provide the same set of functions to the consumer. Whether the data access is cached in between or not. This design choice allows invisible changes to the actual caching technique up to a complete swapping of different caching approaches. There are other benefits as well when it comes to logging and time series measurements.

The following sections will - if applicable - indicate what needs to be done on the IMAP level in order to synchronize the server backend with the cache. This will focus on keeping the IMAP traffic to a minimum.

"List"

The list handler is concerned with the IMAP folder list visible for a user. It is handles folder names, types, and ownership. While folders typically have many other attributes only this small selection has been chosen to be dealt with by the list handler.

The primary reason for this is the fact that folder names and folder types can each be listed using just a single IMAP statement. Additional folder attributes often need to be read using an IMAP statment per folder. In addition the other attributes are less frequently used. Folder attributes not represented by the "List" are represented by the "Folder" element.

  1. Data

The managed data consists only of the folder names and the folder type annotation ('/shared/vendor/kolab/folder-type'). There are several additional information that can be derived from these basic attributes:

  • Namespace of the folder ('personal', 'other', 'shared')
  • Owner of the folder (self, other user, or anonymous)
  • Folder type ('event', 'task', 'note', 'contact', 'journal', ...)
  • Default setting (e.g. the "default" calendar of a user)

These are however a topic for the queries based on the list.

For information about namespace/ownership handling you should refer to the "Folder Namespace" section within "Other Elements" below.

Core methods of the list handler:

/**
 * Returns the list of folders visible to the current user.
 *
 * @return array The list of folders, represented as strings.
 */
public function listFolders();

/**
 * Returns the folder type annotation as associative array.
 *
 * @return array The list folder types with the folder names as key and the
 *               folder type as values.
 */
public function listFolderTypes();
  1. Queries

A number of relevant queries can be based on this relatively small dataset:

  • List all folders with their folder type
  • List all folders of a specified folder type
  • Identify the default folder of a specific folder type
  • Identify the default folder of another user (again given a specific folder type)

Core methods of the basic list query:

/**
 * Returns the folder types as associative array.
 *
 * @return array The list folder types with the folder names as key and the
 *               type as values.
 */
public function listTypes();

/**
 * List all folders of a specific type.
 *
 * @param string $type The folder type the listing should be limited to.
 *
 * @return array The list of folders.
 */
public function listByType($type);

/**
 * Get the default folder for a certain type.
 *
 * @param string $type The type of the share/folder.
 *
 * @return string|boolean The name of the default folder, false if there is no default.
 */
public function getDefault($type);

/**
 * Get the default folder for a certain type from a different owner.
 *
 * @param string $owner The folder owner.
 * @param string $type  The type of the share/folder.
 *
 * @return string|boolean The name of the default folder, false if there is no default.
 */
public function getForeignDefault($owner, $type);
  1. Synchronization

In order to synchronize the cache with the server backend two IMAP commands are needed:

A0002 LIST "" "*"
A0003 GETANNOTATION "*" ("/vendor/kolab/folder-type") ("value.shared")

The second command is not required in case the folder list did not change at all. If only one or very few folders changed in the folder list it might make sense to call "GETANNOTATION" per folder. This could be quicker if the user has access to many folders.

  1. Remarks
  1. The Kolab specific patch to the c-client library that implements the "GETANNOTATION" command is unable to deal with the return value of a 'GETANNOTATION "*"' call. Thus it is forced to deal with the folder type annotation one by one. This introduces significant problems when a user has many folders. At the current state the PHP IMAP extension cannot be recommend for such situations. None of the other supported IMAP drivers have this specific problem. They all support a multi-folder response.
  2. Currently the folder STATUS is also checked on a per-folder basis. One might consider doing this for the complete folder list as well. This is however not supported by the Kolab server at the moment. And the number of folders checked for their status should also always be significantly smaller than the complete folder list.

"Folder"

TBD

"Data"

TBD

Other Elements

The Kolab_Storage library also provides a number of supporting elements that are less visible within the API. Some of them should be mentioned though to highlight important features of the library.

Driver

Currently there are five backend drivers available. Nearly all of them are IMAP based. In theory it would be possible to provide drivers that use alternative means to read and write the groupware data. One could imagine a file based driver that could be used for test purposes. So far the need for such experiments has not arisen though.

The currently supported drivers:

  • "Cclient":

    based on the PHP IMAP extension (which uses the c-client library)

  • "Imap":

    based on the Horde_Imap_Client library (a pure PHP implementation for IMAP access)

  • "Rcube":

    based on the roundcube IMAP library (a pure PHP implementation for IMAP access)

  • "Pear":

    based on the PEAR-Net_IMAP library (a pure PHP implementation for IMAP access)

  • "Mock":

    a mock implementation that handles the data access purely in memory. This is being used for testing purposes.

Folder Namespace

The newer variants of the Kolab_Storage library are capable of using the IMAP namespace information provided by servers with the NAMESPACE capability.

Older versions were using hardcoded namespace information and strings such as "INBOX", "user/", "shared." were directly used in the code. While this works fine for the Kolab server it is hardly portable to many other IMAP setups.