From 91d915a09b7d52c10edb1d4c1298fc2885b8a257 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Fri, 2 Jan 2015 22:39:25 +0100 Subject: DomainTypeAdaptor factory, per type preprocessor pipeline configuration. --- dummyresource/facade.cpp | 138 ++++++++++++++++++-------------------- dummyresource/facade.h | 53 +++++++++++++++ dummyresource/resourcefactory.cpp | 56 +++++++++++++++- dummyresource/resourcefactory.h | 1 + 4 files changed, 174 insertions(+), 74 deletions(-) (limited to 'dummyresource') diff --git a/dummyresource/facade.cpp b/dummyresource/facade.cpp index d3974e9..c167297 100644 --- a/dummyresource/facade.cpp +++ b/dummyresource/facade.cpp @@ -33,44 +33,87 @@ 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 +//This will become a generic implementation that simply takes the resource buffer and local buffer pointer +class DummyEventAdaptor : public Akonadi2::Domain::BufferAdaptor { public: - void setProperty(const QString &key, const QVariant &value, BufferType *buffer) + DummyEventAdaptor() + : BufferAdaptor() { - if (mWriteAccessors.contains(key)) { - auto accessor = mWriteAccessors.value(key); - return accessor(value, buffer); + + } + + 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, BufferType const *buffer) const + virtual QVariant getProperty(const QString &key) const { - if (mReadAccessors.contains(key)) { - auto accessor = mReadAccessors.value(key); - return accessor(buffer); + if (mResourceBuffer && mResourceMapper->mReadAccessors.contains(key)) { + return mResourceMapper->getProperty(key, mResourceBuffer); + } else if (mLocalBuffer) { + return mLocalMapper->getProperty(key, mLocalBuffer); } return QVariant(); } - QHash > mReadAccessors; - QHash > mWriteAccessors; + + Akonadi2::Domain::Buffer::Event const *mLocalBuffer; + DummyEvent const *mResourceBuffer; + + QSharedPointer > mLocalMapper; + QSharedPointer > mResourceMapper; }; +template<> +QSharedPointer DomainTypeAdaptorFactory::createAdaptor(const Akonadi2::Entity &entity) +{ + DummyEvent const *resourceBuffer = 0; + if (auto resourceData = entity.resource()) { + flatbuffers::Verifier verifyer(resourceData->Data(), resourceData->size()); + if (VerifyDummyEventBuffer(verifyer)) { + resourceBuffer = GetDummyEvent(resourceData); + } + } + + Akonadi2::Metadata const *metadataBuffer = 0; + if (auto metadataData = entity.metadata()) { + flatbuffers::Verifier verifyer(metadataData->Data(), metadataData->size()); + if (Akonadi2::VerifyMetadataBuffer(verifyer)) { + metadataBuffer = Akonadi2::GetMetadata(metadataData); + } + } + + Akonadi2::Domain::Buffer::Event const *localBuffer = 0; + if (auto localData = entity.local()) { + flatbuffers::Verifier verifyer(localData->Data(), localData->size()); + if (Akonadi2::Domain::Buffer::VerifyEventBuffer(verifyer)) { + localBuffer = Akonadi2::Domain::Buffer::GetEvent(localData); + } + } + + auto adaptor = QSharedPointer::create(); + adaptor->mLocalBuffer = localBuffer; + adaptor->mResourceBuffer = resourceBuffer; + adaptor->mResourceMapper = mResourceMapper; + adaptor->mLocalMapper = mLocalMapper; + return adaptor; +} + DummyResourceFacade::DummyResourceFacade() : Akonadi2::StoreFacade(), - mResourceAccess(new Akonadi2::ResourceAccess("org.kde.dummy")) + mResourceAccess(new Akonadi2::ResourceAccess("org.kde.dummy")), + mFactory(new DomainTypeAdaptorFactory()) { - PropertyMapper mapper; - mapper.mReadAccessors.insert("summary", [](DummyEvent const *buffer) -> QVariant { + auto mapper = QSharedPointer >::create(); + mapper->mReadAccessors.insert("summary", [](DummyEvent const *buffer) -> QVariant { return QString::fromStdString(buffer->summary()->c_str()); }); + mFactory->mResourceMapper = mapper; } DummyResourceFacade::~DummyResourceFacade() @@ -105,45 +148,6 @@ void DummyResourceFacade::remove(const Akonadi2::Domain::Event &domainObject) // -//This will become a generic implementation that simply takes the resource buffer and local buffer pointer -class DummyEventAdaptor : public Akonadi2::Domain::BufferAdaptor -{ -public: - DummyEventAdaptor() - : BufferAdaptor() - { - - } - - 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 (mResourceBuffer && mResourceMapper.mReadAccessors.contains(key)) { - return mResourceMapper.getProperty(key, mResourceBuffer); - } else if (mLocalBuffer) { - return mLocalMapper.getProperty(key, mLocalBuffer); - } - return QVariant(); - } - - Akonadi2::Domain::Buffer::Event const *mLocalBuffer; - DummyEvent const *mResourceBuffer; - - PropertyMapper mLocalMapper; - PropertyMapper mResourceMapper; - - //Keep query alive so values remain valid - QSharedPointer storage; -}; - static std::function prepareQuery(const Akonadi2::Query &query) { //Compose some functions to make query matching fast. @@ -225,26 +229,16 @@ void DummyResourceFacade::load(const Akonadi2::Query &query, const std::function } } - Akonadi2::Domain::Buffer::Event const *localBuffer = 0; - if (auto localData = buffer.localBuffer()) { - flatbuffers::Verifier verifyer(localData->Data(), localData->size()); - if (Akonadi2::Domain::Buffer::VerifyEventBuffer(verifyer)) { - localBuffer = Akonadi2::Domain::Buffer::GetEvent(localData); - } - } - if (!resourceBuffer || !metadataBuffer) { qWarning() << "invalid buffer " << QString::fromStdString(std::string(static_cast(keyValue), keySize)); return true; } //We probably only want to create all buffers after the scan + //TODO use adapter for query and scan? if (preparedQuery && preparedQuery(std::string(static_cast(keyValue), keySize), resourceBuffer)) { qint64 revision = metadataBuffer ? metadataBuffer->revision() : -1; - auto adaptor = QSharedPointer::create(); - adaptor->mLocalBuffer = localBuffer; - adaptor->mResourceBuffer = resourceBuffer; - adaptor->storage = storage; + auto adaptor = mFactory->createAdaptor(buffer.entity()); auto event = QSharedPointer::create("org.kde.dummy", QString::fromUtf8(static_cast(keyValue), keySize), revision, adaptor); resultCallback(event); } diff --git a/dummyresource/facade.h b/dummyresource/facade.h index c76e62c..46b27ef 100644 --- a/dummyresource/facade.h +++ b/dummyresource/facade.h @@ -21,11 +21,63 @@ #include "common/clientapi.h" #include "common/storage.h" +#include "entity_generated.h" +#include "event_generated.h" +#include "dummycalendar_generated.h" namespace Akonadi2 { class ResourceAccess; } +/** + * 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; +}; + +//The factory should define how to go from an entitybuffer (local + resource buffer), to a domain type adapter. +//It defines how values are split accross local and resource buffer. +//This is required by the facade the read the value, and by the pipeline preprocessors to access the domain values in a generic way. +template +class DomainTypeAdaptorFactory +{ +}; + +template +class DomainTypeAdaptorFactory +{ +public: + QSharedPointer createAdaptor(const Akonadi2::Entity &entity); + +// private: + QSharedPointer > mLocalMapper; + QSharedPointer > mResourceMapper; +}; + class DummyResourceFacade : public Akonadi2::StoreFacade { public: @@ -39,4 +91,5 @@ public: private: void synchronizeResource(const std::function &continuation); QSharedPointer mResourceAccess; + QSharedPointer > mFactory; }; diff --git a/dummyresource/resourcefactory.cpp b/dummyresource/resourcefactory.cpp index c9e4d7a..08222c0 100644 --- a/dummyresource/resourcefactory.cpp +++ b/dummyresource/resourcefactory.cpp @@ -20,10 +20,48 @@ #include "resourcefactory.h" #include "facade.h" #include "entitybuffer.h" +#include "pipeline.h" #include "dummycalendar_generated.h" #include "metadata_generated.h" #include +/* + * Figure out how to implement various classes of processors: + * * read-only (index and such) => domain adapter + * * filter => provide means to move entity elsewhere, and also reflect change in source (I guess?) + * * flag extractors? => like read-only? Or write to local portion of buffer? + * ** $ISSPAM should become part of domain object and is written to the local part of the mail. + * ** => value could be calculated by the server directly + */ +// template +class SimpleProcessor : public Akonadi2::Preprocessor +{ +public: + SimpleProcessor(const std::function &f) + : Akonadi2::Preprocessor(), + mFunction(f) + { + } + + void process(const Akonadi2::PipelineState &state) { + mFunction(state); + } + +protected: + std::function mFunction; +}; + +// template +// class SimpleReadOnlyProcessor : public SimpleProcessor +// { +// public: +// using SimpleProcessor::SimpleProcessor; +// void process(Akonadi2::PipelineState state) { +// mFunction(); +// } +// }; + + static std::string createEvent() { static const size_t attachmentSize = 1024*2; // 2KB @@ -61,6 +99,20 @@ DummyResource::DummyResource() { } +void DummyResource::configurePipeline(Akonadi2::Pipeline *pipeline) +{ + //TODO setup preprocessors for each domain type and pipeline type allowing full customization + //Eventually the order should be self configuring, for now it's hardcoded. + auto eventIndexer = new SimpleProcessor([](const Akonadi2::PipelineState &state) { + //FIXME + // auto adaptor = QSharedPointer::create(); + // adaptor->mLocalBuffer = localBuffer; + // adaptor->mResourceBuffer = resourceBuffer; + // adaptor->storage = storage; + }); + pipeline->setPreprocessors(Akonadi2::Pipeline::NewPipeline, QVector() << eventIndexer); +} + void findByRemoteId(QSharedPointer storage, const QString &rid, std::function callback) { //TODO lookup in rid index instead of doing a full scan @@ -119,7 +171,7 @@ Async::Job DummyResource::synchronizeWithSource(Akonadi2::Pipeline *pipeli DummyCalendar::FinishDummyEventBuffer(m_fbb, buffer); //TODO toRFC4122 would probably be more efficient, but results in non-printable keys. const auto key = QUuid::createUuid().toString().toUtf8(); - pipeline->newEntity(key, m_fbb.GetBufferPointer(), m_fbb.GetSize()); + pipeline->newEntity(key, m_fbb.GetBufferPointer(), m_fbb.GetSize()); } else { //modification //TODO diff and create modification if necessary } @@ -139,7 +191,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.GetBufferPointer(), m_fbb.GetSize()); + pipeline->newEntity("fakekey", m_fbb.GetBufferPointer(), m_fbb.GetSize()); m_fbb.Clear(); } diff --git a/dummyresource/resourcefactory.h b/dummyresource/resourcefactory.h index dba674f..427fcc6 100644 --- a/dummyresource/resourcefactory.h +++ b/dummyresource/resourcefactory.h @@ -33,6 +33,7 @@ public: DummyResource(); Async::Job synchronizeWithSource(Akonadi2::Pipeline *pipeline); void processCommand(int commandId, const QByteArray &data, uint size, Akonadi2::Pipeline *pipeline); + void configurePipeline(Akonadi2::Pipeline *pipeline); private: flatbuffers::FlatBufferBuilder m_fbb; -- cgit v1.2.3