From 44b3de76c93e3e34d02164e219de5e9140fd85a6 Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Tue, 24 Jul 2012 10:50:53 +0200 Subject: [PATCH] Moved serialization functionality into the base library. --- base/base.vcxproj | 8 +-- base/component.cpp | 13 ----- base/component.h | 3 -- base/dictionary.cpp | 46 +++++++++++++++++ base/dictionary.h | 3 ++ base/utility.cpp | 10 ++++ base/utility.h | 2 + base/variant.cpp | 73 ++++++++++++++++++++++++++ base/variant.h | 8 +++ jsonrpc/jsonrpc.vcxproj | 8 +-- jsonrpc/jsonrpcclient.cpp | 10 +++- jsonrpc/messagepart.cpp | 104 -------------------------------------- jsonrpc/messagepart.h | 6 --- 13 files changed, 158 insertions(+), 136 deletions(-) diff --git a/base/base.vcxproj b/base/base.vcxproj index 72cfeb18c..7666a3368 100644 --- a/base/base.vcxproj +++ b/base/base.vcxproj @@ -105,11 +105,11 @@ - $(SolutionDir)\third-party\mmatch;$(IncludePath) + $(SolutionDir)\third-party\mmatch;$(SolutionDir)\third-party\cJSON;$(IncludePath) $(OutDir);$(LibraryPath) - $(SolutionDir)\third-party\mmatch;$(IncludePath) + $(SolutionDir)\third-party\mmatch;$(SolutionDir)\third-party\cJSON;$(IncludePath) $(OutDir);$(LibraryPath) @@ -125,7 +125,7 @@ Windows true - ws2_32.lib;shlwapi.lib;mmatch.lib;libeay32MTd.lib;ssleay32MTd.lib;%(AdditionalDependencies) + ws2_32.lib;shlwapi.lib;mmatch.lib;cJSON.lib;libeay32MTd.lib;ssleay32MTd.lib;%(AdditionalDependencies) ws2_32.lib;shlwapi.lib @@ -149,7 +149,7 @@ true true true - ws2_32.lib;shlwapi.lib;mmatch.lib;libeay32MT.lib;ssleay32MT.lib;%(AdditionalDependencies) + ws2_32.lib;shlwapi.lib;mmatch.lib;cJSON.lib;libeay32MT.lib;ssleay32MT.lib;%(AdditionalDependencies) ws2_32.lib;shlwapi.lib diff --git a/base/component.cpp b/base/component.cpp index 52c27b5a3..b9fe5e8e3 100644 --- a/base/component.cpp +++ b/base/component.cpp @@ -145,19 +145,6 @@ void Component::AddSearchDir(const string& componentDirectory) #endif /* _WIN32 */ } -/** - * Constructor for the Component class. - */ -Component::Component(void) - : m_ModuleHandle(0) -{ } - -/** - * Destructor for the Component class. - */ -Component::~Component(void) -{ } - /** * Retrieves the name of the component. * diff --git a/base/component.h b/base/component.h index a59c1faa7..db7338103 100644 --- a/base/component.h +++ b/base/component.h @@ -35,9 +35,6 @@ public: typedef shared_ptr Ptr; typedef weak_ptr WeakPtr; - Component(void); - virtual ~Component(void); - ConfigObject::Ptr GetConfig(void) const; virtual void Start(void); diff --git a/base/dictionary.cpp b/base/dictionary.cpp index 8626916bb..01500c889 100644 --- a/base/dictionary.cpp +++ b/base/dictionary.cpp @@ -18,6 +18,7 @@ ******************************************************************************/ #include "i2-base.h" +#include using namespace icinga; @@ -77,3 +78,48 @@ void Dictionary::Remove(const string& key) m_Data.erase(it); } + +/** + * Converts a JSON object to a dictionary. + * + * @param json The JSON object. + * @returns A dictionary that is equivalent to the JSON object. + */ +Dictionary::Ptr Dictionary::FromJson(cJSON *json) +{ + Dictionary::Ptr dictionary = boost::make_shared(); + + if (json->type != cJSON_Object) + throw invalid_argument("JSON type must be cJSON_Object."); + + for (cJSON *i = json->child; i != NULL; i = i->next) { + dictionary->Set(i->string, Variant::FromJson(i)); + } + + return dictionary; +} + +/** + * Converts a dictionary to a JSON object. + * + * @param dictionary The dictionary. + * @returns A JSON object that is equivalent to the dictionary. Values that + * cannot be represented in JSON are omitted. + */ +cJSON *Dictionary::ToJson(void) const +{ + cJSON *json = cJSON_CreateObject(); + + try { + string key; + Variant value; + BOOST_FOREACH(tie(key, value), m_Data) { + cJSON_AddItemToObject(json, key.c_str(), value.ToJson()); + } + } catch (...) { + cJSON_Delete(json); + throw; + } + + return json; +} \ No newline at end of file diff --git a/base/dictionary.h b/base/dictionary.h index 919a60870..9c0e5d760 100644 --- a/base/dictionary.h +++ b/base/dictionary.h @@ -105,6 +105,9 @@ public: void Remove(const string& key); + static Dictionary::Ptr FromJson(cJSON *json); + cJSON *ToJson(void) const; + private: map m_Data; }; diff --git a/base/utility.cpp b/base/utility.cpp index 685d6018b..c5eb45b73 100644 --- a/base/utility.cpp +++ b/base/utility.cpp @@ -245,3 +245,13 @@ string Utility::BaseName(const string& path) return result; } + +/** + * Null deleter. Used as a parameter for the shared_ptr constructor. + * + * @param obj The object that should be deleted. + */ +void Utility::NullDeleter(void *obj) +{ + /* Nothing to do here. */ +} diff --git a/base/utility.h b/base/utility.h index 4370be683..3f8938335 100644 --- a/base/utility.h +++ b/base/utility.h @@ -44,6 +44,8 @@ public: static string DirName(const string& path); static string BaseName(const string& path); + static void NullDeleter(void *obj); + private: static bool m_SSLInitialized; diff --git a/base/variant.cpp b/base/variant.cpp index dfddc6ca4..25c3975c4 100644 --- a/base/variant.cpp +++ b/base/variant.cpp @@ -18,6 +18,7 @@ ******************************************************************************/ #include "i2-base.h" +#include using namespace icinga; @@ -40,3 +41,75 @@ bool Variant::IsObject(void) const { return !IsEmpty() && (m_Value.type() == typeid(Object::Ptr)); } + +Variant Variant::FromJson(cJSON *json) +{ + if (json->type == cJSON_Number) + return json->valuedouble; + else if (json->type == cJSON_String) + return json->valuestring; + else if (json->type == cJSON_True) + return 1; + else if (json->type == cJSON_False) + return 0; + else if (json->type == cJSON_Object) + return Dictionary::FromJson(json); + else if (json->type == cJSON_NULL) + return Variant(); + else + throw invalid_argument("Unsupported JSON type."); +} + +string Variant::Serialize(void) const +{ + cJSON *json = ToJson(); + + char *jsonString; + + if (!Application::GetInstance()->IsDebugging()) + jsonString = cJSON_Print(json); + else + jsonString = cJSON_PrintUnformatted(json); + + cJSON_Delete(json); + + string result = jsonString; + + free(jsonString); + + return result; +} + +cJSON *Variant::ToJson(void) const +{ + if (m_Value.type() == typeid(long)) { + return cJSON_CreateNumber(boost::get(m_Value)); + } else if (m_Value.type() == typeid(double)) { + return cJSON_CreateNumber(boost::get(m_Value)); + } else if (m_Value.type() == typeid(string)) { + return cJSON_CreateString(boost::get(m_Value).c_str()); + } else if (m_Value.type() == typeid(Object::Ptr)) { + if (IsObjectType()) { + Dictionary::Ptr dictionary = *this; + return dictionary->ToJson(); + } else { + Logger::Write(LogDebug, "base", "Ignoring unknown object while converting variant to JSON."); + return cJSON_CreateNull(); + } + } else { + throw runtime_error("Invalid variant type."); + } +} + +Variant Variant::Deserialize(const string& jsonString) +{ + cJSON *json = cJSON_Parse(jsonString.c_str()); + + if (!json) + throw_exception(runtime_error("Invalid JSON string")); + + Variant value = FromJson(json); + cJSON_Delete(json); + + return value; +} diff --git a/base/variant.h b/base/variant.h index 4f1c996cd..4f0a4f956 100644 --- a/base/variant.h +++ b/base/variant.h @@ -20,6 +20,8 @@ #ifndef VARIANT_H #define VARIANT_H +struct cJSON; + namespace icinga { @@ -128,6 +130,12 @@ public: return (dynamic_pointer_cast(boost::get(m_Value))); } + static Variant FromJson(cJSON *json); + cJSON *ToJson(void) const; + + string Serialize(void) const; + static Variant Deserialize(const string& jsonString); + private: mutable boost::variant m_Value; }; diff --git a/jsonrpc/jsonrpc.vcxproj b/jsonrpc/jsonrpc.vcxproj index ac8e6ac70..095152f4e 100644 --- a/jsonrpc/jsonrpc.vcxproj +++ b/jsonrpc/jsonrpc.vcxproj @@ -59,11 +59,11 @@ - $(SolutionDir)\base;$(SolutionDir)\third-party\cJSON;$(IncludePath) + $(SolutionDir)\base;$(IncludePath) $(OutDir);$(LibraryPath) - $(SolutionDir)\base;$(SolutionDir)\third-party\cJSON;$(IncludePath) + $(SolutionDir)\base;$(IncludePath) $(OutDir);$(LibraryPath) @@ -79,7 +79,7 @@ Windows true - base.lib;cJSON.lib;%(AdditionalDependencies) + base.lib;%(AdditionalDependencies) @@ -104,7 +104,7 @@ true true true - base.lib;cJSON.lib;%(AdditionalDependencies) + base.lib;%(AdditionalDependencies) diff --git a/jsonrpc/jsonrpcclient.cpp b/jsonrpc/jsonrpcclient.cpp index 6d0871b22..28e872032 100644 --- a/jsonrpc/jsonrpcclient.cpp +++ b/jsonrpc/jsonrpcclient.cpp @@ -40,7 +40,8 @@ JsonRpcClient::JsonRpcClient(TcpClientRole role, shared_ptr sslContext) */ void JsonRpcClient::SendMessage(const MessagePart& message) { - Netstring::WriteStringToIOQueue(this, message.ToJsonString()); + Variant value = message.GetDictionary(); + Netstring::WriteStringToIOQueue(this, value.Serialize()); } /** @@ -52,7 +53,12 @@ void JsonRpcClient::DataAvailableHandler(void) while (Netstring::ReadStringFromIOQueue(this, &jsonString)) { try { - OnNewMessage(GetSelf(), MessagePart(jsonString)); + Variant value = Variant::Deserialize(jsonString); + + if (!value.IsObjectType()) + throw invalid_argument("JSON-RPC message must be a dictionary."); + + OnNewMessage(GetSelf(), MessagePart(value)); } catch (const exception& ex) { Logger::Write(LogCritical, "jsonrpc", "Exception while processing message from JSON-RPC client: " + string(ex.what())); } diff --git a/jsonrpc/messagepart.cpp b/jsonrpc/messagepart.cpp index 48faed4f4..1e90322ce 100644 --- a/jsonrpc/messagepart.cpp +++ b/jsonrpc/messagepart.cpp @@ -18,7 +18,6 @@ ******************************************************************************/ #include "i2-jsonrpc.h" -#include using namespace icinga; @@ -30,24 +29,6 @@ MessagePart::MessagePart(void) m_Dictionary = boost::make_shared(); } -/** - * Constructor for the MessagePart class. - * - * @param jsonString The JSON string that should be used to initialize - * the message. - */ -MessagePart::MessagePart(string jsonString) -{ - json_t *json = cJSON_Parse(jsonString.c_str()); - - if (!json) - throw_exception(runtime_error("Invalid JSON string")); - - m_Dictionary = GetDictionaryFromJson(json); - - cJSON_Delete(json); -} - /** * Constructor for the MessagePart class. * @@ -68,91 +49,6 @@ MessagePart::MessagePart(const MessagePart& message) m_Dictionary = message.GetDictionary(); } -/** - * Converts a JSON object to a dictionary. - * - * @param json The JSON object. - * @returns A dictionary that is equivalent to the JSON object. - */ -Dictionary::Ptr MessagePart::GetDictionaryFromJson(json_t *json) -{ - Dictionary::Ptr dictionary = boost::make_shared(); - - for (cJSON *i = json->child; i != NULL; i = i->next) { - switch (i->type) { - case cJSON_Number: - dictionary->Set(i->string, i->valueint); - break; - case cJSON_String: - dictionary->Set(i->string, i->valuestring); - break; - case cJSON_Object: - dictionary->Set(i->string, GetDictionaryFromJson(i)); - break; - default: - break; - } - } - - return dictionary; -} - -/** - * Converts a dictionary to a JSON object. - * - * @param dictionary The dictionary. - * @returns A JSON object that is equivalent to the dictionary. Values that - * cannot be represented in JSON are omitted. - */ -json_t *MessagePart::GetJsonFromDictionary(const Dictionary::Ptr& dictionary) -{ - cJSON *json; - string valueString; - Dictionary::Ptr valueDictionary; - - json = cJSON_CreateObject(); - - for (Dictionary::Iterator i = dictionary->Begin(); i != dictionary->End(); i++) { - if (i->second.IsScalar()) { - valueString = static_cast(i->second); - cJSON_AddStringToObject(json, i->first.c_str(), valueString.c_str()); - } else if (i->second.IsObjectType()) { - cJSON_AddItemToObject(json, i->first.c_str(), GetJsonFromDictionary(i->second)); - } else { - stringstream msgbuf; - msgbuf << "Dictionary serialization: Ignored property '" << i->first << "' (unknown type)"; - Logger::Write(LogDebug, "jsonrpc", msgbuf.str()); - } - } - - return json; -} - -/** - * Converts a message into a JSON string. - * - * @returns A JSON string representing the message. - */ -string MessagePart::ToJsonString(void) const -{ - json_t *json = GetJsonFromDictionary(m_Dictionary); - char *jsonString; - string result; - - if (!Application::GetInstance()->IsDebugging()) - jsonString = cJSON_Print(json); - else - jsonString = cJSON_PrintUnformatted(json); - - cJSON_Delete(json); - - result = jsonString; - - free(jsonString); - - return result; -} - /** * Retrieves the underlying dictionary for this message. * diff --git a/jsonrpc/messagepart.h b/jsonrpc/messagepart.h index 276d3e928..8a6cc021c 100644 --- a/jsonrpc/messagepart.h +++ b/jsonrpc/messagepart.h @@ -36,12 +36,9 @@ class I2_JSONRPC_API MessagePart { public: MessagePart(void); - MessagePart(string json); MessagePart(const Dictionary::Ptr& dictionary); MessagePart(const MessagePart& message); - string ToJsonString(void) const; - Dictionary::Ptr GetDictionary(void) const; /** @@ -92,9 +89,6 @@ public: private: Dictionary::Ptr m_Dictionary; - - static Dictionary::Ptr GetDictionaryFromJson(json_t *json); - static json_t *GetJsonFromDictionary(const Dictionary::Ptr& dictionary); }; }