sensor-recorder: restore CtxJson to prevent crash issue 55/155555/1
authorkibak.yoon <kibak.yoon@samsung.com>
Fri, 13 Oct 2017 13:29:48 +0000 (22:29 +0900)
committerkibak.yoon <kibak.yoon@samsung.com>
Fri, 13 Oct 2017 13:32:44 +0000 (22:32 +0900)
Change-Id: I7078393fd0613f43b55d65981bd02c65b36c8b14
Signed-off-by: kibak.yoon <kibak.yoon@samsung.com>
CMakeLists.txt
include/CtxJson.h [new file with mode: 0644]
packaging/context-sensor-recorder.spec
src/shared/CtxJson.cpp [new file with mode: 0644]

index 745ada6..412fd39 100644 (file)
@@ -2,7 +2,7 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
 PROJECT(context-sensor-recorder)
 INCLUDE(GNUInstallDirs)
 
-SET(DEPS "glib-2.0 gio-2.0 dlog capi-base-common")
+SET(DEPS "glib-2.0 gio-2.0 json-glib-1.0 dlog capi-base-common")
 SET(INCDIR "${CMAKE_INSTALL_INCLUDEDIR}/context-service")
 
 INCLUDE_DIRECTORIES(
diff --git a/include/CtxJson.h b/include/CtxJson.h
new file mode 100644 (file)
index 0000000..4f661e4
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * 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_JSON_H__
+#define __CONTEXT_JSON_H__
+
+#include <sys/types.h>
+#include <string>
+#include <list>
+#include <ContextTypes.h>
+
+#define _J(cmt, jobj) \
+do { \
+       _SD("%s: %s", (cmt), jobj.str().c_str()); \
+} while (0)
+
+#define EMPTY_JSON_OBJECT      "{}"
+
+namespace ctx {
+
+       class EXPORT_API CtxJson {
+       public:
+               CtxJson();
+               CtxJson(const char *s);
+               CtxJson(const std::string &s);
+
+               /* This CtxJson(const CtxJson &j) only copies the reference to the underlying CtxJson node.
+                * Therefore, changes applied to a CtxJson object affect the other.
+                * If you need to create a 'real' copy of a CtxJson, which can be manipulated separately,
+                * utilize the str() function, e.g., ctx::CtxJson copy(original.str());
+                */
+               CtxJson(const CtxJson &j);
+
+               ~CtxJson();
+
+               CtxJson& operator=(const char *s);
+               CtxJson& operator=(const std::string &s);
+
+               /* This operator=(const CtxJson &j) only copies the reference to the underlying CtxJson node.
+                * Therefore, changes applied to a CtxJson object affect the other.
+                * If you need to create a 'real' copy of a CtxJson, which can be manipulated separately,
+                * utilize the str() function, e.g., ctx::CtxJson copy = original.str();
+                */
+               CtxJson& operator=(const CtxJson &j);
+
+               bool operator==(const CtxJson &rhs);
+               bool operator!=(const CtxJson &rhs);
+
+               std::string str();
+
+               bool getKeys(std::list<std::string> *list);
+               bool valid();
+
+               bool set(const char *path, const char *key, CtxJson &val);
+               bool set(const char *path, const char *key, int val);
+               bool set(const char *path, const char *key, int64_t val);
+               bool set(const char *path, const char *key, double val);
+               bool set(const char *path, const char *key, std::string val);
+               bool set(const char *path, const char *key, GVariant *val);
+
+               bool get(const char *path, const char *key, CtxJson *val);
+               bool get(const char *path, const char *key, int *val);
+               bool get(const char *path, const char *key, int64_t *val);
+               bool get(const char *path, const char *key, double *val);
+               bool get(const char *path, const char *key, std::string *val);
+               bool get(const char *path, const char *key, GVariant **val);
+
+               bool remove(const char *path, const char *key);
+
+               /* Array operations */
+               int getSize(const char *path, const char *key);
+
+               bool append(const char *path, const char *key, CtxJson &val);
+               bool append(const char *path, const char *key, int val);
+               bool append(const char *path, const char *key, int64_t val);
+               bool append(const char *path, const char *key, double val);
+               bool append(const char *path, const char *key, std::string val);
+
+               bool setAt(const char *path, const char *key, int index, CtxJson &val);
+               bool setAt(const char *path, const char *key, int index, int val);
+               bool setAt(const char *path, const char *key, int index, int64_t val);
+               bool setAt(const char *path, const char *key, int index, double val);
+               bool setAt(const char *path, const char *key, int index, std::string val);
+
+               bool getAt(const char *path, const char *key, int index, CtxJson *val);
+               bool getAt(const char *path, const char *key, int index, int *val);
+               bool getAt(const char *path, const char *key, int index, int64_t *val);
+               bool getAt(const char *path, const char *key, int index, double *val);
+               bool getAt(const char *path, const char *key, int index, std::string *val);
+
+       private:
+               typedef struct _JsonNode json_node_t;
+               json_node_t *__jsonNode;
+
+               void __parse(const char *s);
+               void __release();
+               char* __strDup();
+
+               /* For json vs json comparison */
+               bool __getMembers(json_node_t *node, std::list<std::string> &list);
+               bool __nodeEq(json_node_t *lhs, json_node_t *rhs);
+               bool __valueEq(json_node_t *lhs, json_node_t *rhs);
+               bool __objectEq(json_node_t *lhs, json_node_t *rhs);
+               bool __arrayEq(json_node_t *lhs, json_node_t *rhs);
+       };
+
+}      /* namespace ctx */
+
+#endif /* __CONTEXT_JSON_H__ */
index aaadc2d..45f1913 100644 (file)
@@ -9,6 +9,7 @@ Source0:    %{name}-%{version}.tar.gz
 BuildRequires: cmake
 BuildRequires: pkgconfig(glib-2.0)
 BuildRequires: pkgconfig(gio-2.0)
+BuildRequires: pkgconfig(json-glib-1.0)
 BuildRequires: pkgconfig(dlog)
 BuildRequires: pkgconfig(sensor)
 BuildRequires: pkgconfig(capi-base-common)
diff --git a/src/shared/CtxJson.cpp b/src/shared/CtxJson.cpp
new file mode 100644 (file)
index 0000000..c226271
--- /dev/null
@@ -0,0 +1,926 @@
+/*
+ * 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 <cstdio>
+#include <string>
+#include <vector>
+#include <sstream>
+#include <locale>
+#include <iomanip>
+#include <json-glib/json-glib.h>
+#include <CtxJson.h>
+
+#define PATH_DELIM     '.'
+#define MAX_PRECISION 15
+#define GVAR_VALUES    "values"
+#define GVAR_TYPES     "types"
+
+#define STR_EQ(X, Y) (g_strcmp0((X), (Y)) == 0)
+
+using namespace ctx;
+
+static std::string __double_to_string(double in)
+{
+       /* Locale-independent double-to-string conversion */
+       int prec = MAX_PRECISION;
+       std::string out;
+       std::ostringstream ostr;
+
+       ostr.imbue(std::locale("C"));
+       ostr << std::setprecision(prec) << in;
+       out = ostr.str();
+
+       if (out.find('e') == std::string::npos)
+               return out;
+
+       /* If 'out' is in scientific notation */
+       ostr.clear();
+       ostr.str(std::string());
+       ostr.imbue(std::locale("C"));
+
+       /* Get the number of fraction digits to precisely print the number */
+       double number = in * 10;
+       while (static_cast<int>(number) == 0) {
+               number *= 10;
+               ++prec;
+       }
+
+       ostr << std::fixed << std::setprecision(prec) << in;
+       out = ostr.str();
+
+       /* Remove trailing '0' */
+       std::size_t found = out.find_last_not_of("0");
+       if (found != std::string::npos)
+               out.erase(found + 1);
+
+       /* If 'out' ends with '.' */
+       if (out.back() == '.')
+               out.erase(out.end() - 1);
+
+       return out;
+}
+
+static double __string_to_double(const char* in)
+{
+       IF_FAIL_RETURN_TAG(in, 0, _E, "Parameter NULL");
+
+       double out;
+
+       /* Locale-independent string-to-double conversion */
+       std::istringstream istr(in);
+       istr.imbue(std::locale("C"));
+       istr >> out;
+
+       return out;
+}
+
+CtxJson::CtxJson() :
+       __jsonNode(NULL)
+{
+       JsonObject *obj = json_object_new();
+       IF_FAIL_VOID_TAG(obj, _E, "CtxJson object construction failed");
+
+       __jsonNode = json_node_new(JSON_NODE_OBJECT);
+       if (!__jsonNode) {
+               json_object_unref(obj);
+               _E("CtxJson object construction failed");
+       }
+
+       json_node_set_object(__jsonNode, obj);
+       json_object_unref(obj);
+}
+
+CtxJson::CtxJson(const CtxJson &j)
+       : __jsonNode(NULL)
+{
+       __jsonNode = json_node_copy(j.__jsonNode);
+       IF_FAIL_VOID_TAG(__jsonNode, _E, "CtxJson object construction failed");
+}
+
+CtxJson::CtxJson(const char *s)
+       : __jsonNode(NULL)
+{
+       if (s) {
+               __parse(s);
+       } else {
+               __parse(EMPTY_JSON_OBJECT);
+       }
+}
+
+CtxJson::CtxJson(const std::string &s)
+       : __jsonNode(NULL)
+{
+       if (s.empty()) {
+               __parse(EMPTY_JSON_OBJECT);
+       } else {
+               __parse(s.c_str());
+       }
+}
+
+CtxJson::~CtxJson()
+{
+       __release();
+}
+
+void CtxJson::__parse(const char *s)
+{
+       gboolean result;
+       JsonParser *parser = NULL;
+       JsonNode *root = NULL;
+
+       parser = json_parser_new();
+       IF_FAIL_VOID_TAG(parser, _E, "Memory allocation failed");
+
+       result = json_parser_load_from_data(parser, s, -1, NULL);
+       IF_FAIL_CATCH_TAG(result, _E, "Parsing failed");
+
+       root = json_parser_get_root(parser);
+       IF_FAIL_CATCH_TAG(root, _E, "Getting root failed");
+
+       __jsonNode = json_node_copy(root);
+       IF_FAIL_CATCH_TAG(__jsonNode, _E, "Copying failed");
+
+CATCH:
+       if (parser)
+               g_object_unref(parser);
+}
+
+void CtxJson::__release()
+{
+       if (__jsonNode) {
+               json_node_free(__jsonNode);
+               __jsonNode = NULL;
+       }
+}
+
+bool CtxJson::valid()
+{
+       return (__jsonNode != NULL);
+}
+
+CtxJson& CtxJson::operator=(const CtxJson &j)
+{
+       __release();
+       __jsonNode = json_node_copy(j.__jsonNode);
+       if (!__jsonNode) {
+               _E("CtxJson object copy failed");
+       }
+       return *this;
+}
+
+CtxJson& CtxJson::operator=(const char *s)
+{
+       __release();
+       if (s) {
+               __parse(s);
+       } else {
+               __parse(EMPTY_JSON_OBJECT);
+       }
+       return *this;
+}
+
+CtxJson& CtxJson::operator=(const std::string &s)
+{
+       __release();
+       if (s.empty()) {
+               __parse(EMPTY_JSON_OBJECT);
+       } else {
+               __parse(s.c_str());
+       }
+       return *this;
+}
+
+bool CtxJson::operator==(const CtxJson &rhs)
+{
+       return __nodeEq(__jsonNode, rhs.__jsonNode);
+}
+
+bool CtxJson::operator!=(const CtxJson &rhs)
+{
+       return !operator==(rhs);
+}
+
+char* CtxJson::__strDup()
+{
+       IF_FAIL_RETURN_TAG(__jsonNode, NULL, _E, "CtxJson object not initialized");
+
+       JsonGenerator *jgen = NULL;
+       char *output = NULL;
+
+       jgen = json_generator_new();
+       IF_FAIL_CATCH(jgen);
+
+       json_generator_set_root(jgen, __jsonNode);
+       output = json_generator_to_data(jgen, NULL);
+       IF_FAIL_CATCH(output);
+
+       g_object_unref(jgen);
+       return output;
+
+CATCH:
+       if (jgen) {
+               g_object_unref(jgen);
+       }
+
+       _E("Memory allocation failed");
+       return NULL;
+}
+
+std::string CtxJson::str()
+{
+       std::string output;
+       char *_s = __strDup();
+       IF_FAIL_RETURN(_s, output = EMPTY_JSON_OBJECT);
+
+       output = _s;
+       g_free(_s);
+
+       return output;
+}
+
+static std::vector<std::string> __tokenize_path(std::string path)
+{
+       std::vector<std::string> tokens;
+       std::size_t begin = 0;
+       std::size_t end = path.find(PATH_DELIM, 0);
+
+       while (end != std::string::npos) {
+               tokens.push_back(path.substr(begin, end - begin));
+               begin = end + 1;
+               end = path.find(PATH_DELIM, begin);
+       }
+
+       tokens.push_back(path.substr(begin));
+       return tokens;
+}
+
+static JsonObject* __traverse(JsonNode *jnode, const char *path, bool force)
+{
+       IF_FAIL_RETURN_TAG(jnode, NULL, _E, "Invalid parameter");
+
+       unsigned int depth = 0;
+       std::vector<std::string> pathToken;
+       JsonObject *jobj = NULL;
+       JsonObject *childObj = NULL;
+       JsonNode *childNode = NULL;
+
+       jobj = json_node_get_object(jnode);
+       IF_FAIL_RETURN(jobj, NULL);
+
+       if (path)
+               pathToken = __tokenize_path(path);
+
+       for (depth = 0; depth < pathToken.size(); depth++) {
+               if (!json_object_has_member(jobj, pathToken[depth].c_str())) {
+                       if (!force) {
+                               return NULL;
+                       }
+                       childObj = json_object_new();
+                       IF_FAIL_RETURN_TAG(childObj, NULL, _E, "Memory allocation failed");
+                       json_object_set_object_member(jobj, pathToken[depth].c_str(), childObj);
+               }
+               childNode = json_object_get_member(jobj, pathToken[depth].c_str());
+               IF_FAIL_RETURN(childNode && json_node_get_node_type(childNode) == JSON_NODE_OBJECT, NULL);
+
+               jobj = json_node_get_object(childNode);
+               IF_FAIL_RETURN(jobj, NULL);
+       }
+
+       return jobj;
+}
+
+bool CtxJson::set(const char *path, const char *key, CtxJson &val)
+{
+       IF_FAIL_RETURN_TAG(this->__jsonNode, false, _E, "CtxJson object not initialized");
+       IF_FAIL_RETURN_TAG(key && val.__jsonNode, false, _E, "Invalid parameter");
+
+       JsonObject *jobj = __traverse(__jsonNode, path, true);
+       IF_FAIL_RETURN(jobj, false);
+
+       if (json_object_has_member(jobj, key))
+               json_object_remove_member(jobj, key);
+
+       json_object_set_member(jobj, key, val.__jsonNode);
+       val.__jsonNode = NULL;
+       val = CtxJson();
+
+       return true;
+}
+
+bool CtxJson::set(const char *path, const char *key, int val)
+{
+       return set(path, key, static_cast<int64_t>(val));
+}
+
+bool CtxJson::set(const char *path, const char *key, int64_t val)
+{
+       IF_FAIL_RETURN_TAG(this->__jsonNode, false, _E, "CtxJson object not initialized");
+       IF_FAIL_RETURN_TAG(key, false, _E, "Invalid parameter");
+
+       JsonObject *jobj = __traverse(__jsonNode, path, true);
+       IF_FAIL_RETURN(jobj, false);
+
+       if (json_object_has_member(jobj, key))
+               json_object_remove_member(jobj, key);
+
+       json_object_set_int_member(jobj, key, val);
+       return true;
+}
+
+bool CtxJson::set(const char *path, const char *key, double val)
+{
+       return set(path, key, __double_to_string(val));
+}
+
+bool CtxJson::set(const char *path, const char *key, std::string val)
+{
+       IF_FAIL_RETURN_TAG(this->__jsonNode, false, _E, "CtxJson object not initialized");
+       IF_FAIL_RETURN_TAG(key, false, _E, "Invalid parameter");
+
+       JsonObject *jobj = __traverse(__jsonNode, path, true);
+       IF_FAIL_RETURN(jobj, false);
+
+       if (json_object_has_member(jobj, key)) {
+               json_object_remove_member(jobj, key);
+       }
+
+       json_object_set_string_member(jobj, key, val.c_str());
+       return true;
+}
+
+bool CtxJson::set(const char *path, const char *key, GVariant *val)
+{
+#if JSON_CHECK_VERSION(0, 14, 0)
+       IF_FAIL_RETURN_TAG(this->__jsonNode, false, _E, "CtxJson object not initialized");
+       IF_FAIL_RETURN_TAG(key && val, false, _E, "Invalid parameter");
+
+       const gchar *typeStr = g_variant_get_type_string(val);
+       IF_FAIL_RETURN_TAG(typeStr, false, _E, "GVariant manipulation failed");
+
+       json_node_t *node = json_gvariant_serialize(val);
+       IF_FAIL_RETURN_TAG(node, false, _E, "GVariant manipulation failed");
+
+       CtxJson gvarJson;
+       gvarJson.set(NULL, GVAR_TYPES, std::string(typeStr));
+       json_object_set_member(json_node_get_object(gvarJson.__jsonNode), GVAR_VALUES, node);
+
+       return set(path, key, gvarJson);
+#else
+       _E("Insufficient version of json-glib(" JSON_VERSION_S ")");
+       return false;
+#endif
+}
+
+bool CtxJson::get(const char *path, const char *key, CtxJson *val)
+{
+       IF_FAIL_RETURN_TAG(this->__jsonNode, false, _E, "CtxJson object not initialized");
+       IF_FAIL_RETURN_TAG(key && val, false, _E, "Invalid parameter");
+
+       JsonObject *jobj = NULL;
+       JsonNode *node = NULL;
+
+       jobj = __traverse(__jsonNode, path, false);
+       IF_FAIL_RETURN(jobj && json_object_has_member(jobj, key), false);
+
+       node = json_object_dup_member(jobj, key);
+       IF_FAIL_RETURN_TAG(node, false, _E, "Memory allocation failed");
+
+       if (val->__jsonNode) {
+               json_node_free(val->__jsonNode);
+       }
+       val->__jsonNode = node;
+
+       return true;
+}
+
+static JsonNode* __get_value_node(JsonNode *jnode, const char *path, const char *key)
+{
+       JsonNode *node = NULL;
+       JsonObject *jobj = NULL;
+       JsonNodeType ntype;
+
+       jobj = __traverse(jnode, path, false);
+       IF_FAIL_RETURN(jobj && json_object_has_member(jobj, key), NULL);
+
+       node = json_object_get_member(jobj, key);
+       ntype = json_node_get_node_type(node);
+       IF_FAIL_RETURN(ntype == JSON_NODE_VALUE, NULL);
+
+       return node;
+}
+
+bool CtxJson::get(const char *path, const char *key, int *val)
+{
+       IF_FAIL_RETURN_TAG(this->__jsonNode, false, _E, "CtxJson object not initialized");
+       IF_FAIL_RETURN_TAG(key && val, false, _E, "Invalid parameter");
+
+       int64_t v;
+
+       if (get(path, key, &v)) {
+               *val = v;
+               return true;
+       }
+
+       return false;
+}
+
+bool CtxJson::get(const char *path, const char *key, int64_t *val)
+{
+       IF_FAIL_RETURN_TAG(this->__jsonNode, false, _E, "CtxJson object not initialized");
+       IF_FAIL_RETURN_TAG(key && val, false, _E, "Invalid parameter");
+
+       JsonNode *node = __get_value_node(__jsonNode, path, key);
+       IF_FAIL_RETURN(node, false);
+
+       GType vtype = json_node_get_value_type(node);
+       if (vtype == G_TYPE_INT64) {
+               *val = json_node_get_int(node);
+       } else if (vtype == G_TYPE_STRING) {
+               //TODO: if the string is not a number?
+               *val = static_cast<int64_t>(__string_to_double(json_node_get_string(node)));
+       } else {
+               return false;
+       }
+
+       return true;
+}
+
+bool CtxJson::get(const char *path, const char *key, double *val)
+{
+       IF_FAIL_RETURN_TAG(this->__jsonNode, false, _E, "CtxJson object not initialized");
+       IF_FAIL_RETURN_TAG(key && val, false, _E, "Invalid parameter");
+
+       JsonNode *node = __get_value_node(__jsonNode, path, key);
+       IF_FAIL_RETURN(node, false);
+
+       GType vtype = json_node_get_value_type(node);
+       if (vtype == G_TYPE_DOUBLE) {
+               *val = json_node_get_double(node);
+       } else if (vtype == G_TYPE_INT64) {
+               *val = json_node_get_int(node);
+       } else if (vtype == G_TYPE_STRING) {
+               *val = __string_to_double(json_node_get_string(node));
+       } else {
+               return false;
+       }
+
+       return true;
+}
+
+bool CtxJson::get(const char *path, const char *key, std::string *val)
+{
+       IF_FAIL_RETURN_TAG(this->__jsonNode, false, _E, "CtxJson object not initialized");
+       IF_FAIL_RETURN_TAG(key && val, false, _E, "Invalid parameter");
+
+       JsonNode *node = __get_value_node(__jsonNode, path, key);
+       IF_FAIL_RETURN(node, false);
+
+       GType vtype = json_node_get_value_type(node);
+       IF_FAIL_RETURN(vtype == G_TYPE_STRING, false);
+
+       const char *str_val = json_node_get_string(node);
+       IF_FAIL_RETURN_TAG(str_val, false, _E, "Getting string failed");
+
+       *val = str_val;
+       return true;
+}
+
+bool CtxJson::get(const char *path, const char *key, GVariant **val)
+{
+#if JSON_CHECK_VERSION(0, 14, 0)
+       IF_FAIL_RETURN_TAG(this->__jsonNode, false, _E, "CtxJson object not initialized");
+       IF_FAIL_RETURN_TAG(key && val, false, _E, "Invalid parameter");
+
+       bool ret;
+       CtxJson gvarJson;
+       ret = get(path, key, &gvarJson);
+       IF_FAIL_RETURN(ret, false);
+
+       std::string gvarTypes;
+       ret = gvarJson.get(NULL, GVAR_TYPES, &gvarTypes);
+       IF_FAIL_RETURN(ret, false);
+
+       CtxJson gvarValues;
+       ret = gvarJson.get(NULL, GVAR_VALUES, &gvarValues);
+       IF_FAIL_RETURN(ret, false);
+
+       GError *gerr = NULL;
+       *val = json_gvariant_deserialize(gvarValues.__jsonNode, gvarTypes.c_str(), &gerr);
+       HANDLE_GERROR(gerr);
+       IF_FAIL_RETURN(*val, false);
+
+       return true;
+#else
+       _E("Insufficient version of json-glib(" JSON_VERSION_S ")");
+       *val = NULL;
+       return false;
+#endif
+}
+
+bool CtxJson::remove(const char *path, const char *key)
+{
+       IF_FAIL_RETURN_TAG(this->__jsonNode, false, _E, "CtxJson object not initialized");
+       IF_FAIL_RETURN_TAG(key, false, _E, "Invalid parameter");
+
+       JsonObject *jobj = __traverse(__jsonNode, path, true);
+       IF_FAIL_RETURN(jobj, false);
+
+       if (json_object_has_member(jobj, key))
+               json_object_remove_member(jobj, key);
+
+       return true;
+}
+
+static JsonArray* __get_array(JsonNode *jnode, const char *path, const char *key, bool force)
+{
+       JsonNode *node = NULL;
+       JsonArray *arr = NULL;
+       JsonObject *jobj = NULL;
+
+       jobj = __traverse(jnode, path, force);
+       IF_FAIL_RETURN(jobj, NULL);
+
+       if (!json_object_has_member(jobj, key)) {
+               if (force) {
+                       arr = json_array_new();
+                       IF_FAIL_RETURN_TAG(arr, NULL, _E, "Memory allocation failed");
+                       json_object_set_array_member(jobj, key, arr);
+               } else {
+                       return NULL;
+               }
+       }
+       node = json_object_get_member(jobj, key);
+       IF_FAIL_RETURN_TAG(node && json_node_get_node_type(node) == JSON_NODE_ARRAY,
+                       NULL, _W, "Type mismatched: %s", key);
+
+       return json_node_get_array(node);
+}
+
+int CtxJson::getSize(const char *path, const char *key)
+{
+       IF_FAIL_RETURN_TAG(this->__jsonNode, -1, _E, "CtxJson object not initialized");
+       IF_FAIL_RETURN_TAG(key, -1, _E, "Invalid parameter");
+
+       JsonArray *jarr = __get_array(__jsonNode, path, key, false);
+       IF_FAIL_RETURN_TAG(jarr, -1, _D, "Mismatched data type");
+
+       return json_array_get_length(jarr);
+}
+
+bool CtxJson::append(const char *path, const char *key, CtxJson &val)
+{
+       IF_FAIL_RETURN_TAG(this->__jsonNode, false, _E, "CtxJson object not initialized");
+       IF_FAIL_RETURN_TAG(key && val.__jsonNode, false, _E, "Invalid parameter");
+
+       JsonArray *arr = __get_array(__jsonNode, path, key, true);
+       IF_FAIL_RETURN(arr, false);
+
+       json_array_add_element(arr, val.__jsonNode);
+       val.__jsonNode = NULL;
+       val = CtxJson();
+
+       return true;
+}
+
+bool CtxJson::append(const char *path, const char *key, int val)
+{
+       return append(path, key, static_cast<int64_t>(val));
+}
+
+bool CtxJson::append(const char *path, const char *key, int64_t val)
+{
+       IF_FAIL_RETURN_TAG(this->__jsonNode, false, _E, "CtxJson object not initialized");
+       IF_FAIL_RETURN_TAG(key, false, _E, "Invalid parameter");
+
+       JsonArray *arr = __get_array(__jsonNode, path, key, true);
+       IF_FAIL_RETURN(arr, false);
+
+       json_array_add_int_element(arr, val);
+       return true;
+}
+
+bool CtxJson::append(const char *path, const char *key, double val)
+{
+       return append(path, key, __double_to_string(val));
+}
+
+bool CtxJson::append(const char *path, const char *key, std::string val)
+{
+       IF_FAIL_RETURN_TAG(this->__jsonNode, false, _E, "CtxJson object not initialized");
+       IF_FAIL_RETURN_TAG(key, false, _E, "Invalid parameter");
+
+       JsonArray *arr = __get_array(__jsonNode, path, key, true);
+       IF_FAIL_RETURN(arr, false);
+
+       json_array_add_string_element(arr, val.c_str());
+       return true;
+}
+
+static JsonNode* __get_array_elem(JsonNode *jnode, const char *path, const char *key, int index)
+{
+       JsonArray *jarr = __get_array(jnode, path, key, false);
+       IF_FAIL_RETURN_TAG(jarr, NULL, _W, "Mismatched data type");
+
+       int size = json_array_get_length(jarr);
+       IF_FAIL_RETURN(size > index, NULL);
+
+       JsonNode *node = json_array_get_element(jarr, index);
+       IF_FAIL_RETURN_TAG(node, NULL, _E, "Failed to get an array element");
+
+       return node;
+}
+
+bool CtxJson::setAt(const char *path, const char *key, int index, CtxJson &val)
+{
+       IF_FAIL_RETURN_TAG(this->__jsonNode, false, _E, "CtxJson object not initialized");
+       IF_FAIL_RETURN_TAG(val.__jsonNode && key && index >= 0, false, _E, "Invalid parameter");
+
+       JsonNode *node = __get_array_elem(__jsonNode, path, key, index);
+       IF_FAIL_RETURN_TAG(node, false, _W, "Out of range");
+
+       JsonObject *obj = json_node_get_object(val.__jsonNode);
+       IF_FAIL_RETURN_TAG(obj, false, _E, "Getting object failed");
+
+       json_node_set_object(node, obj);
+       json_node_free(val.__jsonNode);
+       val.__jsonNode = NULL;
+       val = CtxJson();
+
+       return true;
+}
+
+bool CtxJson::setAt(const char *path, const char *key, int index, int val)
+{
+       return setAt(path, key, index, static_cast<int64_t>(val));
+}
+
+bool CtxJson::setAt(const char *path, const char *key, int index, int64_t val)
+{
+       IF_FAIL_RETURN_TAG(this->__jsonNode, false, _E, "CtxJson object not initialized");
+       IF_FAIL_RETURN_TAG(key && index >= 0, false, _E, "Invalid parameter");
+
+       JsonNode *node = __get_array_elem(__jsonNode, path, key, index);
+       IF_FAIL_RETURN_TAG(node, false, _W, "Out of range");
+       IF_FAIL_RETURN_TAG(json_node_get_node_type(node) == JSON_NODE_VALUE, false, _E, "Type mismatched: %s[%d]", key, index);
+
+       json_node_set_int(node, val);
+       return true;
+}
+
+bool CtxJson::setAt(const char *path, const char *key, int index, double val)
+{
+       return setAt(path, key, index, __double_to_string(val));
+}
+
+bool CtxJson::setAt(const char *path, const char *key, int index, std::string val)
+{
+       IF_FAIL_RETURN_TAG(this->__jsonNode, false, _E, "CtxJson object not initialized");
+       IF_FAIL_RETURN_TAG(key && index >= 0, false, _E, "Invalid parameter");
+
+       JsonNode *node = __get_array_elem(__jsonNode, path, key, index);
+       IF_FAIL_RETURN_TAG(node, false, _W, "Out of range");
+       IF_FAIL_RETURN_TAG(json_node_get_node_type(node) == JSON_NODE_VALUE, false, _E, "Type mismatched: %s[%d]", key, index);
+
+       json_node_set_string(node, val.c_str());
+       return true;
+}
+
+bool CtxJson::getAt(const char *path, const char *key, int index, CtxJson *val)
+{
+       IF_FAIL_RETURN_TAG(this->__jsonNode, false, _E, "CtxJson object not initialized");
+       IF_FAIL_RETURN_TAG(key && val && index >= 0, false, _E, "Invalid parameter");
+
+       JsonNode *node = __get_array_elem(__jsonNode, path, key, index);
+       IF_FAIL_RETURN(node, false);
+
+       JsonNode *nodeCopy = json_node_copy(node);
+       IF_FAIL_RETURN_TAG(nodeCopy, false, _E, "Memory allocation failed");
+
+       if (val->__jsonNode) {
+               json_node_free(val->__jsonNode);
+       }
+       val->__jsonNode = nodeCopy;
+
+       return true;
+}
+
+bool CtxJson::getAt(const char *path, const char *key, int index, int *val)
+{
+       IF_FAIL_RETURN_TAG(this->__jsonNode, false, _E, "CtxJson object not initialized");
+       IF_FAIL_RETURN_TAG(key && val && index >= 0, false, _E, "Invalid parameter");
+
+       int64_t v;
+       if (getAt(path, key, index, &v)) {
+               *val = v;
+               return true;
+       }
+
+       return false;
+}
+
+bool CtxJson::getAt(const char *path, const char *key, int index, int64_t *val)
+{
+       IF_FAIL_RETURN_TAG(this->__jsonNode, false, _E, "CtxJson object not initialized");
+       IF_FAIL_RETURN_TAG(key && val && index >= 0, false, _E, "Invalid parameter");
+
+       JsonNode *node = __get_array_elem(__jsonNode, path, key, index);
+       IF_FAIL_RETURN(node, false);
+
+       JsonNodeType ntype = json_node_get_node_type(node);
+       IF_FAIL_RETURN_TAG(ntype == JSON_NODE_VALUE, false, _E, "Type mismatched: %s", key);
+
+       GType vtype = json_node_get_value_type(node);
+       if (vtype == G_TYPE_INT64) {
+               *val = json_node_get_int(node);
+       } else if (vtype == G_TYPE_STRING) {
+               *val = static_cast<int64_t>(__string_to_double(json_node_get_string(node)));
+       } else {
+               _E("Type mismatched: %s", key);
+               return false;
+       }
+
+       return true;
+}
+
+bool CtxJson::getAt(const char *path, const char *key, int index, double *val)
+{
+       IF_FAIL_RETURN_TAG(this->__jsonNode, false, _E, "CtxJson object not initialized");
+       IF_FAIL_RETURN_TAG(key && val && index >= 0, false, _E, "Invalid parameter");
+
+       JsonNode *node = __get_array_elem(__jsonNode, path, key, index);
+       IF_FAIL_RETURN(node, false);
+
+       JsonNodeType ntype = json_node_get_node_type(node);
+       IF_FAIL_RETURN_TAG(ntype == JSON_NODE_VALUE, false, _E, "Type mismatched: %s", key);
+
+       GType vtype = json_node_get_value_type(node);
+       if (vtype == G_TYPE_DOUBLE) {
+               *val = json_node_get_double(node);
+       } else if (vtype == G_TYPE_INT64) {
+               *val = json_node_get_int(node);
+       } else if (vtype == G_TYPE_STRING) {
+               *val = __string_to_double(json_node_get_string(node));
+       } else {
+               _E("Type mismatched: %s", key);
+               return false;
+       }
+
+       return true;
+}
+
+bool CtxJson::getAt(const char *path, const char *key, int index, std::string *val)
+{
+       IF_FAIL_RETURN_TAG(this->__jsonNode, false, _E, "CtxJson object not initialized");
+       IF_FAIL_RETURN_TAG(key && val && index >= 0, false, _E, "Invalid parameter");
+
+       JsonNode *node = __get_array_elem(__jsonNode, path, key, index);
+       IF_FAIL_RETURN(node, false);
+
+       JsonNodeType ntype = json_node_get_node_type(node);
+       IF_FAIL_RETURN_TAG(ntype == JSON_NODE_VALUE, false, _E, "Type mismatched: %s", key);
+
+       GType vtype = json_node_get_value_type(node);
+       IF_FAIL_RETURN_TAG(vtype == G_TYPE_STRING, false, _E, "Type mismatched: %s", key);
+
+       const char *str_val = json_node_get_string(node);
+       IF_FAIL_RETURN_TAG(str_val, false, _E, "Getting string failed");
+
+       *val = str_val;
+       return true;
+}
+
+bool CtxJson::__getMembers(json_node_t *node, std::list<std::string> &list)
+{
+       IF_FAIL_RETURN(node, false);
+       list.clear();
+
+       JsonObject *jobj = json_node_get_object(node);
+       IF_FAIL_RETURN_TAG(jobj, false, _E, "Getting CtxJson object failed");
+
+       GList *members = json_object_get_members(jobj);
+       IF_FAIL_RETURN(members, true);
+
+       for (GList *it = g_list_first(members); it; it = g_list_next(it)) {
+               const char *key = static_cast<const char*>(it->data);
+               if (!key) {
+                       list.clear();
+                       g_list_free(members);
+                       _E("Member list extraction failed");
+                       return false;
+               }
+
+               list.push_back(key);
+       }
+
+       g_list_free(members);
+       return true;
+}
+
+bool CtxJson::getKeys(std::list<std::string>* list)
+{
+       IF_FAIL_RETURN_TAG(list, false, _E, "Invalid parameter");
+       return __getMembers(__jsonNode, *list);
+}
+
+bool CtxJson::__nodeEq(json_node_t *lhs, json_node_t *rhs)
+{
+       IF_FAIL_RETURN(lhs && rhs, false);
+
+       JsonNodeType ltype = json_node_get_node_type(lhs);
+       JsonNodeType rtype = json_node_get_node_type(rhs);
+       IF_FAIL_RETURN(ltype == rtype, false);
+
+       switch (ltype) {
+       case JSON_NODE_VALUE:
+               IF_FAIL_RETURN(__valueEq(lhs, rhs), false);
+               break;
+       case JSON_NODE_OBJECT:
+               IF_FAIL_RETURN(__objectEq(lhs, rhs), false);
+               break;
+       case JSON_NODE_ARRAY:
+               IF_FAIL_RETURN(__arrayEq(lhs, rhs), false);
+               break;
+       default:
+               _W("Unsupported type");
+               return false;
+       }
+
+       return true;
+}
+
+bool CtxJson::__valueEq(json_node_t *lhs, json_node_t *rhs)
+{
+       GType ltype = json_node_get_value_type(lhs);
+       GType rtype = json_node_get_value_type(rhs);
+       IF_FAIL_RETURN(ltype == rtype, false);
+
+       switch (ltype) {
+       case G_TYPE_INT64:
+               return json_node_get_int(lhs) == json_node_get_int(rhs);
+       case G_TYPE_DOUBLE:
+               return json_node_get_double(lhs) == json_node_get_double(rhs);
+       case G_TYPE_STRING:
+               return STR_EQ(json_node_get_string(lhs), json_node_get_string(rhs));
+       default:
+               _W("Unsupported type");
+               return false;
+       }
+}
+
+bool CtxJson::__objectEq(json_node_t *lhs, json_node_t *rhs)
+{
+       std::list<std::string> lm, rm;
+       IF_FAIL_RETURN(__getMembers(lhs, lm), false);
+       IF_FAIL_RETURN(__getMembers(rhs, rm), false);
+       IF_FAIL_RETURN(lm.size() == rm.size(), false);
+
+       lm.sort();
+       rm.sort();
+
+       std::list<std::string>::iterator lit, rit;
+       lit = lm.begin();
+       rit = rm.begin();
+
+       while (lit != lm.end()) {
+               IF_FAIL_RETURN(*lit == *rit, false);
+
+               json_node_t *lhsChild = json_object_get_member(json_node_get_object(lhs), (*lit).c_str());
+               json_node_t *rhsChild = json_object_get_member(json_node_get_object(rhs), (*rit).c_str());
+               IF_FAIL_RETURN(__nodeEq(lhsChild, rhsChild), false);
+
+               ++lit;
+               ++rit;
+       }
+
+       return true;
+}
+
+bool CtxJson::__arrayEq(json_node_t *lhs, json_node_t *rhs)
+{
+       JsonArray *larr = json_node_get_array(lhs);
+       JsonArray *rarr = json_node_get_array(rhs);
+
+       int size = json_array_get_length(larr);
+       IF_FAIL_RETURN(size == static_cast<int>(json_array_get_length(rarr)), false);
+
+       for (int i = 0; i < size; ++i) {
+               json_node_t *lhsChild = json_array_get_element(larr, i);
+               json_node_t *rhsChild = json_array_get_element(rarr, i);
+               IF_FAIL_RETURN(__nodeEq(lhsChild, rhsChild), false);
+       }
+
+       return true;
+}