diff options
Diffstat (limited to 'common/domainadaptor.h')
-rw-r--r-- | common/domainadaptor.h | 187 |
1 files changed, 161 insertions, 26 deletions
diff --git a/common/domainadaptor.h b/common/domainadaptor.h index e46e893..e356692 100644 --- a/common/domainadaptor.h +++ b/common/domainadaptor.h | |||
@@ -21,59 +21,194 @@ | |||
21 | 21 | ||
22 | #include "entity_generated.h" | 22 | #include "entity_generated.h" |
23 | #include <QVariant> | 23 | #include <QVariant> |
24 | #include <QString> | 24 | #include <QByteArray> |
25 | #include <functional> | 25 | #include <functional> |
26 | #include "clientapi.h" //for domain parts | 26 | #include "clientapi.h" //for domain parts |
27 | 27 | ||
28 | #include "event_generated.h" | ||
29 | #include "entity_generated.h" | ||
30 | #include "metadata_generated.h" | ||
31 | #include "entitybuffer.h" | ||
32 | |||
28 | /** | 33 | /** |
29 | * The property mapper holds accessor functions for all properties. | 34 | * The property mapper is a non-typesafe virtual dispatch. |
30 | * | 35 | * |
31 | * It is by default initialized with accessors that access the local-only buffer, | 36 | * Instead of using an interface and requring each implementation to override |
32 | * and resource simply have to overwrite those accessors. | 37 | * a virtual method per property, the property mapper can be filled with accessors |
38 | * that extract the properties from resource types. | ||
33 | */ | 39 | */ |
34 | template<typename BufferType> | 40 | template<typename BufferType> |
35 | class PropertyMapper | 41 | class ReadPropertyMapper |
42 | { | ||
43 | public: | ||
44 | virtual QVariant getProperty(const QByteArray &key, BufferType const *buffer) const | ||
45 | { | ||
46 | if (mReadAccessors.contains(key)) { | ||
47 | auto accessor = mReadAccessors.value(key); | ||
48 | return accessor(buffer); | ||
49 | } | ||
50 | return QVariant(); | ||
51 | } | ||
52 | bool hasMapping(const QByteArray &key) const { return mReadAccessors.contains(key); } | ||
53 | QList<QByteArray> availableProperties() const { return mReadAccessors.keys(); } | ||
54 | void addMapping(const QByteArray &property, const std::function<QVariant(BufferType const *)> &mapping) { | ||
55 | mReadAccessors.insert(property, mapping); | ||
56 | } | ||
57 | private: | ||
58 | QHash<QByteArray, std::function<QVariant(BufferType const *)> > mReadAccessors; | ||
59 | }; | ||
60 | |||
61 | template<typename BufferBuilder> | ||
62 | class WritePropertyMapper | ||
36 | { | 63 | { |
37 | public: | 64 | public: |
38 | void setProperty(const QString &key, const QVariant &value, BufferType *buffer) | 65 | virtual void setProperty(const QByteArray &key, const QVariant &value, QList<std::function<void(BufferBuilder &)> > &builderCalls, flatbuffers::FlatBufferBuilder &fbb) const |
39 | { | 66 | { |
40 | if (mWriteAccessors.contains(key)) { | 67 | if (mWriteAccessors.contains(key)) { |
41 | auto accessor = mWriteAccessors.value(key); | 68 | auto accessor = mWriteAccessors.value(key); |
42 | return accessor(value, buffer); | 69 | builderCalls << accessor(value, fbb); |
43 | } | 70 | } |
44 | } | 71 | } |
72 | bool hasMapping(const QByteArray &key) const { return mWriteAccessors.contains(key); } | ||
73 | void addMapping(const QByteArray &property, const std::function<std::function<void(BufferBuilder &)>(const QVariant &, flatbuffers::FlatBufferBuilder &)> &mapping) { | ||
74 | mWriteAccessors.insert(property, mapping); | ||
75 | } | ||
76 | private: | ||
77 | QHash<QByteArray, std::function<std::function<void(BufferBuilder &)>(const QVariant &, flatbuffers::FlatBufferBuilder &)> > mWriteAccessors; | ||
78 | }; | ||
79 | |||
80 | /** | ||
81 | * Defines how to convert qt primitives to flatbuffer ones | ||
82 | * TODO: rename to createProperty or so? | ||
83 | */ | ||
84 | template <class T> | ||
85 | flatbuffers::uoffset_t extractProperty(const QVariant &, flatbuffers::FlatBufferBuilder &fbb); | ||
86 | |||
87 | /** | ||
88 | * Create a buffer from a domain object using the provided mappings | ||
89 | */ | ||
90 | template <class Builder, class Buffer> | ||
91 | flatbuffers::Offset<Buffer> createBufferPart(const Akonadi2::ApplicationDomain::ApplicationDomainType &domainObject, flatbuffers::FlatBufferBuilder &fbb, const WritePropertyMapper<Builder> &mapper) | ||
92 | { | ||
93 | //First create a primitives such as strings using the mappings | ||
94 | QList<std::function<void(Builder &)> > propertiesToAddToResource; | ||
95 | for (const auto &property : domainObject.changedProperties()) { | ||
96 | qWarning() << "copying property " << property; | ||
97 | const auto value = domainObject.getProperty(property); | ||
98 | if (mapper.hasMapping(property)) { | ||
99 | mapper.setProperty(property, domainObject.getProperty(property), propertiesToAddToResource, fbb); | ||
100 | } else { | ||
101 | qWarning() << "no mapping for property available " << property; | ||
102 | } | ||
103 | } | ||
104 | |||
105 | //Then create all porperties using the above generated builderCalls | ||
106 | Builder builder(fbb); | ||
107 | for (auto propertyBuilder : propertiesToAddToResource) { | ||
108 | propertyBuilder(builder); | ||
109 | } | ||
110 | return builder.Finish(); | ||
111 | } | ||
112 | |||
113 | /** | ||
114 | * A generic adaptor implementation that uses a property mapper to read/write values. | ||
115 | * | ||
116 | * TODO: this is the read-only part. Create a write only equivalent | ||
117 | */ | ||
118 | template <class LocalBuffer, class ResourceBuffer> | ||
119 | class GenericBufferAdaptor : public Akonadi2::ApplicationDomain::BufferAdaptor | ||
120 | { | ||
121 | public: | ||
122 | GenericBufferAdaptor() | ||
123 | : BufferAdaptor() | ||
124 | { | ||
125 | |||
126 | } | ||
45 | 127 | ||
46 | virtual QVariant getProperty(const QString &key, BufferType const *buffer) const | 128 | //TODO remove |
129 | void setProperty(const QByteArray &key, const QVariant &value) | ||
47 | { | 130 | { |
48 | if (mReadAccessors.contains(key)) { | 131 | } |
49 | auto accessor = mReadAccessors.value(key); | 132 | |
50 | return accessor(buffer); | 133 | virtual QVariant getProperty(const QByteArray &key) const |
134 | { | ||
135 | if (mResourceBuffer && mResourceMapper->hasMapping(key)) { | ||
136 | return mResourceMapper->getProperty(key, mResourceBuffer); | ||
137 | } else if (mLocalBuffer && mLocalMapper->hasMapping(key)) { | ||
138 | return mLocalMapper->getProperty(key, mLocalBuffer); | ||
51 | } | 139 | } |
140 | qWarning() << "no mapping available for key " << key; | ||
52 | return QVariant(); | 141 | return QVariant(); |
53 | } | 142 | } |
54 | QHash<QString, std::function<QVariant(BufferType const *)> > mReadAccessors; | 143 | |
55 | QHash<QString, std::function<void(const QVariant &, BufferType*)> > mWriteAccessors; | 144 | virtual QList<QByteArray> availableProperties() const |
145 | { | ||
146 | QList<QByteArray> props; | ||
147 | props << mResourceMapper->availableProperties(); | ||
148 | props << mLocalMapper->availableProperties(); | ||
149 | return props; | ||
150 | } | ||
151 | |||
152 | LocalBuffer const *mLocalBuffer; | ||
153 | ResourceBuffer const *mResourceBuffer; | ||
154 | QSharedPointer<ReadPropertyMapper<LocalBuffer> > mLocalMapper; | ||
155 | QSharedPointer<ReadPropertyMapper<ResourceBuffer> > mResourceMapper; | ||
56 | }; | 156 | }; |
57 | 157 | ||
58 | //The factory should define how to go from an entitybuffer (local + resource buffer), to a domain type adapter. | 158 | /** |
59 | //It defines how values are split accross local and resource buffer. | 159 | * Initializes the local property mapper. |
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. | 160 | * |
61 | // template<typename DomainType, typename LocalBuffer, typename ResourceBuffer> | 161 | * Provide an implementation for each application domain type. |
62 | // class DomainTypeAdaptorFactory | 162 | */ |
63 | // { | 163 | template <class T> |
64 | // }; | 164 | QSharedPointer<ReadPropertyMapper<T> > initializeReadPropertyMapper(); |
165 | |||
166 | template <class T> | ||
167 | QSharedPointer<WritePropertyMapper<T> > initializeWritePropertyMapper(); | ||
65 | 168 | ||
66 | template<typename DomainType, typename LocalBuffer, typename ResourceBuffer> | 169 | /** |
67 | class DomainTypeAdaptorFactory/* <typename DomainType, LocalBuffer, ResourceBuffer> */ | 170 | * The factory should define how to go from an entitybuffer (local + resource buffer), to a domain type adapter. |
171 | * It defines how values are split accross local and resource buffer. | ||
172 | * This is required by the facade the read the value, and by the pipeline preprocessors to access the domain values in a generic way. | ||
173 | */ | ||
174 | template<typename DomainType, typename LocalBuffer, typename ResourceBuffer, typename LocalBuilder, typename ResourceBuilder> | ||
175 | class DomainTypeAdaptorFactory | ||
68 | { | 176 | { |
69 | public: | 177 | public: |
178 | DomainTypeAdaptorFactory() : | ||
179 | mLocalMapper(initializeReadPropertyMapper<LocalBuffer>()), | ||
180 | mResourceMapper(QSharedPointer<ReadPropertyMapper<ResourceBuffer> >::create()), | ||
181 | mLocalWriteMapper(initializeWritePropertyMapper<LocalBuilder>()), | ||
182 | mResourceWriteMapper(QSharedPointer<WritePropertyMapper<ResourceBuilder> >::create()) | ||
183 | {}; | ||
70 | virtual ~DomainTypeAdaptorFactory() {}; | 184 | virtual ~DomainTypeAdaptorFactory() {}; |
71 | virtual QSharedPointer<Akonadi2::Domain::BufferAdaptor> createAdaptor(const Akonadi2::Entity &entity) = 0; | 185 | |
72 | virtual void createBuffer(const Akonadi2::Domain::Event &event, flatbuffers::FlatBufferBuilder &fbb) {}; | 186 | /** |
187 | * Creates an adaptor for the given domain and resource types. | ||
188 | * | ||
189 | * This returns by default a GenericBufferAdaptor initialized with the corresponding property mappers. | ||
190 | */ | ||
191 | virtual QSharedPointer<Akonadi2::ApplicationDomain::BufferAdaptor> createAdaptor(const Akonadi2::Entity &entity) | ||
192 | { | ||
193 | const auto resourceBuffer = Akonadi2::EntityBuffer::readBuffer<ResourceBuffer>(entity.resource()); | ||
194 | const auto localBuffer = Akonadi2::EntityBuffer::readBuffer<LocalBuffer>(entity.local()); | ||
195 | // const auto metadataBuffer = Akonadi2::EntityBuffer::readBuffer<Akonadi2::Metadata>(entity.metadata()); | ||
196 | |||
197 | auto adaptor = QSharedPointer<GenericBufferAdaptor<LocalBuffer, ResourceBuffer> >::create(); | ||
198 | adaptor->mLocalBuffer = localBuffer; | ||
199 | adaptor->mLocalMapper = mLocalMapper; | ||
200 | adaptor->mResourceBuffer = resourceBuffer; | ||
201 | adaptor->mResourceMapper = mResourceMapper; | ||
202 | return adaptor; | ||
203 | } | ||
204 | |||
205 | virtual void createBuffer(const Akonadi2::ApplicationDomain::Event &event, flatbuffers::FlatBufferBuilder &fbb) {}; | ||
73 | 206 | ||
74 | protected: | 207 | protected: |
75 | QSharedPointer<PropertyMapper<LocalBuffer> > mLocalMapper; | 208 | QSharedPointer<ReadPropertyMapper<LocalBuffer> > mLocalMapper; |
76 | QSharedPointer<PropertyMapper<ResourceBuffer> > mResourceMapper; | 209 | QSharedPointer<ReadPropertyMapper<ResourceBuffer> > mResourceMapper; |
210 | QSharedPointer<WritePropertyMapper<LocalBuilder> > mLocalWriteMapper; | ||
211 | QSharedPointer<WritePropertyMapper<ResourceBuilder> > mResourceWriteMapper; | ||
77 | }; | 212 | }; |
78 | 213 | ||
79 | 214 | ||