summaryrefslogtreecommitdiffstats
path: root/dummyresource
diff options
context:
space:
mode:
authorChristian Mollekopf <chrigi_1@fastmail.fm>2015-01-02 22:39:25 +0100
committerChristian Mollekopf <chrigi_1@fastmail.fm>2015-01-02 22:39:25 +0100
commit91d915a09b7d52c10edb1d4c1298fc2885b8a257 (patch)
tree407e9a2a1c902a68c78a7d08aab80ba47565fa88 /dummyresource
parent817bff01d15395206c1cc637d0c9ac0905007bf1 (diff)
downloadsink-91d915a09b7d52c10edb1d4c1298fc2885b8a257.tar.gz
sink-91d915a09b7d52c10edb1d4c1298fc2885b8a257.zip
DomainTypeAdaptor factory, per type preprocessor pipeline configuration.
Diffstat (limited to 'dummyresource')
-rw-r--r--dummyresource/facade.cpp138
-rw-r--r--dummyresource/facade.h53
-rw-r--r--dummyresource/resourcefactory.cpp56
-rw-r--r--dummyresource/resourcefactory.h1
4 files changed, 174 insertions, 74 deletions
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 @@
33using namespace DummyCalendar; 33using namespace DummyCalendar;
34using namespace flatbuffers; 34using namespace flatbuffers;
35 35
36/** 36//This will become a generic implementation that simply takes the resource buffer and local buffer pointer
37 * The property mapper holds accessor functions for all properties. 37class DummyEventAdaptor : public Akonadi2::Domain::BufferAdaptor
38 *
39 * It is by default initialized with accessors that access the local-only buffer,
40 * and resource simply have to overwrite those accessors.
41 */
42template<typename BufferType>
43class PropertyMapper
44{ 38{
45public: 39public:
46 void setProperty(const QString &key, const QVariant &value, BufferType *buffer) 40 DummyEventAdaptor()
41 : BufferAdaptor()
47 { 42 {
48 if (mWriteAccessors.contains(key)) { 43
49 auto accessor = mWriteAccessors.value(key); 44 }
50 return accessor(value, buffer); 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.;
51 } 52 }
52 } 53 }
53 54
54 virtual QVariant getProperty(const QString &key, BufferType const *buffer) const 55 virtual QVariant getProperty(const QString &key) const
55 { 56 {
56 if (mReadAccessors.contains(key)) { 57 if (mResourceBuffer && mResourceMapper->mReadAccessors.contains(key)) {
57 auto accessor = mReadAccessors.value(key); 58 return mResourceMapper->getProperty(key, mResourceBuffer);
58 return accessor(buffer); 59 } else if (mLocalBuffer) {
60 return mLocalMapper->getProperty(key, mLocalBuffer);
59 } 61 }
60 return QVariant(); 62 return QVariant();
61 } 63 }
62 QHash<QString, std::function<QVariant(BufferType const *)> > mReadAccessors; 64
63 QHash<QString, std::function<void(const QVariant &, BufferType*)> > mWriteAccessors; 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;
64}; 70};
65 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
66DummyResourceFacade::DummyResourceFacade() 107DummyResourceFacade::DummyResourceFacade()
67 : Akonadi2::StoreFacade<Akonadi2::Domain::Event>(), 108 : Akonadi2::StoreFacade<Akonadi2::Domain::Event>(),
68 mResourceAccess(new Akonadi2::ResourceAccess("org.kde.dummy")) 109 mResourceAccess(new Akonadi2::ResourceAccess("org.kde.dummy")),
110 mFactory(new DomainTypeAdaptorFactory<Akonadi2::Domain::Event, Akonadi2::Domain::Buffer::Event, DummyCalendar::DummyEvent>())
69{ 111{
70 PropertyMapper<DummyEvent> mapper; 112 auto mapper = QSharedPointer<PropertyMapper<DummyEvent> >::create();
71 mapper.mReadAccessors.insert("summary", [](DummyEvent const *buffer) -> QVariant { 113 mapper->mReadAccessors.insert("summary", [](DummyEvent const *buffer) -> QVariant {
72 return QString::fromStdString(buffer->summary()->c_str()); 114 return QString::fromStdString(buffer->summary()->c_str());
73 }); 115 });
116 mFactory->mResourceMapper = mapper;
74} 117}
75 118
76DummyResourceFacade::~DummyResourceFacade() 119DummyResourceFacade::~DummyResourceFacade()
@@ -105,45 +148,6 @@ void DummyResourceFacade::remove(const Akonadi2::Domain::Event &domainObject)
105// 148//
106 149
107 150
108//This will become a generic implementation that simply takes the resource buffer and local buffer pointer
109class DummyEventAdaptor : public Akonadi2::Domain::BufferAdaptor
110{
111public:
112 DummyEventAdaptor()
113 : BufferAdaptor()
114 {
115
116 }
117
118 void setProperty(const QString &key, const QVariant &value)
119 {
120 if (mResourceMapper.mWriteAccessors.contains(key)) {
121 // mResourceMapper.setProperty(key, value, mResourceBuffer);
122 } else {
123 // mLocalMapper.;
124 }
125 }
126
127 virtual QVariant getProperty(const QString &key) const
128 {
129 if (mResourceBuffer && mResourceMapper.mReadAccessors.contains(key)) {
130 return mResourceMapper.getProperty(key, mResourceBuffer);
131 } else if (mLocalBuffer) {
132 return mLocalMapper.getProperty(key, mLocalBuffer);
133 }
134 return QVariant();
135 }
136
137 Akonadi2::Domain::Buffer::Event const *mLocalBuffer;
138 DummyEvent const *mResourceBuffer;
139
140 PropertyMapper<Akonadi2::Domain::Buffer::Event> mLocalMapper;
141 PropertyMapper<DummyEvent> mResourceMapper;
142
143 //Keep query alive so values remain valid
144 QSharedPointer<Akonadi2::Storage> storage;
145};
146
147static std::function<bool(const std::string &key, DummyEvent const *buffer)> prepareQuery(const Akonadi2::Query &query) 151static std::function<bool(const std::string &key, DummyEvent const *buffer)> prepareQuery(const Akonadi2::Query &query)
148{ 152{
149 //Compose some functions to make query matching fast. 153 //Compose some functions to make query matching fast.
@@ -225,26 +229,16 @@ void DummyResourceFacade::load(const Akonadi2::Query &query, const std::function
225 } 229 }
226 } 230 }
227 231
228 Akonadi2::Domain::Buffer::Event const *localBuffer = 0;
229 if (auto localData = buffer.localBuffer()) {
230 flatbuffers::Verifier verifyer(localData->Data(), localData->size());
231 if (Akonadi2::Domain::Buffer::VerifyEventBuffer(verifyer)) {
232 localBuffer = Akonadi2::Domain::Buffer::GetEvent(localData);
233 }
234 }
235
236 if (!resourceBuffer || !metadataBuffer) { 232 if (!resourceBuffer || !metadataBuffer) {
237 qWarning() << "invalid buffer " << QString::fromStdString(std::string(static_cast<char*>(keyValue), keySize)); 233 qWarning() << "invalid buffer " << QString::fromStdString(std::string(static_cast<char*>(keyValue), keySize));
238 return true; 234 return true;
239 } 235 }
240 236
241 //We probably only want to create all buffers after the scan 237 //We probably only want to create all buffers after the scan
238 //TODO use adapter for query and scan?
242 if (preparedQuery && preparedQuery(std::string(static_cast<char*>(keyValue), keySize), resourceBuffer)) { 239 if (preparedQuery && preparedQuery(std::string(static_cast<char*>(keyValue), keySize), resourceBuffer)) {
243 qint64 revision = metadataBuffer ? metadataBuffer->revision() : -1; 240 qint64 revision = metadataBuffer ? metadataBuffer->revision() : -1;
244 auto adaptor = QSharedPointer<DummyEventAdaptor>::create(); 241 auto adaptor = mFactory->createAdaptor(buffer.entity());
245 adaptor->mLocalBuffer = localBuffer;
246 adaptor->mResourceBuffer = resourceBuffer;
247 adaptor->storage = storage;
248 auto event = QSharedPointer<Akonadi2::Domain::Event>::create("org.kde.dummy", QString::fromUtf8(static_cast<char*>(keyValue), keySize), revision, adaptor); 242 auto event = QSharedPointer<Akonadi2::Domain::Event>::create("org.kde.dummy", QString::fromUtf8(static_cast<char*>(keyValue), keySize), revision, adaptor);
249 resultCallback(event); 243 resultCallback(event);
250 } 244 }
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 @@
21 21
22#include "common/clientapi.h" 22#include "common/clientapi.h"
23#include "common/storage.h" 23#include "common/storage.h"
24#include "entity_generated.h"
25#include "event_generated.h"
26#include "dummycalendar_generated.h"
24 27
25namespace Akonadi2 { 28namespace Akonadi2 {
26 class ResourceAccess; 29 class ResourceAccess;
27} 30}
28 31
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
29class DummyResourceFacade : public Akonadi2::StoreFacade<Akonadi2::Domain::Event> 81class DummyResourceFacade : public Akonadi2::StoreFacade<Akonadi2::Domain::Event>
30{ 82{
31public: 83public:
@@ -39,4 +91,5 @@ public:
39private: 91private:
40 void synchronizeResource(const std::function<void()> &continuation); 92 void synchronizeResource(const std::function<void()> &continuation);
41 QSharedPointer<Akonadi2::ResourceAccess> mResourceAccess; 93 QSharedPointer<Akonadi2::ResourceAccess> mResourceAccess;
94 QSharedPointer<DomainTypeAdaptorFactory<Akonadi2::Domain::Event, Akonadi2::Domain::Buffer::Event, DummyCalendar::DummyEvent> > mFactory;
42}; 95};
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 @@
20#include "resourcefactory.h" 20#include "resourcefactory.h"
21#include "facade.h" 21#include "facade.h"
22#include "entitybuffer.h" 22#include "entitybuffer.h"
23#include "pipeline.h"
23#include "dummycalendar_generated.h" 24#include "dummycalendar_generated.h"
24#include "metadata_generated.h" 25#include "metadata_generated.h"
25#include <QUuid> 26#include <QUuid>
26 27
28/*
29 * Figure out how to implement various classes of processors:
30 * * read-only (index and such) => domain adapter
31 * * filter => provide means to move entity elsewhere, and also reflect change in source (I guess?)
32 * * flag extractors? => like read-only? Or write to local portion of buffer?
33 * ** $ISSPAM should become part of domain object and is written to the local part of the mail.
34 * ** => value could be calculated by the server directly
35 */
36// template <typename DomainType>
37class SimpleProcessor : public Akonadi2::Preprocessor
38{
39public:
40 SimpleProcessor(const std::function<void(const Akonadi2::PipelineState &state)> &f)
41 : Akonadi2::Preprocessor(),
42 mFunction(f)
43 {
44 }
45
46 void process(const Akonadi2::PipelineState &state) {
47 mFunction(state);
48 }
49
50protected:
51 std::function<void(const Akonadi2::PipelineState &state)> mFunction;
52};
53
54// template <typename DomainType>
55// class SimpleReadOnlyProcessor : public SimpleProcessor<DomainType>
56// {
57// public:
58// using SimpleProcessor::SimpleProcessor;
59// void process(Akonadi2::PipelineState state) {
60// mFunction();
61// }
62// };
63
64
27static std::string createEvent() 65static std::string createEvent()
28{ 66{
29 static const size_t attachmentSize = 1024*2; // 2KB 67 static const size_t attachmentSize = 1024*2; // 2KB
@@ -61,6 +99,20 @@ DummyResource::DummyResource()
61{ 99{
62} 100}
63 101
102void DummyResource::configurePipeline(Akonadi2::Pipeline *pipeline)
103{
104 //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.
106 auto eventIndexer = new SimpleProcessor([](const Akonadi2::PipelineState &state) {
107 //FIXME
108 // auto adaptor = QSharedPointer<DummyEventAdaptor>::create();
109 // adaptor->mLocalBuffer = localBuffer;
110 // adaptor->mResourceBuffer = resourceBuffer;
111 // adaptor->storage = storage;
112 });
113 pipeline->setPreprocessors<Akonadi2::Domain::Event>(Akonadi2::Pipeline::NewPipeline, QVector<Akonadi2::Preprocessor*>() << eventIndexer);
114}
115
64void findByRemoteId(QSharedPointer<Akonadi2::Storage> storage, const QString &rid, std::function<void(void *keyValue, int keySize, void *dataValue, int dataSize)> callback) 116void findByRemoteId(QSharedPointer<Akonadi2::Storage> storage, const QString &rid, std::function<void(void *keyValue, int keySize, void *dataValue, int dataSize)> callback)
65{ 117{
66 //TODO lookup in rid index instead of doing a full scan 118 //TODO lookup in rid index instead of doing a full scan
@@ -119,7 +171,7 @@ Async::Job<void> DummyResource::synchronizeWithSource(Akonadi2::Pipeline *pipeli
119 DummyCalendar::FinishDummyEventBuffer(m_fbb, buffer); 171 DummyCalendar::FinishDummyEventBuffer(m_fbb, buffer);
120 //TODO toRFC4122 would probably be more efficient, but results in non-printable keys. 172 //TODO toRFC4122 would probably be more efficient, but results in non-printable keys.
121 const auto key = QUuid::createUuid().toString().toUtf8(); 173 const auto key = QUuid::createUuid().toString().toUtf8();
122 pipeline->newEntity(key, m_fbb.GetBufferPointer(), m_fbb.GetSize()); 174 pipeline->newEntity<Akonadi2::Domain::Event>(key, m_fbb.GetBufferPointer(), m_fbb.GetSize());
123 } else { //modification 175 } else { //modification
124 //TODO diff and create modification if necessary 176 //TODO diff and create modification if necessary
125 } 177 }
@@ -139,7 +191,7 @@ void DummyResource::processCommand(int commandId, const QByteArray &data, uint s
139 builder .add_summary(m_fbb.CreateString("summary summary!")); 191 builder .add_summary(m_fbb.CreateString("summary summary!"));
140 auto buffer = builder.Finish(); 192 auto buffer = builder.Finish();
141 DummyCalendar::FinishDummyEventBuffer(m_fbb, buffer); 193 DummyCalendar::FinishDummyEventBuffer(m_fbb, buffer);
142 pipeline->newEntity("fakekey", m_fbb.GetBufferPointer(), m_fbb.GetSize()); 194 pipeline->newEntity<Akonadi2::Domain::Event>("fakekey", m_fbb.GetBufferPointer(), m_fbb.GetSize());
143 m_fbb.Clear(); 195 m_fbb.Clear();
144} 196}
145 197
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:
33 DummyResource(); 33 DummyResource();
34 Async::Job<void> synchronizeWithSource(Akonadi2::Pipeline *pipeline); 34 Async::Job<void> synchronizeWithSource(Akonadi2::Pipeline *pipeline);
35 void processCommand(int commandId, const QByteArray &data, uint size, Akonadi2::Pipeline *pipeline); 35 void processCommand(int commandId, const QByteArray &data, uint size, Akonadi2::Pipeline *pipeline);
36 void configurePipeline(Akonadi2::Pipeline *pipeline);
36 37
37private: 38private:
38 flatbuffers::FlatBufferBuilder m_fbb; 39 flatbuffers::FlatBufferBuilder m_fbb;