Apply on-demand loading of provider objects 11/67311/4
authorMu-Woong Lee <muwoong.lee@samsung.com>
Tue, 26 Apr 2016 08:10:28 +0000 (17:10 +0900)
committerMu-Woong Lee <muwoong.lee@samsung.com>
Wed, 27 Apr 2016 02:47:12 +0000 (11:47 +0900)
This patch only allows on-demand loading & creation of providers.
'destroy-on-idle' logic also needs to be implemented.

Plus, implicit dummy subscribers for the data loggers need to be implemented.

Change-Id: Id97871568d97d832b281c2c531af8495ce29f373
Signed-off-by: Mu-Woong Lee <muwoong.lee@samsung.com>
src/ContextManager.cpp
src/ContextManager.h
src/ProviderHandler.cpp
src/ProviderHandler.h
src/ProviderLoader.cpp
src/ProviderLoader.h
src/trigger/TemplateManager.cpp

index 75478a8..0e918a9 100644 (file)
 
 #include <Types.h>
 #include <DBusTypes.h>
-#include <context_trigger_types_internal.h>
 #include <Json.h>
 #include <ContextProvider.h>
-#include "Server.h"
+
 #include "access_control/Privilege.h"
+#include "trigger/TemplateManager.h"
+#include "Server.h"
 #include "Request.h"
 #include "ProviderHandler.h"
+#include "ProviderLoader.h"
 #include "ContextManager.h"
-#include "trigger/TemplateManager.h"
 
 using namespace ctx;
 
-struct TriggerItemFormat {
-       std::string subject;
-       int operation;
-       Json attributes;
-       Json options;
-       std::string owner;
-       bool unregister;
-       TriggerItemFormat(std::string subj, int ops, Json attr, Json opt, std::string own) :
-               subject(subj),
-               operation(ops),
-               attributes(attr),
-               options(opt),
-               owner(own)
-       {
-               unregister = false;
-       }
-
-       TriggerItemFormat(std::string subj) :
-               subject(subj)
-       {
-               unregister = true;
-       }
-};
-
-static std::list<TriggerItemFormat> __triggerItemList;
-
-ContextManager::ContextManager() :
-       __initialized(false)
+ContextManager::ContextManager()
 {
        ContextProvider::__setContextManager(this);
-       __providerLoader.init();
+       ProviderLoader::init();
 }
 
 ContextManager::~ContextManager()
@@ -71,111 +45,24 @@ ContextManager::~ContextManager()
 
 bool ContextManager::init()
 {
-       __initialized = __providerLoader.loadAll();
        return true;
 }
 
 void ContextManager::release()
 {
-       for (auto& it : __providerHandleMap) {
-               delete it.second;
-       }
-       __providerHandleMap.clear();
-}
-
-bool ContextManager::registerProvider(const char *subject, const char *privilege, ContextProvider *provider)
-{
-       if (__providerHandleMap.find(subject) != __providerHandleMap.end()) {
-               _E("The provider for the subject '%s' is already registered.", subject);
-               return false;
-       }
-
-       _SI("Subj: %s, Priv: %s", subject, privilege);
-
-       ProviderHandler *handle = new(std::nothrow) ProviderHandler(subject, privilege, provider);
-       IF_FAIL_RETURN_TAG(handle, false, _E, "Memory allocation failed");
-
-       __providerHandleMap[subject] = handle;
-       return true;
-}
-
-bool ContextManager::unregisterProvider(const char *subject)
-{
-       auto it = __providerHandleMap.find(subject);
-       if (it == __providerHandleMap.end()) {
-               _E("The provider for the subject '%s' is not found.", subject);
-               return false;
-       }
-
-       delete it->second;
-       __providerHandleMap.erase(it);
-
-       return true;
-}
-
-bool ContextManager::registerTriggerItem(const char *subject, int operation, Json attributes, Json options, const char* owner)
-{
-       IF_FAIL_RETURN_TAG(subject, false, _E, "Invalid parameter");
-
-       if (!__initialized) {
-               __triggerItemList.push_back(TriggerItemFormat(subject, operation, attributes, options, (owner)? owner : ""));
-       } else {
-               trigger::TemplateManager* tmplMgr = trigger::TemplateManager::getInstance();
-               IF_FAIL_RETURN_TAG(tmplMgr, false, _E, "Memory allocation failed");
-               tmplMgr->registerTemplate(subject, operation, attributes, options, owner);
-       }
-
-       return true;
-}
-
-bool ContextManager::unregisterTriggerItem(const char *subject)
-{
-       IF_FAIL_RETURN_TAG(subject, false, _E, "Invalid parameter");
-
-       if (!__initialized) {
-               __triggerItemList.push_back(TriggerItemFormat(subject));
-       } else {
-               trigger::TemplateManager* tmplMgr = trigger::TemplateManager::getInstance();
-               IF_FAIL_RETURN_TAG(tmplMgr, false, _E, "Memory allocation failed");
-               tmplMgr->unregisterTemplate(subject);
-       }
-
-       return true;
-}
-
-bool ContextManager::popTriggerItem(std::string &subject, int &operation, Json &attributes, Json &options, std::string& owner, bool& unregister)
-{
-       IF_FAIL_RETURN(!__triggerItemList.empty(), false);
-
-       TriggerItemFormat format = __triggerItemList.front();
-       __triggerItemList.pop_front();
-
-       subject = format.subject;
-       operation = format.operation;
-       attributes = format.attributes;
-       options = format.options;
-       owner = format.owner;
-       unregister = format.unregister;
-
-       return true;
+       ProviderHandler::purge();
 }
 
 void ContextManager::assignRequest(RequestInfo* request)
 {
-       if (__handleCustomRequest(request)) {
-               delete request;
-               return;
-       }
-
-       auto it = __providerHandleMap.find(request->getSubject());
-       if (it == __providerHandleMap.end()) {
-               _W("Unsupported subject");
+       ProviderHandler *handle = ProviderHandler::getInstance(request->getSubject(), true);
+       if (!handle || !handle->isSupported()) {
                request->reply(ERR_NOT_SUPPORTED);
                delete request;
                return;
        }
 
-       if (!it->second->isAllowed(request->getCredentials())) {
+       if (!handle->isAllowed(request->getCredentials())) {
                _W("Permission denied");
                request->reply(ERR_PERMISSION_DENIED);
                delete request;
@@ -184,17 +71,17 @@ void ContextManager::assignRequest(RequestInfo* request)
 
        switch (request->getType()) {
        case REQ_SUBSCRIBE:
-               it->second->subscribe(request);
+               handle->subscribe(request);
                break;
        case REQ_UNSUBSCRIBE:
-               it->second->unsubscribe(request);
+               handle->unsubscribe(request);
                break;
        case REQ_READ:
        case REQ_READ_SYNC:
-               it->second->read(request);
+               handle->read(request);
                break;
        case REQ_WRITE:
-               it->second->write(request);
+               handle->write(request);
                break;
        case REQ_SUPPORT:
                request->reply(ERR_NONE);
@@ -208,16 +95,24 @@ void ContextManager::assignRequest(RequestInfo* request)
 
 bool ContextManager::isSupported(const char *subject)
 {
-       auto it = __providerHandleMap.find(subject);
-       return (it != __providerHandleMap.end());
+       ProviderHandler *handle = ProviderHandler::getInstance(subject, true);
+
+       if (!handle)
+               return false;
+
+       return handle->isSupported();
 }
 
 bool ContextManager::isAllowed(const Credentials *creds, const char *subject)
 {
        IF_FAIL_RETURN(creds, true);    /* In case internal requests */
-       auto it = __providerHandleMap.find(subject);
-       IF_FAIL_RETURN(it != __providerHandleMap.end(), false);
-       return it->second->isAllowed(creds);
+
+       ProviderHandler *handle = ProviderHandler::getInstance(subject, true);
+
+       if (!handle)
+               return false;
+
+       return handle->isAllowed(creds);
 }
 
 void ContextManager::__publish(const char* subject, Json &option, int error, Json &dataUpdated)
@@ -225,10 +120,10 @@ void ContextManager::__publish(const char* subject, Json &option, int error, Jso
        _I("Publishing '%s'", subject);
        _J("Option", option);
 
-       auto it = __providerHandleMap.find(subject);
-       IF_FAIL_VOID(it != __providerHandleMap.end());
+       ProviderHandler *handle = ProviderHandler::getInstance(subject, false);
+       IF_FAIL_VOID_TAG(handle, _W, "No corresponding provider");
 
-       it->second->publish(option, error, dataUpdated);
+       handle->publish(option, error, dataUpdated);
 }
 
 void ContextManager::__replyToRead(const char* subject, Json &option, int error, Json &dataRead)
@@ -237,10 +132,10 @@ void ContextManager::__replyToRead(const char* subject, Json &option, int error,
        _J("Option", option);
        _J("Data", dataRead);
 
-       auto it = __providerHandleMap.find(subject);
-       IF_FAIL_VOID(it != __providerHandleMap.end());
+       ProviderHandler *handle = ProviderHandler::getInstance(subject, false);
+       IF_FAIL_VOID_TAG(handle, _W, "No corresponding provider");
 
-       it->second->replyToRead(option, error, dataRead);
+       handle->replyToRead(option, error, dataRead);
 }
 
 struct PublishedData {
@@ -301,6 +196,12 @@ bool ContextManager::replyToRead(const char* subject, Json& option, int error, J
        return true;
 }
 
+bool ContextManager::popTriggerTemplate(std::string &subject, int &operation, Json &attribute, Json &option)
+{
+       return ProviderLoader::popTriggerTemplate(subject, operation, attribute, option);
+}
+
+/*
 bool ContextManager::__handleCustomRequest(RequestInfo* request)
 {
        std::string subject = request->getSubject();
@@ -308,7 +209,6 @@ bool ContextManager::__handleCustomRequest(RequestInfo* request)
                                        subject == CONTEXT_TRIGGER_SUBJECT_CUSTOM_REMOVE ||
                                        subject == CONTEXT_TRIGGER_SUBJECT_CUSTOM_PUBLISH, false);
 
-#if 0
        const char* pkg_id = request->getPackageId();
        if (pkg_id == NULL) {
                request->reply(ERR_OPERATION_FAILED);
@@ -341,6 +241,6 @@ bool ContextManager::__handleCustomRequest(RequestInfo* request)
        }
 
        request->reply(error);
-#endif
        return true;
 }
+*/
index 884dd71..a6ebf57 100644 (file)
 
 #include <map>
 #include <IContextManager.h>
-#include "ProviderLoader.h"
 
 namespace ctx {
 
        /* Forward declaration */
        class Credentials;
        class RequestInfo;
-       class ProviderHandler;
 
        class ContextManager : public IContextManager {
        public:
@@ -38,16 +36,13 @@ namespace ctx {
                void assignRequest(ctx::RequestInfo *request);
                bool isSupported(const char *subject);
                bool isAllowed(const Credentials *creds, const char *subject);
-               bool popTriggerItem(std::string &subject, int &operation, ctx::Json &attributes, ctx::Json &options, std::string &owner, bool& unregister);
 
                /* From the interface class */
-               bool registerProvider(const char *subject, const char *privilege, ContextProvider *provider);
-               bool unregisterProvider(const char *subject);
-               bool registerTriggerItem(const char *subject, int operation, ctx::Json attributes, ctx::Json options, const char *owner = NULL);
-               bool unregisterTriggerItem(const char *subject);
                bool publish(const char *subject, ctx::Json &option, int error, ctx::Json &dataUpdated);
                bool replyToRead(const char *subject, ctx::Json &option, int error, ctx::Json &dataRead);
 
+               bool popTriggerTemplate(std::string &subject, int &operation, Json &attribute, Json &option);
+
        private:
                ContextManager();
 
@@ -56,13 +51,6 @@ namespace ctx {
                void __publish(const char *subject, ctx::Json &option, int error, ctx::Json &dataUpdated);
                void __replyToRead(const char *subject, ctx::Json &option, int error, ctx::Json &dataRead);
 
-               /* For custom request */
-               bool __handleCustomRequest(ctx::RequestInfo* request);
-
-               bool __initialized;
-               std::map<std::string, ProviderHandler*> __providerHandleMap;
-               ProviderLoader __providerLoader;
-
                friend class Server;
 
        };      /* class ContextManager */
index 8742495..a9521a2 100644 (file)
 
 using namespace ctx;
 
-ProviderHandler::ProviderHandler(const char *subject, const char *privilege, ContextProvider *provider) :
-       __subject(subject),
-       __privilege(privilege),
-       __provider(provider)
+std::map<std::string, ProviderHandler*> ProviderHandler::__instanceMap;
+
+ProviderHandler::ProviderHandler(const char *subject) :
+       __subject(subject)
 {
 }
 
@@ -44,27 +44,65 @@ ProviderHandler::~ProviderHandler()
        delete __provider;
 }
 
-bool ProviderHandler::isAllowed(const Credentials *creds)
+/* TODO: Return proper error code */
+ProviderHandler* ProviderHandler::getInstance(const char *subject, bool force)
 {
-       IF_FAIL_RETURN(creds, true);    /* In case of internal requests */
-       return privilege_manager::isAllowed(creds, __privilege);
+       InstanceMap::iterator it = __instanceMap.find(subject);
+
+       if (it != __instanceMap.end())
+               return it->second;
+
+       if (!force)
+               return NULL;
+
+       ProviderHandler *handle = new(std::nothrow) ProviderHandler(subject);
+       IF_FAIL_RETURN_TAG(handle, NULL, _E, "Memory allocation failed");
+
+       if (!handle->__loadProvider()) {
+               delete handle;
+               return NULL;
+       }
+
+       __instanceMap[subject] = handle;
+
+       return handle;
+}
+
+void ProviderHandler::purge()
+{
+       for (InstanceMap::iterator it = __instanceMap.begin(); it != __instanceMap.end(); ++it) {
+               delete it->second;
+       }
+
+       __instanceMap.clear();
 }
 
-ContextProvider* ProviderHandler::__getProvider(RequestInfo *request)
+bool ProviderHandler::isSupported()
 {
-       /* TODO: When implementing dynamic so loading... */
-       return __provider;
+       return __provider->isSupported();
+}
+
+bool ProviderHandler::isAllowed(const Credentials *creds)
+{
+       IF_FAIL_RETURN(creds, true);    /* In case of internal requests */
+
+       std::vector<const char*> priv;
+       __provider->getPrivilege(priv);
+
+       for (unsigned int i = 0; i < priv.size(); ++i) {
+               if (!privilege_manager::isAllowed(creds, priv[i]))
+                       return false;
+       }
+
+       return true;
 }
 
 void ProviderHandler::subscribe(RequestInfo *request)
 {
        _I(CYAN("'%s' subscribes '%s' (RID-%d)"), request->getClient(), __subject, request->getId());
 
-       ContextProvider *provider = __getProvider(request);
-       IF_FAIL_VOID(provider);
-
        Json requestResult;
-       int error = provider->subscribe(request->getDescription().str(), &requestResult);
+       int error = __provider->subscribe(request->getDescription().str(), &requestResult);
 
        if (!request->reply(error, requestResult) || error != ERR_NONE) {
                delete request;
@@ -102,12 +140,8 @@ void ProviderHandler::unsubscribe(RequestInfo *request)
                return;
        }
 
-       /* Get the provider */
-       ContextProvider *provider = __getProvider(request);
-       IF_FAIL_VOID(provider);
-
        /* Stop detecting the subject */
-       int error = provider->unsubscribe(reqFound->getDescription());
+       int error = __provider->unsubscribe(reqFound->getDescription());
        request->reply(error);
        delete request;
        delete reqFound;
@@ -117,11 +151,8 @@ void ProviderHandler::read(RequestInfo *request)
 {
        _I(CYAN("'%s' reads '%s' (RID-%d)"), request->getClient(), __subject, request->getId());
 
-       ContextProvider *provider = __getProvider(request);
-       IF_FAIL_VOID(provider);
-
        Json requestResult;
-       int error = provider->read(request->getDescription().str(), &requestResult);
+       int error = __provider->read(request->getDescription().str(), &requestResult);
 
        if (!request->reply(error, requestResult) || error != ERR_NONE) {
                delete request;
@@ -135,11 +166,8 @@ void ProviderHandler::write(RequestInfo *request)
 {
        _I(CYAN("'%s' writes '%s' (RID-%d)"), request->getClient(), __subject, request->getId());
 
-       ContextProvider *provider = __getProvider(request);
-       IF_FAIL_VOID(provider);
-
        Json requestResult;
-       int error = provider->write(request->getDescription(), &requestResult);
+       int error = __provider->write(request->getDescription(), &requestResult);
 
        request->reply(error, requestResult);
        delete request;
@@ -180,6 +208,12 @@ bool ProviderHandler::replyToRead(Json &option, int error, Json &dataRead)
        return true;
 }
 
+bool ProviderHandler::__loadProvider()
+{
+       __provider = __loader.load(__subject);
+       return (__provider != NULL);
+}
+
 ProviderHandler::RequestList::iterator
 ProviderHandler::__findRequest(RequestList &reqList, Json &option)
 {
index d8cea26..634819e 100644 (file)
@@ -19,7 +19,9 @@
 
 #include <string>
 #include <list>
+#include <map>
 #include <ContextProvider.h>
+#include "ProviderLoader.h"
 
 namespace ctx {
 
@@ -27,12 +29,11 @@ namespace ctx {
        class RequestInfo;
 
        class ProviderHandler {
-       public:
                typedef std::list<RequestInfo*> RequestList;
+               typedef std::map<std::string, ProviderHandler*> InstanceMap;
 
-               ProviderHandler(const char *subject, const char *privilege, ContextProvider *provider);
-               ~ProviderHandler();
-
+       public:
+               bool isSupported();
                bool isAllowed(const Credentials *creds);
 
                void subscribe(RequestInfo *request);
@@ -43,14 +44,22 @@ namespace ctx {
                bool publish(ctx::Json &option, int error, ctx::Json &dataUpdated);
                bool replyToRead(ctx::Json &option, int error, ctx::Json &dataRead);
 
+               static ProviderHandler* getInstance(const char *subject, bool force);
+               static void purge();
+
        private:
                const char *__subject;
-               const char *__privilege;
                ContextProvider *__provider;
                RequestList __subscribeRequests;
                RequestList __readRequests;
+               ProviderLoader __loader;
+
+               static InstanceMap __instanceMap;
+
+               ProviderHandler(const char *subject);
+               ~ProviderHandler();
 
-               ContextProvider* __getProvider(RequestInfo *request);
+               bool __loadProvider();
                RequestList::iterator __findRequest(RequestList &reqList, Json &option);
                RequestList::iterator __findRequest(RequestList &reqList, std::string client, int reqId);
                RequestList::iterator __findRequest(RequestList::iterator begin, RequestList::iterator end, Json &option);
index c48a992..e99ba10 100644 (file)
 
 using namespace ctx;
 
-typedef bool (*create_t)();
+typedef ContextProvider* (*create_t)(const char *subject);
 
 std::map<const char*, const char*, CompareSubjectName> ProviderLoader::__providerLibMap;
 
-ProviderLoader::ProviderLoader()
+ProviderLoader::ProviderLoader() :
+       __soHandle(NULL)
 {
 }
 
@@ -40,51 +41,51 @@ ProviderLoader::~ProviderLoader()
 
 ContextProvider* ProviderLoader::load(const char *subject)
 {
-       /* TODO: Implement */
-       return NULL;
+       ProviderLibMap::iterator it = __providerLibMap.find(subject);
+       if (it == __providerLibMap.end()) {
+               _W("No provider for '%s'", subject);
+               return NULL;
+       }
+
+       std::string path = LIB_DIRECTORY;
+       path = path + LIB_PREFIX + it->second + LIB_EXTENSION;
+
+       return __load(path.c_str(), subject);
 }
 
 ContextProvider* ProviderLoader::__load(const char *soPath, const char *subject)
 {
        _I("Load '%s' from '%s'", subject, soPath);
 
-       void *soHandle = dlopen(soPath, RTLD_LAZY | RTLD_GLOBAL);
-       IF_FAIL_RETURN_TAG(soHandle, NULL, _E, "%s", dlerror());
+       __soHandle = dlopen(soPath, RTLD_LAZY | RTLD_GLOBAL);
+       IF_FAIL_RETURN_TAG(__soHandle, NULL, _E, "%s", dlerror());
 
-       create_t create = reinterpret_cast<create_t>(dlsym(soHandle, "create"));
+       create_t create = reinterpret_cast<create_t>(dlsym(__soHandle, "create"));
        if (!create) {
                _E("%s", dlerror());
-               dlclose(soHandle);
+               dlclose(__soHandle);
+               __soHandle = NULL;
                return NULL;
        }
 
-       /* TODO: Update this part for dynamic loading */
-       create();
+       ContextProvider *prvd = create(subject);
+       if (!prvd) {
+               _W("No provider for '%s'", subject);
+               dlclose(__soHandle);
+               __soHandle = NULL;
+               return NULL;
+       }
 
-       return NULL;
+       return prvd;
 }
 
 void ProviderLoader::__unload()
 {
-       /* TODO: Implement */
-}
-
-bool ProviderLoader::loadAll()
-{
-       /* TODO: Remove this function. This is a temporary solution. */
-       std::set<std::string> soPaths;
-
-       for (auto it : __providerLibMap) {
-               std::string path = LIB_DIRECTORY;
-               path = path + LIB_PREFIX + it.second + LIB_EXTENSION;
-               soPaths.insert(path);
-       }
+       if (!__soHandle)
+               return;
 
-       for (std::set<std::string>::iterator it = soPaths.begin(); it != soPaths.end(); ++it) {
-               __load((*it).c_str(), NULL);
-       }
-
-       return true;
+       dlclose(__soHandle);
+       __soHandle = NULL;
 }
 
 bool ProviderLoader::init()
@@ -93,6 +94,7 @@ bool ProviderLoader::init()
 
        for (int i = 0; i < size; ++i) {
                __providerLibMap[subjectLibraryList[i].subject] = subjectLibraryList[i].library;
+               _SD("'%s' -> '%s'", subjectLibraryList[i].subject, subjectLibraryList[i].library);
        }
 
        return true;
index 7623b89..1eb303d 100644 (file)
@@ -25,27 +25,26 @@ namespace ctx {
 
        struct CompareSubjectName {
                bool operator()(const char *left, const char *right) const {
-                       const char *pl = left;
-                       const char *pr = right;
-                       while (pl != NULL && pr != NULL) {
-                               if (*pl < *pr)
+                       while (*left != '\0' && *right != '\0') {
+                               if (*left < *right)
                                        return true;
-                               if (*pl > *pr)
+                               if (*left > *right)
                                        return false;
-                               ++pl;
-                               ++pr;
+                               ++left;
+                               ++right;
                        }
                        return false;
                }
        };
 
        class ProviderLoader {
+               typedef std::map<const char*, const char*, CompareSubjectName> ProviderLibMap;
+
        public:
                ProviderLoader();
                ~ProviderLoader();
 
                ContextProvider* load(const char *subject);
-               bool loadAll();
 
                static bool init();
                static bool popTriggerTemplate(std::string &subject, int &operation, Json &attribute, Json &option);
@@ -54,7 +53,8 @@ namespace ctx {
                ContextProvider* __load(const char *soPath, const char *subject);
                void __unload();
 
-               static std::map<const char*, const char*, CompareSubjectName> __providerLibMap;
+               void *__soHandle;
+               static ProviderLibMap __providerLibMap;
        };
 
 }
index b33e10a..08745e6 100644 (file)
@@ -111,7 +111,7 @@ void TemplateManager::applyTemplates()
        */
 
        /* FIXME */
-       while (ProviderLoader::popTriggerTemplate(subject, operation, attributes, options)) {
+       while (__contextMgr->popTriggerTemplate(subject, operation, attributes, options)) {
                registerTemplate(subject, operation, attributes, options, "");
        }
 }