summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Mollekopf <chrigi_1@fastmail.fm>2015-01-03 00:08:44 +0100
committerChristian Mollekopf <chrigi_1@fastmail.fm>2015-01-03 00:08:44 +0100
commit4067462b0a27984df84b0379c19122d574253dfb (patch)
treee6a413a575b7fd4062da6474907bffd68155706f
parent91d915a09b7d52c10edb1d4c1298fc2885b8a257 (diff)
downloadsink-4067462b0a27984df84b0379c19122d574253dfb.tar.gz
sink-4067462b0a27984df84b0379c19122d574253dfb.zip
Shared domain adaptors between resource and facade.
-rw-r--r--common/domainadaptor.h77
-rw-r--r--common/pipeline.cpp6
-rw-r--r--common/pipeline.h3
-rw-r--r--dummyresource/CMakeLists.txt2
-rw-r--r--dummyresource/domainadaptor.cpp101
-rw-r--r--dummyresource/domainadaptor.h14
-rw-r--r--dummyresource/facade.cpp92
-rw-r--r--dummyresource/facade.h50
-rw-r--r--dummyresource/resourcefactory.cpp12
9 files changed, 212 insertions, 145 deletions
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 @@
1/*
2 * Copyright (C) 2014 Christian Mollekopf <chrigi_1@fastmail.fm>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20#pragma once
21
22#include "entity_generated.h"
23#include <QVariant>
24#include <QString>
25#include <functional>
26#include "clientapi.h" //for domain parts
27
28/**
29 * The property mapper holds accessor functions for all properties.
30 *
31 * It is by default initialized with accessors that access the local-only buffer,
32 * and resource simply have to overwrite those accessors.
33 */
34template<typename BufferType>
35class PropertyMapper
36{
37public:
38 void setProperty(const QString &key, const QVariant &value, BufferType *buffer)
39 {
40 if (mWriteAccessors.contains(key)) {
41 auto accessor = mWriteAccessors.value(key);
42 return accessor(value, buffer);
43 }
44 }
45
46 virtual QVariant getProperty(const QString &key, BufferType const *buffer) const
47 {
48 if (mReadAccessors.contains(key)) {
49 auto accessor = mReadAccessors.value(key);
50 return accessor(buffer);
51 }
52 return QVariant();
53 }
54 QHash<QString, std::function<QVariant(BufferType const *)> > mReadAccessors;
55 QHash<QString, std::function<void(const QVariant &, BufferType*)> > mWriteAccessors;
56};
57
58//The factory should define how to go from an entitybuffer (local + resource buffer), to a domain type adapter.
59//It defines how values are split accross local and resource buffer.
60//This is required by the facade the read the value, and by the pipeline preprocessors to access the domain values in a generic way.
61// template<typename DomainType, typename LocalBuffer, typename ResourceBuffer>
62// class DomainTypeAdaptorFactory
63// {
64// };
65
66template<typename DomainType, typename LocalBuffer, typename ResourceBuffer>
67class DomainTypeAdaptorFactory/* <typename DomainType, LocalBuffer, ResourceBuffer> */
68{
69public:
70 virtual QSharedPointer<Akonadi2::Domain::BufferAdaptor> createAdaptor(const Akonadi2::Entity &entity) = 0;
71
72protected:
73 QSharedPointer<PropertyMapper<LocalBuffer> > mLocalMapper;
74 QSharedPointer<PropertyMapper<ResourceBuffer> > mResourceMapper;
75};
76
77
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:
189 Pipeline *pipeline; 189 Pipeline *pipeline;
190 Pipeline::Type type; 190 Pipeline::Type type;
191 QByteArray key; 191 QByteArray key;
192 Akonadi2::Entity *entity;
192 QVectorIterator<Preprocessor *> filterIt; 193 QVectorIterator<Preprocessor *> filterIt;
193 bool idle; 194 bool idle;
194}; 195};
@@ -239,6 +240,11 @@ Pipeline::Type PipelineState::type() const
239 return d->type; 240 return d->type;
240} 241}
241 242
243const Akonadi2::Entity &PipelineState::entity() const
244{
245 return *d->entity;
246}
247
242void PipelineState::step() 248void PipelineState::step()
243{ 249{
244 if (!d->pipeline) { 250 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 @@
29#include <storage.h> 29#include <storage.h>
30#include <clientapi.h> //For domain types 30#include <clientapi.h> //For domain types
31 31
32#include "entity_generated.h"
33
32namespace Akonadi2 34namespace Akonadi2
33{ 35{
34 36
@@ -112,6 +114,7 @@ public:
112 bool isIdle() const; 114 bool isIdle() const;
113 QByteArray key() const; 115 QByteArray key() const;
114 Pipeline::Type type() const; 116 Pipeline::Type type() const;
117 const Akonadi2::Entity &entity() const;
115 118
116 void step(); 119 void step();
117 void processingCompleted(Preprocessor *filter); 120 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})
5 5
6generate_flatbuffers(dummycalendar) 6generate_flatbuffers(dummycalendar)
7 7
8add_library(${PROJECT_NAME} SHARED facade.cpp resourcefactory.cpp) 8add_library(${PROJECT_NAME} SHARED facade.cpp resourcefactory.cpp domainadaptor.cpp)
9qt5_use_modules(${PROJECT_NAME} Core Network) 9qt5_use_modules(${PROJECT_NAME} Core Network)
10target_link_libraries(${PROJECT_NAME} akonadi2common) 10target_link_libraries(${PROJECT_NAME} akonadi2common)
11 11
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 @@
1
2#include "domainadaptor.h"
3
4#include <QDebug>
5#include <functional>
6
7#include "dummycalendar_generated.h"
8#include "event_generated.h"
9#include "entity_generated.h"
10#include "metadata_generated.h"
11#include "domainadaptor.h"
12#include <common/entitybuffer.h>
13
14using namespace DummyCalendar;
15using namespace flatbuffers;
16
17using namespace DummyCalendar;
18using namespace flatbuffers;
19
20//This will become a generic implementation that simply takes the resource buffer and local buffer pointer
21class DummyEventAdaptor : public Akonadi2::Domain::BufferAdaptor
22{
23public:
24 DummyEventAdaptor()
25 : BufferAdaptor()
26 {
27
28 }
29
30 void setProperty(const QString &key, const QVariant &value)
31 {
32 if (mResourceMapper->mWriteAccessors.contains(key)) {
33 // mResourceMapper.setProperty(key, value, mResourceBuffer);
34 } else {
35 // mLocalMapper.;
36 }
37 }
38
39 virtual QVariant getProperty(const QString &key) const
40 {
41 if (mResourceBuffer && mResourceMapper->mReadAccessors.contains(key)) {
42 return mResourceMapper->getProperty(key, mResourceBuffer);
43 } else if (mLocalBuffer) {
44 return mLocalMapper->getProperty(key, mLocalBuffer);
45 }
46 return QVariant();
47 }
48
49 Akonadi2::Domain::Buffer::Event const *mLocalBuffer;
50 DummyEvent const *mResourceBuffer;
51
52 QSharedPointer<PropertyMapper<Akonadi2::Domain::Buffer::Event> > mLocalMapper;
53 QSharedPointer<PropertyMapper<DummyEvent> > mResourceMapper;
54};
55
56
57DummyEventAdaptorFactory::DummyEventAdaptorFactory()
58 : DomainTypeAdaptorFactory()
59{
60 mResourceMapper = QSharedPointer<PropertyMapper<DummyEvent> >::create();
61 mResourceMapper->mReadAccessors.insert("summary", [](DummyEvent const *buffer) -> QVariant {
62 return QString::fromStdString(buffer->summary()->c_str());
63 });
64 //TODO set accessors for all properties
65
66}
67
68QSharedPointer<Akonadi2::Domain::BufferAdaptor> DummyEventAdaptorFactory::createAdaptor(const Akonadi2::Entity &entity)
69{
70 DummyEvent const *resourceBuffer = 0;
71 if (auto resourceData = entity.resource()) {
72 flatbuffers::Verifier verifyer(resourceData->Data(), resourceData->size());
73 if (VerifyDummyEventBuffer(verifyer)) {
74 resourceBuffer = GetDummyEvent(resourceData);
75 }
76 }
77
78 Akonadi2::Metadata const *metadataBuffer = 0;
79 if (auto metadataData = entity.metadata()) {
80 flatbuffers::Verifier verifyer(metadataData->Data(), metadataData->size());
81 if (Akonadi2::VerifyMetadataBuffer(verifyer)) {
82 metadataBuffer = Akonadi2::GetMetadata(metadataData);
83 }
84 }
85
86 Akonadi2::Domain::Buffer::Event const *localBuffer = 0;
87 if (auto localData = entity.local()) {
88 flatbuffers::Verifier verifyer(localData->Data(), localData->size());
89 if (Akonadi2::Domain::Buffer::VerifyEventBuffer(verifyer)) {
90 localBuffer = Akonadi2::Domain::Buffer::GetEvent(localData);
91 }
92 }
93
94 auto adaptor = QSharedPointer<DummyEventAdaptor>::create();
95 adaptor->mLocalBuffer = localBuffer;
96 adaptor->mResourceBuffer = resourceBuffer;
97 adaptor->mResourceMapper = mResourceMapper;
98 adaptor->mLocalMapper = mLocalMapper;
99 return adaptor;
100}
101
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 @@
1
2#pragma once
3
4#include "common/domainadaptor.h"
5#include "event_generated.h"
6#include "dummycalendar_generated.h"
7#include "entity_generated.h"
8
9class DummyEventAdaptorFactory : public DomainTypeAdaptorFactory<Akonadi2::Domain::Event, Akonadi2::Domain::Buffer::Event, DummyCalendar::DummyEvent>
10{
11public:
12 DummyEventAdaptorFactory();
13 virtual QSharedPointer<Akonadi2::Domain::BufferAdaptor> createAdaptor(const Akonadi2::Entity &entity);
14};
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 @@
28#include "event_generated.h" 28#include "event_generated.h"
29#include "entity_generated.h" 29#include "entity_generated.h"
30#include "metadata_generated.h" 30#include "metadata_generated.h"
31#include "domainadaptor.h"
31#include <common/entitybuffer.h> 32#include <common/entitybuffer.h>
32 33
33using namespace DummyCalendar; 34using namespace DummyCalendar;
34using namespace flatbuffers; 35using namespace flatbuffers;
35 36
36//This will become a generic implementation that simply takes the resource buffer and local buffer pointer
37class DummyEventAdaptor : public Akonadi2::Domain::BufferAdaptor
38{
39public:
40 DummyEventAdaptor()
41 : BufferAdaptor()
42 {
43
44 }
45
46 void setProperty(const QString &key, const QVariant &value)
47 {
48 if (mResourceMapper->mWriteAccessors.contains(key)) {
49 // mResourceMapper.setProperty(key, value, mResourceBuffer);
50 } else {
51 // mLocalMapper.;
52 }
53 }
54
55 virtual QVariant getProperty(const QString &key) const
56 {
57 if (mResourceBuffer && mResourceMapper->mReadAccessors.contains(key)) {
58 return mResourceMapper->getProperty(key, mResourceBuffer);
59 } else if (mLocalBuffer) {
60 return mLocalMapper->getProperty(key, mLocalBuffer);
61 }
62 return QVariant();
63 }
64
65 Akonadi2::Domain::Buffer::Event const *mLocalBuffer;
66 DummyEvent const *mResourceBuffer;
67
68 QSharedPointer<PropertyMapper<Akonadi2::Domain::Buffer::Event> > mLocalMapper;
69 QSharedPointer<PropertyMapper<DummyEvent> > mResourceMapper;
70};
71
72template<>
73QSharedPointer<Akonadi2::Domain::BufferAdaptor> DomainTypeAdaptorFactory<typename Akonadi2::Domain::Event, typename Akonadi2::Domain::Buffer::Event, DummyEvent>::createAdaptor(const Akonadi2::Entity &entity)
74{
75 DummyEvent const *resourceBuffer = 0;
76 if (auto resourceData = entity.resource()) {
77 flatbuffers::Verifier verifyer(resourceData->Data(), resourceData->size());
78 if (VerifyDummyEventBuffer(verifyer)) {
79 resourceBuffer = GetDummyEvent(resourceData);
80 }
81 }
82
83 Akonadi2::Metadata const *metadataBuffer = 0;
84 if (auto metadataData = entity.metadata()) {
85 flatbuffers::Verifier verifyer(metadataData->Data(), metadataData->size());
86 if (Akonadi2::VerifyMetadataBuffer(verifyer)) {
87 metadataBuffer = Akonadi2::GetMetadata(metadataData);
88 }
89 }
90
91 Akonadi2::Domain::Buffer::Event const *localBuffer = 0;
92 if (auto localData = entity.local()) {
93 flatbuffers::Verifier verifyer(localData->Data(), localData->size());
94 if (Akonadi2::Domain::Buffer::VerifyEventBuffer(verifyer)) {
95 localBuffer = Akonadi2::Domain::Buffer::GetEvent(localData);
96 }
97 }
98
99 auto adaptor = QSharedPointer<DummyEventAdaptor>::create();
100 adaptor->mLocalBuffer = localBuffer;
101 adaptor->mResourceBuffer = resourceBuffer;
102 adaptor->mResourceMapper = mResourceMapper;
103 adaptor->mLocalMapper = mLocalMapper;
104 return adaptor;
105}
106
107DummyResourceFacade::DummyResourceFacade() 37DummyResourceFacade::DummyResourceFacade()
108 : Akonadi2::StoreFacade<Akonadi2::Domain::Event>(), 38 : Akonadi2::StoreFacade<Akonadi2::Domain::Event>(),
109 mResourceAccess(new Akonadi2::ResourceAccess("org.kde.dummy")), 39 mResourceAccess(new Akonadi2::ResourceAccess("org.kde.dummy")),
110 mFactory(new DomainTypeAdaptorFactory<Akonadi2::Domain::Event, Akonadi2::Domain::Buffer::Event, DummyCalendar::DummyEvent>()) 40 mFactory(new DummyEventAdaptorFactory)
111{ 41{
112 auto mapper = QSharedPointer<PropertyMapper<DummyEvent> >::create();
113 mapper->mReadAccessors.insert("summary", [](DummyEvent const *buffer) -> QVariant {
114 return QString::fromStdString(buffer->summary()->c_str());
115 });
116 mFactory->mResourceMapper = mapper;
117} 42}
118 43
119DummyResourceFacade::~DummyResourceFacade() 44DummyResourceFacade::~DummyResourceFacade()
@@ -135,19 +60,6 @@ void DummyResourceFacade::remove(const Akonadi2::Domain::Event &domainObject)
135 //Create message buffer and send to resource 60 //Create message buffer and send to resource
136} 61}
137 62
138//Key.value property map using enum or strings with qvariant, or rather typesafe API?
139//typesafe is a shitload more work that we can avoid
140//
141//The Event base implementaiton could take a pointer to a single property mapper,
142//and a void pointer to the mmapped region. => event is copyable and stack allocatable and we avoid large amounts of heap allocated objects
143//-The mapper should in this case live in the other thread
144//-default property mapper implementation can answer "is property X supported?"
145//-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
146//-we could bind the lifetime to the query
147//=> perhaps do heap allocate and use smart pointer?
148//
149
150
151static std::function<bool(const std::string &key, DummyEvent const *buffer)> prepareQuery(const Akonadi2::Query &query) 63static std::function<bool(const std::string &key, DummyEvent const *buffer)> prepareQuery(const Akonadi2::Query &query)
152{ 64{
153 //Compose some functions to make query matching fast. 65 //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 @@
21 21
22#include "common/clientapi.h" 22#include "common/clientapi.h"
23#include "common/storage.h" 23#include "common/storage.h"
24#include "resourcefactory.h"
24#include "entity_generated.h" 25#include "entity_generated.h"
25#include "event_generated.h" 26#include "event_generated.h"
26#include "dummycalendar_generated.h" 27#include "dummycalendar_generated.h"
28#include "common/domainadaptor.h"
27 29
28namespace Akonadi2 { 30namespace Akonadi2 {
29 class ResourceAccess; 31 class ResourceAccess;
30} 32}
31 33
32/**
33 * The property mapper holds accessor functions for all properties.
34 *
35 * It is by default initialized with accessors that access the local-only buffer,
36 * and resource simply have to overwrite those accessors.
37 */
38template<typename BufferType>
39class PropertyMapper
40{
41public:
42 void setProperty(const QString &key, const QVariant &value, BufferType *buffer)
43 {
44 if (mWriteAccessors.contains(key)) {
45 auto accessor = mWriteAccessors.value(key);
46 return accessor(value, buffer);
47 }
48 }
49
50 virtual QVariant getProperty(const QString &key, BufferType const *buffer) const
51 {
52 if (mReadAccessors.contains(key)) {
53 auto accessor = mReadAccessors.value(key);
54 return accessor(buffer);
55 }
56 return QVariant();
57 }
58 QHash<QString, std::function<QVariant(BufferType const *)> > mReadAccessors;
59 QHash<QString, std::function<void(const QVariant &, BufferType*)> > mWriteAccessors;
60};
61
62//The factory should define how to go from an entitybuffer (local + resource buffer), to a domain type adapter.
63//It defines how values are split accross local and resource buffer.
64//This is required by the facade the read the value, and by the pipeline preprocessors to access the domain values in a generic way.
65template<typename DomainType, typename LocalBuffer, typename ResourceBuffer>
66class DomainTypeAdaptorFactory
67{
68};
69
70template<typename LocalBuffer, typename ResourceBuffer>
71class DomainTypeAdaptorFactory<typename Akonadi2::Domain::Event, LocalBuffer, ResourceBuffer>
72{
73public:
74 QSharedPointer<Akonadi2::Domain::BufferAdaptor> createAdaptor(const Akonadi2::Entity &entity);
75
76// private:
77 QSharedPointer<PropertyMapper<LocalBuffer> > mLocalMapper;
78 QSharedPointer<PropertyMapper<ResourceBuffer> > mResourceMapper;
79};
80 34
81class DummyResourceFacade : public Akonadi2::StoreFacade<Akonadi2::Domain::Event> 35class DummyResourceFacade : public Akonadi2::StoreFacade<Akonadi2::Domain::Event>
82{ 36{
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 @@
23#include "pipeline.h" 23#include "pipeline.h"
24#include "dummycalendar_generated.h" 24#include "dummycalendar_generated.h"
25#include "metadata_generated.h" 25#include "metadata_generated.h"
26#include "domainadaptor.h"
26#include <QUuid> 27#include <QUuid>
27 28
28/* 29/*
@@ -101,14 +102,13 @@ DummyResource::DummyResource()
101 102
102void DummyResource::configurePipeline(Akonadi2::Pipeline *pipeline) 103void DummyResource::configurePipeline(Akonadi2::Pipeline *pipeline)
103{ 104{
105 auto factory = QSharedPointer<DummyEventAdaptorFactory>::create();
104 //TODO setup preprocessors for each domain type and pipeline type allowing full customization 106 //TODO setup preprocessors for each domain type and pipeline type allowing full customization
105 //Eventually the order should be self configuring, for now it's hardcoded. 107 //Eventually the order should be self configuring, for now it's hardcoded.
106 auto eventIndexer = new SimpleProcessor([](const Akonadi2::PipelineState &state) { 108 auto eventIndexer = new SimpleProcessor([factory](const Akonadi2::PipelineState &state) {
107 //FIXME 109 auto adaptor = factory->createAdaptor(state.entity());
108 // auto adaptor = QSharedPointer<DummyEventAdaptor>::create(); 110 //Here we can plug in generic preprocessors
109 // adaptor->mLocalBuffer = localBuffer; 111 qDebug() << adaptor->getProperty("summary").toString();
110 // adaptor->mResourceBuffer = resourceBuffer;
111 // adaptor->storage = storage;
112 }); 112 });
113 pipeline->setPreprocessors<Akonadi2::Domain::Event>(Akonadi2::Pipeline::NewPipeline, QVector<Akonadi2::Preprocessor*>() << eventIndexer); 113 pipeline->setPreprocessors<Akonadi2::Domain::Event>(Akonadi2::Pipeline::NewPipeline, QVector<Akonadi2::Preprocessor*>() << eventIndexer);
114} 114}