From ea348c62fdebe1d9c6531fc4491d3316a1e941df Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Fri, 10 Apr 2015 12:32:03 +0200 Subject: checkpoint --- common/clientapi.h | 2 + common/domainadaptor.cpp | 8 +-- common/domainadaptor.h | 112 +++++++++++++++++++++++++++++++--------- dummyresource/domainadaptor.cpp | 111 ++++++++++++++++++++++++++++++++------- dummyresource/domainadaptor.h | 4 ++ tests/domainadaptortest.cpp | 20 +++---- 6 files changed, 199 insertions(+), 58 deletions(-) diff --git a/common/clientapi.h b/common/clientapi.h index 5182547..22448b3 100644 --- a/common/clientapi.h +++ b/common/clientapi.h @@ -234,6 +234,8 @@ public: virtual QVariant getProperty(const QByteArray &key) const { return mAdaptor->getProperty(key); } virtual void setProperty(const QByteArray &key, const QVariant &value){ mChangeSet.insert(key, value); mAdaptor->setProperty(key, value); } + virtual QByteArrayList changedProperties() const { return mChangeSet.keys(); } + qint64 revision() const { return mRevision; } private: QSharedPointer mAdaptor; diff --git a/common/domainadaptor.cpp b/common/domainadaptor.cpp index 5b7c427..5e6f062 100644 --- a/common/domainadaptor.cpp +++ b/common/domainadaptor.cpp @@ -20,16 +20,16 @@ #include "domainadaptor.h" template <> -QSharedPointer > initializePropertyMapper() +QSharedPointer > initializeReadPropertyMapper() { - auto propertyMapper = QSharedPointer >::create(); - propertyMapper->mReadAccessors.insert("summary", [](Akonadi2::ApplicationDomain::Buffer::Event const *buffer) -> QVariant { + auto propertyMapper = QSharedPointer >::create(); + propertyMapper->addMapping("summary", [](Akonadi2::ApplicationDomain::Buffer::Event const *buffer) -> QVariant { if (buffer->summary()) { return QString::fromStdString(buffer->summary()->c_str()); } return QVariant(); }); - propertyMapper->mReadAccessors.insert("uid", [](Akonadi2::ApplicationDomain::Buffer::Event const *buffer) -> QVariant { + propertyMapper->addMapping("uid", [](Akonadi2::ApplicationDomain::Buffer::Event const *buffer) -> QVariant { if (buffer->uid()) { return QString::fromStdString(buffer->uid()->c_str()); } diff --git a/common/domainadaptor.h b/common/domainadaptor.h index 15e3067..5d9574b 100644 --- a/common/domainadaptor.h +++ b/common/domainadaptor.h @@ -38,17 +38,9 @@ * that extract the properties from resource types. */ template -class PropertyMapper +class ReadPropertyMapper { public: - void setProperty(const QByteArray &key, const QVariant &value, BufferType *buffer) - { - if (mWriteAccessors.contains(key)) { - auto accessor = mWriteAccessors.value(key); - return accessor(value, buffer); - } - } - virtual QVariant getProperty(const QByteArray &key, BufferType const *buffer) const { if (mReadAccessors.contains(key)) { @@ -57,12 +49,38 @@ public: } return QVariant(); } + bool hasMapping(const QByteArray &key) const { return mReadAccessors.contains(key); } + QList availableProperties() const { return mReadAccessors.keys(); } + void addMapping(const QByteArray &property, const std::function &mapping) { + mReadAccessors.insert(property, mapping); + } +private: QHash > mReadAccessors; - QHash > mWriteAccessors; +}; + +template +class WritePropertyMapper +{ +public: + virtual void setProperty(const QByteArray &key, const QVariant &value, QList > &builderCalls, flatbuffers::FlatBufferBuilder &fbb) const + { + if (mWriteAccessors.contains(key)) { + auto accessor = mWriteAccessors.value(key); + builderCalls << accessor(value, fbb); + } + } + bool hasMapping(const QByteArray &key) const { return mWriteAccessors.contains(key); } + void addMapping(const QByteArray &property, const std::function(const QVariant &, flatbuffers::FlatBufferBuilder &)> &mapping) { + mWriteAccessors.insert(property, mapping); + } +private: + QHash(const QVariant &, flatbuffers::FlatBufferBuilder &)> > mWriteAccessors; }; /** * A generic adaptor implementation that uses a property mapper to read/write values. + * + * TODO: this is the read-only part. Create a write only equivalent */ template class GenericBufferAdaptor : public Akonadi2::ApplicationDomain::BufferAdaptor @@ -74,20 +92,21 @@ public: } + //TODO remove void setProperty(const QByteArray &key, const QVariant &value) { - if (mResourceMapper && mResourceMapper->mWriteAccessors.contains(key)) { - // mResourceMapper->setProperty(key, value, mResourceBuffer); - } else { - // mLocalMapper.; - } + // if (mResourceMapper && mResourceMapper->hasMapping(key)) { + // // mResourceMapper->setProperty(key, value, mResourceBuffer); + // } else { + // // mLocalMapper.; + // } } virtual QVariant getProperty(const QByteArray &key) const { - if (mResourceBuffer && mResourceMapper->mReadAccessors.contains(key)) { + if (mResourceBuffer && mResourceMapper->hasMapping(key)) { return mResourceMapper->getProperty(key, mResourceBuffer); - } else if (mLocalBuffer && mLocalMapper->mReadAccessors.contains(key)) { + } else if (mLocalBuffer && mLocalMapper->hasMapping(key)) { return mLocalMapper->getProperty(key, mLocalBuffer); } qWarning() << "no mapping available for key " << key; @@ -97,15 +116,58 @@ public: virtual QList availableProperties() const { QList props; - props << mResourceMapper->mReadAccessors.keys(); - props << mLocalMapper->mReadAccessors.keys(); + props << mResourceMapper->availableProperties(); + props << mLocalMapper->availableProperties(); return props; } LocalBuffer const *mLocalBuffer; ResourceBuffer const *mResourceBuffer; - QSharedPointer > mLocalMapper; - QSharedPointer > mResourceMapper; + QSharedPointer > mLocalMapper; + QSharedPointer > mResourceMapper; +}; + +/** + * A generic adaptor implementation that uses a property mapper to read/write values. + */ +template +class GenericWriteBufferAdaptor : public Akonadi2::ApplicationDomain::BufferAdaptor +{ +public: + GenericWriteBufferAdaptor(const BufferAdaptor &buffer) + : BufferAdaptor() + { + for(const auto &property : buffer.availableProperties()) { + setProperty(property, buffer.getProperty(property)); + } + } + + void setProperty(const QByteArray &key, const QVariant &value) + { + // if (mResourceMapper && mResourceMapper->hasMapping(key)) { + // // mResourceMapper->setProperty(key, value, mResourceBuffer); + // } else { + // // mLocalMapper.; + // } + } + + //TODO remove + virtual QVariant getProperty(const QByteArray &key) const + { + Q_ASSERT(false); + } + + virtual QList availableProperties() const + { + Q_ASSERT(false); + QList props; + return props; + } + + // LocalBuffer const *mLocalBuffer; + // ResourceBuffer const *mResourceBuffer; + QSharedPointer > mLocalMapper; + QSharedPointer > mResourceMapper; }; /** @@ -114,7 +176,7 @@ public: * Provide an implementation for each application domain type. */ template -QSharedPointer > initializePropertyMapper(); +QSharedPointer > initializeReadPropertyMapper(); /** * The factory should define how to go from an entitybuffer (local + resource buffer), to a domain type adapter. @@ -125,7 +187,7 @@ template class DomainTypeAdaptorFactory { public: - DomainTypeAdaptorFactory() : mLocalMapper(initializePropertyMapper()) {}; + DomainTypeAdaptorFactory() : mLocalMapper(initializeReadPropertyMapper()) {}; virtual ~DomainTypeAdaptorFactory() {}; /** @@ -150,8 +212,8 @@ public: virtual void createBuffer(const Akonadi2::ApplicationDomain::Event &event, flatbuffers::FlatBufferBuilder &fbb) {}; protected: - QSharedPointer > mLocalMapper; - QSharedPointer > mResourceMapper; + QSharedPointer > mLocalMapper; + QSharedPointer > mResourceMapper; }; diff --git a/dummyresource/domainadaptor.cpp b/dummyresource/domainadaptor.cpp index 74a8dd6..00af3fe 100644 --- a/dummyresource/domainadaptor.cpp +++ b/dummyresource/domainadaptor.cpp @@ -14,42 +14,115 @@ using namespace DummyCalendar; using namespace flatbuffers; +/** + * Defines how to convert qt primitives to flatbuffer ones + * TODO: rename to createProperty or so? + */ +template +uoffset_t extractProperty(const QVariant &, flatbuffers::FlatBufferBuilder &fbb); + +template <> +uoffset_t extractProperty(const QVariant &property, flatbuffers::FlatBufferBuilder &fbb) +{ + if (property.isValid()) { + return fbb.CreateString(property.toString().toStdString()).o; + } + return 0; +} + +/** + * Create a buffer from a domain object using the provided mappings + */ +template +void createBufferPart(const Akonadi2::ApplicationDomain::ApplicationDomainType &domainObject, flatbuffers::FlatBufferBuilder &fbb, const WritePropertyMapper &mapper) +{ + //First create a primitives such as strings using the mappings + QList > propertiesToAddToResource; + for (const auto &property : domainObject.changedProperties()) { + const auto value = domainObject.getProperty(property); + if (mapper.hasMapping(property)) { + mapper.setProperty(property, domainObject.getProperty(property), propertiesToAddToResource, fbb); + } + } + + //Then create all porperties using the above generated builderCalls + Builder builder(fbb); + for (auto propertyBuilder : propertiesToAddToResource) { + propertyBuilder(builder); + } + builder.Finish(); +} + + DummyEventAdaptorFactory::DummyEventAdaptorFactory() : DomainTypeAdaptorFactory() { - //TODO turn this into initializePropertyMapper as well? - mResourceMapper = QSharedPointer >::create(); - mResourceMapper->mReadAccessors.insert("summary", [](DummyEvent const *buffer) -> QVariant { + //TODO turn this into initializeReadPropertyMapper as well? + mResourceMapper = QSharedPointer >::create(); + mResourceMapper->addMapping("summary", [](DummyEvent const *buffer) -> QVariant { if (buffer->summary()) { return QString::fromStdString(buffer->summary()->c_str()); } return QVariant(); }); + + mResourceWriteMapper->addMapping("summary", [](const QVariant &value, flatbuffers::FlatBufferBuilder &fbb) -> std::function { + auto offset = extractProperty(value, fbb); + return [offset](DummyEventBuilder &builder) { builder.add_summary(offset); }; + }); } void DummyEventAdaptorFactory::createBuffer(const Akonadi2::ApplicationDomain::Event &event, flatbuffers::FlatBufferBuilder &fbb) { - flatbuffers::FlatBufferBuilder eventFbb; - eventFbb.Clear(); - { - auto summary = eventFbb.CreateString(event.getProperty("summary").toString().toStdString()); - DummyCalendar::DummyEventBuilder eventBuilder(eventFbb); - eventBuilder.add_summary(summary); - auto eventLocation = eventBuilder.Finish(); - DummyCalendar::FinishDummyEventBuffer(eventFbb, eventLocation); - } + // flatbuffers::FlatBufferBuilder resFbb; + // flatbuffers::FlatBufferBuilder localFbb; + + // QList > propertiesToAddToResource; + // QList > propertiesToAddToLocal; + // for (const auto &property : event.changedProperties()) { + // const auto value = event.getProperty(property); + // if (mResourceWriteMapper && mResourceWriteMapper->hasMapping(property)) { + // mResourceWriteMapper->setProperty(property, value, propertiesToAddToResource, resFbb); + // } if (mLocalWriteMapper && mLocalWriteMapper->hasMapping(property)) { + // mLocalWriteMapper->setProperty(property, value, propertiesToAddToLocal, localFbb); + // } + // } + // DummyEventBuilder resBuilder(resFbb); + // for (auto propertyBuilder : propertiesToAddToResource) { + // propertyBuilder(resBuilder); + // } + // resBuilder.Finish(); + + // DummyEventBuilder localBuilder(localFbb); + // for (auto propertyBuilder : propertiesToAddToResource) { + // propertyBuilder(localBuilder); + // } + // localBuilder.Finish(); + + // TODO: how does a resource specify what goes to a local buffer and what it stores separately? + // flatbuffers::FlatBufferBuilder eventFbb; + // { + // auto summary = extractProperty(event.getProperty("summary"), fbb); + // DummyCalendar::DummyEventBuilder eventBuilder(eventFbb); + // eventBuilder.add_summary(summary); + // auto eventLocation = eventBuilder.Finish(); + // DummyCalendar::FinishDummyEventBuffer(eventFbb, eventLocation); + // } + + //TODO we should only copy values into the local buffer that haven't already been copied by the resource buffer flatbuffers::FlatBufferBuilder localFbb; - { - auto uid = localFbb.CreateString(event.getProperty("uid").toString().toStdString()); - auto localBuilder = Akonadi2::ApplicationDomain::Buffer::EventBuilder(localFbb); - localBuilder.add_uid(uid); - auto location = localBuilder.Finish(); - Akonadi2::ApplicationDomain::Buffer::FinishEventBuffer(localFbb, location); + if (mLocalWriteMapper) { + createBufferPart(event, localFbb, *mLocalWriteMapper); + } + + flatbuffers::FlatBufferBuilder resFbb; + if (mResourceWriteMapper) { + createBufferPart(event, resFbb, *mResourceWriteMapper); } - Akonadi2::EntityBuffer::assembleEntityBuffer(fbb, 0, 0, eventFbb.GetBufferPointer(), eventFbb.GetSize(), localFbb.GetBufferPointer(), localFbb.GetSize()); + Akonadi2::EntityBuffer::assembleEntityBuffer(fbb, 0, 0, resFbb.GetBufferPointer(), resFbb.GetSize(), localFbb.GetBufferPointer(), localFbb.GetSize()); } diff --git a/dummyresource/domainadaptor.h b/dummyresource/domainadaptor.h index 0e2b883..39028c9 100644 --- a/dummyresource/domainadaptor.h +++ b/dummyresource/domainadaptor.h @@ -11,4 +11,8 @@ public: DummyEventAdaptorFactory(); virtual ~DummyEventAdaptorFactory() {}; virtual void createBuffer(const Akonadi2::ApplicationDomain::Event &event, flatbuffers::FlatBufferBuilder &fbb); + +private: + QSharedPointer > mResourceWriteMapper; + QSharedPointer > mLocalWriteMapper; }; diff --git a/tests/domainadaptortest.cpp b/tests/domainadaptortest.cpp index 9cc3938..74c0d62 100644 --- a/tests/domainadaptortest.cpp +++ b/tests/domainadaptortest.cpp @@ -23,16 +23,16 @@ public: void setProperty(const QByteArray &key, const QVariant &value) { - if (mResourceMapper->mWriteAccessors.contains(key)) { - // mResourceMapper.setProperty(key, value, mResourceBuffer); - } else { - // mLocalMapper.; - } + // if (mResourceMapper->mWriteAccessors.contains(key)) { + // // mResourceMapper.setProperty(key, value, mResourceBuffer); + // } else { + // // mLocalMapper.; + // } } virtual QVariant getProperty(const QByteArray &key) const { - if (mResourceBuffer && mResourceMapper->mReadAccessors.contains(key)) { + if (mResourceBuffer && mResourceMapper->hasMapping(key)) { return mResourceMapper->getProperty(key, mResourceBuffer); } else if (mLocalBuffer) { return mLocalMapper->getProperty(key, mLocalBuffer); @@ -43,8 +43,8 @@ public: Akonadi2::ApplicationDomain::Buffer::Event const *mLocalBuffer; Akonadi2::ApplicationDomain::Buffer::Event const *mResourceBuffer; - QSharedPointer > mLocalMapper; - QSharedPointer > mResourceMapper; + QSharedPointer > mLocalMapper; + QSharedPointer > mResourceMapper; }; class TestFactory : public DomainTypeAdaptorFactory @@ -52,8 +52,8 @@ class TestFactory : public DomainTypeAdaptorFactory >::create(); - mResourceMapper->mReadAccessors.insert("summary", [](Akonadi2::ApplicationDomain::Buffer::Event const *buffer) -> QVariant { + mResourceMapper = QSharedPointer >::create(); + mResourceMapper->addMapping("summary", [](Akonadi2::ApplicationDomain::Buffer::Event const *buffer) -> QVariant { if (buffer->summary()) { return QString::fromStdString(buffer->summary()->c_str()); } -- cgit v1.2.3