|
@@ -26,38 +26,217 @@
|
|
#include "qprotobufserializerregistry_p.h"
|
|
#include "qprotobufserializerregistry_p.h"
|
|
#include "qprotobufserializer.h"
|
|
#include "qprotobufserializer.h"
|
|
#include "qprotobufjsonserializer.h"
|
|
#include "qprotobufjsonserializer.h"
|
|
|
|
+#include "qprotobufserializationplugininterface.h"
|
|
|
|
|
|
|
|
+#include <QDir>
|
|
#include <QString>
|
|
#include <QString>
|
|
#include <QHash>
|
|
#include <QHash>
|
|
|
|
+#include <QPluginLoader>
|
|
|
|
+#include <QJsonObject>
|
|
|
|
+#include <QJsonArray>
|
|
|
|
+
|
|
|
|
+namespace {
|
|
|
|
+const QLatin1String Serializationplugin("serializationplugin");
|
|
|
|
+const QLatin1String TypeNames("types");
|
|
|
|
+const QLatin1String MetaData("MetaData");
|
|
|
|
+const QLatin1String Version("version");
|
|
|
|
+const QLatin1String Rating("rating");
|
|
|
|
+const QLatin1String ProtoVersion("protobufVersion");
|
|
|
|
+const QLatin1String PluginName("name");
|
|
|
|
+const QLatin1String ProtobufSerializer("protobuf");
|
|
|
|
+const QLatin1String JsonSerializer("json");
|
|
|
|
+#ifdef _WIN32
|
|
|
|
+const QLatin1String libExtension(".dll");
|
|
|
|
+const QLatin1String libPrefix("");
|
|
|
|
+#else
|
|
|
|
+const QLatin1String libExtension(".so");
|
|
|
|
+const QLatin1String libPrefix("lib");
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+#define STRINGIFY2(s) #s
|
|
|
|
+#define STRINGIFY(s) STRINGIFY2(s)
|
|
|
|
+static const char *QtProtobufPluginPath = STRINGIFY(QT_PROTOBUF_PLUGIN_PATH)"/";
|
|
|
|
|
|
namespace QtProtobuf {
|
|
namespace QtProtobuf {
|
|
-class QProtobufSerializerRegistryPrivate {
|
|
|
|
|
|
+
|
|
|
|
+class QProtobufSerializerRegistryPrivateRecord final
|
|
|
|
+{
|
|
|
|
+public:
|
|
|
|
+ QProtobufSerializerRegistryPrivateRecord() : loader(nullptr) {}
|
|
|
|
+
|
|
|
|
+ void createDefaultImpl()
|
|
|
|
+ {
|
|
|
|
+ if (serializers.find(ProtobufSerializer) == serializers.end()) {
|
|
|
|
+ serializers[ProtobufSerializer] = std::shared_ptr<QAbstractProtobufSerializer>(new QProtobufSerializer);
|
|
|
|
+ }
|
|
|
|
+ if (serializers.find(JsonSerializer) == serializers.end()) {
|
|
|
|
+ serializers[JsonSerializer] = std::shared_ptr<QAbstractProtobufSerializer>(new QProtobufJsonSerializer);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ void loadPluginMetadata(const QString &path, const QString &pluginName)
|
|
|
|
+ {
|
|
|
|
+ // Load default plugin
|
|
|
|
+ if (path.isEmpty() || pluginName.isEmpty()){
|
|
|
|
+ libPath = QtProtobufPluginPath + libPrefix + Serializationplugin + libExtension;
|
|
|
|
+ }
|
|
|
|
+ // Use custom plugin
|
|
|
|
+ else {
|
|
|
|
+ libPath = path + libPrefix + pluginName + libExtension;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ loader = new QPluginLoader(libPath);
|
|
|
|
+ pluginData = loader->metaData();
|
|
|
|
+
|
|
|
|
+ QVariantMap fullJson = pluginData.toVariantMap();
|
|
|
|
+ if (!fullJson.isEmpty()) {
|
|
|
|
+ metaData = fullJson.value(MetaData).toMap();
|
|
|
|
+ pluginLoadedName = metaData.value(PluginName).toString();
|
|
|
|
+ typeArray = metaData.value(TypeNames).toList();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ void loadPlugin()
|
|
|
|
+ {
|
|
|
|
+ QProtobufSerializationPluginInterface *loadedPlugin = qobject_cast<QProtobufSerializationPluginInterface*>(loadPluginImpl());
|
|
|
|
+ if (!pluginData.isEmpty() && loadedPlugin) {
|
|
|
|
+ for (int i = 0; i < typeArray.count(); i++) {
|
|
|
|
+ QString typeName = typeArray.at(i).toString();
|
|
|
|
+ serializers[typeName] = std::shared_ptr<QAbstractProtobufSerializer>(loadedPlugin->serializer(typeName));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ QObject* loadPluginImpl()
|
|
|
|
+ {
|
|
|
|
+ if (loader == nullptr || !loader->load())
|
|
|
|
+ {
|
|
|
|
+ qProtoWarning() << "Can't load plugin from" << libPath << loader->errorString();
|
|
|
|
+ return nullptr;
|
|
|
|
+ }
|
|
|
|
+ return loader->instance();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ std::unordered_map<QString, std::shared_ptr<QAbstractProtobufSerializer>> serializers;
|
|
|
|
+ QJsonObject pluginData;
|
|
|
|
+ QVariantMap metaData;
|
|
|
|
+ QString pluginLoadedName;
|
|
|
|
+ QPluginLoader *loader;
|
|
|
|
+ QString libPath;
|
|
|
|
+ QVariantList typeArray;
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+class QProtobufSerializerRegistryPrivate
|
|
|
|
+{
|
|
|
|
+
|
|
public:
|
|
public:
|
|
- QProtobufSerializerRegistryPrivate() {
|
|
|
|
- serializers["protobuf"] = std::shared_ptr<QAbstractProtobufSerializer>(new QProtobufSerializer);
|
|
|
|
- serializers["json"] = std::shared_ptr<QAbstractProtobufSerializer>(new QProtobufJsonSerializer);
|
|
|
|
|
|
+ QProtobufSerializerRegistryPrivate()
|
|
|
|
+ {
|
|
|
|
+ // create default impl
|
|
|
|
+ std::shared_ptr<QProtobufSerializerRegistryPrivateRecord> plugin = std::shared_ptr<QProtobufSerializerRegistryPrivateRecord>(new QProtobufSerializerRegistryPrivateRecord());
|
|
|
|
+ plugin->createDefaultImpl();
|
|
|
|
+ m_plugins[DefaultImpl] = plugin;
|
|
}
|
|
}
|
|
- std::unordered_map<QString/*id*/, std::shared_ptr<QAbstractProtobufSerializer>> serializers;
|
|
|
|
|
|
+
|
|
|
|
+ static const QString &loadPlugin(const QString &path, const QString &name)
|
|
|
|
+ {
|
|
|
|
+ std::shared_ptr<QProtobufSerializerRegistryPrivateRecord> plugin = std::shared_ptr<QProtobufSerializerRegistryPrivateRecord>(new QProtobufSerializerRegistryPrivateRecord());
|
|
|
|
+ plugin->loadPluginMetadata(path, name);
|
|
|
|
+
|
|
|
|
+ const QString &pluginName = plugin->pluginLoadedName;
|
|
|
|
+ if (m_plugins.find(pluginName) == m_plugins.end()) {
|
|
|
|
+ plugin->loadPlugin();
|
|
|
|
+ m_plugins[pluginName] = plugin;
|
|
|
|
+ }
|
|
|
|
+ return pluginName;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ static std::unordered_map<QString/*pluginName*/, std::shared_ptr<QProtobufSerializerRegistryPrivateRecord>> m_plugins;
|
|
};
|
|
};
|
|
|
|
+
|
|
|
|
+std::unordered_map<QString/*pluginName*/, std::shared_ptr<QProtobufSerializerRegistryPrivateRecord>> QProtobufSerializerRegistryPrivate::m_plugins;
|
|
|
|
+
|
|
}
|
|
}
|
|
|
|
|
|
using namespace QtProtobuf;
|
|
using namespace QtProtobuf;
|
|
|
|
|
|
-QProtobufSerializerRegistry::QProtobufSerializerRegistry() : d(new QProtobufSerializerRegistryPrivate)
|
|
|
|
|
|
+QProtobufSerializerRegistry::QProtobufSerializerRegistry() :
|
|
|
|
+ dPtr(new QProtobufSerializerRegistryPrivate())
|
|
{
|
|
{
|
|
-
|
|
|
|
}
|
|
}
|
|
|
|
|
|
QProtobufSerializerRegistry::~QProtobufSerializerRegistry() = default;
|
|
QProtobufSerializerRegistry::~QProtobufSerializerRegistry() = default;
|
|
|
|
|
|
|
|
+const QString &QProtobufSerializerRegistry::loadPlugin(const QString &path, const QString &name)
|
|
|
|
+{
|
|
|
|
+ return dPtr->loadPlugin(path, name);
|
|
|
|
+}
|
|
|
|
|
|
-std::shared_ptr<QAbstractProtobufSerializer> QProtobufSerializerRegistry::getSerializer(const QString &id)
|
|
|
|
|
|
+std::shared_ptr<QAbstractProtobufSerializer> QProtobufSerializerRegistry::getSerializer(const QString &id, const QString &plugin)
|
|
{
|
|
{
|
|
- return d->serializers.at(id); //throws
|
|
|
|
|
|
+ return dPtr->m_plugins[plugin]->serializers.at(id); //throws
|
|
}
|
|
}
|
|
|
|
|
|
-std::unique_ptr<QAbstractProtobufSerializer> QProtobufSerializerRegistry::acquireSerializer(const QString &/*id*/)
|
|
|
|
|
|
+std::unique_ptr<QAbstractProtobufSerializer> QProtobufSerializerRegistry::acquireSerializer(const QString &/*id*/, const QString &/*plugin*/)
|
|
{
|
|
{
|
|
Q_ASSERT_X(false, "QProtobufSerializerRegistry", "acquireSerializer is unimplemented");
|
|
Q_ASSERT_X(false, "QProtobufSerializerRegistry", "acquireSerializer is unimplemented");
|
|
return std::unique_ptr<QAbstractProtobufSerializer>();
|
|
return std::unique_ptr<QAbstractProtobufSerializer>();
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+float QProtobufSerializerRegistry::pluginVersion(const QString &plugin)
|
|
|
|
+{
|
|
|
|
+ if (dPtr->m_plugins.find(plugin) == dPtr->m_plugins.end())
|
|
|
|
+ return 0.0;
|
|
|
|
+
|
|
|
|
+ std::shared_ptr<QProtobufSerializerRegistryPrivateRecord> implementation = dPtr->m_plugins[plugin];
|
|
|
|
+ if (implementation->metaData.isEmpty())
|
|
|
|
+ return 0.0;
|
|
|
|
+
|
|
|
|
+ return implementation->metaData.value(Version).toFloat();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+QStringList QProtobufSerializerRegistry::pluginSerializers(const QString &plugin)
|
|
|
|
+{
|
|
|
|
+ QStringList strList;
|
|
|
|
+
|
|
|
|
+ if (dPtr->m_plugins.find(plugin) == dPtr->m_plugins.end())
|
|
|
|
+ return strList;
|
|
|
|
+
|
|
|
|
+ std::shared_ptr<QProtobufSerializerRegistryPrivateRecord> implementation = dPtr->m_plugins[plugin];
|
|
|
|
+
|
|
|
|
+ QVariantList typeArray = implementation->metaData.value(TypeNames).toList();
|
|
|
|
+ foreach(QVariant value, typeArray) {
|
|
|
|
+ if (!value.toString().isEmpty()) {
|
|
|
|
+ strList.append(value.toString());
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return strList;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+float QProtobufSerializerRegistry::pluginProtobufVersion(const QString &plugin)
|
|
|
|
+{
|
|
|
|
+ if (dPtr->m_plugins.find(plugin) == dPtr->m_plugins.end())
|
|
|
|
+ return 0.0;
|
|
|
|
+
|
|
|
|
+ std::shared_ptr<QProtobufSerializerRegistryPrivateRecord> implementation = dPtr->m_plugins[plugin];
|
|
|
|
+ if (implementation.get() && implementation->metaData.isEmpty())
|
|
|
|
+ return 0.0;
|
|
|
|
+
|
|
|
|
+ return implementation->metaData.value(ProtoVersion).toFloat();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+int QProtobufSerializerRegistry::pluginRating(const QString &plugin)
|
|
|
|
+{
|
|
|
|
+ if (dPtr->m_plugins.find(plugin) == dPtr->m_plugins.end())
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+ std::shared_ptr<QProtobufSerializerRegistryPrivateRecord> implementation = dPtr->m_plugins[plugin];
|
|
|
|
+ if (implementation->metaData.isEmpty())
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+ return implementation->metaData.value(Rating).toInt();
|
|
|
|
+}
|