From 4067462b0a27984df84b0379c19122d574253dfb Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Sat, 3 Jan 2015 00:08:44 +0100 Subject: Shared domain adaptors between resource and facade. --- common/domainadaptor.h | 77 +++++++++++++++++++++++++++++ common/pipeline.cpp | 6 +++ common/pipeline.h | 3 ++ dummyresource/CMakeLists.txt | 2 +- dummyresource/domainadaptor.cpp | 101 ++++++++++++++++++++++++++++++++++++++ dummyresource/domainadaptor.h | 14 ++++++ dummyresource/facade.cpp | 92 +--------------------------------- dummyresource/facade.h | 50 +------------------ dummyresource/resourcefactory.cpp | 12 ++--- 9 files changed, 212 insertions(+), 145 deletions(-) create mode 100644 common/domainadaptor.h create mode 100644 dummyresource/domainadaptor.cpp create mode 100644 dummyresource/domainadaptor.h diff --git a/common/domainadaptor.h b/common/domainadaptor.h new file mode 100644 index 0000000..e8f586b --- /dev/null +++ b/common/domainadaptor.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2014 Christian Mollekopf + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#pragma once + +#include "entity_generated.h" +#include +#include +#include +#include "clientapi.h" //for domain parts + +/** + * 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: + virtual QSharedPointer createAdaptor(const Akonadi2::Entity &entity) = 0; + +protected: + QSharedPointer > mLocalMapper; + QSharedPointer > mResourceMapper; +}; + + diff --git a/common/pipeline.cpp b/common/pipeline.cpp index 8d00480..18b6d51 100644 --- a/common/pipeline.cpp +++ b/common/pipeline.cpp @@ -189,6 +189,7 @@ public: Pipeline *pipeline; Pipeline::Type type; QByteArray key; + Akonadi2::Entity *entity; QVectorIterator filterIt; bool idle; }; @@ -239,6 +240,11 @@ Pipeline::Type PipelineState::type() const return d->type; } +const Akonadi2::Entity &PipelineState::entity() const +{ + return *d->entity; +} + void PipelineState::step() { if (!d->pipeline) { diff --git a/common/pipeline.h b/common/pipeline.h index 8373899..6005331 100644 --- a/common/pipeline.h +++ b/common/pipeline.h @@ -29,6 +29,8 @@ #include #include //For domain types +#include "entity_generated.h" + namespace Akonadi2 { @@ -112,6 +114,7 @@ public: bool isIdle() const; QByteArray key() const; Pipeline::Type type() const; + const Akonadi2::Entity &entity() const; void step(); void processingCompleted(Preprocessor *filter); diff --git a/dummyresource/CMakeLists.txt b/dummyresource/CMakeLists.txt index a2caf29..abd315f 100644 --- a/dummyresource/CMakeLists.txt +++ b/dummyresource/CMakeLists.txt @@ -5,7 +5,7 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) generate_flatbuffers(dummycalendar) -add_library(${PROJECT_NAME} SHARED facade.cpp resourcefactory.cpp) +add_library(${PROJECT_NAME} SHARED facade.cpp resourcefactory.cpp domainadaptor.cpp) qt5_use_modules(${PROJECT_NAME} Core Network) target_link_libraries(${PROJECT_NAME} akonadi2common) diff --git a/dummyresource/domainadaptor.cpp b/dummyresource/domainadaptor.cpp new file mode 100644 index 0000000..5d046ff --- /dev/null +++ b/dummyresource/domainadaptor.cpp @@ -0,0 +1,101 @@ + +#include "domainadaptor.h" + +#include +#include + +#include "dummycalendar_generated.h" +#include "event_generated.h" +#include "entity_generated.h" +#include "metadata_generated.h" +#include "domainadaptor.h" +#include + +using namespace DummyCalendar; +using namespace flatbuffers; + +using namespace DummyCalendar; +using namespace flatbuffers; + +//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; + + QSharedPointer > mLocalMapper; + QSharedPointer > mResourceMapper; +}; + + +DummyEventAdaptorFactory::DummyEventAdaptorFactory() + : DomainTypeAdaptorFactory() +{ + mResourceMapper = QSharedPointer >::create(); + mResourceMapper->mReadAccessors.insert("summary", [](DummyEvent const *buffer) -> QVariant { + return QString::fromStdString(buffer->summary()->c_str()); + }); + //TODO set accessors for all properties + +} + +QSharedPointer DummyEventAdaptorFactory::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; +} + diff --git a/dummyresource/domainadaptor.h b/dummyresource/domainadaptor.h new file mode 100644 index 0000000..881b7f3 --- /dev/null +++ b/dummyresource/domainadaptor.h @@ -0,0 +1,14 @@ + +#pragma once + +#include "common/domainadaptor.h" +#include "event_generated.h" +#include "dummycalendar_generated.h" +#include "entity_generated.h" + +class DummyEventAdaptorFactory : public DomainTypeAdaptorFactory +{ +public: + DummyEventAdaptorFactory(); + virtual QSharedPointer createAdaptor(const Akonadi2::Entity &entity); +}; diff --git a/dummyresource/facade.cpp b/dummyresource/facade.cpp index c167297..b4d98c6 100644 --- a/dummyresource/facade.cpp +++ b/dummyresource/facade.cpp @@ -28,92 +28,17 @@ #include "event_generated.h" #include "entity_generated.h" #include "metadata_generated.h" +#include "domainadaptor.h" #include using namespace DummyCalendar; using namespace flatbuffers; -//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; - - 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")), - mFactory(new DomainTypeAdaptorFactory()) + mFactory(new DummyEventAdaptorFactory) { - auto mapper = QSharedPointer >::create(); - mapper->mReadAccessors.insert("summary", [](DummyEvent const *buffer) -> QVariant { - return QString::fromStdString(buffer->summary()->c_str()); - }); - mFactory->mResourceMapper = mapper; } DummyResourceFacade::~DummyResourceFacade() @@ -135,19 +60,6 @@ void DummyResourceFacade::remove(const Akonadi2::Domain::Event &domainObject) //Create message buffer and send to resource } -//Key.value property map using enum or strings with qvariant, or rather typesafe API? -//typesafe is a shitload more work that we can avoid -// -//The Event base implementaiton could take a pointer to a single property mapper, -//and a void pointer to the mmapped region. => event is copyable and stack allocatable and we avoid large amounts of heap allocated objects -//-The mapper should in this case live in the other thread -//-default property mapper implementation can answer "is property X supported?" -//-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? -// - - static std::function prepareQuery(const Akonadi2::Query &query) { //Compose some functions to make query matching fast. diff --git a/dummyresource/facade.h b/dummyresource/facade.h index 46b27ef..e01d254 100644 --- a/dummyresource/facade.h +++ b/dummyresource/facade.h @@ -21,62 +21,16 @@ #include "common/clientapi.h" #include "common/storage.h" +#include "resourcefactory.h" #include "entity_generated.h" #include "event_generated.h" #include "dummycalendar_generated.h" +#include "common/domainadaptor.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 { diff --git a/dummyresource/resourcefactory.cpp b/dummyresource/resourcefactory.cpp index 08222c0..da6969a 100644 --- a/dummyresource/resourcefactory.cpp +++ b/dummyresource/resourcefactory.cpp @@ -23,6 +23,7 @@ #include "pipeline.h" #include "dummycalendar_generated.h" #include "metadata_generated.h" +#include "domainadaptor.h" #include /* @@ -101,14 +102,13 @@ DummyResource::DummyResource() void DummyResource::configurePipeline(Akonadi2::Pipeline *pipeline) { + auto factory = QSharedPointer::create(); //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; + auto eventIndexer = new SimpleProcessor([factory](const Akonadi2::PipelineState &state) { + auto adaptor = factory->createAdaptor(state.entity()); + //Here we can plug in generic preprocessors + qDebug() << adaptor->getProperty("summary").toString(); }); pipeline->setPreprocessors(Akonadi2::Pipeline::NewPipeline, QVector() << eventIndexer); } -- cgit v1.2.3