Add DBusClient & IDBusClientListener 48/59648/2
authorMu-Woong Lee <muwoong.lee@samsung.com>
Wed, 17 Feb 2016 06:20:20 +0000 (15:20 +0900)
committerMu-Woong Lee <muwoong.lee@samsung.com>
Wed, 17 Feb 2016 06:40:49 +0000 (15:40 +0900)
They replace the former request_handler implemented in context-common.
Note that, request_handler is now just a wrapper between DBusClient and each API, thus it will be removed later.

Change-Id: If62abfbced70cb93ad8178796f7b70035e1ec2fc
Signed-off-by: Mu-Woong Lee <muwoong.lee@samsung.com>
src/DBusClient.cpp [new file with mode: 0644]
src/DBusClient.h [new file with mode: 0644]
src/IDBusClientListener.h [new file with mode: 0644]
src/context_history.cpp
src/context_trigger.cpp
src/request_handler.cpp [new file with mode: 0644]
src/request_handler.h [new file with mode: 0644]
src/rule_validator.cpp
testsuite/CMakeLists.txt

diff --git a/src/DBusClient.cpp b/src/DBusClient.cpp
new file mode 100644 (file)
index 0000000..e85944e
--- /dev/null
@@ -0,0 +1,332 @@
+/*
+ * 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_internal.h>
+#include <ScopeMutex.h>
+#include "DBusClient.h"
+
+using namespace ctx;
+
+static const gchar __introspection[] =
+       "<node>"
+       "       <interface name='" DBUS_IFACE "'>"
+       "               <method name='" METHOD_RESPOND "'>"
+       "                       <arg type='i' name='" ARG_REQID "' direction='in'/>"
+       "                       <arg type='s' name='" ARG_SUBJECT "' direction='in'/>"
+       "                       <arg type='i' name='" ARG_RESULT_ERR "' direction='in'/>"
+       "                       <arg type='s' name='" ARG_OUTPUT "' direction='in'/>"
+       "               </method>"
+       "       </interface>"
+       "</node>";
+
+GDBusConnection *DBusClient::__connection = NULL;
+GDBusNodeInfo *DBusClient::__nodeInfo = NULL;
+std::atomic_int DBusClient::__instanceCount(0);
+std::map<std::string, IDBusClientListener*> DBusClient::__listenerMap;
+
+DBusClient::DBusClient()
+{
+       ++__instanceCount;
+}
+
+DBusClient::~DBusClient()
+{
+       if (--__instanceCount == 0)
+               __release();
+}
+
+void DBusClient::__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(name, METHOD_RESPOND), _W, "Invalid method: %s", name);
+
+       gint reqId = 0;
+       const gchar *subject = NULL;
+       gint error = 0;
+       const gchar *data = NULL;
+
+       g_variant_get(param, "(i&si&s)", &reqId, &subject, &error, &data);
+       _D("[Response] ReqId: %d, Subject: %s, Error: %d", reqId, subject, error);
+       IF_FAIL_VOID_TAG(subject && data, _W, "Invalid parameter");
+
+       auto it = __listenerMap.find(subject);
+       it->second->onPublish(subject, reqId, error, data);
+
+       g_dbus_method_invocation_return_value(invocation, NULL);
+}
+
+bool DBusClient::__init()
+{
+       static GMutex mutex;
+       ScopeMutex sm(&mutex);
+
+       if (__connection)
+               return true;
+
+       GError *gerr = NULL;
+       gchar *addr = NULL;
+       GDBusInterfaceVTable vtable;
+       guint regId;
+
+       __nodeInfo = g_dbus_node_info_new_for_xml(__introspection, NULL);
+       IF_FAIL_RETURN_TAG(__nodeInfo != NULL, false, _E, "Initialization failed");
+
+       addr = g_dbus_address_get_for_bus_sync(G_BUS_TYPE_SESSION, NULL, &gerr);
+       HANDLE_GERROR(gerr);
+       IF_FAIL_CATCH_TAG(addr != NULL, _E, "Getting address failed");
+       _SD("Address: %s", addr);
+
+       __connection = g_dbus_connection_new_for_address_sync(addr,
+                       (GDBusConnectionFlags)(G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT | G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION),
+                       NULL, NULL, &gerr);
+       g_free(addr);
+       HANDLE_GERROR(gerr);
+       IF_FAIL_CATCH_TAG(__connection != NULL, _E, "Connection failed");
+
+       vtable.method_call = __onMethodCalled;
+       vtable.get_property = NULL;
+       vtable.set_property = NULL;
+
+       regId = g_dbus_connection_register_object(__connection, DBUS_PATH,
+                       __nodeInfo->interfaces[0], &vtable, NULL, NULL, &gerr);
+       HANDLE_GERROR(gerr);
+       IF_FAIL_CATCH_TAG(regId>0, _E, "Object registration failed");
+
+       _I("DBus connection established");
+       _D("DBus name: %s", g_dbus_connection_get_unique_name(__connection));
+       return true;
+
+CATCH:
+       __release();
+       return false;
+}
+
+void DBusClient::__release()
+{
+       if (__connection) {
+               g_dbus_connection_flush_sync(__connection, NULL, NULL);
+               g_dbus_connection_close_sync(__connection, NULL, NULL);
+               g_object_unref(__connection);
+               __connection = NULL;
+       }
+
+       if (__nodeInfo) {
+               g_dbus_node_info_unref(__nodeInfo);
+               __nodeInfo = NULL;
+       }
+
+       _I("DBus connection released");
+}
+
+int DBusClient::__request(int type, int reqId, const char *subject, const char *input,
+               std::string *result, std::string *outputData)
+{
+       _D("Requesting: %d, %d, %s", type, reqId, subject);
+
+       if (input == NULL)
+               input = EMPTY_JSON_OBJECT;
+
+       /* FIXME: the second param is the security cookie, which is deprected in 3.0.
+        * We need to completely REMOVE this parameter from the dbus protocol. */
+       GVariant *param = g_variant_new("(isiss)", type, "", reqId, subject, input);
+       IF_FAIL_RETURN_TAG(param, ERR_OUT_OF_MEMORY, _E, "Memory allocation failed");
+
+       GError *err = NULL;
+       GVariant *response = g_dbus_connection_call_sync(__connection, DBUS_DEST, DBUS_PATH, DBUS_IFACE,
+                       METHOD_REQUEST, param, NULL, G_DBUS_CALL_FLAGS_NONE, DBUS_TIMEOUT, NULL, &err);
+       HANDLE_GERROR(err);
+       IF_FAIL_RETURN_TAG(response, ERR_OPERATION_FAILED, _E, "Method call failed");
+
+       gint error = ERR_OPERATION_FAILED;
+       const gchar *resultStr = NULL;
+       const gchar *dataStr = NULL;
+
+       g_variant_get(response, "(i&s&s)", &error, &resultStr, &dataStr);
+
+       if (result && resultStr)
+               *result = resultStr;
+
+       if (outputData && dataStr)
+               *outputData = dataStr;
+
+       g_variant_unref(response);
+
+       return error;
+}
+
+int DBusClient::__request(int type, int reqId, const char* subject, const char* input)
+{
+       _D("Requesting: %d, %d, %s", type, reqId, subject);
+
+       if (input == NULL)
+               input = EMPTY_JSON_OBJECT;
+
+       /* FIXME: the second param is the security cookie, which is deprected in 3.0.
+        * We need to completely REMOVE this parameter from the dbus protocol. */
+       GVariant *param = g_variant_new("(isiss)", type, "", reqId, subject, input);
+       IF_FAIL_RETURN_TAG(param, ERR_OUT_OF_MEMORY, _E, "Memory allocation failed");
+
+       GError *err = NULL;
+       g_dbus_connection_call(__connection, DBUS_DEST, DBUS_PATH, DBUS_IFACE,
+                       METHOD_REQUEST, param, NULL, G_DBUS_CALL_FLAGS_NONE, DBUS_TIMEOUT, NULL, NULL, &err);
+
+       if (err) {
+               HANDLE_GERROR(err);
+               return ERR_OPERATION_FAILED;
+       }
+
+       return ERR_NONE;
+}
+
+int DBusClient::__generateReqId()
+{
+       static GMutex mutex;
+       static int reqId = 0;
+
+       ctx::ScopeMutex sm(&mutex);
+
+       /* Overflow handling */
+       if (++reqId < 0)
+               reqId = 1;
+
+       return reqId;
+}
+
+void DBusClient::addListener(std::string subject, IDBusClientListener *listener)
+{
+       _D("Registering the listener for '%s'", subject.c_str());
+
+       static GMutex mutex;
+       ctx::ScopeMutex sm(&mutex);
+
+       __listenerMap[subject] = listener;
+}
+
+int DBusClient::isSupported(std::string subject)
+{
+       IF_FAIL_RETURN(__init(), ERR_OPERATION_FAILED);
+
+       return __request(REQ_SUPPORT, __generateReqId(), subject.c_str(), NULL, NULL, NULL);
+}
+
+int DBusClient::subscribe(std::string subject, json option, int *reqId, json *result)
+{
+       IF_FAIL_RETURN(__init(), ERR_OPERATION_FAILED);
+       ASSERT_NOT_NULL(reqId);
+
+       *reqId = __generateReqId();
+
+       _I("[Subscribe] ReqId: %d, Subject: %s", *reqId, subject.c_str());
+
+       std::string resultStr;
+       int error = __request(REQ_SUBSCRIBE, *reqId, subject.c_str(), option.str().c_str(), &resultStr, NULL);
+
+       if (result)
+               *result = resultStr;
+
+       _D("Error: %#x", error);
+       _SD("Result: %s", resultStr.c_str());
+
+       return error;
+}
+
+int DBusClient::unsubscribe(std::string subject, int reqId)
+{
+       IF_FAIL_RETURN(__init(), ERR_OPERATION_FAILED);
+
+       _I("[Unsubscribe] ReqId: %d, Subject: %s", reqId, subject.c_str());
+
+       return __request(REQ_UNSUBSCRIBE, reqId, subject.c_str(), NULL, NULL, NULL);
+}
+
+int DBusClient::read(std::string subject, json option, int *reqId, json *result)
+{
+       IF_FAIL_RETURN(__init(), ERR_OPERATION_FAILED);
+       ASSERT_NOT_NULL(reqId);
+
+       *reqId = __generateReqId();
+
+       _I("[Read] ReqId: %d, Subject: %s", *reqId, subject.c_str());
+
+       std::string resultStr;
+       int error = __request(REQ_READ, *reqId, subject.c_str(), option.str().c_str(), &resultStr, NULL);
+
+       if (result)
+               *result = resultStr;
+
+       _D("Error: %#x", error);
+       _SD("Result: %s", resultStr.c_str());
+
+       return error;
+}
+
+int DBusClient::readSync(std::string subject, json option, int *reqId, json *outputData)
+{
+       IF_FAIL_RETURN(__init(), ERR_OPERATION_FAILED);
+       ASSERT_NOT_NULL(reqId);
+       ASSERT_NOT_NULL(outputData);
+
+       *reqId = __generateReqId();
+
+       _I("[ReadSync] ReqId: %d, Subject: %s", *reqId, subject.c_str());
+
+       std::string output;
+       int error = __request(REQ_READ_SYNC, *reqId, subject.c_str(), option.str().c_str(), NULL, &output);
+
+       *outputData = output;
+
+       _D("Error: %#x", error);
+       _SD("Data: %s", output.c_str());
+
+       return error;
+}
+
+int DBusClient::write(std::string subject, json inputData)
+{
+       IF_FAIL_RETURN(__init(), ERR_OPERATION_FAILED);
+
+       int reqId = __generateReqId();
+
+       _I("[Write] ReqId: %d, Subject: %s", reqId, subject.c_str());
+       _SD("Data: %s", inputData.str().c_str());
+
+       int error = __request(REQ_WRITE, reqId, subject.c_str(), inputData.str().c_str());
+       _D("Error: %#x", error);
+
+       return error;
+}
+
+int DBusClient::write(std::string subject, json inputData, json *result)
+{
+       IF_FAIL_RETURN(__init(), ERR_OPERATION_FAILED);
+
+       int reqId = __generateReqId();
+
+       _I("[Write with reply] ReqId: %d, Subject: %s", reqId, subject.c_str());
+       _SD("Data: %s", inputData.str().c_str());
+
+       std::string resultStr;
+       int error = __request(REQ_WRITE, reqId, subject.c_str(), inputData.str().c_str(), &resultStr, NULL);
+
+       if (result)
+               *result = resultStr;
+
+       _D("Error: %#x", error);
+       _SD("Result: %s", resultStr.c_str());
+
+       return error;
+}
diff --git a/src/DBusClient.h b/src/DBusClient.h
new file mode 100644 (file)
index 0000000..4078dbc
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * 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_DBUS_CLIENT_H_
+#define _CONTEXT_DBUS_CLIENT_H_
+
+#include <glib.h>
+#include <gio/gio.h>
+#include <string>
+#include <map>
+#include <atomic>
+#include "IDBusClientListener.h"
+
+namespace ctx {
+
+       class DBusClient {
+       public:
+               DBusClient();
+               ~DBusClient();
+
+               void addListener(std::string subject, IDBusClientListener *listener);
+
+               int isSupported(std::string subject);
+
+               int subscribe(std::string subject, json option, int *reqId, json *result);
+               int unsubscribe(std::string subject, int reqId);
+               int read(std::string subject, json option, int *reqId, json *result);
+               int readSync(std::string subject, json option, int *reqId, json *outputData);
+               int write(std::string subject, json inputData);
+               int write(std::string subject, json inputData, json *result);
+
+       private:
+               static void __onMethodCalled(GDBusConnection *conn, const gchar *sender,
+                               const gchar *path, const gchar *iface, const gchar *name,
+                               GVariant *param, GDBusMethodInvocation *invocation, gpointer userData);
+
+               bool __init();
+               void __release();
+               int __request(int type, int reqId, const char *subject, const char *input,
+                               std::string *result, std::string *outputData);
+               int __request(int type, int reqId, const char *subject, const char *input);
+               int __generateReqId();
+
+
+               static GDBusConnection *__connection;
+               static GDBusNodeInfo *__nodeInfo;
+               static std::atomic_int __instanceCount;
+               static std::map<std::string, IDBusClientListener*> __listenerMap;
+
+       };      /* class ctx::DBusClient */
+
+}      /* namespace ctx */
+
+#endif // _CONTEXT_DBUS_CLIENT_H_
diff --git a/src/IDBusClientListener.h b/src/IDBusClientListener.h
new file mode 100644 (file)
index 0000000..69bd0d2
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * 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_I_DBUS_CLIENT_LISTENER_H_
+#define _CONTEXT_I_DBUS_CLIENT_LISTENER_H_
+
+#include <string>
+#include <json.h>
+
+namespace ctx {
+
+       class IDBusClientListener {
+       public:
+               virtual ~IDBusClientListener() {}
+               virtual void onPublish(std::string subject, int reqId, int error, json event) = 0;
+       };
+
+}      /* namespace ctx */
+
+#endif /* End of _CONTEXT_I_DBUS_CLIENT_LISTENER_H_ */
index eea980e..d418690 100644 (file)
@@ -16,9 +16,9 @@
 
 #include <map>
 #include <json.h>
-#include <request_handler.h>
 #include <context_history.h>
 #include <context_history_types_internal.h>
+#include "request_handler.h"
 
 #define TYPE_INT 0
 #define TYPE_STRING 1
index fe03b69..606e3fa 100644 (file)
@@ -25,7 +25,7 @@
 #include <context_trigger_internal.h>
 #include <context_trigger_types_internal.h>
 #include <pkgmgr-info.h>
-#include <request_handler.h>
+#include "request_handler.h"
 #include "rule_validator.h"
 #include "priv_util.h"
 
diff --git a/src/request_handler.cpp b/src/request_handler.cpp
new file mode 100644 (file)
index 0000000..920ee23
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+
+/* TODO: Remove this request_handler. All APIs and the testsuite should use DBusClient directly. */
+
+#include <string>
+#include <map>
+
+#include <types_internal.h>
+#include <ScopeMutex.h>
+#include "DBusClient.h"
+#include "request_handler.h"
+
+using namespace ctx;
+
+class DBusClientListenerImpl : public IDBusClientListener {
+public:
+       DBusClientListenerImpl() {}
+       ~DBusClientListenerImpl() {}
+       void setCb(std::string subject, request_handler::subject_response_cb cb);
+       void onPublish(std::string subject, int reqId, int error, json event);
+private:
+       std::map<std::string, request_handler::subject_response_cb> __callbackMap;
+};
+
+void DBusClientListenerImpl::setCb(std::string subject, request_handler::subject_response_cb cb)
+{
+       __callbackMap[subject] = cb;
+}
+
+void DBusClientListenerImpl::onPublish(std::string subject, int reqId, int error, json event)
+{
+       auto it = __callbackMap.find(subject);
+       IF_FAIL_VOID_TAG(it != __callbackMap.end(), _W, "Unregistered subject");
+       it->second(subject.c_str(), reqId, error, event);
+}
+
+static DBusClientListenerImpl __dbusListener;
+static DBusClient __dbusClient;
+
+EXTAPI int ctx::request_handler::subscribe(const char* subject, ctx::json* option, int* req_id, ctx::json* request_result)
+{
+       return __dbusClient.subscribe(subject, option ? *option : NULL, req_id, request_result);
+}
+
+EXTAPI int ctx::request_handler::unsubscribe(const char* subject, int req_id)
+{
+       return __dbusClient.unsubscribe(subject, req_id);
+}
+
+EXTAPI int ctx::request_handler::read(const char* subject, ctx::json* option, int* req_id, ctx::json* request_result)
+{
+       return __dbusClient.read(subject, option ? *option : NULL, req_id, request_result);
+}
+
+EXTAPI int ctx::request_handler::read_sync(const char* subject, ctx::json* option, int* req_id, ctx::json* data_read)
+{
+       return __dbusClient.readSync(subject, option ? *option : NULL, req_id, data_read);
+}
+
+EXTAPI int ctx::request_handler::write(const char* subject, ctx::json* data)
+{
+       return __dbusClient.write(subject, *data);
+}
+
+EXTAPI int ctx::request_handler::write_with_reply(const char* subject, ctx::json* data, ctx::json* request_result)
+{
+       return __dbusClient.write(subject, *data, request_result);
+}
+
+EXTAPI int ctx::request_handler::is_supported(const char* subject)
+{
+       return __dbusClient.isSupported(subject);
+}
+
+EXTAPI bool ctx::request_handler::register_callback(const char* subject, subject_response_cb callback)
+{
+       __dbusListener.setCb(subject, callback);
+       __dbusClient.addListener(subject, &__dbusListener);
+       return true;
+}
diff --git a/src/request_handler.h b/src/request_handler.h
new file mode 100644 (file)
index 0000000..d90f6f1
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * 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_LIB_REQUEST_HANDLER_H__
+#define __CONTEXT_LIB_REQUEST_HANDLER_H__
+
+#include <json.h>
+
+namespace ctx { namespace request_handler {
+
+       /*
+        */
+       typedef void(* subject_response_cb)(const char* subject, int req_id, int error, ctx::json response);
+
+       /*
+        */
+       bool register_callback(const char* subject, subject_response_cb callback);
+
+       /*
+        */
+       int subscribe(const char* subject, ctx::json* option, int* req_id, ctx::json* request_result = NULL);
+
+       /*
+        */
+       int unsubscribe(const char* subject, int req_id);
+
+       /*
+        */
+       int read(const char* subject, ctx::json* option, int* req_id, ctx::json* request_result = NULL);
+
+       /*
+        */
+       int read_sync(const char* subject, ctx::json* option, int* req_id, ctx::json* data_read);
+
+       /*
+        */
+       int write(const char* subject, ctx::json* data);
+
+       /*
+        */
+       int write_with_reply(const char* subject, ctx::json* data, ctx::json* request_result = NULL);
+
+       /*
+        */
+       int is_supported(const char* subject);
+
+} }    /* namespace ctx::request_handler */
+
+#endif // __CONTEXT_LIB_REQUEST_HANDLER_H__
index f1a1f8a..f4bb504 100644 (file)
@@ -20,7 +20,7 @@
 #include <types_internal.h>
 #include <context_trigger.h>
 #include <context_trigger_types_internal.h>
-#include <request_handler.h>
+#include "request_handler.h"
 #include "rule_validator.h"
 
 #define KEY_TEMPLATE "templates"
index 65981a5..30e85d2 100644 (file)
@@ -4,6 +4,9 @@ SET(TEST_EXEC context-test)
 
 # Source List
 FILE(GLOB_RECURSE TEST_SRCS src/*.cpp)
+INCLUDE_DIRECTORIES(
+       ${CMAKE_SOURCE_DIR}/src
+)
 
 ADD_EXECUTABLE(${TEST_EXEC} ${TEST_SRCS})
 TARGET_LINK_LIBRARIES(${TEST_EXEC} ${api_pkg_LDFLAGS} ${target} -pie)