From 7ae8c8719497ec7556f532bab061d3758976f792 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Fri, 24 Jul 2015 17:26:25 +0200 Subject: Mode FacadeFactory to separate file, mutex protected it, and loaded resource The factory is potentially used from several queries simultaneously, so it's now mutex protected. Additionally we try to load the plugins directly in the factory. --- common/CMakeLists.txt | 1 + common/clientapi.cpp | 6 +--- common/clientapi.h | 94 +----------------------------------------------- common/facadefactory.cpp | 79 ++++++++++++++++++++++++++++++++++++++++ common/facadefactory.h | 91 ++++++++++++++++++++++++++++++++++++++++++++++ common/facadeinterface.h | 51 ++++++++++++++++++++++++++ 6 files changed, 224 insertions(+), 98 deletions(-) create mode 100644 common/facadefactory.cpp create mode 100644 common/facadefactory.h create mode 100644 common/facadeinterface.h (limited to 'common') diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 56ae59b..a69c62c 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -14,6 +14,7 @@ set(command_SRCS log.cpp entitybuffer.cpp clientapi.cpp + facadefactory.cpp commands.cpp facade.cpp pipeline.cpp diff --git a/common/clientapi.cpp b/common/clientapi.cpp index c19ea4f..a98340c 100644 --- a/common/clientapi.cpp +++ b/common/clientapi.cpp @@ -28,13 +28,9 @@ namespace async }; } // namespace async -namespace Akonadi2 -{ -void FacadeFactory::registerStaticFacades() +namespace Akonadi2 { - registerFacade("resourceconfig"); -} void Store::shutdown(const QByteArray &identifier) { diff --git a/common/clientapi.h b/common/clientapi.h index 4644ae1..d860305 100644 --- a/common/clientapi.h +++ b/common/clientapi.h @@ -35,6 +35,7 @@ #include "resultprovider.h" #include "domain/applicationdomaintype.h" #include "resourceconfig.h" +#include "facadefactory.h" #include "log.h" namespace async { @@ -82,98 +83,6 @@ public: }; -/** - * Interface for the store facade. - * - * All methods are synchronous. - * Facades are stateful (they hold connections to resources and database). - * - * TODO: would it make sense to split the write, read and notification parts? (we could potentially save some connections) - */ -template -class StoreFacade { -public: - virtual ~StoreFacade(){}; - QByteArray type() const { return ApplicationDomain::getTypeName(); } - virtual KAsync::Job create(const DomainType &domainObject) = 0; - virtual KAsync::Job modify(const DomainType &domainObject) = 0; - virtual KAsync::Job remove(const DomainType &domainObject) = 0; - virtual KAsync::Job load(const Query &query, const QSharedPointer > &resultProvider) = 0; -}; - - -/** - * Facade factory that returns a store facade implementation, by loading a plugin and providing the relevant implementation. - * - * If we were to provide default implementations for certain capabilities. Here would be the place to do so. - */ - -class FacadeFactory { -public: - typedef std::function(const QByteArray &)> FactoryFunction; - - void registerStaticFacades(); - - //FIXME: proper singleton implementation - static FacadeFactory &instance() - { - static FacadeFactory factory; - return factory; - } - - static QByteArray key(const QByteArray &resource, const QByteArray &type) - { - return resource + type; - } - - template - void registerFacade(const QByteArray &resource) - { - const QByteArray typeName = ApplicationDomain::getTypeName(); - mFacadeRegistry.insert(key(resource, typeName), [](const QByteArray &instanceIdentifier){ return std::make_shared(instanceIdentifier); }); - } - - /* - * Allows the registrar to register a specific instance. - * - * Primarily for testing. - */ - template - void registerFacade(const QByteArray &resource, const FactoryFunction &customFactoryFunction) - { - const QByteArray typeName = ApplicationDomain::getTypeName(); - mFacadeRegistry.insert(key(resource, typeName), customFactoryFunction); - } - - /* - * Can be used to clear the factory. - * - * Primarily for testing. - */ - void resetFactory() - { - mFacadeRegistry.clear(); - } - - template - std::shared_ptr > getFacade(const QByteArray &resource, const QByteArray &instanceIdentifier) - { - const QByteArray typeName = ApplicationDomain::getTypeName(); - if (auto factoryFunction = mFacadeRegistry.value(key(resource, typeName))) { - return std::static_pointer_cast >(factoryFunction(instanceIdentifier)); - } - qWarning() << "Failed to find facade for resource: " << resource << " and type: " << typeName; - return std::shared_ptr >(); - } - -private: - FacadeFactory() - { - registerStaticFacades(); - } - - QHash mFacadeRegistry; -}; /** * Store interface used in the client API. @@ -231,7 +140,6 @@ public: // Query all resources and aggregate results KAsync::iterate(getResources(query.resources)) .template each([query, resultSet](const QByteArray &resource, KAsync::Future &future) { - //TODO pass resource identifier to factory auto facade = FacadeFactory::instance().getFacade(resourceName(resource), resource); if (facade) { facade->load(query, resultSet).template then([&future](){future.setFinished();}).exec(); diff --git a/common/facadefactory.cpp b/common/facadefactory.cpp new file mode 100644 index 0000000..f833b06 --- /dev/null +++ b/common/facadefactory.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2014 Christian Mollekopf + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ +#include "facadefactory.h" + +#include "resourcefacade.h" +#include "resource.h" + +using namespace Akonadi2; + +QMutex FacadeFactory::sMutex; + +FacadeFactory::FacadeFactory() +{ + registerStaticFacades(); +} + +FacadeFactory &FacadeFactory::instance() +{ + QMutexLocker locker(&sMutex); + static FacadeFactory *instance = 0; + if (!instance) { + instance = new FacadeFactory; + } + return *instance; +} + +QByteArray FacadeFactory::key(const QByteArray &resource, const QByteArray &type) +{ + return resource + type; +} + +void FacadeFactory::resetFactory() +{ + QMutexLocker locker(&sMutex); + mFacadeRegistry.clear(); +} + +void FacadeFactory::registerStaticFacades() +{ + registerFacade("resourceconfig"); +} + +std::shared_ptr FacadeFactory::getFacade(const QByteArray &resource, const QByteArray &instanceIdentifier, const QByteArray &typeName) +{ + QMutexLocker locker(&sMutex); + + const QByteArray k = key(resource, typeName); + if (!mFacadeRegistry.contains(k)) { + Akonadi2::ResourceFactory::load(QString::fromLatin1(resource)); + } + + if (auto factoryFunction = mFacadeRegistry.value(k)) { + return factoryFunction(instanceIdentifier); + } + qWarning() << "Failed to find facade for resource: " << resource << " and type: " << typeName; + return std::shared_ptr(); +} + +void FacadeFactory::registerFacade(const QByteArray &resource, const FactoryFunction &customFactoryFunction, const QByteArray typeName) +{ + mFacadeRegistry.insert(key(resource, typeName), customFactoryFunction); +} diff --git a/common/facadefactory.h b/common/facadefactory.h new file mode 100644 index 0000000..4a6a698 --- /dev/null +++ b/common/facadefactory.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2014 Christian Mollekopf + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#pragma once + +#include +#include +#include +#include +#include + +#include "facadeinterface.h" +#include "domain/applicationdomaintype.h" +#include "log.h" + +namespace Akonadi2 { + +/** + * Facade factory that returns a store facade implementation, by loading a plugin and providing the relevant implementation. + * + * If we were to provide default implementations for certain capabilities. Here would be the place to do so. + */ +class FacadeFactory { +public: + typedef std::function(const QByteArray &)> FactoryFunction; + + void registerStaticFacades(); + + static FacadeFactory &instance(); + + static QByteArray key(const QByteArray &resource, const QByteArray &type); + + template + void registerFacade(const QByteArray &resource) + { + registerFacade(resource, [](const QByteArray &instanceIdentifier){ return std::make_shared(instanceIdentifier); }, ApplicationDomain::getTypeName()); + } + + /* + * Allows the registrar to register a specific instance. + * + * Primarily for testing. + */ + template + void registerFacade(const QByteArray &resource, const FactoryFunction &customFactoryFunction) + { + registerFacade(resource, customFactoryFunction, ApplicationDomain::getTypeName()); + } + + /* + * Can be used to clear the factory. + * + * Primarily for testing. + */ + void resetFactory(); + + template + std::shared_ptr > getFacade(const QByteArray &resource, const QByteArray &instanceIdentifier) + { + const QByteArray typeName = ApplicationDomain::getTypeName(); + return std::static_pointer_cast >(getFacade(resource, instanceIdentifier, typeName)); + } + +private: + FacadeFactory(); + std::shared_ptr getFacade(const QByteArray &resource, const QByteArray &instanceIdentifier, const QByteArray &typeName); + void registerFacade(const QByteArray &resource, const FactoryFunction &customFactoryFunction, const QByteArray typeName); + + QHash mFacadeRegistry; + static QMutex sMutex; +}; + +} + diff --git a/common/facadeinterface.h b/common/facadeinterface.h new file mode 100644 index 0000000..a88c104 --- /dev/null +++ b/common/facadeinterface.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2014 Christian Mollekopf + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#pragma once + +#include +#include +#include +#include "domain/applicationdomaintype.h" +#include "resultprovider.h" + +namespace Akonadi2 { +class Query; + +/** + * Interface for the store facade. + * + * All methods are synchronous. + * Facades are stateful (they hold connections to resources and database). + * + * TODO: would it make sense to split the write, read and notification parts? (we could potentially save some connections) + */ +template +class StoreFacade { +public: + virtual ~StoreFacade(){}; + QByteArray type() const { return ApplicationDomain::getTypeName(); } + virtual KAsync::Job create(const DomainType &domainObject) = 0; + virtual KAsync::Job modify(const DomainType &domainObject) = 0; + virtual KAsync::Job remove(const DomainType &domainObject) = 0; + virtual KAsync::Job load(const Query &query, const QSharedPointer > &resultProvider) = 0; +}; + +} -- cgit v1.2.3