This patch just copies the legacy code files from Tizen 3.0 context-service.
Change-Id: Ie615be0baaf8997c895eb42a537722a1f28f6267
Signed-off-by: Mu-Woong Lee <muwoong.lee@samsung.com>
SET(DEPS glib-2.0 gio-2.0 dlog capi-base-common)
-FILE(GLOB_RECURSE SRCS *.cpp)
+FILE(GLOB SRCS *.cpp)
MESSAGE("Sources: ${SRCS}")
INCLUDE(FindPkgConfig)
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <unistd.h>
+#include <glib.h>
+#include <app_manager.h>
+#include <Types.h>
+#include <DBusTypes.h>
+#include "DBusServer.h"
+#include "access_control/PeerCreds.h"
+#include "ClientRequest.h"
+
+ctx::ClientRequest::ClientRequest(int type, int reqId, const char *subj, const char *desc,
+ ctx::Credentials *creds, const char *sender, GDBusMethodInvocation *inv) :
+ RequestInfo(type, reqId, subj, desc),
+ __credentials(creds),
+ __dbusSender(sender),
+ __invocation(inv)
+{
+}
+
+ctx::ClientRequest::~ClientRequest()
+{
+ if (__invocation)
+ g_dbus_method_invocation_return_value(__invocation, g_variant_new("(iss)", ERR_OPERATION_FAILED, EMPTY_JSON_OBJECT, EMPTY_JSON_OBJECT));
+
+ delete __credentials;
+}
+
+const ctx::Credentials* ctx::ClientRequest::getCredentials()
+{
+ return __credentials;
+}
+
+const char* ctx::ClientRequest::getPackageId()
+{
+ if (__credentials)
+ return __credentials->packageId;
+
+ return NULL;
+}
+
+const char* ctx::ClientRequest::getClient()
+{
+ if (__credentials)
+ return __credentials->client;
+
+ return NULL;
+}
+
+bool ctx::ClientRequest::reply(int error)
+{
+ IF_FAIL_RETURN(__invocation, true);
+
+ _I("Reply %#x", error);
+
+ g_dbus_method_invocation_return_value(__invocation, g_variant_new("(iss)", error, EMPTY_JSON_OBJECT, EMPTY_JSON_OBJECT));
+ __invocation = NULL;
+ return true;
+}
+
+bool ctx::ClientRequest::reply(int error, ctx::Json& requestResult)
+{
+ IF_FAIL_RETURN(__invocation, true);
+ IF_FAIL_RETURN(error != ERR_NONE || __type != REQ_READ_SYNC, true);
+
+ std::string result = requestResult.str();
+ IF_FAIL_RETURN(!result.empty(), false);
+
+ _I("Reply %#x", error);
+ _SD("Result: %s", result.c_str());
+
+ g_dbus_method_invocation_return_value(__invocation, g_variant_new("(iss)", error, result.c_str(), EMPTY_JSON_OBJECT));
+ __invocation = NULL;
+
+ return true;
+}
+
+bool ctx::ClientRequest::reply(int error, ctx::Json& requestResult, ctx::Json& dataRead)
+{
+ if (__invocation == NULL) {
+ return publish(error, dataRead);
+ }
+
+ std::string result = requestResult.str();
+ std::string data = dataRead.str();
+ IF_FAIL_RETURN(!result.empty() && !data.empty(), false);
+
+ _I("Reply %#x", error);
+ _SD("Result: %s", result.c_str());
+ _SD("Data: %s", data.c_str());
+
+ g_dbus_method_invocation_return_value(__invocation, g_variant_new("(iss)", error, result.c_str(), data.c_str()));
+ __invocation = NULL;
+
+ return true;
+}
+
+bool ctx::ClientRequest::publish(int error, ctx::Json& data)
+{
+ DBusServer::publish(__dbusSender, __reqId, __subject, error, data.str());
+ return true;
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _CONTEXT_CLIENT_REQUEST_H_
+#define _CONTEXT_CLIENT_REQUEST_H_
+
+#include <gio/gio.h>
+#include "Request.h"
+
+namespace ctx {
+
+ class ClientRequest : public RequestInfo {
+ public:
+ ClientRequest(int type, int reqId, const char *subj, const char *desc,
+ Credentials *creds, const char *sender, GDBusMethodInvocation *inv);
+ ~ClientRequest();
+
+ const Credentials* getCredentials();
+ const char* getPackageId();
+ const char* getClient();
+ bool reply(int error);
+ bool reply(int error, ctx::Json &requestResult);
+ bool reply(int error, ctx::Json &requestResult, ctx::Json &dataRead);
+ bool publish(int error, ctx::Json &data);
+
+ private:
+ Credentials *__credentials;
+ std::string __dbusSender;
+ GDBusMethodInvocation *__invocation;
+ };
+
+} /* namespace ctx */
+
+#endif /* End of _CONTEXT_CLIENT_REQUEST_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <glib.h>
+#include <list>
+
+#include <Types.h>
+#include <DBusTypes.h>
+#include <Json.h>
+#include <ContextProvider.h>
+#include <CustomRegister.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"
+
+using namespace ctx::trigger;
+using namespace ctx;
+
+ContextManager::ContextManager()
+{
+ ContextProvider::__setContextManager(this);
+ CustomRegister::__setCustomRegister(this);
+ ProviderLoader::init();
+}
+
+ContextManager::~ContextManager()
+{
+ release();
+}
+
+bool ContextManager::init()
+{
+ return true;
+}
+
+void ContextManager::release()
+{
+ ProviderHandler::purge();
+}
+
+void ContextManager::assignRequest(RequestInfo* request)
+{
+ std::string subject = request->getSubject();
+ if (subject.empty()) {
+ _W("Empty subject name");
+ request->reply(ERR_NOT_SUPPORTED);
+ delete request;
+ return;
+ }
+
+ ProviderHandler *handle = ProviderHandler::getInstance(subject, true);
+ if (!handle || !handle->isSupported()) {
+ request->reply(ERR_NOT_SUPPORTED);
+ delete request;
+ return;
+ }
+
+ if (request->getType() != REQ_SUPPORT && !handle->isAllowed(request->getCredentials())) {
+ _W("Permission denied");
+ request->reply(ERR_PERMISSION_DENIED);
+ delete request;
+ return;
+ }
+
+ switch (request->getType()) {
+ case REQ_SUBSCRIBE:
+ handle->subscribe(request);
+ break;
+ case REQ_UNSUBSCRIBE:
+ handle->unsubscribe(request);
+ break;
+ case REQ_READ:
+ case REQ_READ_SYNC:
+ handle->read(request);
+ break;
+ case REQ_WRITE:
+ handle->write(request);
+ break;
+ case REQ_SUPPORT:
+ request->reply(ERR_NONE);
+ delete request;
+ break;
+ default:
+ _E("Invalid type of request");
+ delete request;
+ }
+}
+
+bool ContextManager::isSupported(const char *subject)
+{
+ 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 */
+
+ 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);
+
+ ProviderHandler *handle = ProviderHandler::getInstance(subject, false);
+ IF_FAIL_VOID_TAG(handle, _W, "No corresponding provider");
+
+ handle->publish(option, error, dataUpdated);
+}
+
+void ContextManager::__replyToRead(const char* subject, Json &option, int error, Json &dataRead)
+{
+ _I("Sending data of '%s'", subject);
+ _J("Option", option);
+ _J("Data", dataRead);
+
+ ProviderHandler *handle = ProviderHandler::getInstance(subject, false);
+ IF_FAIL_VOID_TAG(handle, _W, "No corresponding provider");
+
+ handle->replyToRead(option, error, dataRead);
+}
+
+struct PublishedData {
+ int type;
+ ContextManager *mgr;
+ std::string subject;
+ int error;
+ Json option;
+ Json data;
+ PublishedData(int t, ContextManager *m, const char* s, Json& o, int e, Json& d)
+ : type(t), mgr(m), subject(s), error(e)
+ {
+ option = o.str();
+ data = d.str();
+ }
+};
+
+gboolean ContextManager::__threadSwitcher(gpointer data)
+{
+ PublishedData *tuple = static_cast<PublishedData*>(data);
+
+ switch (tuple->type) {
+ case REQ_SUBSCRIBE:
+ tuple->mgr->__publish(tuple->subject.c_str(), tuple->option, tuple->error, tuple->data);
+ break;
+ case REQ_READ:
+ tuple->mgr->__replyToRead(tuple->subject.c_str(), tuple->option, tuple->error, tuple->data);
+ break;
+ default:
+ _W("Invalid type");
+ }
+
+ delete tuple;
+ return FALSE;
+}
+
+bool ContextManager::publish(const char* subject, Json& option, int error, Json& dataUpdated)
+{
+ IF_FAIL_RETURN_TAG(subject, false, _E, "Invalid parameter");
+
+ PublishedData *tuple = new(std::nothrow) PublishedData(REQ_SUBSCRIBE, this, subject, option, error, dataUpdated);
+ IF_FAIL_RETURN_TAG(tuple, false, _E, "Memory allocation failed");
+
+ g_idle_add(__threadSwitcher, tuple);
+
+ return true;
+}
+
+bool ContextManager::replyToRead(const char* subject, Json& option, int error, Json& dataRead)
+{
+ IF_FAIL_RETURN_TAG(subject, false, _E, "Invalid parameter");
+
+ PublishedData *tuple = new(std::nothrow) PublishedData(REQ_READ, this, subject, option, error, dataRead);
+ IF_FAIL_RETURN_TAG(tuple, false, _E, "Memory allocation failed");
+
+ g_idle_add(__threadSwitcher, tuple);
+
+ return true;
+}
+
+bool ContextManager::popTriggerTemplate(std::string &subject, int &operation, Json &attribute, Json &option)
+{
+ return ProviderLoader::popTriggerTemplate(subject, operation, attribute, option);
+}
+
+/* Only for explicit request of custom provider */
+bool ContextManager::registerCustomProvider(const char* subject, int operation, ctx::Json &attribute, ctx::Json &option, const char* owner)
+{
+ IF_FAIL_RETURN_TAG(ProviderHandler::getInstance(subject, true), false, _E, "Register provider failed");
+
+ TemplateManager* tmplMgr = TemplateManager::getInstance();
+ IF_FAIL_RETURN_TAG(tmplMgr, false, _E, "Memory allocation failed");
+ tmplMgr->registerTemplate(subject, operation, attribute, option, owner);
+
+ return true;
+}
+
+bool ContextManager::unregisterCustomProvider(const char* subject)
+{
+ TemplateManager* tmplMgr = TemplateManager::getInstance();
+ IF_FAIL_RETURN_TAG(tmplMgr, false, _E, "Memory allocation failed");
+ tmplMgr->unregisterTemplate(subject);
+
+ int error = ProviderHandler::unregisterCustomProvider(subject);
+ IF_FAIL_RETURN_TAG(error == ERR_NONE, false, _E, "Unregister provider failed");
+
+ return true;
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _CONTEXT_CONTEXT_MANAGER_H_
+#define _CONTEXT_CONTEXT_MANAGER_H_
+
+#include <map>
+#include <IContextManager.h>
+#include <ICustomRegister.h>
+
+namespace ctx {
+
+ /* Forward declaration */
+ class Credentials;
+ class RequestInfo;
+
+ class ContextManager : public IContextManager, ICustomRegister {
+ public:
+ ~ContextManager();
+
+ bool init();
+ void release();
+
+ void assignRequest(ctx::RequestInfo *request);
+ bool isSupported(const char *subject);
+ bool isAllowed(const Credentials *creds, const char *subject);
+
+ /* From the interface class */
+ 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 registerCustomProvider(const char* subject, int operation, ctx::Json &attribute, ctx::Json &option, const char* owner);
+ bool unregisterCustomProvider(const char* subject);
+
+ bool popTriggerTemplate(std::string &subject, int &operation, Json &attribute, Json &option);
+
+ private:
+ ContextManager();
+
+ static gboolean __threadSwitcher(gpointer data);
+
+ 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);
+
+ friend class Server;
+
+ }; /* class ContextManager */
+
+} /* namespace ctx */
+
+#endif /* _CONTEXT_CONTEXT_MANAGER_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <signal.h>
+#include <app_manager.h>
+
+#include <Types.h>
+#include <DBusTypes.h>
+#include "Server.h"
+#include "ClientRequest.h"
+#include "access_control/PeerCreds.h"
+#include "DBusServer.h"
+
+using namespace ctx;
+
+static const gchar __introspection_xml[] =
+ "<node>"
+ " <interface name='" DBUS_IFACE "'>"
+ " <method name='" METHOD_REQUEST "'>"
+ " <arg type='i' name='" ARG_REQTYPE "' direction='in'/>"
+ " <arg type='s' name='" ARG_COOKIE "' direction='in'/>"
+ " <arg type='i' name='" ARG_REQID "' direction='in'/>"
+ " <arg type='s' name='" ARG_SUBJECT "' direction='in'/>"
+ " <arg type='s' name='" ARG_INPUT "' direction='in'/>"
+ " <arg type='i' name='" ARG_RESULT_ERR "' direction='out'/>"
+ " <arg type='s' name='" ARG_RESULT_ADD "' direction='out'/>"
+ " <arg type='s' name='" ARG_OUTPUT "' direction='out'/>"
+ " </method>"
+ " <method name='" METHOD_CHK_PRIV_APPLAUNCH "'>"
+ " <arg type='i' name='" ARG_RESULT_ERR "' direction='out'/>"
+ " </method>"
+ " <method name='" METHOD_CHK_PRIV_CALL "'>"
+ " <arg type='i' name='" ARG_RESULT_ERR "' direction='out'/>"
+ " </method>"
+ " <method name='" METHOD_CHK_PRIV_NOTIFICATION "'>"
+ " <arg type='i' name='" ARG_RESULT_ERR "' direction='out'/>"
+ " </method>"
+ " </interface>"
+ "</node>";
+
+DBusServer *DBusServer::__theInstance = NULL;
+
+DBusServer::DBusServer() :
+ __owner(-1),
+ __connection(NULL),
+ __nodeInfo(NULL)
+{
+}
+
+DBusServer::~DBusServer()
+{
+ __release();
+}
+
+void DBusServer::__processRequest(const char *sender, GVariant *param, GDBusMethodInvocation *invocation)
+{
+ gint reqType = 0;
+ const gchar *cookie = NULL;
+ gint reqId = 0;
+ const gchar *subject = NULL;
+ const gchar *input = NULL;
+
+ g_variant_get(param, "(i&si&s&s)", &reqType, &cookie, &reqId, &subject, &input);
+ IF_FAIL_VOID_TAG(reqType > 0 && reqId > 0 && cookie && subject && input, _E, "Invalid request");
+
+ _I("[%d] ReqId: %d, Subject: %s", reqType, reqId, subject);
+ _SI("Input: %s", input);
+
+ Credentials *creds = NULL;
+
+ if (!peer_creds::get(__connection, sender, cookie, &creds)) {
+ _E("Peer credentialing failed");
+ g_dbus_method_invocation_return_value(invocation, g_variant_new("(iss)", ERR_OPERATION_FAILED, EMPTY_JSON_OBJECT, EMPTY_JSON_OBJECT));
+ return;
+ }
+
+ ClientRequest *request = new(std::nothrow) ClientRequest(reqType, reqId, subject, input, creds, sender, invocation);
+ if (!request) {
+ _E("Memory allocation failed");
+ g_dbus_method_invocation_return_value(invocation, g_variant_new("(iss)", ERR_OPERATION_FAILED, EMPTY_JSON_OBJECT, EMPTY_JSON_OBJECT));
+ delete creds;
+ return;
+ }
+
+ Server::sendRequest(request);
+}
+
+void DBusServer::__reply(GDBusMethodInvocation *invocation, int error)
+{
+ g_dbus_method_invocation_return_value(invocation, g_variant_new("(i)", error));
+}
+
+void DBusServer::__onMethodCalled(GDBusConnection *conn, const gchar *sender,
+ const gchar *path, const gchar *iface, const gchar *name,
+ GVariant *param, GDBusMethodInvocation *invocation, gpointer userData)
+{
+ IF_FAIL_VOID_TAG(STR_EQ(path, DBUS_PATH), _W, "Invalid path: %s", path);
+ IF_FAIL_VOID_TAG(STR_EQ(iface, DBUS_IFACE), _W, "Invalid interface: %s", path);
+
+ if (STR_EQ(name, METHOD_REQUEST)) {
+ __theInstance->__processRequest(sender, param, invocation);
+ } else {
+ __theInstance->__reply(invocation, ERR_NONE);
+ }
+}
+
+void DBusServer::__onBusAcquired(GDBusConnection *conn, const gchar *name, gpointer userData)
+{
+ GDBusInterfaceVTable vtable;
+ vtable.method_call = __onMethodCalled;
+ vtable.get_property = NULL;
+ vtable.set_property = NULL;
+
+ guint regId = g_dbus_connection_register_object(conn, DBUS_PATH,
+ __theInstance->__nodeInfo->interfaces[0], &vtable, NULL, NULL, NULL);
+
+ if (regId <= 0) {
+ _E("Failed to acquire dbus");
+ raise(SIGTERM);
+ }
+
+ __theInstance->__connection = conn;
+ _I("Dbus connection acquired");
+}
+
+void DBusServer::__onNameAcquired(GDBusConnection *conn, const gchar *name, gpointer userData)
+{
+ _SI("Dbus name acquired: %s", name);
+ Server::activate();
+}
+
+void DBusServer::__onNameLost(GDBusConnection *conn, const gchar *name, gpointer userData)
+{
+ _E("Dbus name lost");
+ raise(SIGTERM);
+}
+
+void DBusServer::__onCallDone(GObject *source, GAsyncResult *res, gpointer userData)
+{
+ _I("Call %u done", *static_cast<unsigned int*>(userData));
+
+ GDBusConnection *conn = G_DBUS_CONNECTION(source);
+ GError *error = NULL;
+ g_dbus_connection_call_finish(conn, res, &error);
+ HANDLE_GERROR(error);
+}
+
+bool DBusServer::__init()
+{
+ __nodeInfo = g_dbus_node_info_new_for_xml(__introspection_xml, NULL);
+ IF_FAIL_RETURN_TAG(__nodeInfo != NULL, false, _E, "Initialization failed");
+
+ __owner = g_bus_own_name(G_BUS_TYPE_SESSION, DBUS_DEST, G_BUS_NAME_OWNER_FLAGS_NONE,
+ __onBusAcquired, __onNameAcquired, __onNameLost, NULL, NULL);
+
+ __theInstance = this;
+ return true;
+}
+
+void DBusServer::__release()
+{
+ if (__connection) {
+ g_dbus_connection_flush_sync(__connection, NULL, NULL);
+ }
+
+ if (__owner > 0) {
+ g_bus_unown_name(__owner);
+ __owner = 0;
+ }
+
+ if (__connection) {
+ g_dbus_connection_close_sync(__connection, NULL, NULL);
+ g_object_unref(__connection);
+ __connection = NULL;
+ }
+
+ if (__nodeInfo) {
+ g_dbus_node_info_unref(__nodeInfo);
+ __nodeInfo = NULL;
+ }
+}
+
+void DBusServer::__publish(const char *dest, int reqId, const char *subject, int error, const char *data)
+{
+ _SI("Publish: %s, %d, %s, %#x, %s", dest, reqId, subject, error, data);
+
+ GVariant *param = g_variant_new("(isis)", reqId, subject, error, data);
+ IF_FAIL_VOID_TAG(param, _E, "Memory allocation failed");
+
+ g_dbus_connection_call(__connection, dest, DBUS_PATH, DBUS_IFACE,
+ METHOD_RESPOND, param, NULL, G_DBUS_CALL_FLAGS_NONE, DBUS_TIMEOUT, NULL, NULL, NULL);
+}
+
+void DBusServer::__call(const char *dest, const char *obj, const char *iface, const char *method, GVariant *param)
+{
+ static unsigned int callCount = 0;
+ ++callCount;
+
+ _SI("Call %u: %s, %s, %s.%s", callCount, dest, obj, iface, method);
+
+ g_dbus_connection_call(__connection, dest, obj, iface, method, param, NULL,
+ G_DBUS_CALL_FLAGS_NONE, DBUS_TIMEOUT, NULL, __onCallDone, &callCount);
+}
+
+void DBusServer::publish(std::string dest, int reqId, std::string subject, int error, std::string data)
+{
+ IF_FAIL_VOID_TAG(__theInstance, _E, "Not initialized");
+ __theInstance->__publish(dest.c_str(), reqId, subject.c_str(), error, data.c_str());
+}
+
+void DBusServer::call(std::string dest, std::string obj, std::string iface, std::string method, GVariant *param)
+{
+ IF_FAIL_VOID_TAG(__theInstance, _E, "Not initialized");
+ __theInstance->__call(dest.c_str(), obj.c_str(), iface.c_str(), method.c_str(), param);
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _CONTEXT_DBUS_SERVER_H_
+#define _CONTEXT_DBUS_SERVER_H_
+
+#include <glib.h>
+#include <gio/gio.h>
+#include <string>
+
+namespace ctx {
+
+ class DBusServer {
+ public:
+ ~DBusServer();
+
+ static void publish(std::string dest, int reqId, std::string subject, int error, std::string data);
+ static void call(std::string dest, std::string obj, std::string iface, std::string method, GVariant *param);
+
+ private:
+ DBusServer();
+
+ static void __onMethodCalled(GDBusConnection *conn, const gchar *sender,
+ const gchar *path, const gchar *iface, const gchar *name,
+ GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data);
+ static void __onBusAcquired(GDBusConnection *conn, const gchar *name, gpointer userData);
+ static void __onNameAcquired(GDBusConnection *conn, const gchar *name, gpointer userData);
+ static void __onNameLost(GDBusConnection *conn, const gchar *name, gpointer userData);
+ static void __onCallDone(GObject *source, GAsyncResult *res, gpointer userData);
+
+ bool __init();
+ void __release();
+ void __publish(const char *dest, int reqId, const char *subject, int error, const char *data);
+ void __call(const char *dest, const char *obj, const char *iface, const char *method, GVariant *param);
+
+ void __processRequest(const char *sender, GVariant *param, GDBusMethodInvocation *invocation);
+ void __reply(GDBusMethodInvocation *invocation, int error);
+
+ static DBusServer *__theInstance;
+
+ guint __owner;
+ GDBusConnection *__connection;
+ GDBusNodeInfo *__nodeInfo;
+
+ friend class Server;
+
+ }; /* class ctx::DBusServer */
+
+} /* namespace ctx */
+
+#endif /* End of _CONTEXT_DBUS_SERVER_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <glib.h>
+#include <Types.h>
+#include <ProviderTypes.h>
+#include "access_control/Privilege.h"
+#include "Request.h"
+#include "ProviderHandler.h"
+
+#define DELETE_DELAY 20
+
+using namespace ctx;
+
+std::map<std::string, ProviderHandler*> ProviderHandler::__instanceMap;
+
+ProviderHandler::ProviderHandler(const std::string &subject) :
+ __subject(subject),
+ __deleteScheduled(false)
+{
+ _D("Subject: %s", __subject.c_str());
+}
+
+ProviderHandler::~ProviderHandler()
+{
+ _D("Subject: %s", __subject.c_str());
+
+ for (RequestInfo*& info : __subscribeRequests) {
+ delete info;
+ }
+ __subscribeRequests.clear();
+
+ for (RequestInfo*& info : __readRequests) {
+ delete info;
+ }
+ __readRequests.clear();
+
+ delete __provider;
+}
+
+/* TODO: Return proper error code */
+ProviderHandler* ProviderHandler::getInstance(std::string subject, bool force)
+{
+ 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();
+}
+
+int ProviderHandler::unregisterCustomProvider(std::string subject)
+{
+ InstanceMap::iterator it = __instanceMap.find(subject);
+ IF_FAIL_RETURN_TAG(it != __instanceMap.end(), ERR_NOT_SUPPORTED, _E, "'%s' not found", subject.c_str());
+
+ __instanceMap.erase(subject);
+ delete it->second;
+
+ _D("'%s' unregistered", subject.c_str());
+ return ERR_NONE;
+}
+
+bool ProviderHandler::isSupported()
+{
+ /* If idle, self destruct */
+ __scheduleToDelete();
+
+ return __provider->isSupported();
+}
+
+bool ProviderHandler::isAllowed(const Credentials *creds)
+{
+ /* If idle, self destruct */
+ __scheduleToDelete();
+
+ 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.c_str(), request->getId());
+
+ Json requestResult;
+ int error = __provider->subscribe(request->getDescription().str(), &requestResult);
+
+ if (!request->reply(error, requestResult) || error != ERR_NONE) {
+ delete request;
+ /* If idle, self destruct */
+ __scheduleToDelete();
+ return;
+ }
+
+ __subscribeRequests.push_back(request);
+}
+
+void ProviderHandler::unsubscribe(RequestInfo *request)
+{
+ _I(CYAN("'%s' unsubscribes '%s' (RID-%d)"), request->getClient(), __subject.c_str(), request->getId());
+
+ /* Search the subscribe request to be removed */
+ auto target = __findRequest(__subscribeRequests, request->getClient(), request->getId());
+ if (target == __subscribeRequests.end()) {
+ _W("Unknown request");
+ delete request;
+ return;
+ }
+
+ /* Keep the pointer to the request found */
+ RequestInfo *reqFound = *target;
+
+ /* Remove the request from the list */
+ __subscribeRequests.erase(target);
+
+ /* Check if there exist the same requests */
+ if (__findRequest(__subscribeRequests, reqFound->getDescription()) != __subscribeRequests.end()) {
+ /* Do not stop detecting the subject */
+ _D("A same request from '%s' exists", reqFound->getClient());
+ request->reply(ERR_NONE);
+ delete request;
+ delete reqFound;
+ return;
+ }
+
+ /* Stop detecting the subject */
+ int error = __provider->unsubscribe(reqFound->getDescription());
+ request->reply(error);
+ delete request;
+ delete reqFound;
+
+ /* If idle, self destruct */
+ __scheduleToDelete();
+}
+
+void ProviderHandler::read(RequestInfo *request)
+{
+ _I(CYAN("'%s' reads '%s' (RID-%d)"), request->getClient(), __subject.c_str(), request->getId());
+
+ Json requestResult;
+ int error = __provider->read(request->getDescription().str(), &requestResult);
+
+ if (!request->reply(error, requestResult) || error != ERR_NONE) {
+ delete request;
+ /* If idle, self destruct */
+ __scheduleToDelete();
+ return;
+ }
+
+ __readRequests.push_back(request);
+}
+
+void ProviderHandler::write(RequestInfo *request)
+{
+ _I(CYAN("'%s' writes '%s' (RID-%d)"), request->getClient(), __subject.c_str(), request->getId());
+
+ Json requestResult;
+ request->getDescription().set(NULL, KEY_CLIENT_PKG_ID, request->getPackageId()? request->getPackageId() : "SYSTEM");
+ int error = __provider->write(request->getDescription(), &requestResult);
+
+ request->reply(error, requestResult);
+ delete request;
+
+ /* If idle, self destruct */
+ __scheduleToDelete();
+}
+
+bool ProviderHandler::publish(Json &option, int error, Json &dataUpdated)
+{
+ auto end = __subscribeRequests.end();
+ auto target = __findRequest(__subscribeRequests.begin(), end, option);
+
+ while (target != end) {
+ if (!(*target)->publish(error, dataUpdated)) {
+ return false;
+ }
+ target = __findRequest(++target, end, option);
+ }
+
+ return true;
+}
+
+bool ProviderHandler::replyToRead(Json &option, int error, Json &dataRead)
+{
+ auto end = __readRequests.end();
+ auto target = __findRequest(__readRequests.begin(), end, option);
+ auto prev = target;
+
+ Json dummy;
+
+ while (target != end) {
+ (*target)->reply(error, dummy, dataRead);
+ prev = target;
+ target = __findRequest(++target, end, option);
+
+ delete *prev;
+ __readRequests.erase(prev);
+ }
+
+ /* If idle, self destruct */
+ __scheduleToDelete();
+
+ return true;
+}
+
+bool ProviderHandler::__loadProvider()
+{
+ __provider = __loader.load(__subject.c_str());
+ return (__provider != NULL);
+}
+
+bool ProviderHandler::__idle()
+{
+ return __subscribeRequests.empty() && __readRequests.empty();
+}
+
+void ProviderHandler::__scheduleToDelete()
+{
+ if (__provider->unloadable() && !__deleteScheduled && __idle()) {
+ __deleteScheduled = true;
+ g_timeout_add_seconds(DELETE_DELAY, __deletor, this);
+ _D("Delete scheduled for '%s' (%#x)", __subject.c_str(), this);
+ }
+}
+
+gboolean ProviderHandler::__deletor(gpointer data)
+{
+ ProviderHandler *handle = static_cast<ProviderHandler*>(data);
+
+ if (handle->__idle()) {
+ __instanceMap.erase(handle->__subject);
+ delete handle;
+ return FALSE;
+ }
+
+ handle->__deleteScheduled = false;
+ return FALSE;
+}
+
+ProviderHandler::RequestList::iterator
+ProviderHandler::__findRequest(RequestList &reqList, Json &option)
+{
+ return __findRequest(reqList.begin(), reqList.end(), option);
+}
+
+ProviderHandler::RequestList::iterator
+ProviderHandler::__findRequest(RequestList &reqList, std::string client, int reqId)
+{
+ for (auto it = reqList.begin(); it != reqList.end(); ++it) {
+ if (client == (*it)->getClient() && reqId == (*it)->getId()) {
+ return it;
+ }
+ }
+ return reqList.end();
+}
+
+ProviderHandler::RequestList::iterator
+ProviderHandler::__findRequest(RequestList::iterator begin, RequestList::iterator end, Json &option)
+{
+ for (auto it = begin; it != end; ++it) {
+ if (option == (*it)->getDescription()) {
+ return it;
+ }
+ }
+ return end;
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _CONTEXT_PROVIDER_HANDLER_H_
+#define _CONTEXT_PROVIDER_HANDLER_H_
+
+#include <string>
+#include <list>
+#include <map>
+#include <ContextProvider.h>
+#include "ProviderLoader.h"
+
+namespace ctx {
+
+ class Credentials;
+ class RequestInfo;
+
+ class ProviderHandler {
+ typedef std::list<RequestInfo*> RequestList;
+ typedef std::map<std::string, ProviderHandler*> InstanceMap;
+
+ public:
+ bool isSupported();
+ bool isAllowed(const Credentials *creds);
+
+ void subscribe(RequestInfo *request);
+ void unsubscribe(RequestInfo *request);
+ void read(RequestInfo *request);
+ void write(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(std::string subject, bool force);
+ static void purge();
+ static int unregisterCustomProvider(std::string subject);
+
+ private:
+ std::string __subject;
+ ContextProvider *__provider;
+ RequestList __subscribeRequests;
+ RequestList __readRequests;
+ ProviderLoader __loader;
+ bool __deleteScheduled;
+
+ static InstanceMap __instanceMap;
+
+ ProviderHandler(const std::string &subject);
+ ~ProviderHandler();
+
+ bool __loadProvider();
+ bool __idle();
+ void __scheduleToDelete();
+
+ 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);
+
+ static gboolean __deletor(gpointer data);
+
+ }; /* class ProviderHandler */
+
+} /* namespace ctx */
+
+#endif /* _CONTEXT_PROVIDER_HANDLER_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <set>
+#include <Types.h>
+#include <ContextProvider.h>
+#include <ProviderList.h>
+#include "ProviderLoader.h"
+
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
+
+using namespace ctx;
+
+typedef ContextProvider* (*create_t)(const char *subject);
+
+std::map<const char*, const char*, CompareSubjectName> ProviderLoader::__providerLibMap;
+
+ProviderLoader::ProviderLoader() :
+ __soHandle(NULL)
+{
+}
+
+ProviderLoader::~ProviderLoader()
+{
+ __unload();
+}
+
+ContextProvider* ProviderLoader::load(const char *subject)
+{
+ ProviderLibMap::iterator it = __providerLibMap.find(subject);
+ if (it == __providerLibMap.end()) {
+ _W("No provider for '%s'", subject);
+ return NULL;
+ }
+
+ std::string path(_LIBDIR_ LIB_PREFIX);
+ path = path + it->second + LIB_EXTENSION;
+
+ return __load(path.c_str(), subject);
+}
+
+ContextProvider* ProviderLoader::__load(const char *soPath, const char *subject)
+{
+ _SI("Load '%s' from '%s'", subject, soPath);
+
+ __soHandle = g_module_open(soPath, G_MODULE_BIND_LAZY);
+ IF_FAIL_RETURN_TAG(__soHandle, NULL, _E, "%s", g_module_error());
+
+ gpointer symbol;
+
+ if (!g_module_symbol(__soHandle, "CreateProvider", &symbol) || symbol == NULL) {
+ _W("%s", g_module_error());
+ g_module_close(__soHandle);
+ __soHandle = NULL;
+ return NULL;
+ }
+
+ create_t create = reinterpret_cast<create_t>(symbol);
+
+ ContextProvider *prvd = create(subject);
+ if (!prvd) {
+ _W("No provider for '%s'", subject);
+ g_module_close(__soHandle);
+ __soHandle = NULL;
+ return NULL;
+ }
+
+ return prvd;
+}
+
+void ProviderLoader::__unload()
+{
+ if (!__soHandle)
+ return;
+
+ g_module_close(__soHandle);
+ __soHandle = NULL;
+}
+
+bool ProviderLoader::init()
+{
+ int size = ARRAY_SIZE(subjectLibraryList);
+
+ 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;
+}
+
+bool ProviderLoader::popTriggerTemplate(std::string &subject, int &operation, Json &attribute, Json &option)
+{
+ static int i = 0;
+ static int size = ARRAY_SIZE(triggerTemplateList);
+
+ if (i == size)
+ return false;
+
+ subject = triggerTemplateList[i].subject;
+ operation = triggerTemplateList[i].operation;
+ attribute = triggerTemplateList[i].attribute;
+ option = triggerTemplateList[i].option;
+
+ ++i;
+ return true;
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _CONTEXT_PROVIDER_LOADER_H_
+#define _CONTEXT_PROVIDER_LOADER_H_
+
+#include <gmodule.h>
+#include <map>
+
+namespace ctx {
+
+ class ContextProvider;
+
+ struct CompareSubjectName {
+ bool operator()(const char *left, const char *right) const {
+ while (*left != '\0' && *right != '\0') {
+ if (*left < *right)
+ return true;
+ if (*left > *right)
+ return false;
+ ++left;
+ ++right;
+ }
+ return false;
+ }
+ };
+
+ class ProviderLoader {
+ typedef std::map<const char*, const char*, CompareSubjectName> ProviderLibMap;
+
+ public:
+ ProviderLoader();
+ ~ProviderLoader();
+
+ ContextProvider* load(const char *subject);
+
+ static bool init();
+ static bool popTriggerTemplate(std::string &subject, int &operation, Json &attribute, Json &option);
+
+ private:
+ ContextProvider* __load(const char *soPath, const char *subject);
+ void __unload();
+
+ GModule *__soHandle;
+ static ProviderLibMap __providerLibMap;
+ };
+
+}
+
+#endif /* _CONTEXT_PROVIDER_LOADER_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <glib.h>
+#include <Types.h>
+#include "Request.h"
+
+ctx::RequestInfo::RequestInfo(int type, int reqId, const char* subj, const char* desc) :
+ __type(type),
+ __reqId(reqId),
+ __subject(subj),
+ __description(desc)
+{
+}
+
+ctx::RequestInfo::~RequestInfo()
+{
+}
+
+int ctx::RequestInfo::getType()
+{
+ return __type;
+}
+
+int ctx::RequestInfo::getId()
+{
+ return __reqId;
+}
+
+const ctx::Credentials* ctx::RequestInfo::getCredentials()
+{
+ return NULL;
+}
+
+const char* ctx::RequestInfo::getPackageId()
+{
+ return NULL;
+}
+
+const char* ctx::RequestInfo::getClient()
+{
+ return NULL;
+}
+
+const char* ctx::RequestInfo::getSubject()
+{
+ return __subject.c_str();
+}
+
+ctx::Json& ctx::RequestInfo::getDescription()
+{
+ return __description;
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _CONTEXT_REQUEST_INFO_H_
+#define _CONTEXT_REQUEST_INFO_H_
+
+#include <string>
+#include <Json.h>
+
+namespace ctx {
+
+ /* Forward declaration */
+ class Credentials;
+
+ class RequestInfo {
+ public:
+ RequestInfo(int type, int reqId, const char *subj, const char *desc);
+ virtual ~RequestInfo();
+
+ int getType();
+ int getId();
+ const char* getSubject();
+ ctx::Json& getDescription();
+
+ virtual const Credentials* getCredentials();
+ virtual const char* getPackageId();
+ /* TODO: remove this getClient() */
+ virtual const char* getClient();
+ virtual bool reply(int error) = 0;
+ virtual bool reply(int error, ctx::Json &requestResult) = 0;
+ virtual bool reply(int error, ctx::Json &requestResult, ctx::Json &dataRead) = 0;
+ virtual bool publish(int error, ctx::Json &data) = 0;
+
+ protected:
+ int __type;
+ int __reqId;
+ std::string __subject;
+ ctx::Json __description;
+ };
+
+} /* namespace ctx */
+
+#endif /* End of _CONTEXT_REQUEST_INFO_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <new>
+#include <glib.h>
+#include <glib-object.h>
+
+#include <Types.h>
+#include <TimerManager.h>
+#include <DatabaseManager.h>
+#include "DBusServer.h"
+#include "ContextManager.h"
+#include "policy/PolicyManager.h"
+#include "trigger/Trigger.h"
+#include "Server.h"
+
+#define RUN(L) g_main_loop_run((L))
+#define QUIT(L) if (g_main_loop_is_running((L)) == TRUE) g_main_loop_quit((L))
+
+
+static GMainLoop *mainloop = NULL;
+static bool started = false;
+
+static ctx::ContextManager *__contextMgr = NULL;
+static ctx::DBusServer *__dbusHandle = NULL;
+static ctx::PolicyManager *__policyMgr = NULL;
+static ctx::trigger::Trigger *__contextTrigger = NULL;
+static ctx::TimerManager __timerManager;
+
+/* TODO: re-organize activation & deactivation processes */
+void ctx::Server::initialize()
+{
+ _I("Init Dbus Connection");
+ __dbusHandle = new(std::nothrow) ctx::DBusServer();
+ IF_FAIL_VOID_TAG(__dbusHandle, _E, "Memory allocation failed");
+ IF_FAIL_VOID_TAG(__dbusHandle->__init(), _E, "Initialization Failed");
+
+ // Start the main loop
+ _I(CYAN("Launching Context-Service"));
+ RUN(mainloop);
+}
+
+void ctx::Server::activate()
+{
+ IF_FAIL_VOID(!started);
+
+ bool result = false;
+
+ _I("Init Database Manager");
+ IF_FAIL_CATCH(DatabaseManager::__init());
+
+ _I("Init Context Manager");
+ __contextMgr = new(std::nothrow) ctx::ContextManager();
+ IF_FAIL_CATCH_TAG(__contextMgr, _E, "Memory allocation failed");
+ result = __contextMgr->init();
+ IF_FAIL_CATCH_TAG(result, _E, "Initialization Failed");
+
+ _I("Init Context Trigger");
+ __contextTrigger = new(std::nothrow) ctx::trigger::Trigger();
+ IF_FAIL_CATCH_TAG(__contextTrigger, _E, "Memory allocation failed");
+ result = __contextTrigger->init(__contextMgr);
+ IF_FAIL_CATCH_TAG(result, _E, "Initialization Failed");
+
+ _I("Init Policy Manager");
+ __policyMgr = new(std::nothrow) ctx::PolicyManager(__contextMgr);
+ IF_FAIL_CATCH_TAG(__policyMgr, _E, "Memory allocation failed");
+
+ started = true;
+ _I(CYAN("Context-Service Launched"));
+ return;
+
+CATCH:
+ _E(RED("Launching Failed"));
+
+ // Stop the main loop
+ QUIT(mainloop);
+}
+
+void ctx::Server::release()
+{
+ _I(CYAN("Terminating Context-Service"));
+ started = false;
+
+ _I("Release Policy Manager");
+ delete __policyMgr;
+
+ _I("Release Context Trigger");
+ if (__contextTrigger)
+ __contextTrigger->release();
+
+ _I("Release Context Manager");
+ if (__contextMgr)
+ __contextMgr->release();
+
+ _I("Release Database Manager");
+ DatabaseManager::__release();
+
+ delete __contextTrigger;
+ delete __contextMgr;
+ delete __dbusHandle;
+}
+
+static gboolean __postponeRequestAssignment(gpointer data)
+{
+ ctx::Server::sendRequest(static_cast<ctx::RequestInfo*>(data));
+ return FALSE;
+}
+
+void ctx::Server::sendRequest(ctx::RequestInfo* request)
+{
+ if (!started) {
+ _W("Service not ready...");
+ g_idle_add(__postponeRequestAssignment, request);
+ return;
+ }
+
+ if (__contextTrigger->assignRequest(request))
+ return;
+
+ __contextMgr->assignRequest(request);
+}
+
+static void __signalHandler(int signo)
+{
+ _I("SIGNAL %d received", signo);
+
+ // Stop the main loop
+ QUIT(mainloop);
+}
+
+int main(int argc, char* argv[])
+{
+ static struct sigaction signalAction;
+ signalAction.sa_handler = __signalHandler;
+ sigemptyset(&signalAction.sa_mask);
+
+ sigaction(SIGINT, &signalAction, NULL);
+ sigaction(SIGHUP, &signalAction, NULL);
+ sigaction(SIGTERM, &signalAction, NULL);
+ sigaction(SIGQUIT, &signalAction, NULL);
+ sigaction(SIGABRT, &signalAction, NULL);
+
+#if !defined(GLIB_VERSION_2_36)
+ g_type_init();
+#endif
+
+ _I("Init MainLoop");
+ mainloop = g_main_loop_new(NULL, FALSE);
+
+ ctx::Server::initialize();
+ ctx::Server::release();
+
+ g_main_loop_unref(mainloop);
+
+ return EXIT_SUCCESS;
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _CONTEXT_SERVER_H_
+#define _CONTEXT_SERVER_H_
+
+namespace ctx {
+
+ class RequestInfo;
+
+ class Server {
+ public:
+ static void initialize();
+ static void activate();
+ static void release();
+ static void sendRequest(RequestInfo* request);
+
+ };
+
+} /* namespace ctx */
+
+#endif /* End of _CONTEXT_SERVER_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cynara-creds-gdbus.h>
+#include <cynara-session.h>
+#include <app_manager.h>
+#include <package_manager.h>
+#include <Types.h>
+#include "PeerCreds.h"
+
+ctx::Credentials::Credentials(char *pkgId, char *cli, char *sess, char *usr) :
+ packageId(pkgId),
+ client(cli),
+ session(sess),
+ user(usr)
+{
+}
+
+ctx::Credentials::~Credentials()
+{
+ g_free(packageId);
+ g_free(client);
+ g_free(session);
+ g_free(user);
+}
+
+bool ctx::peer_creds::get(GDBusConnection *connection, const char *uniqueName, const char *cookie, ctx::Credentials **creds)
+{
+ pid_t pid = 0;
+ char *app_id = NULL;
+ char *packageId = NULL;
+ gchar *client = NULL;
+ char *session = NULL;
+ gchar *user = NULL;
+
+ int err = cynara_creds_gdbus_get_pid(connection, uniqueName, &pid);
+ IF_FAIL_RETURN_TAG(err == CYNARA_API_SUCCESS, false, _E, "Peer credentialing failed");
+
+ session = cynara_session_from_pid(pid);
+ IF_FAIL_CATCH_TAG(session, _E, "Peer credentialing failed");
+
+ err = cynara_creds_gdbus_get_client(connection, uniqueName, CLIENT_METHOD_DEFAULT, &client);
+ IF_FAIL_CATCH_TAG(err == CYNARA_API_SUCCESS, _E, "Peer credentialing failed");
+
+ err = cynara_creds_gdbus_get_user(connection, uniqueName, USER_METHOD_DEFAULT, &user);
+ IF_FAIL_CATCH_TAG(err == CYNARA_API_SUCCESS, _E, "Peer credentialing failed");
+
+ app_manager_get_app_id(pid, &app_id);
+ package_manager_get_package_id_by_app_id(app_id, &packageId);
+ _D("AppId: %s, PackageId: %s", app_id, packageId);
+ g_free(app_id);
+
+ *creds = new(std::nothrow) Credentials(packageId, client, session, user);
+ IF_FAIL_CATCH_TAG(*creds, _E, "Memory allocation failed");
+
+ return true;
+
+CATCH:
+ g_free(packageId);
+ g_free(client);
+ g_free(session);
+ g_free(user);
+ return false;
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _CONTEXT_PEER_CREDENTIALS_H_
+#define _CONTEXT_PEER_CREDENTIALS_H_
+
+#include <sys/types.h>
+#include <gio/gio.h>
+#include <string>
+
+namespace ctx {
+
+ class Credentials {
+ public:
+ char *packageId;
+ char *client; /* default: smack label */
+ char *session;
+ char *user; /* default: UID */
+ Credentials(char *pkgId, char *cli, char *sess, char *usr);
+ ~Credentials();
+ };
+
+ namespace peer_creds {
+
+ bool get(GDBusConnection *connection, const char *uniqueName, const char *cookie, Credentials **creds);
+
+ } /* namespace peer_creds */
+} /* namespace ctx */
+
+#endif /* End of _CONTEXT_PEER_CREDENTIALS_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string>
+#include <cynara-client.h>
+#include <Types.h>
+#include "PeerCreds.h"
+#include "Privilege.h"
+
+#define PRIV_PREFIX "http://tizen.org/privilege/"
+#define CACHE_SIZE 100
+
+class PermissionChecker {
+private:
+ cynara *__cynara;
+
+ PermissionChecker()
+ {
+ cynara_configuration *conf;
+
+ int err = cynara_configuration_create(&conf);
+ IF_FAIL_VOID_TAG(err == CYNARA_API_SUCCESS, _E, "Cynara configuration creation failed");
+
+ err = cynara_configuration_set_cache_size(conf, CACHE_SIZE);
+ if (err != CYNARA_API_SUCCESS) {
+ _E("Cynara cache size set failed");
+ cynara_configuration_destroy(conf);
+ return;
+ }
+
+ err = cynara_initialize(&__cynara, conf);
+ cynara_configuration_destroy(conf);
+ if (err != CYNARA_API_SUCCESS) {
+ _E("Cynara initialization failed");
+ __cynara = NULL;
+ return;
+ }
+
+ _I("Cynara initialized");
+ }
+
+ ~PermissionChecker()
+ {
+ if (__cynara)
+ cynara_finish(__cynara);
+
+ _I("Cynara deinitialized");
+ }
+
+public:
+ static PermissionChecker& getInstance()
+ {
+ static PermissionChecker instance;
+ return instance;
+ }
+
+ bool hasPermission(const ctx::Credentials *creds, const char *privilege)
+ {
+ IF_FAIL_RETURN_TAG(__cynara, false, _E, "Cynara not initialized");
+ int ret = cynara_check(__cynara, creds->client, creds->session, creds->user, privilege);
+ return (ret == CYNARA_API_ACCESS_ALLOWED);
+ }
+};
+
+bool ctx::privilege_manager::isAllowed(const ctx::Credentials *creds, const char *privilege)
+{
+ IF_FAIL_RETURN(creds && privilege, true);
+
+ std::string priv = PRIV_PREFIX;
+ priv += privilege;
+
+ return PermissionChecker::getInstance().hasPermission(creds, priv.c_str());
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _CONTEXT_PRIVILEGE_MANAGER_H_
+#define _CONTEXT_PRIVILEGE_MANAGER_H_
+
+namespace ctx {
+
+ /* Forward declaration */
+ class Credentials;
+
+ namespace privilege_manager {
+
+ bool isAllowed(const Credentials *creds, const char *privilege);
+
+ } /* namespace privilege_manager */
+} /* namespace ctx */
+
+#endif /* End of _CONTEXT_PRIVILEGE_MANAGER_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <Types.h>
+#include <DBusTypes.h>
+#include <ProviderTypes.h>
+#include <SensorRecorderTypes.h>
+#include "../ContextManager.h"
+#include "PolicyRequest.h"
+#include "PolicyManager.h"
+
+using namespace ctx;
+
+PolicyManager::PolicyManager(ContextManager *contextMgr) :
+ __contextMgr(contextMgr)
+{
+ __subscribe(SUBJ_CUSTOM);
+
+ __subscribe(SUBJ_APP_LOGGER);
+ __subscribe(SUBJ_BATTERY_LOGGER);
+ __subscribe(SUBJ_MEDIA_LOGGER);
+ __subscribe(SUBJ_PLACE_DETECTION);
+ __subscribe(SUBJ_STATE_WIFI);
+
+ __subscribe(SUBJ_SENSOR_PEDOMETER);
+ __subscribe(SUBJ_SENSOR_PRESSURE);
+ __subscribe(SUBJ_SENSOR_SLEEP_MONITOR);
+ __subscribe(SUBJ_SENSOR_HEART_RATE);
+}
+
+PolicyManager::~PolicyManager()
+{
+ for (auto &it : __subscriptionMap) {
+ PolicyRequest *req = new(std::nothrow) PolicyRequest(REQ_UNSUBSCRIBE, it.first, it.second, NULL);
+ if (!req) {
+ _E("Memory allocation failed");
+ continue;
+ }
+ __contextMgr->assignRequest(req);
+ }
+
+ __subscriptionMap.clear();
+}
+
+void PolicyManager::__subscribe(const char *subject)
+{
+ static int rid = 0;
+ ++rid;
+
+ PolicyRequest *req = new(std::nothrow) PolicyRequest(REQ_SUBSCRIBE, rid, subject, NULL);
+ IF_FAIL_VOID_TAG(req, _E, "Memory allocation failed");
+
+ __contextMgr->assignRequest(req);
+
+ __subscriptionMap[rid] = subject;
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _CONTEXT_POLICY_MANAGER_H_
+#define _CONTEXT_POLICY_MANAGER_H_
+
+#include <map>
+
+namespace ctx {
+
+ class ContextManger;
+
+ class PolicyManager {
+ public:
+ ~PolicyManager();
+
+ private:
+ PolicyManager(ContextManager *contextMgr);
+
+ void __subscribe(const char *subject);
+
+ ContextManager *__contextMgr;
+ std::map<int, const char*> __subscriptionMap;
+
+ friend class Server;
+ };
+
+} /* namespace ctx */
+
+#endif /* _CONTEXT_POLICY_MANAGER_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "PolicyRequest.h"
+
+using namespace ctx;
+
+PolicyRequest::PolicyRequest(int type, int reqId, const char *subj, const char *desc) :
+ RequestInfo(type, reqId, subj, desc)
+{
+}
+
+PolicyRequest::~PolicyRequest()
+{
+}
+
+const char* PolicyRequest::getClient()
+{
+ return "POLICY";
+}
+
+bool PolicyRequest::reply(int error)
+{
+ return true;
+}
+
+bool PolicyRequest::reply(int error, ctx::Json &requestResult)
+{
+ return true;
+}
+
+bool PolicyRequest::reply(int error, ctx::Json &requestResult, ctx::Json &dataRead)
+{
+ return true;
+}
+
+bool PolicyRequest::publish(int error, ctx::Json &data)
+{
+ return true;
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _CONTEXT_POLICY_REQUEST_H_
+#define _CONTEXT_POLICY_REQUEST_H_
+
+#include "../Request.h"
+
+namespace ctx {
+
+ class PolicyRequest : public RequestInfo {
+ public:
+ PolicyRequest(int type, int reqId, const char *subj, const char *desc);
+ ~PolicyRequest();
+
+ const char* getClient();
+
+ bool reply(int error);
+ bool reply(int error, ctx::Json &requestResult);
+ bool reply(int error, ctx::Json &requestResult, ctx::Json &dataRead);
+ bool publish(int error, ctx::Json &data);
+ };
+
+} /* namespace ctx */
+
+#endif /* End of _CONTEXT_POLICY_REQUEST_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <Types.h>
+#include <Json.h>
+#include <app_control.h>
+#include <app_control_internal.h>
+#include <bundle.h>
+#include <device/display.h>
+#include <notification.h>
+#include <notification_internal.h>
+#include <vconf.h>
+#include <TriggerRuleTypes.h>
+#include "../DBusServer.h"
+#include "ActionManager.h"
+
+using namespace ctx;
+
+static void __triggerActionAppControl(Json& action);
+static void __triggerActionNotification(Json& action, std::string pkgId);
+static void __triggerActionDbusCall(Json& action);
+
+void trigger::action_manager::triggerAction(Json& action, std::string pkgId)
+{
+ std::list<std::string> types;
+ action.getKeys(&types);
+ IF_FAIL_VOID_TAG(types.size() == 1, _E, "Invalid action");
+
+ std::string& type = *(types.begin());
+
+ if (type.compare(TRIG_RULE_KEY_APP_LAUNCH) == 0) {
+ __triggerActionAppControl(action);
+ } else if (type.compare(TRIG_RULE_KEY_NOTIFICATION) == 0) {
+ __triggerActionNotification(action, pkgId);
+ } else if (type.compare(TRIG_RULE_KEY_DBUS_CALL) == 0) {
+ __triggerActionDbusCall(action);
+ }
+}
+
+void __triggerActionAppControl(Json& action)
+{
+ int error;
+ std::string appctlStr;
+ action.get(TRIG_RULE_KEY_APP_LAUNCH, TRIG_RULE_KEY_APP_LAUNCH_APP_CONTROL, &appctlStr);
+
+ char* str = static_cast<char*>(malloc(appctlStr.length()));
+ if (str == NULL) {
+ _E("Memory allocation failed");
+ return;
+ }
+ appctlStr.copy(str, appctlStr.length(), 0);
+ bundle_raw* encoded = reinterpret_cast<unsigned char*>(str);
+ bundle* appctlBundle = bundle_decode(encoded, appctlStr.length());
+
+ app_control_h app = NULL;
+ app_control_create(&app);
+ app_control_import_from_bundle(app, appctlBundle);
+
+ error = app_control_send_launch_request(app, NULL, NULL);
+ if (error != APP_CONTROL_ERROR_NONE) {
+ _E("Launch request failed(%d)", error);
+ } else {
+ _D("Launch request succeeded");
+ }
+ bundle_free(appctlBundle);
+ free(str);
+ app_control_destroy(app);
+
+ error = device_display_change_state(DISPLAY_STATE_NORMAL);
+ if (error != DEVICE_ERROR_NONE) {
+ _E("Change display state failed(%d)", error);
+ }
+}
+
+void __triggerActionNotification(Json& action, std::string pkgId)
+{
+ int error;
+ notification_h notification = notification_create(NOTIFICATION_TYPE_NOTI);
+ std::string title;
+ if (action.get(TRIG_RULE_KEY_NOTIFICATION, TRIG_RULE_KEY_NOTI_TITLE, &title)) {
+ error = notification_set_text(notification, NOTIFICATION_TEXT_TYPE_TITLE, title.c_str(), NULL, NOTIFICATION_VARIABLE_TYPE_NONE);
+ if (error != NOTIFICATION_ERROR_NONE) {
+ _E("Set notification title failed(%d)", error);
+ }
+ }
+
+ std::string content;
+ if (action.get(TRIG_RULE_KEY_NOTIFICATION, TRIG_RULE_KEY_NOTI_CONTENT, &content)) {
+ error = notification_set_text(notification, NOTIFICATION_TEXT_TYPE_CONTENT, content.c_str(), NULL, NOTIFICATION_VARIABLE_TYPE_NONE);
+ if (error != NOTIFICATION_ERROR_NONE) {
+ _E("Set notification contents failed(%d)", error);
+ }
+ }
+
+ std::string imagePath;
+ if (action.get(TRIG_RULE_KEY_NOTIFICATION, TRIG_RULE_KEY_NOTI_ICON_PATH, &imagePath)) {
+ error = notification_set_image(notification, NOTIFICATION_IMAGE_TYPE_ICON, imagePath.c_str());
+ if (error != NOTIFICATION_ERROR_NONE) {
+ _E("Set notification icon image failed(%d)", error);
+ }
+ }
+
+ std::string appctlStr;
+ char* str = NULL;
+ bundle_raw* encoded = NULL;
+ bundle* appctlBundle = NULL;
+ app_control_h app = NULL;
+ if (action.get(TRIG_RULE_KEY_NOTIFICATION, TRIG_RULE_KEY_NOTI_APP_CONTROL, &appctlStr)) {
+ str = static_cast<char*>(malloc(appctlStr.length()));
+ if (str == NULL) {
+ _E("Memory allocation failed");
+ notification_free(notification);
+ return;
+ }
+ appctlStr.copy(str, appctlStr.length(), 0);
+ encoded = reinterpret_cast<unsigned char*>(str);
+ appctlBundle = bundle_decode(encoded, appctlStr.length());
+
+ app_control_create(&app);
+ app_control_import_from_bundle(app, appctlBundle);
+
+ error = notification_set_launch_option(notification, NOTIFICATION_LAUNCH_OPTION_APP_CONTROL, app);
+ if (error != NOTIFICATION_ERROR_NONE) {
+ _E("Set launch option failed(%d)", error);
+ }
+ }
+
+ if (!pkgId.empty()) {
+ error = notification_set_pkgname(notification, pkgId.c_str());
+ if (error != NOTIFICATION_ERROR_NONE) {
+ _E("Set package id(%s) failed(%#x)", pkgId.c_str(), error);
+ }
+ }
+
+ int soundOn = 0;
+ error = vconf_get_bool(VCONFKEY_SETAPPL_SOUND_STATUS_BOOL, &soundOn);
+ if (error < 0) {
+ _E("vconf error (%d)", error);
+ } else if (soundOn) {
+ error = notification_set_sound(notification, NOTIFICATION_SOUND_TYPE_DEFAULT, NULL);
+ if (error != NOTIFICATION_ERROR_NONE) {
+ _E("Set notification sound failed(%d)", error);
+ }
+ }
+
+ int vibrationOn = 0;
+ error = vconf_get_bool(VCONFKEY_SETAPPL_VIBRATION_STATUS_BOOL, &vibrationOn);
+ if (error < 0) {
+ _E("vconf error (%d)", error);
+ } else if (vibrationOn) {
+ error = notification_set_vibration(notification, NOTIFICATION_VIBRATION_TYPE_DEFAULT, NULL);
+ if (error != NOTIFICATION_ERROR_NONE) {
+ _E("Set notification vibration failed(%d)", error);
+ }
+ }
+
+ error = notification_post(notification);
+ if (error != NOTIFICATION_ERROR_NONE) {
+ _E("Post notification failed(%d)", error);
+ } else {
+ _D("Post notification succeeded");
+ }
+
+ bundle_free(appctlBundle);
+ free(str);
+ notification_free(notification);
+ if (app) {
+ app_control_destroy(app);
+ }
+
+ error = device_display_change_state(DISPLAY_STATE_NORMAL);
+ if (error != DEVICE_ERROR_NONE) {
+ _E("Change display state failed(%d)", error);
+ }
+}
+
+void __triggerActionDbusCall(Json& action)
+{
+ std::string busName, object, iface, method;
+ GVariant *param = NULL;
+
+ action.get(TRIG_RULE_KEY_DBUS_CALL, TRIG_RULE_KEY_DBUS_NAME, &busName);
+ IF_FAIL_VOID_TAG(!busName.empty(), _E, "No target bus name");
+
+ action.get(TRIG_RULE_KEY_DBUS_CALL, TRIG_RULE_KEY_DBUS_OBJECT, &object);
+ IF_FAIL_VOID_TAG(!object.empty(), _E, "No object path");
+
+ action.get(TRIG_RULE_KEY_DBUS_CALL, TRIG_RULE_KEY_DBUS_INTERFACE, &iface);
+ IF_FAIL_VOID_TAG(!iface.empty(), _E, "No interface name");
+
+ action.get(TRIG_RULE_KEY_DBUS_CALL, TRIG_RULE_KEY_DBUS_METHOD, &method);
+ IF_FAIL_VOID_TAG(!method.empty(), _E, "No method name");
+
+ action.get(TRIG_RULE_KEY_DBUS_CALL, TRIG_RULE_KEY_DBUS_PARAMETER, ¶m);
+
+ DBusServer::call(busName, object, iface, method, param);
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _CONTEXT_TRIGGER_ACTION_MANAGER_H_
+#define _CONTEXT_TRIGGER_ACTION_MANAGER_H_
+
+namespace ctx {
+ /* Forward Declaration */
+ class Json;
+
+namespace trigger {
+
+ namespace action_manager {
+
+ void triggerAction(Json& action, std::string pkgId);
+
+ } /* namespace action_manager */
+
+} /* namespace trigger*/
+} /* namespace ctx */
+
+#endif /* End of _CONTEXT_TRIGGER_ACTION_MANAGER_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <Types.h>
+#include "../access_control/Privilege.h"
+#include "../ContextManager.h"
+#include "ContextMonitor.h"
+#include "IContextListener.h"
+#include "FactRequest.h"
+
+using namespace ctx;
+using namespace trigger;
+
+static int __lastRid;
+static int __lastErr;
+
+ContextMonitor *ContextMonitor::__instance = NULL;
+ContextManager *ContextMonitor::__contextMgr = NULL;
+
+static int __generateReqId()
+{
+ static int reqId = 0;
+
+ if (++reqId < 0) {
+ // Overflow handling
+ reqId = 1;
+ }
+
+ return reqId;
+}
+
+ContextMonitor::ContextMonitor()
+{
+}
+
+ContextMonitor::~ContextMonitor()
+{
+}
+
+void ContextMonitor::setContextManager(ContextManager* ctxMgr)
+{
+ __contextMgr = ctxMgr;
+}
+
+ContextMonitor* ContextMonitor::getInstance()
+{
+ IF_FAIL_RETURN_TAG(__contextMgr, NULL, _E, "Context manager is needed");
+
+ IF_FAIL_RETURN(!__instance, __instance);
+
+ __instance = new(std::nothrow) ContextMonitor();
+ IF_FAIL_RETURN_TAG(__instance, NULL, _E, "Memory alllocation failed");
+
+ return __instance;
+}
+
+void ContextMonitor::destroy()
+{
+ if (__instance) {
+ delete __instance;
+ __instance = NULL;
+ }
+}
+
+int ContextMonitor::subscribe(int ruleId, std::string subject, Json option, IContextListener* listener)
+{
+ int reqId = __subscribe(subject.c_str(), &option, listener);
+ IF_FAIL_RETURN_TAG(reqId > 0, reqId, _E, "Subscribe event failed");
+ _D(YELLOW("Subscribe event(rule%d). req%d"), ruleId, reqId);
+
+ return ERR_NONE;
+}
+
+int ContextMonitor::__subscribe(const char* subject, Json* option, IContextListener* listener)
+{
+ IF_FAIL_RETURN(subject, ERR_INVALID_PARAMETER);
+
+ int rid = __findSub(REQ_SUBSCRIBE, subject, option);
+ if (rid > 0) {
+ __addListener(REQ_SUBSCRIBE, rid, listener);
+ _D("Duplicated request for %s", subject);
+ return rid;
+ }
+
+ rid = __generateReqId();
+
+ FactRequest *req = new(std::nothrow) FactRequest(REQ_SUBSCRIBE,
+ rid, subject, option ? option->str().c_str() : NULL, this);
+ IF_FAIL_RETURN_TAG(req, ERR_OUT_OF_MEMORY, _E, "Memory allocation failed");
+
+ __contextMgr->assignRequest(req);
+ __addSub(REQ_SUBSCRIBE, rid, subject, option, listener);
+
+ if (__lastErr != ERR_NONE) {
+ __removeSub(REQ_SUBSCRIBE, rid);
+ _E("Subscription request failed: %#x", __lastErr);
+ return __lastErr;
+ }
+
+ return rid;
+}
+
+int ContextMonitor::unsubscribe(int ruleId, std::string subject, Json option, IContextListener* listener)
+{
+ int rid = __findSub(REQ_SUBSCRIBE, subject.c_str(), &option);
+ if (rid < 0) {
+ _D("Invalid unsubscribe request");
+ return ERR_INVALID_PARAMETER;
+ }
+
+ if (__removeListener(REQ_SUBSCRIBE, rid, listener) <= 0) {
+ __unsubscribe(subject.c_str(), rid);
+ }
+ _D(YELLOW("Unsubscribe event(rule%d). req%d"), ruleId, rid);
+
+ return ERR_NONE;
+}
+
+void ContextMonitor::__unsubscribe(const char *subject, int subscriptionId)
+{
+ FactRequest *req = new(std::nothrow) FactRequest(REQ_UNSUBSCRIBE, subscriptionId, subject, NULL, NULL);
+ IF_FAIL_VOID_TAG(req, _E, "Memory allocation failed");
+
+ __contextMgr->assignRequest(req);
+ __removeSub(REQ_SUBSCRIBE, subscriptionId);
+}
+
+int ContextMonitor::read(std::string subject, Json option, IContextListener* listener)
+{
+ int reqId = __read(subject.c_str(), &option, listener);
+ IF_FAIL_RETURN_TAG(reqId > 0, ERR_OPERATION_FAILED, _E, "Read condition failed");
+ _D(YELLOW("Read condition(%s). req%d"), subject.c_str(), reqId);
+
+ return ERR_NONE;
+}
+
+int ContextMonitor::__read(const char* subject, Json* option, IContextListener* listener)
+{
+ IF_FAIL_RETURN(subject, ERR_INVALID_PARAMETER);
+
+ int rid = __findSub(REQ_READ, subject, option);
+ if (rid > 0) {
+ __addListener(REQ_READ, rid, listener);
+ _D("Duplicated request for %s", subject);
+ return rid;
+ }
+
+ rid = __generateReqId();
+
+ FactRequest *req = new(std::nothrow) FactRequest(REQ_READ,
+ rid, subject, option ? option->str().c_str() : NULL, this);
+ IF_FAIL_RETURN_TAG(req, -1, _E, "Memory allocation failed");
+
+ __contextMgr->assignRequest(req);
+ __addSub(REQ_READ, rid, subject, option, listener);
+
+ if (__lastErr != ERR_NONE) {
+ _E("Read request failed: %#x", __lastErr);
+ return -1;
+ }
+
+ return rid;
+}
+
+bool ContextMonitor::isSupported(std::string subject)
+{
+ return __contextMgr->isSupported(subject.c_str());
+}
+
+bool ContextMonitor::isAllowed(const char *client, const char *subject)
+{
+ //TODO: re-implement this in the proper 3.0 style
+ //return __contextMgr->isAllowed(client, subject);
+ return true;
+}
+
+int ContextMonitor::__findSub(RequestType type, const char* subject, Json* option)
+{
+ // @return request id
+ std::map<int, SubscrInfo*>* map = (type == REQ_SUBSCRIBE)? &__subscrMap : &__readMap;
+
+ Json jOpt;
+ if (option) {
+ jOpt = *option;
+ }
+
+ for (auto it = map->begin(); it != map->end(); ++it) {
+ if ((*(it->second)).subject == subject && (*(it->second)).option == jOpt) {
+ return it->first;
+ }
+ }
+
+ return -1;
+}
+
+bool ContextMonitor::__addSub(RequestType type, int sid, const char* subject, Json* option, IContextListener* listener)
+{
+ std::map<int, SubscrInfo*>* map = (type == REQ_SUBSCRIBE)? &__subscrMap : &__readMap;
+
+ SubscrInfo *info = new(std::nothrow) SubscrInfo(sid, subject, option);
+ IF_FAIL_RETURN_TAG(info, false, _E, "Memory allocation failed");
+ info->listenerList.push_back(listener);
+
+ map->insert(std::pair<int, SubscrInfo*>(sid, info));
+ return true;
+}
+
+void ContextMonitor::__removeSub(RequestType type, const char* subject, Json* option)
+{
+ std::map<int, SubscrInfo*>* map = (type == REQ_SUBSCRIBE)? &__subscrMap : &__readMap;
+
+ Json jOpt;
+ if (option) {
+ jOpt = *option;
+ }
+
+ for (auto it = map->begin(); it != map->end(); ++it) {
+ if ((*(it->second)).subject == subject && (*(it->second)).option == jOpt) {
+ delete it->second;
+ map->erase(it);
+ return;
+ }
+ }
+}
+
+void ContextMonitor::__removeSub(RequestType type, int sid)
+{
+ std::map<int, SubscrInfo*>* map = (type == REQ_SUBSCRIBE)? &__subscrMap : &__readMap;
+
+ SubscrInfo* info = map->at(sid);
+ info->listenerList.clear();
+
+ delete info;
+ map->erase(sid);
+
+ return;
+}
+
+int ContextMonitor::__addListener(RequestType type, int sid, IContextListener* listener)
+{
+ // @return number of listeners for the corresponding sid
+ std::map<int, SubscrInfo*>* map = (type == REQ_SUBSCRIBE)? &__subscrMap : &__readMap;
+
+ auto it = map->find(sid);
+
+ SubscrInfo* info = it->second;
+ info->listenerList.push_back(listener);
+
+ return info->listenerList.size();
+}
+
+int ContextMonitor::__removeListener(RequestType type, int sid, IContextListener* listener)
+{
+ // @return number of listeners for the corresponding sid
+ std::map<int, SubscrInfo*>* map = (type == REQ_SUBSCRIBE)? &__subscrMap : &__readMap;
+
+ auto it = map->find(sid);
+
+ SubscrInfo* info = it->second;
+
+ for (auto it2 = info->listenerList.begin(); it2 != info->listenerList.end(); ++it2) {
+ if (*it2 == listener) {
+ info->listenerList.erase(it2);
+ break;
+ }
+ }
+
+ return info->listenerList.size();
+}
+
+void ContextMonitor::replyResult(int reqId, int error, Json* requestResult)
+{
+ _D("Request result received: %d", reqId);
+
+ __lastRid = reqId;
+ __lastErr = error;
+}
+
+void ContextMonitor::replyResult(int reqId, int error, const char* subject, Json* option, Json* fact)
+{
+ _D(YELLOW("Condition received: subject(%s), option(%s), fact(%s)"), subject, option->str().c_str(), fact->str().c_str());
+
+ auto it = __readMap.find(reqId);
+ IF_FAIL_VOID_TAG(it != __readMap.end(), _E, "Request id not found");
+
+ SubscrInfo* info = it->second;
+ for (auto it2 = info->listenerList.begin(); it2 != info->listenerList.end(); ++it2) {
+ (*it2)->onConditionReceived(subject, *option, *fact);
+ }
+
+ __removeSub(REQ_READ, reqId);
+}
+
+void ContextMonitor::publishFact(int reqId, int error, const char* subject, Json* option, Json* fact)
+{
+ _D(YELLOW("Event received: subject(%s), option(%s), fact(%s)"), subject, option->str().c_str(), fact->str().c_str());
+
+ auto it = __subscrMap.find(reqId);
+ IF_FAIL_VOID_TAG(it != __subscrMap.end(), _E, "Request id not found");
+
+ SubscrInfo* info = it->second;
+ for (auto it2 = info->listenerList.begin(); it2 != info->listenerList.end(); ++it2) {
+ (*it2)->onEventReceived(subject, *option, *fact);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _CONTEXT_TRIGGER_CONTEXT_MONITOR_H_
+#define _CONTEXT_TRIGGER_CONTEXT_MONITOR_H_
+
+#include <list>
+#include <map>
+#include <Json.h>
+#include <DBusTypes.h>
+
+namespace ctx {
+
+ class ContextManager;
+
+namespace trigger {
+
+ class IContextListener;
+ class FactRequest;
+
+ class ContextMonitor {
+ public:
+ static ContextMonitor* getInstance();
+ static void setContextManager(ContextManager* ctxMgr);
+ static void destroy();
+
+ int subscribe(int ruleId, std::string subject, Json option, IContextListener* listener);
+ int unsubscribe(int ruleId, std::string subject, Json option, IContextListener* listener);
+ int read(std::string subject, Json option, IContextListener* listener);
+ bool isSupported(std::string subject);
+ bool isAllowed(const char *client, const char *subject);
+
+ void replyResult(int reqId, int error, Json *requestResult = NULL);
+ void replyResult(int reqId, int error, const char *subject, Json *option, Json *fact);
+ void publishFact(int reqId, int error, const char *subject, Json *option, Json *fact);
+
+ private:
+ ContextMonitor();
+ ContextMonitor(const ContextMonitor& other);
+ ~ContextMonitor();
+
+ static ContextMonitor *__instance;
+ static ContextManager *__contextMgr;
+
+ int __subscribe(const char* subject, Json* option, IContextListener* listener);
+ void __unsubscribe(const char *subject, int subscriptionId);
+ int __read(const char *subject, Json *option, IContextListener* listener);
+
+ struct SubscrInfo {
+ int sid;
+ std::string subject;
+ Json option;
+ std::list<IContextListener*> listenerList;
+
+ SubscrInfo(int id, const char *subj, Json *opt) :
+ sid(id),
+ subject(subj)
+ {
+ if (opt)
+ option = *opt;
+ }
+ };
+
+ std::map<int, SubscrInfo*> __subscrMap;
+ std::map<int, SubscrInfo*> __readMap;
+
+ int __findSub(RequestType type, const char *subject, Json *option);
+ bool __addSub(RequestType type, int sid, const char *subject, Json *option, IContextListener* listener);
+ void __removeSub(RequestType type, const char *subject, Json *option);
+ void __removeSub(RequestType type, int sid);
+ int __addListener(RequestType type, int sid, IContextListener* listener);
+ int __removeListener(RequestType type, int sid, IContextListener* listener);
+
+ }; /* class ContextMonitor */
+
+} /* namespace trigger */
+} /* namespace ctx */
+
+#endif /* End of _CONTEXT_TRIGGER_CONTEXT_MONITOR_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <Types.h>
+#include "FactRequest.h"
+
+using namespace ctx;
+using namespace ctx::trigger;
+
+FactRequest::FactRequest(int type, int reqId, const char* subj, const char* desc, ContextMonitor* ctxMonitor) :
+ RequestInfo(type, reqId, subj, desc),
+ __ctxMonitor(ctxMonitor),
+ __replied(false)
+{
+}
+
+FactRequest::~FactRequest()
+{
+ reply(ERR_OPERATION_FAILED);
+}
+
+const char* FactRequest::getClient()
+{
+ return "TRIGGER";
+}
+
+bool FactRequest::reply(int error)
+{
+ IF_FAIL_RETURN(!__replied && __ctxMonitor, true);
+ __ctxMonitor->replyResult(__reqId, error);
+ __replied = (error != ERR_NONE);
+ return true;
+}
+
+bool FactRequest::reply(int error, Json& requestResult)
+{
+ IF_FAIL_RETURN(!__replied && __ctxMonitor, true);
+ __ctxMonitor->replyResult(__reqId, error, &requestResult);
+ __replied = (error != ERR_NONE);
+ return true;
+}
+
+bool FactRequest::reply(int error, Json& requestResult, Json& dataRead)
+{
+ IF_FAIL_RETURN(!__replied && __ctxMonitor, true);
+ __ctxMonitor->replyResult(__reqId, error, __subject.c_str(), &getDescription(), &dataRead);
+ return (__replied = true);
+}
+
+bool FactRequest::publish(int error, Json& data)
+{
+ IF_FAIL_RETURN(__ctxMonitor, true);
+ __ctxMonitor->publishFact(__reqId, error, __subject.c_str(), &getDescription(), &data);
+ return true;
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _CONTEXT_TRIGGER_FACT_REQUEST_H_
+#define _CONTEXT_TRIGGER_FACT_REQUEST_H_
+
+#include "ContextMonitor.h"
+#include "../Request.h"
+
+namespace ctx {
+
+namespace trigger {
+
+ class FactRequest : public RequestInfo {
+ public:
+ FactRequest(int type, int reqId, const char* subj, const char* desc, ContextMonitor* ctxMonitor);
+ ~FactRequest();
+
+ const char* getClient();
+ bool reply(int error);
+ bool reply(int error, ctx::Json& requestResult);
+ bool reply(int error, ctx::Json& requestResult, ctx::Json& dataRead);
+ bool publish(int error, ctx::Json& data);
+
+ private:
+ ContextMonitor *__ctxMonitor;
+ bool __replied;
+ };
+
+} /* namespace trigger */
+} /* namespace ctx */
+
+#endif /* End of _CONTEXT_TRIGGER_FACT_REQUEST_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _CONTEXT_TRIGGER_FACT_TYPES_H_
+#define _CONTEXT_TRIGGER_FACT_TYPES_H_
+
+#define FACT_KEY_EVENT "event"
+#define FACT_KEY_CONDITION "condition"
+#define FACT_KEY_NAME "name"
+#define FACT_KEY_OPTION "option"
+#define FACT_KEY_DATA "data"
+
+#endif /* End of _CONTEXT_TRIGGER_FACT_TYPES_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _CONTEXT_TRIGGER_I_CONTEXT_LISTENER_H_
+#define _CONTEXT_TRIGGER_I_CONTEXT_LISTENER_H_
+
+namespace ctx {
+ /* Forward Declaration */
+ class Json;
+
+namespace trigger {
+
+ class IContextListener {
+ public:
+ virtual ~IContextListener() {}
+
+ virtual void onEventReceived(std::string name, Json option, Json data) = 0;
+
+ virtual void onConditionReceived(std::string name, Json option, Json data) = 0;
+ };
+
+} /* namespace trigger */
+} /* namespace ctx */
+
+#endif /* End of _CONTEXT_TRIGGER_I_CONTEXT_LISTENER_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <TriggerRuleTypes.h>
+#include "Rule.h"
+#include "ActionManager.h"
+#include "RuleEvaluator.h"
+#include "ContextMonitor.h"
+#include "FactTypes.h"
+#include "RuleManager.h"
+
+using namespace ctx;
+using namespace ctx::trigger;
+
+RuleManager *Rule::__ruleMgr = NULL;
+
+Rule::Rule(int i, Json& d, const char* p, RuleManager* rm) :
+ __result(EMPTY_JSON_OBJECT),
+ id(i),
+ pkgId(p)
+{
+ // Rule manager
+ if (!__ruleMgr) {
+ __ruleMgr = rm;
+ }
+
+ // Statement
+ __statement = d.str();
+
+ // Event
+ Json e;
+ d.get(NULL, TRIG_RULE_KEY_EVENT, &e);
+ __event = new(std::nothrow) ContextItem(e);
+
+ // Condition
+ int condNum = d.getSize(NULL, TRIG_RULE_KEY_CONDITION);
+ for (int j = 0; j < condNum; j++) {
+ Json c;
+ d.getAt(NULL, TRIG_RULE_KEY_CONDITION, j, &c);
+ __condition.push_back(new(std::nothrow) ContextItem(c));
+ }
+
+ // Extra
+ Json extra;
+ d.get(NULL, _TRIG_RULE_KEY_EXTRA, &extra);
+ __extra = extra.str();
+
+ // Action
+ Json a;
+ d.get(NULL, TRIG_RULE_KEY_ACTION, &a);
+ __action = a.str();
+}
+
+Rule::~Rule()
+{
+ // Release resources
+ delete __event;
+ for (auto it = __condition.begin(); it != __condition.end(); ++it) {
+ delete *it;
+ }
+}
+
+int Rule::start(void)
+{
+ // Subscribe event
+ int error = ContextMonitor::getInstance()->subscribe(id, __event->name, __event->option, this);
+ IF_FAIL_RETURN_TAG(error == ERR_NONE, error, _E, "Failed to start rule%d", id);
+
+ return error;
+}
+
+int Rule::stop(void)
+{
+ // Unsubscribe event
+ int error = ContextMonitor::getInstance()->unsubscribe(id, __event->name, __event->option, this);
+ if (error == ERR_NOT_SUPPORTED) {
+ _E("Stop rule%d (event not supported)");
+ return ERR_NONE;
+ }
+ IF_FAIL_RETURN_TAG(error == ERR_NONE, error, _E, "Failed to stop rule%d", id);
+
+ return error;
+}
+
+bool Rule::__setConditionOptionBasedOnEvent(Json& option)
+{
+ // Set condition option if it references event data
+ std::list<std::string> optionKeys;
+ option.getKeys(&optionKeys);
+
+ for (auto it = optionKeys.begin(); it != optionKeys.end(); ++it) {
+ std::string optKey = (*it);
+
+ std::string optVal;
+ if (option.get(NULL, optKey.c_str(), &optVal)) {
+ if (optVal.find("?") != 0) {
+ continue;
+ }
+
+ std::string eventKey = optVal.substr(1, optVal.length() - 1);
+
+ std::string newStr;
+ int new_val;
+ if (__result.get(FACT_KEY_EVENT "." FACT_KEY_DATA, eventKey.c_str(), &newStr)) {
+ option.set(NULL, optKey.c_str(), newStr);
+ } else if (__result.get(FACT_KEY_EVENT "." FACT_KEY_DATA, eventKey.c_str(), &new_val)) {
+ option.set(NULL, optKey.c_str(), new_val);
+ } else {
+ _W("Failed to find '%s' in event data", eventKey.c_str());
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+void Rule::onEventReceived(std::string name, Json option, Json data)
+{
+ if (__result != EMPTY_JSON_OBJECT) {
+ __clearResult();
+ }
+
+ // Check if creator package is uninstalled
+ if (RuleManager::isUninstalledPackage(pkgId)) {
+ _D("Creator(%s) of rule%d is uninstalled.", pkgId.c_str(), id);
+ g_idle_add(__handleUninstalledRule, &pkgId);
+ return;
+ }
+
+ _D("Rule%d received event data", id);
+
+ // Set event data
+ __result.set(FACT_KEY_EVENT, FACT_KEY_NAME, name);
+ __result.set(FACT_KEY_EVENT, FACT_KEY_OPTION, option);
+ __result.set(FACT_KEY_EVENT, FACT_KEY_DATA, data);
+
+ if (__condition.size() == 0) {
+ __onContextDataPrepared();
+ return;
+ }
+
+ IF_FAIL_VOID_TAG(RuleEvaluator::evaluateRule(__statement, __result), _E, "Event not matched");
+
+ // Request read conditions
+ for (auto it = __condition.begin(); it != __condition.end(); ++it) {
+ Json condOption = (*it)->option.str();
+ if (!__setConditionOptionBasedOnEvent(condOption)) { // condOption should be copy of original option.
+ __clearResult();
+ return;
+ }
+
+ int error = ContextMonitor::getInstance()->read((*it)->name.c_str(), condOption, this);
+ IF_FAIL_VOID_TAG(error == ERR_NONE, _E, "Failed to read condition");
+ }
+
+ // TODO timer set
+}
+
+void Rule::onConditionReceived(std::string name, Json option, Json data)
+{
+ _D("Rule%d received condition data", id);
+
+ // Set condition data
+ Json item;
+ item.set(NULL, FACT_KEY_NAME, name);
+ item.set(NULL, FACT_KEY_OPTION, option);
+ item.set(NULL, FACT_KEY_DATA, data);
+ __result.append(NULL, FACT_KEY_CONDITION, item);
+
+ if (__result.getSize(NULL, FACT_KEY_CONDITION) == (int) __condition.size()) {
+ __onContextDataPrepared();
+ }
+}
+
+void Rule::__clearResult()
+{
+ __result = EMPTY_JSON_OBJECT;
+ // TODO timer cancel
+}
+
+void Rule::__onContextDataPrepared(void)
+{
+ if (RuleEvaluator::evaluateRule(__statement, __result)) {
+ action_manager::triggerAction(__action, pkgId);
+ }
+ __clearResult();
+}
+
+gboolean Rule::__handleUninstalledRule(gpointer data)
+{
+ std::string* pkgId = static_cast<std::string*>(data);
+ __ruleMgr->handleRuleOfUninstalledPackage(*pkgId);
+
+ return FALSE;
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _CONTEXT_TRIGGER_RULE_H_
+#define _CONTEXT_TRIGGER_RULE_H_
+
+#include <string>
+#include <list>
+#include <Json.h>
+#include "IContextListener.h"
+
+namespace ctx {
+
+namespace trigger {
+
+ class RuleManager;
+
+ class Rule : public IContextListener {
+ private:
+ struct ContextItem {
+ std::string name;
+ ctx::Json option;
+ ContextItem(ctx::Json item) {
+ std::list<std::string> keyList;
+ item.getKeys(&keyList);
+ name = *keyList.begin();
+
+ ctx::Json o;
+ if (item.get(name.c_str(), TRIG_RULE_KEY_OPTION, &o))
+ option = o.str();
+ }
+ };
+
+ ctx::Json __statement;
+ ContextItem* __event;
+ std::list<ContextItem*> __condition;
+ ctx::Json __extra;
+ ctx::Json __action;
+ ctx::Json __result;
+
+ static RuleManager* __ruleMgr;
+
+ void __clearResult(void);
+ bool __setConditionOptionBasedOnEvent(ctx::Json& option);
+ void __onContextDataPrepared(void);
+
+ static gboolean __handleUninstalledRule(gpointer data);
+
+ public:
+ int id;
+ std::string pkgId;
+
+ Rule(int i, ctx::Json& d, const char* p, RuleManager* rm);
+ ~Rule();
+
+ int start(void);
+ int stop(void);
+
+ void onEventReceived(std::string name, ctx::Json option, ctx::Json data);
+ void onConditionReceived(std::string name, ctx::Json option, ctx::Json data);
+
+ };
+
+} /* namespace trigger */
+} /* namespace ctx */
+
+#endif /* End of _CONTEXT_TRIGGER_RULE_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <Json.h>
+#include <Types.h>
+#include <TriggerRuleTypes.h>
+#include "RuleEvaluator.h"
+#include "FactTypes.h"
+
+#define OPERATOR_EQ "=="
+#define OPERATOR_NEQ "!="
+#define OPERATOR_LEQ "<="
+#define OPERATOR_GEQ ">="
+#define OPERATOR_LT "<"
+#define OPERATOR_GT ">"
+
+using namespace ctx;
+using namespace ctx::trigger;
+
+RuleEvaluator::RuleEvaluator()
+{
+}
+
+template <typename T>
+bool RuleEvaluator::__evaluateSingleData(T factVal, Json& comparison, std::string op)
+{
+ T ruleVal;
+ comparison.get(NULL, TRIG_RULE_KEY_VALUE, &ruleVal);
+
+ if (op == TRIG_RULE_OP_EQUAL_TO) {
+ return (ruleVal == factVal);
+ } else if (op == TRIG_RULE_OP_NOT_EQUAL_TO) {
+ return (ruleVal != factVal);
+ } else if (op == TRIG_RULE_OP_GREATER_THAN) {
+ return (ruleVal > factVal);
+ } else if (op == TRIG_RULE_OP_GREATER_THAN_OR_EQUAL_TO) {
+ return (ruleVal >= factVal);
+ } else if (op == TRIG_RULE_OP_LESS_THAN) {
+ return (ruleVal < factVal);
+ } else if (op == TRIG_RULE_OP_LESS_THAN_OR_EQUAL_TO) {
+ return (ruleVal <= factVal);
+ }
+
+ return false;
+}
+
+template <typename T>
+bool RuleEvaluator::__evaluateDualData(T factVal, Json& comparison, std::string op)
+{
+ T ruleVal1, ruleVal2;
+ comparison.getAt(NULL, TRIG_RULE_KEY_VALUE, 0, &ruleVal1);
+ comparison.getAt(NULL, TRIG_RULE_KEY_VALUE, 1, &ruleVal2);
+
+ if (op == TRIG_RULE_OP_IN) {
+ return (ruleVal1 <= factVal && factVal <= ruleVal2);
+ } else if (op == TRIG_RULE_OP_NOT_IN) {
+ return (factVal < ruleVal1 || ruleVal2 < factVal);
+ }
+
+ return false;
+}
+
+template <typename T>
+bool RuleEvaluator::__evaluateMultipleData(T factVal, Json& comparison, std::string op)
+{
+ T ruleVal;
+ for (int i = 0; comparison.getAt(NULL, TRIG_RULE_KEY_VALUE, i, &ruleVal); i++) {
+ if (ruleVal == factVal) {
+ if (op == TRIG_RULE_OP_ONE_OF) {
+ return true;
+ } else if (op == TRIG_RULE_OP_NONE_OF) {
+ return false;
+ }
+ }
+ }
+
+ if (op == TRIG_RULE_OP_NONE_OF) {
+ return true;
+ }
+
+ return false;
+}
+
+template <typename T>
+bool RuleEvaluator::__evaluateData(T factVal, Json& comparison)
+{
+ std::string op;
+ comparison.get(NULL, TRIG_RULE_KEY_OPERATOR, &op);
+
+ if (op == TRIG_RULE_OP_EQUAL_TO || op == TRIG_RULE_OP_NOT_EQUAL_TO ||
+ op == TRIG_RULE_OP_GREATER_THAN || op == TRIG_RULE_OP_GREATER_THAN_OR_EQUAL_TO ||
+ op == TRIG_RULE_OP_LESS_THAN || op == TRIG_RULE_OP_LESS_THAN_OR_EQUAL_TO) {
+ return __evaluateSingleData(factVal, comparison, op);
+ } else if (op == TRIG_RULE_OP_IN || op == TRIG_RULE_OP_NOT_IN) {
+ return __evaluateDualData(factVal, comparison, op);
+ } else if (op == TRIG_RULE_OP_ONE_OF || op == TRIG_RULE_OP_NONE_OF) {
+ return __evaluateMultipleData(factVal, comparison, op);
+ }
+
+ return false;
+}
+
+void RuleEvaluator::__replaceSingleDataReferences(Json& eventFactData, Json& ruleComp, std::string& dataKey)
+{
+ std::string refVal;
+ std::string eventRefStr;
+ int eventRefInt;
+
+ if (!ruleComp.get(dataKey.c_str(), TRIG_RULE_KEY_VALUE, &refVal)) {
+ return;
+ }
+
+ if (refVal.substr(0, 1) != TRIG_RULE_REF_KEY_PREFIX) {
+ return;
+ }
+
+ std::string eventKey = refVal.substr(1, refVal.length() - 1);
+ if (eventFactData.get(NULL, eventKey.c_str(), &eventRefStr)) {
+ ruleComp.set(dataKey.c_str(), TRIG_RULE_KEY_VALUE, eventRefStr);
+ } else if (eventFactData.get(NULL, eventKey.c_str(), &eventRefInt)) {
+ ruleComp.set(dataKey.c_str(), TRIG_RULE_KEY_VALUE, eventRefInt);
+ } else {
+ _W("Attribute %s not found in event_data", eventKey.c_str());
+ }
+}
+
+void RuleEvaluator::__replaceMultipleDataReferences(Json& eventFactData, Json& ruleComp, std::string& dataKey)
+{
+ std::string refVal;
+ std::string eventRefStr;
+ int eventRefInt;
+
+ for (int i = 0; ruleComp.getAt(dataKey.c_str(), TRIG_RULE_KEY_VALUE, i, &refVal); i++) {
+ if (refVal.substr(0, 1) != TRIG_RULE_REF_KEY_PREFIX) {
+ continue;
+ }
+
+ std::string eventKey = refVal.substr(1, refVal.length() - 1);
+ if (eventFactData.get(NULL, eventKey.c_str(), &eventRefStr)) {
+ ruleComp.setAt(dataKey.c_str(), TRIG_RULE_KEY_VALUE, i, eventRefStr);
+ } else if (eventFactData.get(NULL, eventKey.c_str(), &eventRefInt)) {
+ ruleComp.setAt(dataKey.c_str(), TRIG_RULE_KEY_VALUE, i, eventRefInt);
+ } else {
+ _W("Attribute %s not found in event_data", eventKey.c_str());
+ }
+ }
+}
+
+void RuleEvaluator::__replaceDataReferences(Json eventFactData, Json& ruleComp)
+{
+ // Replace referencing data to actual value
+ std::list<std::string> compKeys;
+ ruleComp.getKeys(&compKeys);
+
+ for (auto it = compKeys.begin(); it != compKeys.end(); ++it) {
+ std::string dataKey = *it;
+
+ std::string op;
+ ruleComp.get(dataKey.c_str(), TRIG_RULE_KEY_OPERATOR, &op);
+
+ std::string val;
+ if (op == TRIG_RULE_OP_EQUAL_TO || op == TRIG_RULE_OP_NOT_EQUAL_TO ||
+ op == TRIG_RULE_OP_GREATER_THAN || op == TRIG_RULE_OP_GREATER_THAN_OR_EQUAL_TO ||
+ op == TRIG_RULE_OP_LESS_THAN || op == TRIG_RULE_OP_LESS_THAN_OR_EQUAL_TO) {
+
+ __replaceSingleDataReferences(eventFactData, ruleComp, dataKey);
+ } else {
+ __replaceMultipleDataReferences(eventFactData, ruleComp, dataKey);
+ }
+ }
+}
+
+bool RuleEvaluator::__evaluateItem(Json& factItem, Json& ruleItem, std::string logicalOp)
+{
+ std::string name;
+ factItem.get(NULL, FACT_KEY_NAME, &name);
+
+ Json comparison;
+ ruleItem.get(name.c_str(), TRIG_RULE_KEY_COMPARISON, &comparison);
+
+ std::list<std::string> compKeys;
+ comparison.getKeys(&compKeys);
+ if (compKeys.size() == 0) {
+ return true;
+ }
+
+ bool isConjunction = (TRIG_RULE_LOGICAL_CONJUNCTION == logicalOp);
+
+ for (auto it = compKeys.begin(); it != compKeys.end(); ++it) {
+ std::string dataKey = *it;
+
+ Json comp;
+ comparison.get(NULL, dataKey.c_str(), &comp);
+
+ std::string factValStr;
+ int factValInt;
+
+ bool result;
+ if (factItem.get(FACT_KEY_DATA, dataKey.c_str(), &factValStr)) {
+ result = __evaluateData(factValStr, comp);
+ } else if (factItem.get(FACT_KEY_DATA, dataKey.c_str(), &factValInt)) {
+ result = __evaluateData(factValInt, comp);
+ } else {
+ _W("Could not get value corresponding to data key %s", dataKey.c_str());
+ result = false;
+ }
+
+ if (isConjunction && !result) {
+ return false;
+ } else if (!isConjunction && result) {
+ return true;
+ }
+ }
+ return isConjunction;
+}
+
+bool RuleEvaluator::__evaluateRuleEvent(Json& fact, Json& rule)
+{
+ Json factItem;
+ Json ruleItem;
+ fact.get(NULL, FACT_KEY_EVENT, &factItem);
+ rule.get(NULL, TRIG_RULE_KEY_EVENT, &ruleItem);
+
+ std::string eventOp;
+ rule.get(_TRIG_RULE_KEY_EXTRA, _TRIG_RULE_KEY_EVENT_LOGICAL_OP, &eventOp);
+
+ return __evaluateItem(factItem, ruleItem, eventOp);
+}
+
+Json RuleEvaluator::__getConditionFact(Json& fact, Json& ruleCond)
+{
+ std::list<std::string> condKey;
+ ruleCond.getKeys(&condKey);
+ std::string ruleCondName = *(condKey.begin());
+
+ Json factCond;
+ for (int i = 0; fact.getAt(NULL, FACT_KEY_CONDITION, i, &factCond); i++) {
+ // Check if fact item name is matched with condition
+ std::string factCondName;
+ factCond.get(NULL, FACT_KEY_NAME, &factCondName);
+ if (factCondName != ruleCondName) {
+ continue;
+ }
+
+ // Check if fact item option is mathced with condition
+ Json ruleCondOption;
+ Json factCondOption;
+ ruleCond.get(ruleCondName.c_str(), TRIG_RULE_KEY_OPTION, &ruleCondOption);
+ factCond.get(NULL, FACT_KEY_OPTION, &factCondOption);
+ if (factCondOption == ruleCondOption) {
+ return factCond;
+ }
+ }
+
+ _W(YELLOW("find condition failed for condition"));
+ return EMPTY_JSON_OBJECT;
+}
+
+bool RuleEvaluator::__evaluateRuleCondition(Json& fact, Json& rule)
+{
+ std::string ruleOp;
+ rule.get(_TRIG_RULE_KEY_EXTRA, _TRIG_RULE_KEY_RULE_LOGICAL_OP, &ruleOp);
+ bool isConjunction = (TRIG_RULE_LOGICAL_CONJUNCTION == ruleOp);
+
+ Json ruleCond;
+ for (int i = 0; rule.getAt(NULL, TRIG_RULE_KEY_CONDITION, i, &ruleCond); i++) {
+ Json factCond = __getConditionFact(fact, ruleCond);
+
+ bool result;
+ if (factCond == EMPTY_JSON_OBJECT) {
+ result = false;
+ } else {
+ std::string condOp;
+ rule.getAt(_TRIG_RULE_KEY_EXTRA, _TRIG_RULE_KEY_CONDITION_LOGICAL_OP, i, &condOp);
+ result = __evaluateItem(factCond, ruleCond, condOp);
+ }
+
+ if (isConjunction && !result) {
+ return false;
+ } else if (!isConjunction && result) {
+ return true;
+ }
+ }
+
+ return isConjunction;
+}
+
+bool RuleEvaluator::__replaceOptionReferences(Json eventFactData, Json& ruleOption)
+{
+ // Replace referencing option to actual value
+ std::string refVal;
+ std::string eventRefStr;
+ int eventRefInt;
+
+ std::list<std::string> keyList;
+ ruleOption.getKeys(&keyList);
+
+ for (std::list<std::string>::iterator it = keyList.begin(); it != keyList.end(); ++it) {
+ std::string optionKey = *it;
+
+ if (!ruleOption.get(NULL, optionKey.c_str(), &refVal)) {
+ continue;
+ }
+ if (!(refVal.substr(0, 1) == TRIG_RULE_REF_KEY_PREFIX)) {
+ continue;
+ }
+
+ std::string eventKey = refVal.substr(1, refVal.length() - 1);
+ if (eventFactData.get(NULL, eventKey.c_str(), &eventRefStr)) {
+ ruleOption.set(NULL, optionKey.c_str(), eventRefStr);
+ } else if (eventFactData.get(NULL, eventKey.c_str(), &eventRefInt)) {
+ ruleOption.set(NULL, optionKey.c_str(), eventRefInt);
+ } else {
+ _W("Option %s not found in event_data", eventKey.c_str());
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool RuleEvaluator::__replaceEventReferences(Json& fact, Json& rule)
+{
+ // Replace referencing data/option to actual value
+ Json eventFactData;
+ if (!fact.get(FACT_KEY_EVENT, FACT_KEY_DATA, &eventFactData)) {
+ _E("No event data found, error");
+ return false;
+ }
+
+ Json ruleCond;
+ for (int i = 0; rule.getAt(NULL, TRIG_RULE_KEY_CONDITION, i, &ruleCond); i++) {
+ std::list<std::string> condKey;
+ ruleCond.getKeys(&condKey);
+ std::string ruleCondName = *(condKey.begin());
+
+ Json ruleComp;
+ for (int j = 0; ruleCond.getAt(ruleCondName.c_str(), TRIG_RULE_KEY_COMPARISON, j, &ruleComp); j++) {
+ __replaceDataReferences(eventFactData, ruleComp);
+ }
+
+ Json ruleOption;
+ if (ruleCond.get(ruleCondName.c_str(), TRIG_RULE_KEY_OPTION, &ruleOption)) {
+ __replaceOptionReferences(eventFactData, ruleOption);
+ }
+ }
+
+ return true;
+}
+
+bool RuleEvaluator::evaluateRule(Json rule, Json fact)
+{
+ _D("Rule is %s ", rule.str().c_str());
+ _D("fact is %s ", fact.str().c_str());
+
+ RuleEvaluator eval;
+ bool ret;
+ Json tempJson;
+ if (fact.get(NULL, FACT_KEY_CONDITION, &tempJson)) {
+ Json ruleCopy(rule.str());
+ if (!eval.__replaceEventReferences(fact, ruleCopy)) {
+ _W("Replace failed");
+ }
+ ret = eval.__evaluateRuleCondition(fact, ruleCopy);
+ _D("Checking condition %s", ret ? "true" : "false");
+ } else {
+ ret = eval.__evaluateRuleEvent(fact, rule);
+ _D("Checking event %s", ret ? "true" : "false");
+ }
+
+ return ret;
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _CONTEXT_TRIGGER_RULE_EVALUATOR_H_
+#define _CONTEXT_TRIGGER_RULE_EVALUATOR_H_
+
+namespace ctx {
+
+ class Json;
+
+namespace trigger {
+
+ class RuleEvaluator {
+ private:
+ RuleEvaluator();
+
+ bool __evaluateRuleEvent(ctx::Json& fact, ctx::Json& rule);
+ bool __evaluateRuleCondition(ctx::Json& fact, ctx::Json& rule);
+ bool __evaluateItem(ctx::Json& factItem, ctx::Json& ruleItem, std::string logicalOp);
+ template <typename T> bool __evaluateData(T factVal, Json& comparison);
+ template <typename T> bool __evaluateSingleData(T factVal, Json& comparison, std::string op);
+ template <typename T> bool __evaluateDualData(T factVal, Json& comparison, std::string op);
+ template <typename T> bool __evaluateMultipleData(T factVal, Json& comparison, std::string op);
+
+ ctx::Json __getConditionFact(ctx::Json& fact, ctx::Json& ruleCond);
+
+ bool __replaceEventReferences(ctx::Json& fact, ctx::Json& rule);
+ void __replaceDataReferences(ctx::Json eventFactData, ctx::Json& ruleComp);
+ void __replaceSingleDataReferences(ctx::Json& eventFactData, ctx::Json& ruleComp, std::string& dataKey);
+ void __replaceMultipleDataReferences(ctx::Json& eventFactData, ctx::Json& ruleComp, std::string& dataKey);
+ bool __replaceOptionReferences(ctx::Json eventFactData, ctx::Json& ruleOption);
+
+ public:
+ static bool evaluateRule(ctx::Json rule, ctx::Json data);
+ };
+
+} /* namespace trigger */
+} /* namespace ctx */
+
+#endif /* End of _CONTEXT_TRIGGER_RULE_EVALUATOR_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sstream>
+#include <TriggerTypes.h>
+#include <TriggerRuleTypes.h>
+#include <package_manager.h>
+#include <Json.h>
+#include "RuleManager.h"
+#include "ContextMonitor.h"
+#include "Rule.h"
+
+#define RULE_TABLE "ContextTriggerRule"
+#define RULE_IDS_JSON "{ \"" TRIG_KEY_ENABLED_IDS "\" : [ ] , \"" TRIG_KEY_DISABLED_IDS "\" : [ ] }";
+
+using namespace ctx;
+using namespace ctx::trigger;
+
+static int __stringToInt(std::string str)
+{
+ int i;
+ std::istringstream convert(str);
+
+ if (!(convert >> i))
+ i = 0;
+
+ return i;
+}
+
+static std::string __intToString(int i)
+{
+ std::ostringstream convert;
+ convert << i;
+ std::string str = convert.str();
+ return str;
+}
+
+RuleManager::RuleManager()
+{
+}
+
+RuleManager::~RuleManager()
+{
+ // Release rule instances
+ _D("Release rule instances");
+ for (auto it = __ruleMap.begin(); it != __ruleMap.end(); ++it) {
+ Rule* rule = static_cast<Rule*>(it->second);
+
+ int error = rule->stop();
+ if (error != ERR_NONE) {
+ _E("Failed to stop rule%d", it->first);
+ }
+
+ delete rule;
+ }
+ __ruleMap.clear();
+}
+
+bool RuleManager::init()
+{
+ bool ret;
+ int error;
+
+ // Create tables into db (rule, template)
+ std::string q1 = std::string("status INTEGER DEFAULT 0 NOT NULL, creator TEXT DEFAULT '' NOT NULL,")
+ + "packageId TEXT DEFAULT '' NOT NULL, description TEXT DEFAULT '',"
+ + "details TEXT DEFAULT '' NOT NULL";
+ ret = __dbManager.createTableSync(RULE_TABLE, q1.c_str(), NULL);
+ IF_FAIL_RETURN_TAG(ret, false, _E, "Create rule table failed");
+
+ // Before re-enable rules, handle uninstalled app's rules
+ if (__getUninstalledApp() > 0) {
+ error = __clearRuleOfUninstalledPackage(true);
+ IF_FAIL_RETURN_TAG(error == ERR_NONE, false, _E, "Failed to remove uninstalled apps' rules while initialization");
+ }
+ ret = __reenableRule();
+
+ return ret;
+}
+
+void RuleManager::handleRuleOfUninstalledPackage(std::string pkgId)
+{
+ __uninstalledPackages.insert(pkgId);
+ __clearRuleOfUninstalledPackage();
+}
+
+int RuleManager::__getUninstalledApp(void)
+{
+ // Return number of uninstalled apps
+ std::string q1 = "SELECT DISTINCT packageId FROM ContextTriggerRule";
+
+ std::vector<Json> record;
+ bool ret = __dbManager.executeSync(q1.c_str(), &record);
+ IF_FAIL_RETURN_TAG(ret, -1, _E, "Query package ids of registered rules failed");
+
+ std::vector<Json>::iterator vecEnd = record.end();
+ for (std::vector<Json>::iterator vecPos = record.begin(); vecPos != vecEnd; ++vecPos) {
+ Json elem = *vecPos;
+ std::string pkgId;
+ elem.get(NULL, "packageId", &pkgId);
+
+ if (isUninstalledPackage(pkgId)) {
+ __uninstalledPackages.insert(pkgId);
+ }
+ }
+
+ return __uninstalledPackages.size();
+}
+
+bool RuleManager::isUninstalledPackage(std::string pkgId)
+{
+ IF_FAIL_RETURN_TAG(!pkgId.empty(), false, _D, "Empty package id");
+
+ package_info_h pkgInfo;
+ int error = package_manager_get_package_info(pkgId.c_str(), &pkgInfo);
+
+ if (error == PACKAGE_MANAGER_ERROR_NONE) {
+ package_info_destroy(pkgInfo);
+ } else if (error == PACKAGE_MANAGER_ERROR_NO_SUCH_PACKAGE) {
+ // Uninstalled package found
+ _D("Uninstalled package found: %s", pkgId.c_str());
+ return true;
+ } else {
+ _E("Failed to get package info(%s): %d", pkgId.c_str(), error);
+ }
+
+ return false;
+}
+
+int RuleManager::__clearRuleOfUninstalledPackage(bool isInit)
+{
+ if (__uninstalledPackages.size() <= 0) {
+ return ERR_NONE;
+ }
+
+ int error;
+ bool ret;
+
+ _D("Clear uninstalled packages' rule started");
+ // Package list
+ std::string pkgList = "(";
+ std::set<std::string>::iterator it = __uninstalledPackages.begin();
+ pkgList += "packageId = '" + *it + "'";
+ it++;
+ for (; it != __uninstalledPackages.end(); ++it) {
+ pkgList += " OR packageId = '" + *it + "'";
+ }
+ pkgList += ")";
+
+ // After event received, disable all the enabled rules of uninstalled apps
+ if (!isInit) {
+ std::string q1 = "SELECT rowId FROM ContextTriggerRule WHERE status = 2 and (";
+ q1 += pkgList;
+ q1 += ")";
+
+ std::vector<Json> record;
+ ret = __dbManager.executeSync(q1.c_str(), &record);
+ IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Failed to query enabled rules of uninstalled packages");
+
+ std::vector<Json>::iterator vecEnd = record.end();
+ for (std::vector<Json>::iterator vecPos = record.begin(); vecPos != vecEnd; ++vecPos) {
+ Json elem = *vecPos;
+ int ruleId;
+ elem.get(NULL, "rowId", &ruleId);
+ error = disableRule(ruleId);
+ IF_FAIL_RETURN_TAG(error == ERR_NONE, error, _E, "Failed to disable rule");
+ }
+ _D("Uninstalled packages' rules are disabled");
+ }
+
+ // Delete rules of uninstalled packages from DB
+ std::string q2 = "DELETE FROM ContextTriggerRule WHERE " + pkgList;
+ std::vector<Json> dummy;
+ ret = __dbManager.executeSync(q2.c_str(), &dummy);
+ IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Failed to remove rules from db");
+ _D("Uninstalled packages' rules are deleted from db");
+
+ __uninstalledPackages.clear();
+
+ return ERR_NONE;
+}
+
+int RuleManager::pauseRuleWithItem(std::string& subject)
+{
+ std::string q = "SELECT rowId FROM ContextTriggerRule WHERE (status=2) AND (details LIKE '%\"ITEM_NAME\":\"" + subject + "\"%');";
+ std::vector<Json> record;
+ bool ret = __dbManager.executeSync(q.c_str(), &record);
+ IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Failed to query rowIds to be paused");
+ IF_FAIL_RETURN(record.size() > 0, ERR_NONE);
+
+ _D("Pause rules related to %s", subject.c_str());
+ std::vector<Json>::iterator vecEnd = record.end();
+ for (std::vector<Json>::iterator vecPos = record.begin(); vecPos != vecEnd; ++vecPos) {
+ Json elem = *vecPos;
+ int rowId;
+ elem.get(NULL, "rowId", &rowId);
+
+ int error = pauseRule(rowId);
+ IF_FAIL_RETURN_TAG(error == ERR_NONE, error, _E, "Failed to disable rules using custom item");
+ }
+
+ return ERR_NONE;
+}
+
+int RuleManager::resumeRuleWithItem(std::string& subject)
+{
+ std::string q = "SELECT rowId FROM ContextTriggerRule WHERE (status=1) AND (details LIKE '%\"ITEM_NAME\":\"" + subject + "\"%');";
+ std::vector<Json> record;
+ bool ret = __dbManager.executeSync(q.c_str(), &record);
+ IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Query paused rule ids failed");
+ IF_FAIL_RETURN(record.size() > 0, ERR_NONE);
+
+ _D("Resume rules related to %s", subject.c_str());
+ std::string qRowId;
+ std::vector<Json>::iterator vecEnd = record.end();
+ for (std::vector<Json>::iterator vecPos = record.begin(); vecPos != vecEnd; ++vecPos) {
+ Json elem = *vecPos;
+ int rowId;
+ elem.get(NULL, "rowId", &rowId);
+
+ int error = enableRule(rowId);
+ IF_FAIL_RETURN_TAG(error == ERR_NONE, error, _E, "Failed to resume rule");
+ }
+
+ return ERR_NONE;
+}
+
+bool RuleManager::__reenableRule(void)
+{
+ int error;
+ std::string q = "SELECT rowId FROM ContextTriggerRule WHERE status = 2";
+
+ std::vector<Json> record;
+ bool ret = __dbManager.executeSync(q.c_str(), &record);
+ IF_FAIL_RETURN_TAG(ret, false, _E, "Query rowIds of enabled rules failed");
+ IF_FAIL_RETURN_TAG(record.size() > 0, true, _D, "No rule to re-enable");
+
+ _D(YELLOW("Re-enable rule started"));
+
+ std::string qRowId;
+ qRowId.clear();
+ std::vector<Json>::iterator vecEnd = record.end();
+ for (std::vector<Json>::iterator vecPos = record.begin(); vecPos != vecEnd; ++vecPos) {
+ Json elem = *vecPos;
+ int rowId;
+ elem.get(NULL, "rowId", &rowId);
+
+ error = enableRule(rowId);
+ if (error == ERR_NOT_SUPPORTED) {
+ qRowId += "(rowId = " + __intToString(rowId) + ") OR ";
+ } else if (error != ERR_NONE) {
+ _E("Re-enable rule%d failed(%d)", rowId, error);
+ }
+ }
+ IF_FAIL_RETURN(!qRowId.empty(), true);
+ qRowId = qRowId.substr(0, qRowId.length() - 4);
+
+ // For rules which is failed to re-enable
+ std::string qUpdate = "UPDATE ContextTriggerRule SET status = 1 WHERE " + qRowId;
+ std::vector<Json> record2;
+ ret = __dbManager.executeSync(qUpdate.c_str(), &record2);
+ IF_FAIL_RETURN_TAG(ret, false, _E, "Failed to update rules as paused");
+
+ return true;
+}
+
+bool RuleManager::__ruleEquals(Json& lRule, Json& rRule)
+{
+ // Compare event
+ Json lEvent, rEvent;
+ lRule.get(NULL, TRIG_RULE_KEY_EVENT, &lEvent);
+ rRule.get(NULL, TRIG_RULE_KEY_EVENT, &rEvent);
+
+ std::string lEOp, rEOp;
+ lRule.get(_TRIG_RULE_KEY_EXTRA, _TRIG_RULE_KEY_EVENT_LOGICAL_OP, &lEOp);
+ rRule.get(_TRIG_RULE_KEY_EXTRA, _TRIG_RULE_KEY_EVENT_LOGICAL_OP, &rEOp);
+
+ if (lEOp != rEOp || lEvent != rEvent)
+ return false;
+
+ // Compare conditions
+ int lCondCnt, rCondCnt;
+ lCondCnt = lRule.getSize(NULL, TRIG_RULE_KEY_CONDITION);
+ rCondCnt = rRule.getSize(NULL, TRIG_RULE_KEY_CONDITION);
+ if (lCondCnt != rCondCnt)
+ return false;
+
+ std::string lOp, rOp;
+ lRule.get(_TRIG_RULE_KEY_EXTRA, _TRIG_RULE_KEY_RULE_LOGICAL_OP, &lOp);
+ rRule.get(_TRIG_RULE_KEY_EXTRA, _TRIG_RULE_KEY_RULE_LOGICAL_OP, &rOp);
+ if (lOp != rOp)
+ return false;
+
+ for (int i = 0; i < lCondCnt; i++) {
+ bool found = false;
+ Json lCond;
+ lRule.getAt(NULL, TRIG_RULE_KEY_CONDITION, i, &lCond);
+
+ std::string lCOp;
+ lRule.getAt(_TRIG_RULE_KEY_EXTRA, _TRIG_RULE_KEY_CONDITION_LOGICAL_OP, i, &lCOp);
+
+ for (int j = 0; j < lCondCnt; j++) {
+ Json rCond;
+ rRule.getAt(NULL, TRIG_RULE_KEY_CONDITION, j, &rCond);
+
+ std::string rCOp;
+ rRule.getAt(_TRIG_RULE_KEY_EXTRA, _TRIG_RULE_KEY_CONDITION_LOGICAL_OP, j, &rCOp);
+
+ if (lCOp == rCOp && lCond == rCond) {
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ return false;
+ }
+
+ // Compare action
+ Json lAction, rAction;
+ lRule.get(NULL, TRIG_RULE_KEY_ACTION, &lAction);
+ rRule.get(NULL, TRIG_RULE_KEY_ACTION, &rAction);
+ if (lAction != rAction)
+ return false;
+
+ return true;
+}
+
+int64_t RuleManager::__getDuplicatedRuleId(std::string pkgId, Json& rule)
+{
+ std::string q = "SELECT rowId, description, details FROM ContextTriggerRule WHERE packageId = '";
+ q += pkgId;
+ q += "'";
+
+ std::vector<Json> record;
+ bool ret = __dbManager.executeSync(q.c_str(), &record);
+ IF_FAIL_RETURN_TAG(ret, false, _E, "Query rowId, details by package id failed");
+
+ std::string rDesc;
+ rule.get(NULL, TRIG_RULE_KEY_DESCRIPTION, &rDesc);
+ Json rDetails = rule.str();
+ rDetails.remove(NULL, TRIG_RULE_KEY_DESCRIPTION);
+
+ std::vector<Json>::iterator vecEnd = record.end();
+ for (std::vector<Json>::iterator vecPos = record.begin(); vecPos != vecEnd; ++vecPos) {
+ Json elem = *vecPos;
+ std::string dStr;
+ Json details;
+
+ elem.get(NULL, "details", &dStr);
+ details = dStr;
+
+ if (__ruleEquals(rDetails, details)) {
+ int64_t rowId;
+ elem.get(NULL, "rowId", &rowId);
+
+ // Description comparison
+ std::string desc;
+ elem.get(NULL, "description", &desc);
+ if (rDesc.compare(desc)) {
+ // Only description is changed
+ std::string qUpdate = "UPDATE ContextTriggerRule SET description='" + rDesc + "' WHERE rowId = " + __intToString(rowId);
+
+ std::vector<Json> dummy;
+ ret = __dbManager.executeSync(qUpdate.c_str(), &dummy);
+ if (ret) {
+ _D("Rule%lld description is updated", rowId);
+ } else {
+ _W("Failed to update description of rule%lld", rowId);
+ }
+ }
+
+ return rowId;
+ }
+ }
+
+ return -1;
+}
+
+int RuleManager::__verifyRule(Json& rule, const char* creator)
+{
+ ContextMonitor* ctxMonitor = ContextMonitor::getInstance();
+ IF_FAIL_RETURN_TAG(ctxMonitor, ERR_OUT_OF_MEMORY, _E, "Memory allocation failed");
+
+ // Event
+ Json event;
+ rule.get(NULL, TRIG_RULE_KEY_EVENT, &event);
+
+ std::list<std::string> eventKey;
+ event.getKeys(&eventKey);
+ IF_FAIL_RETURN_TAG(eventKey.size() == 1, ERR_INVALID_PARAMETER, _E, "Invalid event");
+
+ std::string eventName = *eventKey.begin();
+ IF_FAIL_RETURN_TAG(ctxMonitor->isSupported(eventName), ERR_NOT_SUPPORTED, _I, "Event(%s) is not supported", eventName.c_str());
+
+ if (!ctxMonitor->isAllowed(creator, eventName.c_str())) {
+ _W("Permission denied for '%s'", eventName.c_str());
+ return ERR_PERMISSION_DENIED;
+ }
+
+ // Conditions
+ Json cond;
+ for (int i = 0; rule.getAt(NULL, TRIG_RULE_KEY_CONDITION, i, &cond); i++) {
+ std::list<std::string> condKey;
+ cond.getKeys(&condKey);
+ IF_FAIL_RETURN_TAG(condKey.size() == 1, ERR_INVALID_PARAMETER, _E, "Invalid condition");
+
+ std::string condName = *condKey.begin();
+ IF_FAIL_RETURN_TAG(ctxMonitor->isSupported(condName), ERR_NOT_SUPPORTED, _I, "Condition(%s) is not supported", condName.c_str());
+
+ if (!ctxMonitor->isAllowed(creator, condName.c_str())) {
+ _W("Permission denied for '%s'", condName.c_str());
+ return ERR_PERMISSION_DENIED;
+ }
+ }
+
+ return ERR_NONE;
+}
+
+int RuleManager::addRule(std::string creator, const char* pkgId, Json rule, Json* ruleId)
+{
+ bool ret;
+ int64_t rid;
+
+ // Check if all items are supported && allowed to access
+ int err = __verifyRule(rule, creator.c_str());
+ IF_FAIL_RETURN(err == ERR_NONE, err);
+
+ // Check if duplicated rule exits
+ if ((rid = __getDuplicatedRuleId(pkgId, rule)) > 0) {
+ // Save rule id
+ ruleId->set(NULL, TRIG_KEY_RULE_ID, rid);
+ _D("Duplicated rule found");
+ return ERR_NONE;
+ }
+
+ // Insert rule to rule table, get rule id
+ Json record;
+ std::string description;
+ rule.get(NULL, TRIG_RULE_KEY_DESCRIPTION, &description);
+
+ Json details = rule.str();
+ details.remove(NULL, TRIG_RULE_KEY_DESCRIPTION);
+ record.set(NULL, "details", details.str());
+
+ record.set(NULL, "creator", creator);
+ if (pkgId) {
+ record.set(NULL, "packageId", pkgId);
+ }
+ record.set(NULL, "description", description);
+
+ ret = __dbManager.insertSync(RULE_TABLE, record, &rid);
+ IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Insert rule to db failed");
+
+ // Save rule id
+ ruleId->set(NULL, TRIG_KEY_RULE_ID, rid);
+
+ _D("Add rule%d succeeded", (int)rid);
+ return ERR_NONE;
+}
+
+
+int RuleManager::removeRule(int ruleId)
+{
+ bool ret;
+
+ // Delete rule from DB
+ std::string query = "DELETE FROM 'ContextTriggerRule' where rowId = ";
+ query += __intToString(ruleId);
+
+ std::vector<Json> record;
+ ret = __dbManager.executeSync(query.c_str(), &record);
+ IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Remove rule from db failed");
+
+ _D("Remove rule%d succeeded", ruleId);
+
+ return ERR_NONE;
+}
+
+int RuleManager::enableRule(int ruleId)
+{
+ int error;
+ std::string query;
+ std::vector<Json> record;
+ std::vector<Json> dummy;
+ std::string pkgId;
+ Json jRule;
+ std::string tmp;
+ std::string idStr = __intToString(ruleId);
+
+ Rule* rule;
+
+ // Get rule Json by rule id;
+ query = "SELECT details, packageId FROM ContextTriggerRule WHERE rowId = ";
+ query += idStr;
+ error = (__dbManager.executeSync(query.c_str(), &record))? ERR_NONE : ERR_OPERATION_FAILED;
+ IF_FAIL_RETURN_TAG(error == ERR_NONE, error, _E, "Query rule by rule id failed");
+
+ record[0].get(NULL, "details", &tmp);
+ jRule = tmp;
+ record[0].get(NULL, "packageId", &pkgId);
+
+ // Create a rule instance
+ rule = new(std::nothrow) Rule(ruleId, jRule, pkgId.c_str(), this);
+ IF_FAIL_RETURN_TAG(rule, ERR_OUT_OF_MEMORY, _E, "Failed to create rule instance");
+
+ // Start the rule
+ error = rule->start();
+ IF_FAIL_CATCH_TAG(error == ERR_NONE, _E, "Failed to start rule%d", ruleId);
+
+ // Update db to set 'enabled'
+ query = "UPDATE ContextTriggerRule SET status = 2 WHERE rowId = ";
+ query += idStr;
+ error = (__dbManager.executeSync(query.c_str(), &dummy))? ERR_NONE : ERR_OPERATION_FAILED;
+ IF_FAIL_CATCH_TAG(error == ERR_NONE, _E, "Update db failed");
+
+ // Add rule instance to __ruleMap
+ __ruleMap[ruleId] = rule;
+
+ _D(YELLOW("Enable Rule%d succeeded"), ruleId);
+ return ERR_NONE;
+
+CATCH:
+ delete rule;
+ rule = NULL;
+
+ return error;
+}
+
+int RuleManager::disableRule(int ruleId)
+{
+ bool ret;
+ int error;
+
+ auto it = __ruleMap.find(ruleId);
+ bool paused = (it == __ruleMap.end());
+
+ // For 'enabled' rule, not 'paused'
+ if (!paused) {
+ // Stop the rule
+ Rule* rule = static_cast<Rule*>(it->second);
+ error = rule->stop();
+ IF_FAIL_RETURN_TAG(error == ERR_NONE, error, _E, "Failed to stop rule%d", ruleId);
+
+ // Remove rule instance from __ruleMap
+ delete rule;
+ __ruleMap.erase(it);
+ }
+
+ // Update db to set 'disabled' // TODO skip while clear uninstalled rule
+ std::string query = "UPDATE ContextTriggerRule SET status = 0 WHERE rowId = ";
+ query += __intToString(ruleId);
+ std::vector<Json> record;
+ ret = __dbManager.executeSync(query.c_str(), &record);
+ IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Update db failed");
+
+ _D(YELLOW("Disable Rule%d succeeded"), ruleId);
+ return ERR_NONE;
+}
+
+int RuleManager::pauseRule(int ruleId)
+{
+ bool ret;
+ int error;
+
+ auto it = __ruleMap.find(ruleId);
+ IF_FAIL_RETURN_TAG(it != __ruleMap.end(), ERR_OPERATION_FAILED, _E, "Rule instance not found");
+
+ // Stop the rule
+ Rule* rule = static_cast<Rule*>(it->second);
+ error = rule->stop();
+ IF_FAIL_RETURN_TAG(error == ERR_NONE, error, _E, "Failed to stop rule%d", ruleId);
+
+ // Update db to set 'paused'
+ std::string query = "UPDATE ContextTriggerRule SET status = 1 WHERE rowId = ";
+
+ query += __intToString(ruleId);
+ std::vector<Json> record;
+ ret = __dbManager.executeSync(query.c_str(), &record);
+ IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Update db failed");
+
+ // Remove rule instance from __ruleMap
+ delete rule;
+ __ruleMap.erase(it);
+
+ _D(YELLOW("Pause Rule%d"), ruleId);
+ return ERR_NONE;
+}
+
+int RuleManager::checkRule(std::string pkgId, int ruleId)
+{
+ // Get package id
+ std::string q = "SELECT packageId FROM ContextTriggerRule WHERE rowId =";
+ q += __intToString(ruleId);
+
+ std::vector<Json> record;
+ bool ret = __dbManager.executeSync(q.c_str(), &record);
+ IF_FAIL_RETURN_TAG(ret, false, _E, "Query package id by rule id failed");
+
+ if (record.size() == 0) {
+ return ERR_NO_DATA;
+ }
+
+ std::string p;
+ record[0].get(NULL, "packageId", &p);
+
+ if (p.compare(pkgId) == 0) {
+ return ERR_NONE;
+ }
+
+ return ERR_NO_DATA;
+}
+
+bool RuleManager::isRuleEnabled(int ruleId)
+{
+ std::string q = "SELECT status FROM ContextTriggerRule WHERE rowId =";
+ q += __intToString(ruleId);
+
+ std::vector<Json> record;
+ bool ret = __dbManager.executeSync(q.c_str(), &record);
+ IF_FAIL_RETURN_TAG(ret, false, _E, "Query enabled by rule id failed");
+
+ int status;
+ record[0].get(NULL, "status", &status);
+
+ return (status != 0);
+}
+
+int RuleManager::getRuleById(std::string pkgId, int ruleId, Json* requestResult)
+{
+ std::string q = "SELECT description FROM ContextTriggerRule WHERE (packageId = '";
+ q += pkgId;
+ q += "') and (rowId = ";
+ q += __intToString(ruleId);
+ q += ")";
+
+ std::vector<Json> record;
+ bool ret = __dbManager.executeSync(q.c_str(), &record);
+ IF_FAIL_RETURN_TAG(ret, false, _E, "Query rule by rule id failed");
+
+ if (record.size() == 0) {
+ return ERR_NO_DATA;
+ } else if (record.size() != 1) {
+ return ERR_OPERATION_FAILED;
+ }
+
+ std::string description;
+ record[0].get(NULL, "description", &description);
+
+ (*requestResult).set(NULL, TRIG_KEY_RULE_ID, ruleId);
+ (*requestResult).set(NULL, TRIG_RULE_KEY_DESCRIPTION, description);
+
+ return ERR_NONE;
+}
+
+int RuleManager::getRuleIds(std::string pkgId, Json* requestResult)
+{
+ (*requestResult) = RULE_IDS_JSON;
+
+ std::string q = "SELECT rowId, status FROM ContextTriggerRule WHERE (packageId = '";
+ q += pkgId;
+ q += "')";
+
+ std::vector<Json> record;
+ bool ret = __dbManager.executeSync(q.c_str(), &record);
+ IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Query rules failed");
+
+ std::vector<Json>::iterator vecEnd = record.end();
+ for (std::vector<Json>::iterator vecPos = record.begin(); vecPos != vecEnd; ++vecPos) {
+ Json elem = *vecPos;
+ std::string id;
+ int status;
+
+ elem.get(NULL, "rowId", &id);
+ elem.get(NULL, "status", &status);
+
+ if (status >= 1) {
+ (*requestResult).append(NULL, TRIG_KEY_ENABLED_IDS, __stringToInt(id));
+ } else if (status == 0) {
+ (*requestResult).append(NULL, TRIG_KEY_DISABLED_IDS, __stringToInt(id));
+ }
+ }
+
+ return ERR_NONE;
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _CONTEXT_TRIGGER_RULE_MANAGER_H_
+#define _CONTEXT_TRIGGER_RULE_MANAGER_H_
+
+#include <set>
+#include <map>
+#include <DatabaseManager.h>
+
+namespace ctx {
+
+ class Json;
+
+namespace trigger {
+
+ class Trigger;
+ class Rule;
+
+ class RuleManager {
+ public:
+ RuleManager();
+ ~RuleManager();
+
+ bool init();
+ int addRule(std::string creator, const char* pkgId, Json rule, Json* ruleId);
+ int removeRule(int ruleId);
+ int enableRule(int ruleId);
+ int disableRule(int ruleId);
+ int getRuleById(std::string pkgId, int ruleId, Json* requestResult);
+ int getRuleIds(std::string pkgId, Json* requestResult);
+ int checkRule(std::string pkgId, int ruleId);
+ bool isRuleEnabled(int ruleId);
+ int pauseRuleWithItem(std::string& subject);
+ int pauseRule(int ruleId);
+ int resumeRuleWithItem(std::string& subject);
+ void handleRuleOfUninstalledPackage(std::string pkgId);
+
+ static bool isUninstalledPackage(std::string pkgId);
+
+ private:
+ bool __reenableRule(void);
+ int __verifyRule(Json& rule, const char* creator);
+ int64_t __getDuplicatedRuleId(std::string pkgId, Json& rule);
+ bool __ruleEquals(Json& lRule, Json& rRule);
+ int __getUninstalledApp(void);
+ int __clearRuleOfUninstalledPackage(bool isInit = false);
+ void __applyTemplates(void);
+
+ std::set<std::string> __uninstalledPackages;
+ std::map<int, Rule*> __ruleMap;
+ DatabaseManager __dbManager;
+ }; /* class RuleManager */
+
+} /* namespace trigger */
+} /* namespace ctx */
+
+#endif /* End of _CONTEXT_TRIGGER_RULE_MANAGER_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sstream>
+#include <Types.h>
+#include <TriggerTypes.h>
+#include "../ContextManager.h"
+#include "RuleManager.h"
+#include "TemplateManager.h"
+
+using namespace ctx;
+using namespace ctx::trigger;
+
+TemplateManager *TemplateManager::__instance = NULL;
+ContextManager *TemplateManager::__contextMgr = NULL;
+RuleManager *TemplateManager::__ruleMgr = NULL;
+
+static std::string __intToString(int i)
+{
+ std::ostringstream convert;
+ convert << i;
+ std::string str = convert.str();
+ return str;
+}
+
+TemplateManager::TemplateManager()
+{
+}
+
+TemplateManager::~TemplateManager()
+{
+}
+
+void TemplateManager::setManager(ContextManager* ctxMgr, RuleManager* ruleMgr)
+{
+ __contextMgr = ctxMgr;
+ __ruleMgr = ruleMgr;
+}
+
+TemplateManager* TemplateManager::getInstance()
+{
+ IF_FAIL_RETURN_TAG(__contextMgr, NULL, _E, "Context manager is needed");
+ IF_FAIL_RETURN_TAG(__ruleMgr, NULL, _E, "Rule manager is needed");
+
+ IF_FAIL_RETURN(!__instance, __instance);
+
+ __instance = new(std::nothrow) TemplateManager();
+ IF_FAIL_RETURN_TAG(__instance, NULL, _E, "Memory alllocation failed");
+
+ return __instance;
+}
+
+void TemplateManager::destroy()
+{
+ IF_FAIL_VOID(__instance);
+
+ __instance->applyTemplates();
+
+ delete __instance;
+ __instance = NULL;
+}
+
+bool TemplateManager::init()
+{
+ std::string q = std::string("CREATE TABLE IF NOT EXISTS ContextTriggerTemplate ")
+ + "(name TEXT DEFAULT '' NOT NULL PRIMARY KEY, operation INTEGER DEFAULT 3 NOT NULL, "
+ + "attributes TEXT DEFAULT '' NOT NULL, options TEXT DEFAULT '' NOT NULL, owner TEXT DEFAULT '' NOT NULL)";
+
+ std::vector<Json> record;
+ bool ret = __dbManager.executeSync(q.c_str(), &record);
+ IF_FAIL_RETURN_TAG(ret, false, _E, "Create template table failed");
+
+ // Apply templates
+ applyTemplates();
+
+ return true;
+}
+
+void TemplateManager::applyTemplates()
+{
+ std::string subject;
+ int operation;
+ Json attributes;
+ Json options;
+ std::string owner;
+ std::string query;
+ query.clear();
+
+ while (__contextMgr->popTriggerTemplate(subject, operation, attributes, options)) {
+ registerTemplate(subject, operation, attributes, options, "");
+ }
+}
+
+void TemplateManager::registerTemplate(std::string subject, int operation, Json attributes, Json options, std::string owner)
+{
+ _D("[Add template] Subject: %s, Ops: %d, Owner: %s", subject.c_str(), operation, owner.c_str());
+ _J("Attr", attributes);
+ _J("Opt", options);
+
+ std::string query = "UPDATE ContextTriggerTemplate SET operation=" + __intToString(operation)
+ + ", attributes='" + attributes.str() + "', options='" + options.str() + "', owner='" + owner
+ + "' WHERE name='" + subject + "'; ";
+
+ query += "INSERT OR IGNORE INTO ContextTriggerTemplate (name, operation, attributes, options, owner) VALUES ('"
+ + subject + "', " + __intToString(operation) + ", '" + attributes.str() + "', '" + options.str() + "', '"
+ + owner + "'); ";
+
+ std::vector<Json> record;
+ bool ret = __dbManager.executeSync(query.c_str(), &record);
+ IF_FAIL_VOID_TAG(ret, _E, "Update template db failed");
+
+ if (!owner.empty()) {
+ __ruleMgr->resumeRuleWithItem(subject);
+ }
+}
+
+void TemplateManager::unregisterTemplate(std::string subject)
+{
+ _D("[Remove template] Subject: %s", subject.c_str());
+ std::string query = "DELETE FROM ContextTriggerTemplate WHERE name = '" + subject + "'; ";
+
+ std::vector<Json> record;
+ bool ret = __dbManager.executeSync(query.c_str(), &record);
+ IF_FAIL_VOID_TAG(ret, _E, "Update template db failed");
+
+ __ruleMgr->pauseRuleWithItem(subject);
+}
+
+
+std::string TemplateManager::__addTemplate(std::string &subject, int &operation, Json &attributes, Json &options, std::string &owner)
+{
+ _D("[Add template] Subject: %s, Ops: %d, Owner: %s", subject.c_str(), operation, owner.c_str());
+ _J("Attr", attributes);
+ _J("Opt", options);
+
+ std::string query = "UPDATE ContextTriggerTemplate SET operation=" + __intToString(operation)
+ + ", attributes='" + attributes.str() + "', options='" + options.str() + "', owner='" + owner
+ + "' WHERE name='" + subject + "'; ";
+
+ query += "INSERT OR IGNORE INTO ContextTriggerTemplate (name, operation, attributes, options, owner) VALUES ('"
+ + subject + "', " + __intToString(operation) + ", '" + attributes.str() + "', '" + options.str() + "', '"
+ + owner + "'); ";
+
+ return query;
+}
+
+std::string TemplateManager::__removeTemplate(std::string &subject)
+{
+ _D("[Remove template] Subject: %s", subject.c_str());
+ std::string query = "DELETE FROM ContextTriggerTemplate WHERE name = '" + subject + "'; ";
+
+ return query;
+}
+
+int TemplateManager::getTemplate(std::string &subject, Json* tmpl)
+{
+ if (!__contextMgr->isSupported(subject.c_str()))
+ return ERR_NOT_SUPPORTED;
+
+ // Update latest template information
+ std::string q = "SELECT * FROM ContextTriggerTemplate WHERE name = '" + subject + "'";
+
+ std::vector<Json> record;
+ bool ret = __dbManager.executeSync(q.c_str(), &record);
+ IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Query template failed");
+ IF_FAIL_RETURN_TAG(record.size() > 0, ERR_NOT_SUPPORTED, _E, "Template(%s) not found", subject.c_str());
+ IF_FAIL_RETURN_TAG(record.size() == 1, ERR_OPERATION_FAILED, _E, "Tepmlate duplicated");
+
+ (*tmpl) = *record.begin();
+
+ std::string optStr;
+ std::string attrStr;
+ tmpl->get(NULL, TRIG_TMPL_KEY_OPTION, &optStr);
+ tmpl->get(NULL, TRIG_TMPL_KEY_ATTRIBUTE, &attrStr);
+
+ Json opt = optStr;
+ Json attr = attrStr;
+
+ tmpl->set(NULL, TRIG_TMPL_KEY_OPTION, opt);
+ tmpl->set(NULL, TRIG_TMPL_KEY_ATTRIBUTE, attr);
+
+ return ERR_NONE;
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _CONTEXT_TRIGGER_TEMPLATE_MANAGER_H_
+#define _CONTEXT_TRIGGER_TEMPLATE_MANAGER_H_
+
+#include <Json.h>
+#include <DatabaseManager.h>
+
+namespace ctx {
+
+ class ContextManager;
+
+namespace trigger {
+
+ class RuleManager;
+
+ class TemplateManager {
+ public:
+ static TemplateManager* getInstance();
+ static void setManager(ContextManager* ctxMgr, RuleManager* ruleMgr);
+ static void destroy();
+
+ bool init();
+ void applyTemplates();
+ int getTemplate(std::string &subject, Json* tmpl);
+ void registerTemplate(std::string subject, int operation, Json attributes, Json options, std::string owner);
+ void unregisterTemplate(std::string subject);
+
+ private:
+ TemplateManager();
+ TemplateManager(const TemplateManager& other);
+ ~TemplateManager();
+
+ static TemplateManager *__instance;
+ static ContextManager *__contextMgr;
+ static RuleManager *__ruleMgr;
+
+ DatabaseManager __dbManager;
+
+ std::string __addTemplate(std::string &subject, int &operation, Json &attributes, Json &options, std::string &owner);
+ std::string __removeTemplate(std::string &subject);
+
+ }; /* class TemplateManager */
+
+} /* namespace trigger */
+} /* namespace ctx */
+
+#endif /* End of _CONTEXT_TRIGGER_TEMPLATE_MANAGER_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <Types.h>
+#include <TriggerTypes.h>
+#include "Trigger.h"
+#include "ContextMonitor.h"
+#include "TemplateManager.h"
+#include "RuleManager.h"
+
+using namespace ctx;
+using namespace ctx::trigger;
+
+Trigger::Trigger() :
+ __ruleMgr(NULL)
+{
+}
+
+Trigger::~Trigger()
+{
+}
+
+bool Trigger::init(ContextManager* ctxMgr)
+{
+ // Do the necessary initialization process.
+ // This function is called from the main thread during the service launching process.
+ _D("Context Trigger Init");
+ __processInitialize(ctxMgr);
+
+ return true;
+}
+
+void Trigger::release()
+{
+ // Release the occupied resources.
+ // This function is called from the main thread during the service termination process.
+
+ _D("Template Manager Destroy");
+ TemplateManager::destroy();
+
+ _D("Rule Manager Release");
+ delete __ruleMgr;
+ __ruleMgr = NULL;
+
+ _D("Context Monitor Destroy");
+ ContextMonitor::destroy();
+}
+
+bool Trigger::assignRequest(RequestInfo* request)
+{
+ std::string subject = request->getSubject();
+ if (subject != SUBJ_TRIGGER_ADD && subject != SUBJ_TRIGGER_REMOVE &&
+ subject != SUBJ_TRIGGER_ENABLE && subject != SUBJ_TRIGGER_DISABLE &&
+ subject != SUBJ_TRIGGER_GET && subject != SUBJ_TRIGGER_GET_RULE_IDS &&
+ subject != SUBJ_TRIGGER_GET_TEMPLATE) {
+ return false;
+ }
+
+ __processRequest(request);
+ return true;
+}
+
+void Trigger::__processRequest(RequestInfo* request)
+{
+ // Process the request, and reply to the client if necessary.
+ const char* reqSubj = request->getSubject();
+ _D("Request is %s", reqSubj);
+ std::string subject(reqSubj);
+
+ if (subject == SUBJ_TRIGGER_ADD) {
+ __addRule(request);
+ } else if (subject == SUBJ_TRIGGER_REMOVE) {
+ __removeRule(request);
+ } else if (subject == SUBJ_TRIGGER_ENABLE) {
+ __enableRule(request);
+ } else if (subject == SUBJ_TRIGGER_DISABLE) {
+ __disableRule(request);
+ } else if (subject == SUBJ_TRIGGER_GET) {
+ __getRuleById(request);
+ } else if (subject == SUBJ_TRIGGER_GET_RULE_IDS) {
+ __getRuleIds(request);
+ } else if (subject == SUBJ_TRIGGER_GET_TEMPLATE) {
+ __getTemplate(request);
+ } else {
+ _E("Invalid request");
+ }
+
+ delete request;
+}
+
+void Trigger::__processInitialize(ContextManager* mgr)
+{
+ // Context Monitor
+ ContextMonitor::setContextManager(mgr);
+
+ // Rule Manager
+ __ruleMgr = new(std::nothrow) RuleManager();
+ IF_FAIL_VOID_TAG(__ruleMgr, _E, "Memory allocation failed");
+
+ // Template Manager
+ TemplateManager::setManager(mgr, __ruleMgr);
+ TemplateManager* tmplMgr = TemplateManager::getInstance();
+ IF_FAIL_VOID_TAG(tmplMgr, _E, "Memory allocation failed");
+
+ // Initialization
+ if (!tmplMgr->init()) {
+ _E("Template manager initialization failed");
+ raise(SIGTERM);
+ }
+
+ if (!__ruleMgr->init()) {
+ _E("Context trigger initialization failed");
+ raise(SIGTERM);
+ }
+}
+
+void Trigger::__addRule(RequestInfo* request)
+{
+ Json ruleId;
+
+ const char* client = request->getClient();
+ if (client == NULL) {
+ request->reply(ERR_OPERATION_FAILED);
+ return;
+ }
+
+ const char* pkgId = request->getPackageId();
+
+ int error = __ruleMgr->addRule(client, pkgId, request->getDescription(), &ruleId);
+ _I("'%s' adds a rule (Error: %#x)", request->getClient(), error);
+
+ request->reply(error, ruleId);
+}
+
+void Trigger::__removeRule(RequestInfo* request)
+{
+ int id;
+ int error;
+
+ const char* pkgId = request->getPackageId();
+
+ Json ruleId = request->getDescription();
+ ruleId.get(NULL, TRIG_KEY_RULE_ID, &id);
+
+ error = __ruleMgr->checkRule((pkgId)? pkgId : "", id);
+ if (error != ERR_NONE) {
+ request->reply(error);
+ return;
+ }
+
+ bool ret = __ruleMgr->isRuleEnabled(id);
+ if (ret) {
+ request->reply(ERR_RULE_ENABLED);
+ return;
+ }
+
+ error = __ruleMgr->removeRule(id);
+ _I("'%s' removes rule%d (Error: %#x)", request->getClient(), id, error);
+ request->reply(error);
+}
+
+void Trigger::__enableRule(RequestInfo* request)
+{
+ int id;
+ int error;
+
+ const char* pkgId = request->getPackageId();
+
+ Json ruleId = request->getDescription();
+ ruleId.get(NULL, TRIG_KEY_RULE_ID, &id);
+
+ error = __ruleMgr->checkRule((pkgId)? pkgId : "", id);
+ if (error != ERR_NONE) {
+ request->reply(error);
+ return;
+ }
+
+ bool ret = __ruleMgr->isRuleEnabled(id);
+ if (ret) {
+ request->reply(ERR_RULE_ENABLED);
+ return;
+ }
+
+ error = __ruleMgr->enableRule(id);
+ _I("'%s' enables rule%d (Error: %#x)", request->getClient(), id, error);
+ request->reply(error);
+}
+
+void Trigger::__disableRule(RequestInfo* request)
+{
+ int id;
+ int error;
+
+ const char* pkgId = request->getPackageId();
+
+ Json ruleId = request->getDescription();
+ ruleId.get(NULL, TRIG_KEY_RULE_ID, &id);
+
+ error = __ruleMgr->checkRule((pkgId)? pkgId : "", id);
+ if (error != ERR_NONE) {
+ request->reply(error);
+ return;
+ }
+
+ bool ret = __ruleMgr->isRuleEnabled(id);
+ if (!ret) {
+ request->reply(ERR_RULE_NOT_ENABLED);
+ return;
+ }
+
+ error = __ruleMgr->disableRule(id);
+ _I("'%s' disables rule%d (Error: %#x)", request->getClient(), id, error);
+ request->reply(error);
+}
+
+void Trigger::__getRuleById(RequestInfo* request)
+{
+ int error;
+
+ Json option = request->getDescription();
+ int id;
+ option.get(NULL, TRIG_KEY_RULE_ID, &id);
+
+ const char* pkgId = request->getPackageId();
+
+ Json readData;
+ error = __ruleMgr->getRuleById((pkgId)? pkgId : "", id, &readData);
+
+ Json dummy;
+ request->reply(error, dummy, readData);
+}
+
+void Trigger::__getRuleIds(RequestInfo* request)
+{
+ int error;
+
+ const char* pkgId = request->getPackageId();
+
+ Json readData;
+ error = __ruleMgr->getRuleIds((pkgId)? pkgId : "", &readData);
+
+ Json dummy;
+ request->reply(error, dummy, readData);
+}
+
+void Trigger::__getTemplate(RequestInfo* request)
+{
+ int error;
+
+ Json option = request->getDescription();
+ std::string name;
+ option.get(NULL, TRIG_TMPL_KEY_SUBJECT, &name);
+
+ TemplateManager* tmplMgr = TemplateManager::getInstance();
+ if (!tmplMgr) {
+ _E("Memory allocation failed");
+ request->reply(ERR_OUT_OF_MEMORY);
+ return;
+ }
+
+ Json tmpl;
+ error = tmplMgr->getTemplate(name, &tmpl);
+
+ Json dummy;
+ request->reply(error, dummy, tmpl);
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _CONTEXT_TRIGGER_TRIGGER_H_
+#define _CONTEXT_TRIGGER_TRIGGER_H_
+
+#include "../Request.h"
+
+namespace ctx {
+
+ class client_request;
+ class ContextManager;
+
+namespace trigger {
+
+ class RuleManager;
+
+ class Trigger {
+ public:
+ Trigger();
+ ~Trigger();
+
+ bool init(ContextManager* ctxMgr);
+ void release();
+
+ bool assignRequest(RequestInfo* request);
+
+ private:
+ void __processRequest(RequestInfo* request);
+ void __processInitialize(ContextManager* mgr);
+
+ void __addRule(RequestInfo* request);
+ void __removeRule(RequestInfo* request);
+ void __enableRule(RequestInfo* request);
+ void __disableRule(RequestInfo* request);
+ void __getRuleById(RequestInfo* request);
+ void __getRuleIds(RequestInfo* request);
+ void __getTemplate(RequestInfo* request);
+
+ RuleManager* __ruleMgr;
+ };
+
+} /* namespace trigger */
+} /* namespace ctx */
+
+#endif /* End of _CONTEXT_TRIGGER_TRIGGER_H_ */