virtual sources: avoid name collisions with normal sources (MB #9664)

As suspected in the previous commit for this issue, the engine still
picks the normal <datastore> when asked for "./Calendar". This patch
renames, for example, "calendar" to "calendar+todo@calendar" to avoid
cluttering the global namespaces for URIs with sources that clients
should not synchronize against.

The "@" separator is used because it is already a reserved character
for config names, albeit not yet for source names. A slash "/" would
have been nicer because it cannot be part of a source name, but when
trying that the Synthesis engine treated the second part as URI
parameters (instead of part of the source name).
This commit is contained in:
Patrick Ohly 2010-02-15 18:03:56 +01:00
parent c041165c0c
commit f93b323150
2 changed files with 31 additions and 6 deletions

View file

@ -1583,7 +1583,16 @@ void SyncContext::startLoopThread()
SyncSource *SyncContext::findSource(const char *name)
{
return m_sourceListPtr ? (*m_sourceListPtr)[name] : NULL;
if (!m_sourceListPtr) {
return NULL;
}
const char *realname = strrchr(name, m_findSourceSeparator);
if (realname) {
realname++;
} else {
realname = name;
}
return (*m_sourceListPtr)[realname];
}
SyncContext *SyncContext::findContext(const char *sessionName)
@ -2038,8 +2047,19 @@ void SyncContext::getConfigXML(string &xml, string &configname)
BOOST_FOREACH(SyncSource *source, *m_sourceListPtr) {
string fragment;
source->getDatastoreXML(fragment, fragments);
string name;
datastores << " <datastore name='" << source->getName() << "' type='plugin'>\n" <<
// Make sure that sub-datastores do not interfere with the global URI namespace
// by adding a <superdatastore>/ prefix. That way we can have a "calendar"
// alias for "calendar+todo" without conflicting with the underlying
// "calendar", which will be called "calendar+todo/calendar" in the XML config.
name = source->getVirtualSource();
if (!name.empty()) {
name += m_findSourceSeparator;
}
name += source->getName();
datastores << " <datastore name='" << name << "' type='plugin'>\n" <<
" <dbtypeid>" << source->getSynthesisID() << "</dbtypeid>\n" <<
fragment;
@ -2115,12 +2135,13 @@ void SyncContext::getConfigXML(string &xml, string &configname)
vSource->throwError ("virtual data source currently only supports events+tasks combinations");
}
datastores << " <superdatastore name= '" << vSource->getName() <<"'> \n";
datastores << " <contains datastore = '" << mappedSources[0] <<"'>\n"
string name = vSource->getName();
datastores << " <superdatastore name= '" << name << "'> \n";
datastores << " <contains datastore = '" << name << m_findSourceSeparator << mappedSources[0] <<"'>\n"
<< " <dispatchfilter>F.ISEVENT:=1</dispatchfilter>\n"
<< " <guidprefix>e</guidprefix>\n"
<< " </contains>\n"
<<"\n <contains datastore = '" << mappedSources[1] <<"'>\n"
<< "\n <contains datastore = '" << name << m_findSourceSeparator << mappedSources[1] <<"'>\n"
<< " <dispatchfilter>F.ISEVENT:=0</dispatchfilter>\n"
<< " <guidprefix>t</guidprefix>\n"
<<" </contains>\n" ;
@ -2735,7 +2756,7 @@ SyncMLStatus SyncContext::doSync()
target;
target = m_engine.OpenSubkey(targets, sysync::KEYVAL_ID_NEXT, true)) {
s = m_engine.GetStrValue(target, "dbname");
SyncSource *source = (*m_sourceListPtr)[s];
SyncSource *source = findSource(s.c_str());
if (source) {
m_engine.SetInt32Value(target, "enabled", 1);
int slow = 0;

View file

@ -349,10 +349,14 @@ class SyncContext : public SyncConfig, public ConfigUserInterface {
* session. Called by Synthesis DB plugin to find active
* sources.
*
* @param name can be both <SyncSource::getName()> as well as <prefix>_<SyncSource::getName()>
* (necessary when renaming sources in the Synthesis XML config)
*
* @TODO: roll SourceList into SyncContext and
* make this non-static
*/
static SyncSource *findSource(const char *name);
static const char m_findSourceSeparator = '@';
/**
* Find the active sync context for the given session.