File indexing completed on 2024-05-12 05:25:58
0001 /* 0002 * Copyright (C) 2014 Christian Mollekopf <chrigi_1@fastmail.fm> 0003 * 0004 * This program is free software; you can redistribute it and/or modify 0005 * it under the terms of the GNU General Public License as published by 0006 * the Free Software Foundation; either version 2 of the License, or 0007 * (at your option) any later version. 0008 * 0009 * This program is distributed in the hope that it will be useful, 0010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0012 * GNU General Public License for more details. 0013 * 0014 * You should have received a copy of the GNU General Public License 0015 * along with this program; if not, write to the 0016 * Free Software Foundation, Inc., 0017 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 0018 */ 0019 0020 #pragma once 0021 0022 #include <QVariant> 0023 #include <QByteArray> 0024 #include <functional> 0025 0026 #include "domaintypeadaptorfactoryinterface.h" 0027 #include "domain/applicationdomaintype.h" 0028 #include "domain/typeimplementations.h" 0029 #include "bufferadaptor.h" 0030 #include "entity_generated.h" 0031 #include "entitybuffer.h" 0032 #include "propertymapper.h" 0033 #include "log.h" 0034 0035 /** 0036 * Create a buffer from a domain object using the provided mappings 0037 */ 0038 template <class Builder, class Buffer> 0039 flatbuffers::Offset<Buffer> 0040 createBufferPart(const Sink::ApplicationDomain::ApplicationDomainType &domainObject, flatbuffers::FlatBufferBuilder &fbb, const PropertyMapper &mapper) 0041 { 0042 // First create a primitives such as strings using the mappings 0043 QList<std::function<void(void *builder)>> propertiesToAddToResource; 0044 for (const auto &property : domainObject.changedProperties()) { 0045 // SinkTrace() << "copying property " << property; 0046 const auto value = domainObject.getProperty(property); 0047 if (mapper.hasMapping(property)) { 0048 mapper.setProperty(property, domainObject.getProperty(property), propertiesToAddToResource, fbb); 0049 } else { 0050 // SinkTrace() << "no mapping for property available " << property; 0051 } 0052 } 0053 0054 // Then create all porperties using the above generated builderCalls 0055 Builder builder(fbb); 0056 for (auto propertyBuilder : propertiesToAddToResource) { 0057 propertyBuilder(&builder); 0058 } 0059 return builder.Finish(); 0060 } 0061 0062 /** 0063 * Create the buffer and finish the FlatBufferBuilder. 0064 * 0065 * After this the buffer can be extracted from the FlatBufferBuilder object. 0066 */ 0067 template <typename Buffer, typename BufferBuilder> 0068 static void createBufferPartBuffer(const Sink::ApplicationDomain::ApplicationDomainType &domainObject, flatbuffers::FlatBufferBuilder &fbb, PropertyMapper &mapper) 0069 { 0070 auto pos = createBufferPart<BufferBuilder, Buffer>(domainObject, fbb, mapper); 0071 // Because we cannot template the following call 0072 // Sink::ApplicationDomain::Buffer::FinishEventBuffer(fbb, pos); 0073 // FIXME: This means all buffers in here must have the AKFB identifier 0074 fbb.Finish(pos, "AKFB"); 0075 flatbuffers::Verifier verifier(fbb.GetBufferPointer(), fbb.GetSize()); 0076 if (!verifier.VerifyBuffer<Buffer>(nullptr)) { 0077 SinkWarning_(0, "bufferadaptor") << "Created invalid uffer"; 0078 } 0079 } 0080 0081 class IndexPropertyMapper 0082 { 0083 public: 0084 typedef std::function<QVariant(TypeIndex &index, const Sink::ApplicationDomain::BufferAdaptor &adaptor)> Accessor; 0085 virtual ~IndexPropertyMapper(){}; 0086 0087 virtual QVariant getProperty(const QByteArray &key, TypeIndex &index, const Sink::ApplicationDomain::BufferAdaptor &adaptor) const 0088 { 0089 auto accessor = mReadAccessors.value(key); 0090 Q_ASSERT(accessor); 0091 if (!accessor) { 0092 return QVariant(); 0093 } 0094 return accessor(index, adaptor); 0095 } 0096 0097 bool hasMapping(const QByteArray &key) const 0098 { 0099 return mReadAccessors.contains(key); 0100 } 0101 0102 QList<QByteArray> availableProperties() const 0103 { 0104 return mReadAccessors.keys(); 0105 } 0106 0107 template<typename Property> 0108 void addIndexLookupProperty(const Accessor &accessor) 0109 { 0110 mReadAccessors.insert(Property::name, accessor); 0111 } 0112 0113 private: 0114 QHash<QByteArray, Accessor> mReadAccessors; 0115 }; 0116 0117 /** 0118 * A generic adaptor implementation that uses a property mapper to read/write values. 0119 */ 0120 class DatastoreBufferAdaptor : public Sink::ApplicationDomain::BufferAdaptor 0121 { 0122 public: 0123 DatastoreBufferAdaptor() : BufferAdaptor() 0124 { 0125 } 0126 0127 virtual void setProperty(const QByteArray &key, const QVariant &value) Q_DECL_OVERRIDE 0128 { 0129 SinkWarning() << "Can't set property " << key; 0130 Q_ASSERT(false); 0131 } 0132 0133 virtual QVariant getProperty(const QByteArray &key) const Q_DECL_OVERRIDE 0134 { 0135 if (mLocalBuffer && mLocalMapper->hasMapping(key)) { 0136 return mLocalMapper->getProperty(key, mLocalBuffer); 0137 } else if (mIndex && mIndexMapper->hasMapping(key)) { 0138 return mIndexMapper->getProperty(key, *mIndex, *this); 0139 } 0140 return QVariant(); 0141 } 0142 0143 /** 0144 * Returns all available properties for which a mapping exists (no matter what the buffer contains) 0145 */ 0146 virtual QList<QByteArray> availableProperties() const Q_DECL_OVERRIDE 0147 { 0148 return mLocalMapper->availableProperties() + mIndexMapper->availableProperties(); 0149 } 0150 0151 void const *mLocalBuffer; 0152 QSharedPointer<PropertyMapper> mLocalMapper; 0153 QSharedPointer<IndexPropertyMapper> mIndexMapper; 0154 TypeIndex *mIndex; 0155 }; 0156 0157 /** 0158 * The factory should define how to go from an entitybuffer (local buffer), to a domain type adapter. 0159 * It defines how values are split accross local and resource buffer. 0160 * This is required by the facade the read the value, and by the pipeline preprocessors to access the domain values in a generic way. 0161 */ 0162 template <typename DomainType> 0163 class DomainTypeAdaptorFactory : public DomainTypeAdaptorFactoryInterface 0164 { 0165 typedef typename Sink::ApplicationDomain::TypeImplementation<DomainType>::Buffer LocalBuffer; 0166 typedef typename Sink::ApplicationDomain::TypeImplementation<DomainType>::BufferBuilder LocalBuilder; 0167 0168 public: 0169 DomainTypeAdaptorFactory() 0170 : mPropertyMapper(QSharedPointer<PropertyMapper>::create()), 0171 mIndexMapper(QSharedPointer<IndexPropertyMapper>::create()) 0172 { 0173 Sink::ApplicationDomain::TypeImplementation<DomainType>::configure(*mPropertyMapper); 0174 Sink::ApplicationDomain::TypeImplementation<DomainType>::configure(*mIndexMapper); 0175 } 0176 0177 virtual ~DomainTypeAdaptorFactory(){}; 0178 0179 /** 0180 * Creates an adaptor for the given domain types. 0181 * 0182 * This returns by default a DatastoreBufferAdaptor initialized with the corresponding property mappers. 0183 */ 0184 virtual QSharedPointer<Sink::ApplicationDomain::BufferAdaptor> createAdaptor(const Sink::Entity &entity, TypeIndex *index = nullptr) Q_DECL_OVERRIDE 0185 { 0186 auto adaptor = QSharedPointer<DatastoreBufferAdaptor>::create(); 0187 adaptor->mLocalBuffer = Sink::EntityBuffer::readBuffer<LocalBuffer>(entity.local()); 0188 adaptor->mLocalMapper = mPropertyMapper; 0189 adaptor->mIndexMapper = mIndexMapper; 0190 adaptor->mIndex = index; 0191 return std::move(adaptor); 0192 } 0193 0194 virtual bool 0195 createBuffer(const Sink::ApplicationDomain::ApplicationDomainType &domainObject, flatbuffers::FlatBufferBuilder &fbb, void const *metadataData = 0, size_t metadataSize = 0) Q_DECL_OVERRIDE 0196 { 0197 flatbuffers::FlatBufferBuilder localFbb; 0198 createBufferPartBuffer<LocalBuffer, LocalBuilder>(domainObject, localFbb, *mPropertyMapper); 0199 Sink::EntityBuffer::assembleEntityBuffer(fbb, metadataData, metadataSize, 0, 0, localFbb.GetBufferPointer(), localFbb.GetSize()); 0200 return true; 0201 } 0202 0203 virtual bool createBuffer(const QSharedPointer<Sink::ApplicationDomain::BufferAdaptor> &bufferAdaptor, flatbuffers::FlatBufferBuilder &fbb, void const *metadataData = nullptr, size_t metadataSize = 0) Q_DECL_OVERRIDE 0204 { 0205 //TODO rewrite the unterlying functions so we don't have to wrap the bufferAdaptor 0206 auto newObject = Sink::ApplicationDomain::ApplicationDomainType("", "", 0, bufferAdaptor); 0207 //Serialize all properties 0208 newObject.setChangedProperties(bufferAdaptor->availableProperties().toSet()); 0209 return createBuffer(newObject, fbb, metadataData, metadataSize); 0210 } 0211 0212 0213 protected: 0214 QSharedPointer<PropertyMapper> mPropertyMapper; 0215 QSharedPointer<IndexPropertyMapper> mIndexMapper; 0216 }; 0217 0218 /** 0219 * A default adaptorfactory implemenation that simply instantiates a generic resource 0220 */ 0221 template<typename DomainType> 0222 class DefaultAdaptorFactory : public DomainTypeAdaptorFactory<DomainType> 0223 { 0224 public: 0225 DefaultAdaptorFactory() : DomainTypeAdaptorFactory<DomainType>() {} 0226 virtual ~DefaultAdaptorFactory(){} 0227 }; 0228