Integrate the legacy context-service into the agent service (1/2) 88/122088/1
authorMu-Woong Lee <muwoong.lee@samsung.com>
Thu, 30 Mar 2017 06:59:32 +0000 (15:59 +0900)
committerMu-Woong Lee <muwoong.lee@samsung.com>
Thu, 30 Mar 2017 06:59:32 +0000 (15:59 +0900)
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>
41 files changed:
src/agent/CMakeLists.txt
src/agent/legacy/ClientRequest.cpp [new file with mode: 0644]
src/agent/legacy/ClientRequest.h [new file with mode: 0644]
src/agent/legacy/ContextManager.cpp [new file with mode: 0644]
src/agent/legacy/ContextManager.h [new file with mode: 0644]
src/agent/legacy/DBusServer.cpp [new file with mode: 0644]
src/agent/legacy/DBusServer.h [new file with mode: 0644]
src/agent/legacy/ProviderHandler.cpp [new file with mode: 0644]
src/agent/legacy/ProviderHandler.h [new file with mode: 0644]
src/agent/legacy/ProviderLoader.cpp [new file with mode: 0644]
src/agent/legacy/ProviderLoader.h [new file with mode: 0644]
src/agent/legacy/Request.cpp [new file with mode: 0644]
src/agent/legacy/Request.h [new file with mode: 0644]
src/agent/legacy/Server.cpp [new file with mode: 0644]
src/agent/legacy/Server.h [new file with mode: 0644]
src/agent/legacy/access_control/PeerCreds.cpp [new file with mode: 0644]
src/agent/legacy/access_control/PeerCreds.h [new file with mode: 0644]
src/agent/legacy/access_control/Privilege.cpp [new file with mode: 0644]
src/agent/legacy/access_control/Privilege.h [new file with mode: 0644]
src/agent/legacy/policy/PolicyManager.cpp [new file with mode: 0644]
src/agent/legacy/policy/PolicyManager.h [new file with mode: 0644]
src/agent/legacy/policy/PolicyRequest.cpp [new file with mode: 0644]
src/agent/legacy/policy/PolicyRequest.h [new file with mode: 0644]
src/agent/legacy/trigger/ActionManager.cpp [new file with mode: 0644]
src/agent/legacy/trigger/ActionManager.h [new file with mode: 0644]
src/agent/legacy/trigger/ContextMonitor.cpp [new file with mode: 0644]
src/agent/legacy/trigger/ContextMonitor.h [new file with mode: 0644]
src/agent/legacy/trigger/FactRequest.cpp [new file with mode: 0644]
src/agent/legacy/trigger/FactRequest.h [new file with mode: 0644]
src/agent/legacy/trigger/FactTypes.h [new file with mode: 0644]
src/agent/legacy/trigger/IContextListener.h [new file with mode: 0644]
src/agent/legacy/trigger/Rule.cpp [new file with mode: 0644]
src/agent/legacy/trigger/Rule.h [new file with mode: 0644]
src/agent/legacy/trigger/RuleEvaluator.cpp [new file with mode: 0644]
src/agent/legacy/trigger/RuleEvaluator.h [new file with mode: 0644]
src/agent/legacy/trigger/RuleManager.cpp [new file with mode: 0644]
src/agent/legacy/trigger/RuleManager.h [new file with mode: 0644]
src/agent/legacy/trigger/TemplateManager.cpp [new file with mode: 0644]
src/agent/legacy/trigger/TemplateManager.h [new file with mode: 0644]
src/agent/legacy/trigger/Trigger.cpp [new file with mode: 0644]
src/agent/legacy/trigger/Trigger.h [new file with mode: 0644]

index 114362f..a97f2b1 100644 (file)
@@ -4,7 +4,7 @@ SET(target "contextd-agent")
 
 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)
diff --git a/src/agent/legacy/ClientRequest.cpp b/src/agent/legacy/ClientRequest.cpp
new file mode 100644 (file)
index 0000000..e625bf0
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * 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;
+}
diff --git a/src/agent/legacy/ClientRequest.h b/src/agent/legacy/ClientRequest.h
new file mode 100644 (file)
index 0000000..69d18e1
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * 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_ */
diff --git a/src/agent/legacy/ContextManager.cpp b/src/agent/legacy/ContextManager.cpp
new file mode 100644 (file)
index 0000000..7d07966
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ * 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;
+}
diff --git a/src/agent/legacy/ContextManager.h b/src/agent/legacy/ContextManager.h
new file mode 100644 (file)
index 0000000..9be24c1
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * 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_ */
diff --git a/src/agent/legacy/DBusServer.cpp b/src/agent/legacy/DBusServer.cpp
new file mode 100644 (file)
index 0000000..ff43612
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ * 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);
+}
diff --git a/src/agent/legacy/DBusServer.h b/src/agent/legacy/DBusServer.h
new file mode 100644 (file)
index 0000000..c4b1c32
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * 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_ */
diff --git a/src/agent/legacy/ProviderHandler.cpp b/src/agent/legacy/ProviderHandler.cpp
new file mode 100644 (file)
index 0000000..2ce7f69
--- /dev/null
@@ -0,0 +1,310 @@
+/*
+ * 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;
+}
diff --git a/src/agent/legacy/ProviderHandler.h b/src/agent/legacy/ProviderHandler.h
new file mode 100644 (file)
index 0000000..58225f7
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * 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_ */
diff --git a/src/agent/legacy/ProviderLoader.cpp b/src/agent/legacy/ProviderLoader.cpp
new file mode 100644 (file)
index 0000000..8a7d6a6
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * 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;
+}
diff --git a/src/agent/legacy/ProviderLoader.h b/src/agent/legacy/ProviderLoader.h
new file mode 100644 (file)
index 0000000..ab5a427
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * 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_ */
diff --git a/src/agent/legacy/Request.cpp b/src/agent/legacy/Request.cpp
new file mode 100644 (file)
index 0000000..d900fcc
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * 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;
+}
diff --git a/src/agent/legacy/Request.h b/src/agent/legacy/Request.h
new file mode 100644 (file)
index 0000000..9750b2f
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * 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_ */
diff --git a/src/agent/legacy/Server.cpp b/src/agent/legacy/Server.cpp
new file mode 100644 (file)
index 0000000..197b0d6
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * 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;
+}
diff --git a/src/agent/legacy/Server.h b/src/agent/legacy/Server.h
new file mode 100644 (file)
index 0000000..cd93bbf
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * 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_ */
diff --git a/src/agent/legacy/access_control/PeerCreds.cpp b/src/agent/legacy/access_control/PeerCreds.cpp
new file mode 100644 (file)
index 0000000..336da5a
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * 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;
+}
diff --git a/src/agent/legacy/access_control/PeerCreds.h b/src/agent/legacy/access_control/PeerCreds.h
new file mode 100644 (file)
index 0000000..255244e
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * 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_ */
diff --git a/src/agent/legacy/access_control/Privilege.cpp b/src/agent/legacy/access_control/Privilege.cpp
new file mode 100644 (file)
index 0000000..da2bdae
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * 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());
+}
diff --git a/src/agent/legacy/access_control/Privilege.h b/src/agent/legacy/access_control/Privilege.h
new file mode 100644 (file)
index 0000000..6eb1198
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * 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_ */
diff --git a/src/agent/legacy/policy/PolicyManager.cpp b/src/agent/legacy/policy/PolicyManager.cpp
new file mode 100644 (file)
index 0000000..3f97344
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * 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;
+}
diff --git a/src/agent/legacy/policy/PolicyManager.h b/src/agent/legacy/policy/PolicyManager.h
new file mode 100644 (file)
index 0000000..ce9b315
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * 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_ */
diff --git a/src/agent/legacy/policy/PolicyRequest.cpp b/src/agent/legacy/policy/PolicyRequest.cpp
new file mode 100644 (file)
index 0000000..63cf8ae
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * 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;
+}
diff --git a/src/agent/legacy/policy/PolicyRequest.h b/src/agent/legacy/policy/PolicyRequest.h
new file mode 100644 (file)
index 0000000..2ed28c7
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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_ */
diff --git a/src/agent/legacy/trigger/ActionManager.cpp b/src/agent/legacy/trigger/ActionManager.cpp
new file mode 100644 (file)
index 0000000..b45671f
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * 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, &param);
+
+       DBusServer::call(busName, object, iface, method, param);
+}
diff --git a/src/agent/legacy/trigger/ActionManager.h b/src/agent/legacy/trigger/ActionManager.h
new file mode 100644 (file)
index 0000000..273f450
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * 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_ */
diff --git a/src/agent/legacy/trigger/ContextMonitor.cpp b/src/agent/legacy/trigger/ContextMonitor.cpp
new file mode 100644 (file)
index 0000000..5dab7f5
--- /dev/null
@@ -0,0 +1,318 @@
+/*
+ * 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);
+       }
+}
diff --git a/src/agent/legacy/trigger/ContextMonitor.h b/src/agent/legacy/trigger/ContextMonitor.h
new file mode 100644 (file)
index 0000000..473cac2
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * 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_ */
diff --git a/src/agent/legacy/trigger/FactRequest.cpp b/src/agent/legacy/trigger/FactRequest.cpp
new file mode 100644 (file)
index 0000000..fc09d9d
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * 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;
+}
diff --git a/src/agent/legacy/trigger/FactRequest.h b/src/agent/legacy/trigger/FactRequest.h
new file mode 100644 (file)
index 0000000..8c54fe8
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * 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_ */
diff --git a/src/agent/legacy/trigger/FactTypes.h b/src/agent/legacy/trigger/FactTypes.h
new file mode 100644 (file)
index 0000000..fe50f11
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * 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_ */
diff --git a/src/agent/legacy/trigger/IContextListener.h b/src/agent/legacy/trigger/IContextListener.h
new file mode 100644 (file)
index 0000000..826ab41
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * 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_ */
diff --git a/src/agent/legacy/trigger/Rule.cpp b/src/agent/legacy/trigger/Rule.cpp
new file mode 100644 (file)
index 0000000..33b2ef8
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * 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;
+}
diff --git a/src/agent/legacy/trigger/Rule.h b/src/agent/legacy/trigger/Rule.h
new file mode 100644 (file)
index 0000000..1192b6e
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * 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_ */
diff --git a/src/agent/legacy/trigger/RuleEvaluator.cpp b/src/agent/legacy/trigger/RuleEvaluator.cpp
new file mode 100644 (file)
index 0000000..b0e5833
--- /dev/null
@@ -0,0 +1,385 @@
+/*
+ * 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;
+}
diff --git a/src/agent/legacy/trigger/RuleEvaluator.h b/src/agent/legacy/trigger/RuleEvaluator.h
new file mode 100644 (file)
index 0000000..3e79682
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * 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_ */
diff --git a/src/agent/legacy/trigger/RuleManager.cpp b/src/agent/legacy/trigger/RuleManager.cpp
new file mode 100644 (file)
index 0000000..11a9561
--- /dev/null
@@ -0,0 +1,697 @@
+/*
+ * 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;
+}
diff --git a/src/agent/legacy/trigger/RuleManager.h b/src/agent/legacy/trigger/RuleManager.h
new file mode 100644 (file)
index 0000000..cf47eee
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * 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_ */
diff --git a/src/agent/legacy/trigger/TemplateManager.cpp b/src/agent/legacy/trigger/TemplateManager.cpp
new file mode 100644 (file)
index 0000000..65ddc39
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * 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;
+}
diff --git a/src/agent/legacy/trigger/TemplateManager.h b/src/agent/legacy/trigger/TemplateManager.h
new file mode 100644 (file)
index 0000000..c91ef15
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * 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_ */
diff --git a/src/agent/legacy/trigger/Trigger.cpp b/src/agent/legacy/trigger/Trigger.cpp
new file mode 100644 (file)
index 0000000..bb3c7aa
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+ * 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);
+}
diff --git a/src/agent/legacy/trigger/Trigger.h b/src/agent/legacy/trigger/Trigger.h
new file mode 100644 (file)
index 0000000..161c99e
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * 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_ */