From c83c2ef64b5a1e4b1dc0102df36687caebb96ff0 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Wed, 24 Dec 2014 02:15:41 +0100 Subject: unifying buffer, and a better way to implement domain object adapters. --- dummyresource/facade.cpp | 98 ++++++++++++++++++++++++++++++--------- dummyresource/resourcefactory.cpp | 4 +- 2 files changed, 77 insertions(+), 25 deletions(-) (limited to 'dummyresource') diff --git a/dummyresource/facade.cpp b/dummyresource/facade.cpp index c2871bb..458aba6 100644 --- a/dummyresource/facade.cpp +++ b/dummyresource/facade.cpp @@ -25,15 +25,51 @@ #include "common/resourceaccess.h" #include "common/commands.h" #include "dummycalendar_generated.h" +#include "event_generated.h" +#include "entitybuffer_generated.h" +#include "metadata_generated.h" using namespace DummyCalendar; using namespace flatbuffers; +/** + * The property mapper holds accessor functions for all properties. + * + * It is by default initialized with accessors that access the local-only buffer, + * and resource simply have to overwrite those accessors. + */ +template +class PropertyMapper +{ +public: + void setProperty(const QString &key, const QVariant &value, BufferType *buffer) + { + if (mWriteAccessors.contains(key)) { + auto accessor = mWriteAccessors.value(key); + return accessor(value, buffer); + } + } + + virtual QVariant getProperty(const QString &key, BufferType const *buffer) const + { + if (mReadAccessors.contains(key)) { + auto accessor = mReadAccessors.value(key); + return accessor(buffer); + } + return QVariant(); + } + QHash > mReadAccessors; + QHash > mWriteAccessors; +}; + DummyResourceFacade::DummyResourceFacade() : Akonadi2::StoreFacade(), mResourceAccess(new Akonadi2::ResourceAccess("org.kde.dummy")) { - // connect(mResourceAccess.data(), &ResourceAccess::ready, this, onReadyChanged); + PropertyMapper mapper; + mapper.mReadAccessors.insert("summary", [](DummyEvent const *buffer) -> QVariant { + return QString::fromStdString(buffer->summary()->c_str()); + }); } DummyResourceFacade::~DummyResourceFacade() @@ -65,32 +101,43 @@ void DummyResourceFacade::remove(const Akonadi2::Domain::Event &domainObject) //-how do we free/munmap the data if we don't know when no one references it any longer? => no munmap needed, but read transaction to keep pointer alive //-we could bind the lifetime to the query //=> perhaps do heap allocate and use smart pointer? -class DummyEventAdaptor : public Akonadi2::Domain::Event +// + + +//This will become a generic implementation that simply takes the resource buffer and local buffer pointer +class DummyEventAdaptor : public Akonadi2::Domain::BufferAdaptor { public: - DummyEventAdaptor(const QString &resource, const QString &identifier, qint64 revision) - :Akonadi2::Domain::Event(resource, identifier, revision) + DummyEventAdaptor() + : BufferAdaptor() { + } - //TODO - // void setProperty(const QString &key, const QVariant &value) - // { - // //Record changes to send to resource? - // //The buffer is readonly - // } + void setProperty(const QString &key, const QVariant &value) + { + if (mResourceMapper.mWriteAccessors.contains(key)) { + // mResourceMapper.setProperty(key, value, mResourceBuffer); + } else { + // mLocalMapper.; + } + } virtual QVariant getProperty(const QString &key) const { - if (key == "summary") { - //FIXME how do we check availability for on-demand request? - return QString::fromStdString(buffer->summary()->c_str()); + if (mResourceBuffer && mResourceMapper.mReadAccessors.contains(key)) { + return mResourceMapper.getProperty(key, mResourceBuffer); + } else if (mLocalBuffer) { + return mLocalMapper.getProperty(key, mLocalBuffer); } return QVariant(); } - //Data is read-only - DummyEvent const *buffer; + Akonadi2::Domain::Buffer::Event const *mLocalBuffer; + DummyEvent const *mResourceBuffer; + + PropertyMapper mLocalMapper; + PropertyMapper mResourceMapper; //Keep query alive so values remain valid QSharedPointer storage; @@ -140,6 +187,7 @@ void DummyResourceFacade::load(const Akonadi2::Query &query, const std::function qDebug() << "load called"; synchronizeResource([=]() { + qDebug() << "sync complete"; //Now that the sync is complete we can execute the query const auto preparedQuery = prepareQuery(query); @@ -151,15 +199,19 @@ void DummyResourceFacade::load(const Akonadi2::Query &query, const std::function storage->startTransaction(Akonadi2::Storage::ReadOnly); //Because we have no indexes yet, we always do a full scan storage->scan("", [=](void *keyValue, int keySize, void *dataValue, int dataSize) -> bool { - //TODO read the three buffers qDebug() << QString::fromStdString(std::string(static_cast(keyValue), keySize)); - auto eventBuffer = GetDummyEvent(dataValue); - if (preparedQuery && preparedQuery(std::string(static_cast(keyValue), keySize), eventBuffer)) { - //TODO set proper revision - qint64 revision = 0; - auto event = QSharedPointer::create("org.kde.dummy", QString::fromUtf8(static_cast(keyValue), keySize), revision); - event->buffer = eventBuffer; - event->storage = storage; + auto buffer = Akonadi2::GetEntityBuffer(dataValue); + auto resourceBuffer = GetDummyEvent(buffer->resource()); + auto metadataBuffer = Akonadi2::GetMetadata(buffer->resource()); + auto localBuffer = Akonadi2::Domain::Buffer::GetEvent(buffer->local()); + //We probably only want to create all buffers after the scan + if (preparedQuery && preparedQuery(std::string(static_cast(keyValue), keySize), resourceBuffer)) { + qint64 revision = metadataBuffer->revision(); + auto adaptor = QSharedPointer::create(); + adaptor->mLocalBuffer = localBuffer; + adaptor->mResourceBuffer = resourceBuffer; + adaptor->storage = storage; + auto event = QSharedPointer::create("org.kde.dummy", QString::fromUtf8(static_cast(keyValue), keySize), revision, adaptor); resultCallback(event); } return true; diff --git a/dummyresource/resourcefactory.cpp b/dummyresource/resourcefactory.cpp index 2c43981..6b93985 100644 --- a/dummyresource/resourcefactory.cpp +++ b/dummyresource/resourcefactory.cpp @@ -103,7 +103,7 @@ void DummyResource::synchronizeWithSource(Akonadi2::Pipeline *pipeline) const auto key = QUuid::createUuid().toString().toUtf8(); //TODO can we really just start populating the buffer and pass the buffer builder? qDebug() << "new event"; - pipeline->newEntity(key, m_fbb); + pipeline->newEntity(key, m_fbb.GetBufferPointer(), m_fbb.GetSize()); } else { //modification //TODO diff and create modification if necessary } @@ -121,7 +121,7 @@ void DummyResource::processCommand(int commandId, const QByteArray &data, uint s builder .add_summary(m_fbb.CreateString("summary summary!")); auto buffer = builder.Finish(); DummyCalendar::FinishDummyEventBuffer(m_fbb, buffer); - pipeline->newEntity("fakekey", m_fbb); + pipeline->newEntity("fakekey", m_fbb.GetBufferPointer(), m_fbb.GetSize()); m_fbb.Clear(); } -- cgit v1.2.3