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>
#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()
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;
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);
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)
_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)
_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 {
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();
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);
}
request->reply(error);
-#endif
return true;
}
+*/
#include <map>
#include <IContextManager.h>
-#include "ProviderLoader.h"
namespace ctx {
/* Forward declaration */
class Credentials;
class RequestInfo;
- class ProviderHandler;
class ContextManager : public IContextManager {
public:
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();
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 */
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)
{
}
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;
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;
{
_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;
{
_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;
return true;
}
+bool ProviderHandler::__loadProvider()
+{
+ __provider = __loader.load(__subject);
+ return (__provider != NULL);
+}
+
ProviderHandler::RequestList::iterator
ProviderHandler::__findRequest(RequestList &reqList, Json &option)
{
#include <string>
#include <list>
+#include <map>
#include <ContextProvider.h>
+#include "ProviderLoader.h"
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);
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);
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)
{
}
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()
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;
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);
ContextProvider* __load(const char *soPath, const char *subject);
void __unload();
- static std::map<const char*, const char*, CompareSubjectName> __providerLibMap;
+ void *__soHandle;
+ static ProviderLibMap __providerLibMap;
};
}
*/
/* FIXME */
- while (ProviderLoader::popTriggerTemplate(subject, operation, attributes, options)) {
+ while (__contextMgr->popTriggerTemplate(subject, operation, attributes, options)) {
registerTemplate(subject, operation, attributes, options, "");
}
}