287 lines
11 KiB
C++
287 lines
11 KiB
C++
/*
|
|
* Copyright (C) 2008-2009 Patrick Ohly <patrick.ohly@gmx.de>
|
|
* Copyright (C) 2009 Intel Corporation
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) version 3.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
* 02110-1301 USA
|
|
*/
|
|
|
|
#ifndef INCL_TRACKINGSYNCSOURCE
|
|
#define INCL_TRACKINGSYNCSOURCE
|
|
|
|
#include <syncevo/SyncSource.h>
|
|
#include <syncevo/ConfigNode.h>
|
|
|
|
#include <boost/shared_ptr.hpp>
|
|
#include <string>
|
|
#include <map>
|
|
|
|
#include <syncevo/declarations.h>
|
|
SE_BEGIN_CXX
|
|
|
|
/**
|
|
* This class implements change tracking. Data sources which want to use
|
|
* this functionality have to provide the following functionality
|
|
* by implementing the pure virtual functions below:
|
|
* - open() the data
|
|
* - enumerate all existing items
|
|
* - provide LUID and "revision string":
|
|
* The LUID must remain *constant* when the user edits an item (it
|
|
* may change when SyncEvolution changes an item), whereas the
|
|
* revision string must *change* each time the item is changed
|
|
* by anyone.
|
|
* Both can be arbitrary strings, but keeping them simple (printable
|
|
* ASCII, no white spaces, no equal sign) makes debugging simpler
|
|
* because they can be stored as they are as key/value pairs in the
|
|
* sync source's change tracking config node (the .other.ini files when
|
|
* using file-based configuration). More complex strings use escape
|
|
* sequences introduced with an exclamation mark for unsafe characters.
|
|
* - import/export/update single items
|
|
* - persistently store all changes in flush()
|
|
* - clean up in close()
|
|
*
|
|
* A derived class may (but doesn't have to) override additional
|
|
* functions to modify or replace the default implementations, e.g.:
|
|
* - dumping the complete database (export())
|
|
*
|
|
* Potential implementations of the revision string are:
|
|
* - a modification time stamp
|
|
* - a hash value of a textual representation of the item
|
|
* (beware, such a hash might change as the textual representation
|
|
* changes even though the item is unchanged)
|
|
*/
|
|
class TrackingSyncSource : public TestingSyncSource,
|
|
virtual public SyncSourceRevisions,
|
|
virtual public SyncSourceBlob,
|
|
virtual public SyncSourceAdmin
|
|
{
|
|
public:
|
|
/**
|
|
* Creates a new tracking sync source.
|
|
*
|
|
* @param granularity sync sources whose revision string
|
|
* is based on time should specify the number
|
|
* of seconds which has to pass before changes
|
|
* are detected reliably (see SyncSourceRevisions
|
|
* for details), otherwise pass 0
|
|
*/
|
|
TrackingSyncSource(const SyncSourceParams ¶ms,
|
|
int granularitySeconds = 1);
|
|
~TrackingSyncSource() {}
|
|
|
|
/**
|
|
* ConfigNode used for change tracking in SyncSourceRevisions.
|
|
* Derived classes might need that when implementing operations
|
|
* which have side effects on other items (for example,
|
|
* EvolutionCalendarSource::removeItem()).
|
|
*/
|
|
ConfigNode &getTrackingNode() { return *m_trackingNode; }
|
|
|
|
/**
|
|
* returns a list of all know sources for the kind of items
|
|
* supported by this sync source
|
|
*/
|
|
virtual Databases getDatabases() = 0;
|
|
|
|
/**
|
|
* Actually opens the data source specified in the constructor,
|
|
* will throw the normal exceptions if that fails. Should
|
|
* not modify the state of the sync source.
|
|
*
|
|
* The expectation is that this call is fairly light-weight, but
|
|
* does enough checking to determine whether the source is
|
|
* usable. More expensive operations (like determining changes)
|
|
* should be done in the beginSync() callback.
|
|
*
|
|
* In clients, it will be called for all sources before
|
|
* the sync starts. In servers, it is called for each source once
|
|
* the client asks for it, but not sooner.
|
|
*/
|
|
virtual void open() = 0;
|
|
|
|
/**
|
|
* A quick check whether the source currently has data. Currently
|
|
* used as part of the "allow slow sync" checking after open() and
|
|
* before beginSync(). Returning false is acceptable when it is
|
|
* uncertain and too expensive to check.
|
|
*/
|
|
virtual bool isEmpty() = 0;
|
|
|
|
/**
|
|
* A unique identifier for the current state of the complete database.
|
|
* The semantic is the following:
|
|
* - empty string implies "state unknown" or "identifier not supported" (the default implementation)
|
|
* - id not empty and id_1 == id_2 implies "nothing has changed";
|
|
* the inverse is not true (ids may be different although nothing has changed)
|
|
*/
|
|
virtual std::string databaseRevision() { return ""; }
|
|
|
|
/**
|
|
* fills the complete mapping from LUID to revision string of all
|
|
* currently existing items
|
|
*
|
|
* Usually both LUID and revision string must be non-empty. The
|
|
* only exception is a refresh-from-client: in that case the
|
|
* revision string may be empty. The implementor of this call
|
|
* cannot know whether empty strings are allowed, therefore it
|
|
* should not throw errors when it cannot create a non-empty
|
|
* string. The caller of this method will detect situations where
|
|
* a non-empty string is necessary and none was provided.
|
|
*/
|
|
virtual void listAllItems(SyncSourceRevisions::RevisionMap_t &revisions) = 0;
|
|
|
|
/**
|
|
* Called at the start of the sync session to tell
|
|
* the derived class about the cached information if (and only
|
|
* if) listAllItems() and updateAllItems() were not called. The derived class
|
|
* might not need this information, so the default implementation
|
|
* simply ignores.
|
|
*
|
|
* A more complex API could have been defined to only prepare the
|
|
* information when needed, but that seemed unnecessarily complex.
|
|
*/
|
|
virtual void setAllItems(const RevisionMap_t &revisions) {}
|
|
|
|
/**
|
|
* updates the revision map to reflect the current state
|
|
*
|
|
* May be called instead of listAllItems() if the caller has
|
|
* a valid list to start from. If the implementor
|
|
* cannot update the list, it must start from scratch by
|
|
* reseting the list and calling listAllItems(). The default
|
|
* implementation of this method does that.
|
|
*/
|
|
virtual void updateAllItems(SyncSourceRevisions::RevisionMap_t &revisions) {
|
|
revisions.clear();
|
|
listAllItems(revisions);
|
|
}
|
|
|
|
/**
|
|
* Create or modify an item.
|
|
*
|
|
* The sync source should be flexible: if the LUID is non-empty, it
|
|
* shall modify the item referenced by the LUID. If the LUID is
|
|
* empty, the normal operation is to add it. But if the item
|
|
* already exists (e.g., a calendar event which was imported
|
|
* by the user manually), then the existing item should be
|
|
* updated also in the second case.
|
|
*
|
|
* Passing a LUID of an item which does not exist is an error.
|
|
* This error should be reported instead of covering it up by
|
|
* (re)creating the item.
|
|
*
|
|
* Errors are signaled by throwing an exception. Returning empty
|
|
* strings in the result is an error which triggers an "item could
|
|
* not be stored" error.
|
|
*
|
|
* @param luid identifies the item to be modified, empty for creating
|
|
* @param item contains the new content of the item
|
|
* @param raw item has internal format instead of engine format;
|
|
* testing and backup/restore might use such an internal format
|
|
* which may be different (more complete!) than the
|
|
* format when talking to the sync engine
|
|
* @return the result of inserting the item
|
|
*/
|
|
virtual InsertItemResult insertItem(const std::string &luid, const std::string &item, bool raw) = 0;
|
|
|
|
/**
|
|
* Return item data in engine format.
|
|
*
|
|
* Must throw a STATUS_NOT_FOUND (= 404) StatusException when the
|
|
* item does not exist.
|
|
*
|
|
* @param luid identifies the item
|
|
* @param raw return item in internal format instead of engine format
|
|
* @retval item item data
|
|
*/
|
|
virtual void readItem(const std::string &luid, std::string &item, bool raw) = 0;
|
|
|
|
/**
|
|
* delete the item (renamed so that it can be wrapped by deleteItem())
|
|
*
|
|
* Must throw a STATUS_NOT_FOUND (= 404) StatusException when the
|
|
* item does not exist.
|
|
*/
|
|
virtual void removeItem(const string &luid) = 0;
|
|
|
|
/**
|
|
* optional: write all changes, throw error if that fails
|
|
*
|
|
* This is called while the sync is still active whereas
|
|
* close() is called afterwards. Reporting problems
|
|
* as early as possible may be useful at some point,
|
|
* but currently doesn't make a relevant difference.
|
|
*/
|
|
virtual void flush() {}
|
|
|
|
/**
|
|
* closes the data source so that it can be reopened
|
|
*
|
|
* Just as open() it should not affect the state of
|
|
* the database unless some previous action requires
|
|
* it.
|
|
*/
|
|
virtual void close() = 0;
|
|
|
|
/**
|
|
* Returns the preferred mime type of the items handled by the sync source.
|
|
* Example: "text/x-vcard"
|
|
*/
|
|
virtual std::string getMimeType() const = 0;
|
|
|
|
/**
|
|
* Returns the version of the mime type used by client.
|
|
* Example: "2.1"
|
|
*/
|
|
virtual std::string getMimeVersion() const = 0;
|
|
|
|
using SyncSource::getName;
|
|
|
|
private:
|
|
void checkStatus(SyncSourceReport &changes);
|
|
boost::shared_ptr<ConfigNode> m_trackingNode;
|
|
|
|
/**
|
|
* Stores meta information besides the item list:
|
|
* - "databaseRevision" = result of databaseRevision() at end of last sync
|
|
*
|
|
* Shares the same key/value store as m_trackingNode,
|
|
* which uses the "item-" prefix in its keys to
|
|
* avoid name clashes.
|
|
*/
|
|
boost::shared_ptr<ConfigNode> m_metaNode;
|
|
|
|
protected:
|
|
/* implementations of SyncSource callbacks */
|
|
virtual void beginSync(const std::string &lastToken, const std::string &resumeToken);
|
|
virtual std::string endSync(bool success);
|
|
virtual void deleteItem(const string &luid);
|
|
virtual InsertItemResult insertItem(const std::string &luid, const std::string &item);
|
|
virtual void readItem(const std::string &luid, std::string &item);
|
|
virtual InsertItemResult insertItemRaw(const std::string &luid, const std::string &item);
|
|
virtual void readItemRaw(const std::string &luid, std::string &item);
|
|
virtual void enableServerMode();
|
|
virtual bool serverModeEnabled() const;
|
|
virtual std::string getPeerMimeType() const;
|
|
|
|
private:
|
|
InsertItemResult doInsertItem(const std::string &luid, const std::string &item, bool raw);
|
|
InsertItemResult continueInsertItem(const boost::function<InsertItemResult ()> &check, const std::string &luid);
|
|
};
|
|
|
|
|
|
SE_END_CXX
|
|
#endif // INCL_TRACKINGSYNCSOURCE
|