summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common/entitybuffer.cpp7
-rw-r--r--common/entitybuffer.h3
-rw-r--r--common/facade.h42
-rw-r--r--common/pipeline.cpp65
-rw-r--r--tests/dummyresourcetest.cpp41
5 files changed, 131 insertions, 27 deletions
diff --git a/common/entitybuffer.cpp b/common/entitybuffer.cpp
index 33a52fd..c14c86d 100644
--- a/common/entitybuffer.cpp
+++ b/common/entitybuffer.cpp
@@ -6,7 +6,7 @@
6 6
7using namespace Akonadi2; 7using namespace Akonadi2;
8 8
9EntityBuffer::EntityBuffer(void *dataValue, int dataSize) 9EntityBuffer::EntityBuffer(const void *dataValue, int dataSize)
10 : mEntity(nullptr) 10 : mEntity(nullptr)
11{ 11{
12 flatbuffers::Verifier verifyer(reinterpret_cast<const uint8_t *>(dataValue), dataSize); 12 flatbuffers::Verifier verifyer(reinterpret_cast<const uint8_t *>(dataValue), dataSize);
@@ -18,6 +18,11 @@ EntityBuffer::EntityBuffer(void *dataValue, int dataSize)
18 } 18 }
19} 19}
20 20
21bool EntityBuffer::isValid() const
22{
23 return mEntity;
24}
25
21const Akonadi2::Entity &EntityBuffer::entity() 26const Akonadi2::Entity &EntityBuffer::entity()
22{ 27{
23 return *mEntity; 28 return *mEntity;
diff --git a/common/entitybuffer.h b/common/entitybuffer.h
index dd7588e..a58aae9 100644
--- a/common/entitybuffer.h
+++ b/common/entitybuffer.h
@@ -8,11 +8,12 @@ struct Entity;
8 8
9class EntityBuffer { 9class EntityBuffer {
10public: 10public:
11 EntityBuffer(void *dataValue, int size); 11 EntityBuffer(const void *dataValue, int size);
12 const uint8_t *resourceBuffer(); 12 const uint8_t *resourceBuffer();
13 const uint8_t *metadataBuffer(); 13 const uint8_t *metadataBuffer();
14 const uint8_t *localBuffer(); 14 const uint8_t *localBuffer();
15 const Entity &entity(); 15 const Entity &entity();
16 bool isValid() const;
16 17
17 static void extractResourceBuffer(void *dataValue, int dataSize, const std::function<void(const uint8_t *, size_t size)> &handler); 18 static void extractResourceBuffer(void *dataValue, int dataSize, const std::function<void(const uint8_t *, size_t size)> &handler);
18 /* 19 /*
diff --git a/common/facade.h b/common/facade.h
index abd4113..2ee7f42 100644
--- a/common/facade.h
+++ b/common/facade.h
@@ -28,6 +28,8 @@
28#include "resourceaccess.h" 28#include "resourceaccess.h"
29#include "commands.h" 29#include "commands.h"
30#include "createentity_generated.h" 30#include "createentity_generated.h"
31#include "modifyentity_generated.h"
32#include "deleteentity_generated.h"
31#include "domainadaptor.h" 33#include "domainadaptor.h"
32#include "entitybuffer.h" 34#include "entitybuffer.h"
33#include "log.h" 35#include "log.h"
@@ -128,6 +130,7 @@ public:
128 { 130 {
129 if (!mDomainTypeAdaptorFactory) { 131 if (!mDomainTypeAdaptorFactory) {
130 Warning() << "No domain type adaptor factory available"; 132 Warning() << "No domain type adaptor factory available";
133 return KAsync::error<void>();
131 } 134 }
132 flatbuffers::FlatBufferBuilder entityFbb; 135 flatbuffers::FlatBufferBuilder entityFbb;
133 mDomainTypeAdaptorFactory->createBuffer(domainObject, entityFbb); 136 mDomainTypeAdaptorFactory->createBuffer(domainObject, entityFbb);
@@ -136,14 +139,18 @@ public:
136 139
137 KAsync::Job<void> modify(const DomainType &domainObject) Q_DECL_OVERRIDE 140 KAsync::Job<void> modify(const DomainType &domainObject) Q_DECL_OVERRIDE
138 { 141 {
139 //TODO 142 if (!mDomainTypeAdaptorFactory) {
140 return KAsync::null<void>(); 143 Warning() << "No domain type adaptor factory available";
144 return KAsync::error<void>();
145 }
146 flatbuffers::FlatBufferBuilder entityFbb;
147 mDomainTypeAdaptorFactory->createBuffer(domainObject, entityFbb);
148 return sendModifyCommand(domainObject.identifier(), domainObject.revision(), bufferTypeForDomainType(), QByteArrayList(), QByteArray::fromRawData(reinterpret_cast<const char*>(entityFbb.GetBufferPointer()), entityFbb.GetSize()));
141 } 149 }
142 150
143 KAsync::Job<void> remove(const DomainType &domainObject) Q_DECL_OVERRIDE 151 KAsync::Job<void> remove(const DomainType &domainObject) Q_DECL_OVERRIDE
144 { 152 {
145 //TODO 153 return sendDeleteCommand(domainObject.identifier(), domainObject.revision(), bufferTypeForDomainType());
146 return KAsync::null<void>();
147 } 154 }
148 155
149 //TODO JOBAPI return job from sync continuation to execute it as subjob? 156 //TODO JOBAPI return job from sync continuation to execute it as subjob?
@@ -199,6 +206,33 @@ protected:
199 return mResourceAccess->sendCommand(Akonadi2::Commands::CreateEntityCommand, fbb); 206 return mResourceAccess->sendCommand(Akonadi2::Commands::CreateEntityCommand, fbb);
200 } 207 }
201 208
209 KAsync::Job<void> sendModifyCommand(const QByteArray &uid, qint64 revision, const QByteArray &resourceBufferType, const QByteArrayList &deletedProperties, const QByteArray &buffer)
210 {
211 flatbuffers::FlatBufferBuilder fbb;
212 auto entityId = fbb.CreateString(uid.constData());
213 //This is the resource buffer type and not the domain type
214 auto type = fbb.CreateString(resourceBufferType.constData());
215 //FIXME
216 auto deletions = 0;
217 auto delta = Akonadi2::EntityBuffer::appendAsVector(fbb, buffer.constData(), buffer.size());
218 auto location = Akonadi2::Commands::CreateModifyEntity(fbb, revision, entityId, deletions, type, delta);
219 Akonadi2::Commands::FinishModifyEntityBuffer(fbb, location);
220 mResourceAccess->open();
221 return mResourceAccess->sendCommand(Akonadi2::Commands::ModifyEntityCommand, fbb);
222 }
223
224 KAsync::Job<void> sendDeleteCommand(const QByteArray &uid, qint64 revision, const QByteArray &resourceBufferType)
225 {
226 flatbuffers::FlatBufferBuilder fbb;
227 auto entityId = fbb.CreateString(uid.constData());
228 //This is the resource buffer type and not the domain type
229 auto type = fbb.CreateString(resourceBufferType.constData());
230 auto location = Akonadi2::Commands::CreateDeleteEntity(fbb, revision, entityId, type);
231 Akonadi2::Commands::FinishDeleteEntityBuffer(fbb, location);
232 mResourceAccess->open();
233 return mResourceAccess->sendCommand(Akonadi2::Commands::DeleteEntityCommand, fbb);
234 }
235
202 KAsync::Job<void> synchronizeResource(bool sync, bool processAll) 236 KAsync::Job<void> synchronizeResource(bool sync, bool processAll)
203 { 237 {
204 //TODO check if a sync is necessary 238 //TODO check if a sync is necessary
diff --git a/common/pipeline.cpp b/common/pipeline.cpp
index afb9e34..1197408 100644
--- a/common/pipeline.cpp
+++ b/common/pipeline.cpp
@@ -84,13 +84,16 @@ void Pipeline::setPreprocessors(const QString &entityType, Type pipelineType, co
84 }; 84 };
85} 85}
86 86
87Storage &Pipeline::storage() const
88void Pipeline::setAdaptorFactory(const QString &entityType, DomainTypeAdaptorFactoryInterface::Ptr factory) 87void Pipeline::setAdaptorFactory(const QString &entityType, DomainTypeAdaptorFactoryInterface::Ptr factory)
89{ 88{
90 return d->storage;
91 d->adaptorFactory.insert(entityType, factory); 89 d->adaptorFactory.insert(entityType, factory);
92} 90}
93 91
92Storage &Pipeline::storage() const
93{
94 return d->storage;
95}
96
94void Pipeline::null() 97void Pipeline::null()
95{ 98{
96 //TODO: is there really any need for the null pipeline? if so, it should be doing something ;) 99 //TODO: is there really any need for the null pipeline? if so, it should be doing something ;)
@@ -111,7 +114,7 @@ KAsync::Job<void> Pipeline::newEntity(void const *command, size_t size)
111 { 114 {
112 flatbuffers::Verifier verifyer(reinterpret_cast<const uint8_t *>(command), size); 115 flatbuffers::Verifier verifyer(reinterpret_cast<const uint8_t *>(command), size);
113 if (!Akonadi2::Commands::VerifyCreateEntityBuffer(verifyer)) { 116 if (!Akonadi2::Commands::VerifyCreateEntityBuffer(verifyer)) {
114 qWarning() << "invalid buffer, not a create entity buffer"; 117 Warning() << "invalid buffer, not a create entity buffer";
115 return KAsync::error<void>(); 118 return KAsync::error<void>();
116 } 119 }
117 } 120 }
@@ -122,7 +125,7 @@ KAsync::Job<void> Pipeline::newEntity(void const *command, size_t size)
122 { 125 {
123 flatbuffers::Verifier verifyer(reinterpret_cast<const uint8_t *>(createEntity->delta()->Data()), createEntity->delta()->size()); 126 flatbuffers::Verifier verifyer(reinterpret_cast<const uint8_t *>(createEntity->delta()->Data()), createEntity->delta()->size());
124 if (!Akonadi2::VerifyEntityBuffer(verifyer)) { 127 if (!Akonadi2::VerifyEntityBuffer(verifyer)) {
125 qWarning() << "invalid buffer, not an entity buffer"; 128 Warning() << "invalid buffer, not an entity buffer";
126 return KAsync::error<void>(); 129 return KAsync::error<void>();
127 } 130 }
128 } 131 }
@@ -142,7 +145,7 @@ KAsync::Job<void> Pipeline::newEntity(void const *command, size_t size)
142 145
143 storage().write(key.data(), key.size(), fbb.GetBufferPointer(), fbb.GetSize()); 146 storage().write(key.data(), key.size(), fbb.GetBufferPointer(), fbb.GetSize());
144 storage().setMaxRevision(newRevision); 147 storage().setMaxRevision(newRevision);
145 Log() << "Pipeline: wrote entity: "<< newRevision; 148 Log() << "Pipeline: wrote entity: " << key << newRevision;
146 149
147 return KAsync::start<void>([this, key, entityType](KAsync::Future<void> &future) { 150 return KAsync::start<void>([this, key, entityType](KAsync::Future<void> &future) {
148 PipelineState state(this, NewPipeline, key, d->newPipeline[entityType], [&future]() { 151 PipelineState state(this, NewPipeline, key, d->newPipeline[entityType], [&future]() {
@@ -162,51 +165,72 @@ KAsync::Job<void> Pipeline::modifiedEntity(void const *command, size_t size)
162 { 165 {
163 flatbuffers::Verifier verifyer(reinterpret_cast<const uint8_t *>(command), size); 166 flatbuffers::Verifier verifyer(reinterpret_cast<const uint8_t *>(command), size);
164 if (!Akonadi2::Commands::VerifyModifyEntityBuffer(verifyer)) { 167 if (!Akonadi2::Commands::VerifyModifyEntityBuffer(verifyer)) {
165 qWarning() << "invalid buffer, not a modify entity buffer"; 168 Warning() << "invalid buffer, not a modify entity buffer";
166 return KAsync::error<void>(); 169 return KAsync::error<void>();
167 } 170 }
168 } 171 }
169 auto modifyEntity = Akonadi2::Commands::GetModifyEntity(command); 172 auto modifyEntity = Akonadi2::Commands::GetModifyEntity(command);
173 Q_ASSERT(modifyEntity);
170 174
171 //TODO rename modifyEntity->domainType to bufferType 175 //TODO rename modifyEntity->domainType to bufferType
172 const QByteArray entityType = QByteArray(reinterpret_cast<char const*>(modifyEntity->domainType()->Data()), modifyEntity->domainType()->size()); 176 const QByteArray entityType = QByteArray(reinterpret_cast<char const*>(modifyEntity->domainType()->Data()), modifyEntity->domainType()->size());
173 const QByteArray key = QByteArray(reinterpret_cast<char const*>(modifyEntity->entityId()->Data()), modifyEntity->entityId()->size()); 177 const QByteArray key = QByteArray(reinterpret_cast<char const*>(modifyEntity->entityId()->Data()), modifyEntity->entityId()->size());
178 if (entityType.isEmpty() || key.isEmpty()) {
179 Warning() << "entity type or key " << entityType << key;
180 return KAsync::error<void>();
181 }
174 { 182 {
175 flatbuffers::Verifier verifyer(reinterpret_cast<const uint8_t *>(modifyEntity->delta()->Data()), modifyEntity->delta()->size()); 183 flatbuffers::Verifier verifyer(reinterpret_cast<const uint8_t *>(modifyEntity->delta()->Data()), modifyEntity->delta()->size());
176 if (!Akonadi2::VerifyEntityBuffer(verifyer)) { 184 if (!Akonadi2::VerifyEntityBuffer(verifyer)) {
177 qWarning() << "invalid buffer, not an entity buffer"; 185 Warning() << "invalid buffer, not an entity buffer";
178 return KAsync::error<void>(); 186 return KAsync::error<void>();
179 } 187 }
180 } 188 }
181 189
182 auto adaptorFactory = d->adaptorFactory.value(entityType); 190 auto adaptorFactory = d->adaptorFactory.value(entityType);
183 if (adaptorFactory) { 191 if (!adaptorFactory) {
184 qWarning() << "no adaptor factory"; 192 Warning() << "no adaptor factory for type " << entityType;
185 return KAsync::error<void>(); 193 return KAsync::error<void>();
186 } 194 }
187 195
188 auto diffEntity = Akonadi2::GetEntity(modifyEntity->delta()->Data()); 196 auto diffEntity = Akonadi2::GetEntity(modifyEntity->delta()->Data());
197 Q_ASSERT(diffEntity);
189 auto diff = adaptorFactory->createAdaptor(*diffEntity); 198 auto diff = adaptorFactory->createAdaptor(*diffEntity);
190 199
191 Akonadi2::ApplicationDomain::ApplicationDomainType::Ptr domainType; 200 QSharedPointer<Akonadi2::ApplicationDomain::BufferAdaptor> current;
192 storage().scan(QByteArray::fromRawData(key.data(), key.size()), [&domainType](const QByteArray &data) -> bool { 201 storage().scan(QByteArray::fromRawData(key.data(), key.size()), [&current, adaptorFactory](const QByteArray &data) -> bool {
193 auto existingEntity = Akonadi2::GetEntity(data.data()); 202 Akonadi2::EntityBuffer buffer(const_cast<const char *>(data.data()), data.size());
194 domainType = getDomainType(*existingEntity); 203 if (!buffer.isValid()) {
204 Warning() << "Read invalid buffer from disk";
205 } else {
206 current = adaptorFactory->createAdaptor(buffer.entity());
207 }
195 return false; 208 return false;
196 }); 209 });
197 //TODO error handler 210 //TODO error handler
198 211
212 if (!current) {
213 Warning() << "Failed to read local value ";
214 return KAsync::error<void>();
215 }
216
217 //resource and uid don't matter at this point
218 const Akonadi2::ApplicationDomain::ApplicationDomainType existingObject("", "", newRevision, current);
219 auto newObject = Akonadi2::ApplicationDomain::ApplicationDomainType::getInMemoryRepresentation<Akonadi2::ApplicationDomain::ApplicationDomainType>(existingObject);
220
199 //Apply diff 221 //Apply diff
200 //FIXME only apply the properties that are available in the buffer 222 //FIXME only apply the properties that are available in the buffer
201 for (const auto &property : diff->availableProperties()) { 223 for (const auto &property : diff->availableProperties()) {
202 domainType->setProperty(property, diff->getProperty(property)); 224 newObject->setProperty(property, diff->getProperty(property));
203 } 225 }
226
204 //Remove deletions 227 //Remove deletions
205 for (const auto &property : *modifyEntity->deletions()) { 228 if (modifyEntity->deletions()) {
206 domainType->setProperty(QByteArray::fromRawData(property->data(), property->size()), QVariant()); 229 for (const auto &property : *modifyEntity->deletions()) {
230 newObject->setProperty(QByteArray::fromRawData(property->data(), property->size()), QVariant());
231 }
207 } 232 }
208 233
209
210 //Add metadata buffer 234 //Add metadata buffer
211 flatbuffers::FlatBufferBuilder metadataFbb; 235 flatbuffers::FlatBufferBuilder metadataFbb;
212 auto metadataBuilder = Akonadi2::MetadataBuilder(metadataFbb); 236 auto metadataBuilder = Akonadi2::MetadataBuilder(metadataFbb);
@@ -215,16 +239,15 @@ KAsync::Job<void> Pipeline::modifiedEntity(void const *command, size_t size)
215 auto metadataBuffer = metadataBuilder.Finish(); 239 auto metadataBuffer = metadataBuilder.Finish();
216 Akonadi2::FinishMetadataBuffer(metadataFbb, metadataBuffer); 240 Akonadi2::FinishMetadataBuffer(metadataFbb, metadataBuffer);
217 241
218
219 flatbuffers::FlatBufferBuilder fbb; 242 flatbuffers::FlatBufferBuilder fbb;
220 adaptorFactory->createBuffer(*domainType, fbb, metadataFbb.GetBufferPointer(), metadataFbb.GetSize()); 243 adaptorFactory->createBuffer(*newObject, fbb, metadataFbb.GetBufferPointer(), metadataFbb.GetSize());
221 244
222 //TODO don't overwrite the old entry, but instead store a new revision 245 //TODO don't overwrite the old entry, but instead store a new revision
223 storage().write(key.data(), key.size(), fbb.GetBufferPointer(), fbb.GetSize()); 246 storage().write(key.data(), key.size(), fbb.GetBufferPointer(), fbb.GetSize());
224 storage().setMaxRevision(newRevision); 247 storage().setMaxRevision(newRevision);
225 248
226 return KAsync::start<void>([this, key, entityType](KAsync::Future<void> &future) { 249 return KAsync::start<void>([this, key, entityType](KAsync::Future<void> &future) {
227 PipelineState state(this, ModifiedPipeline, key, d->newPipeline[entityType], [&future]() { 250 PipelineState state(this, ModifiedPipeline, key, d->modifiedPipeline[entityType], [&future]() {
228 future.setFinished(); 251 future.setFinished();
229 }); 252 });
230 d->activePipelines << state; 253 d->activePipelines << state;
@@ -241,7 +264,7 @@ KAsync::Job<void> Pipeline::deletedEntity(void const *command, size_t size)
241 { 264 {
242 flatbuffers::Verifier verifyer(reinterpret_cast<const uint8_t *>(command), size); 265 flatbuffers::Verifier verifyer(reinterpret_cast<const uint8_t *>(command), size);
243 if (!Akonadi2::Commands::VerifyDeleteEntityBuffer(verifyer)) { 266 if (!Akonadi2::Commands::VerifyDeleteEntityBuffer(verifyer)) {
244 qWarning() << "invalid buffer, not a delete entity buffer"; 267 Warning() << "invalid buffer, not a delete entity buffer";
245 return KAsync::error<void>(); 268 return KAsync::error<void>();
246 } 269 }
247 } 270 }
diff --git a/tests/dummyresourcetest.cpp b/tests/dummyresourcetest.cpp
index 49558f8..7499d62 100644
--- a/tests/dummyresourcetest.cpp
+++ b/tests/dummyresourcetest.cpp
@@ -208,6 +208,47 @@ private Q_SLOTS:
208 qDebug() << value->getProperty("summary").toString(); 208 qDebug() << value->getProperty("summary").toString();
209 } 209 }
210 210
211 void testWriteModifyDelete()
212 {
213 Akonadi2::ApplicationDomain::Event event;
214 event.setProperty("uid", "testuid");
215 QCOMPARE(event.getProperty("uid").toByteArray(), QByteArray("testuid"));
216 event.setProperty("summary", "summaryValue");
217 Akonadi2::Store::create<Akonadi2::ApplicationDomain::Event>(event, "org.kde.dummy.instance1");
218
219 Akonadi2::Query query;
220 query.resources << "org.kde.dummy.instance1";
221 query.syncOnDemand = false;
222 query.processAll = true;
223 query.propertyFilter.insert("uid", "testuid");
224
225 //Test create
226 Akonadi2::ApplicationDomain::Event event2;
227 {
228 async::SyncListResult<Akonadi2::ApplicationDomain::Event::Ptr> result(Akonadi2::Store::load<Akonadi2::ApplicationDomain::Event>(query));
229 result.exec();
230 QCOMPARE(result.size(), 1);
231 auto value = result.first();
232 QCOMPARE(value->getProperty("uid").toByteArray(), QByteArray("testuid"));
233 QCOMPARE(value->getProperty("summary").toByteArray(), QByteArray("summaryValue"));
234 event2 = *value;
235 }
236
237 event2.setProperty("uid", "testuid");
238 event2.setProperty("summary", "summaryValue2");
239 Akonadi2::Store::modify<Akonadi2::ApplicationDomain::Event>(event2, "org.kde.dummy.instance1");
240
241 //Test modify
242 {
243 async::SyncListResult<Akonadi2::ApplicationDomain::Event::Ptr> result(Akonadi2::Store::load<Akonadi2::ApplicationDomain::Event>(query));
244 result.exec();
245 QCOMPARE(result.size(), 1);
246 auto value = result.first();
247 QCOMPARE(value->getProperty("uid").toByteArray(), QByteArray("testuid"));
248 QCOMPARE(value->getProperty("summary").toByteArray(), QByteArray("summaryValue2"));
249 }
250 }
251
211}; 252};
212 253
213QTEST_MAIN(DummyResourceTest) 254QTEST_MAIN(DummyResourceTest)