luna-sysmgr-common
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
JSONUtils.h
Go to the documentation of this file.
1 /* @@@LICENSE
2 *
3 * Copyright (c) 2010-2012 Hewlett-Packard Development Company, L.P.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 * LICENSE@@@ */
18 
19 #ifndef JSONUTILS_H
20 #define JSONUTILS_H
21 
22 #include "Settings.h"
23 
24 #include <lunaservice.h>
25 #include <pbnjson.h>
26 #include <pbnjson.hpp>
27 
28 /*
29  * Helper macros to build schemas in a more reliable, readable & editable way in C++
30  */
31 
32 #define STR(x) #x
33 
34 extern const char * STANDARD_JSON_SUCCESS;
35 
41 // Build a standard reply as a const char * string consistently
42 #define STANDARD_JSON_SUCCESS "{\"returnValue\":true}"
43 #define STANDARD_JSON_ERROR(errorCode, errorText) "{\"returnValue\":false,\"errorCode\":"STR(errorCode)",\"errorText\":\"" errorText "\"}"
44 #define MISSING_PARAMETER_ERROR(name, type) "{\"returnValue\":false,\"errorCode\":2,\"errorText\":\"Missing '" STR(name) "' " STR(type) " parameter.\"}"
45 #define INVALID_PARAMETER_ERROR(name, type) "{\"returnValue\":false,\"errorCode\":3,\"errorText\":\"Invalid '" STR(name) "' " STR(type) " parameter value.\"}"
46 
47 // Test the name of a json parameter to determine if it's a system parameter that we should ignore. Pass a (char *)
48 #define IS_SYSTEM_PARAMETER(x) ((x) && *(x) == '$')
49 #define SYSTEM_PARAMETERS "\"$activity\":{\"type\":\"object\",\"optional\":true}"
50 
51 // Build a schema as a const char * string without any execution overhead
52 #define SCHEMA_ANY "{}"
53 #define SCHEMA_0 "{\"type\":\"object\",\"properties\":{" SYSTEM_PARAMETERS "},\"additionalProperties\":false}" // Rejects any parameter. Only valid message is "{}"
54 #define SCHEMA_1(param) "{\"type\":\"object\",\"properties\":{" param "," SYSTEM_PARAMETERS "},\"additionalProperties\":false}" // Ex: SCHEMA_1(REQUIRED(age,integer))
55 #define SCHEMA_2(p1, p2) "{\"type\":\"object\",\"properties\":{" p1 "," p2 "," SYSTEM_PARAMETERS "},\"additionalProperties\":false}" // Ex: SCHEMA_2(REQUIRED(age,integer),OPTIONAL(nickname,string)
56 #define SCHEMA_3(p1, p2, p3) "{\"type\":\"object\",\"properties\":{" p1 "," p2 "," p3 "," SYSTEM_PARAMETERS "},\"additionalProperties\":false}"
57 #define SCHEMA_4(p1, p2, p3, p4) "{\"type\":\"object\",\"properties\":{" p1 "," p2 "," p3 "," p4 "," SYSTEM_PARAMETERS "},\"additionalProperties\":false}"
58 #define SCHEMA_5(p1, p2, p3, p4, p5) "{\"type\":\"object\",\"properties\":{" p1 "," p2 "," p3 "," p4 "," p5 "," SYSTEM_PARAMETERS "},\"additionalProperties\":false}"
59 #define SCHEMA_6(p1, p2, p3, p4, p5, p6) "{\"type\":\"object\",\"properties\":{" p1 "," p2 "," p3 "," p4 "," p5 "," p6 "," SYSTEM_PARAMETERS "},\"additionalProperties\":false}"
60 #define SCHEMA_7(p1, p2, p3, p4, p5, p6, p7) "{\"type\":\"object\",\"properties\":{" p1 "," p2 "," p3 "," p4 "," p5 "," p6 "," p7 "," SYSTEM_PARAMETERS "},\"additionalProperties\":false}"
61 #define SCHEMA_8(p1, p2, p3, p4, p5, p6, p7, p8)"{\"type\":\"object\",\"properties\":{" p1 "," p2 "," p3 "," p4 "," p5 "," p6 "," p7 "," p8 "," SYSTEM_PARAMETERS "},\"additionalProperties\":false}"
62 
63 
64 // Macros to use in place of the parameters in the SCHEMA_xxx macros above
65 #define REQUIRED(name, type) "\"" #name "\":{\"type\":\"" #type "\"}"
66 #define OPTIONAL(name, type) "\"" #name "\":{\"type\":\"" #type "\",\"optional\":true}"
67 
68 // Build a Union Schema
69 #define REQUIRED_UNION_2(name, type1, type2) "\"" #name "\":{\"type\":[{\"type\":\"" #type1 "\"},{\"type\":\"" #type2 "\"}]}"
70 
71 // Build an Object Schema as a const char * string
72 #define NAKED_OBJECT_EMPTY(objName) "\"" #objName "\":{\"type\":\"object\",\"properties\":{" SYSTEM_PARAMETERS "},\"additionalProperties\":false}"
73 #define OBJECT_EMPTY(objName) "{\"" #objName "\":{\"type\":\"object\",\"properties\":{" SYSTEM_PARAMETERS "},\"additionalProperties\":false}}"
74 
75 #define NAKED_OBJECT_REQUIRED_1(objName, p1, type1) "\"" #objName "\":{\"type\":\"object\",\"properties\":{" REQUIRED(p1, type1) "," SYSTEM_PARAMETERS "},\"additionalProperties\":false}"
76 #define OBJECT_REQUIRED_1(objName, p1, type1) "{\"" #objName "\":{\"type\":\"object\",\"properties\":{" REQUIRED(p1, type1) "," SYSTEM_PARAMETERS "},\"additionalProperties\":false}}"
77 
78 #define NAKED_OBJECT_OPTIONAL_1(objName, p1, type1) "\"" #objName "\":{\"type\":\"object\",\"properties\":{" OPTIONAL(p1, type1) "," SYSTEM_PARAMETERS "},\"additionalProperties\":false}"
79 #define OBJECT_OPTIONAL_1(objName, p1, type1) "{\"" #objName "\":{\"type\":\"object\",\"properties\":{" OPTIONAL(p1, type1) "," SYSTEM_PARAMETERS "},\"additionalProperties\":false}}"
80 
81 #define NAKED_OBJECT_REQUIRED_2(objName, p1, type1, p2, type2) "\"" #objName "\":{\"type\":\"object\",\"properties\":{" REQUIRED(p1, type1) "," REQUIRED(p2, type2) "," SYSTEM_PARAMETERS "},\"additionalProperties\":false}"
82 #define OBJECT_REQUIRED_2(objName, p1, type1, p2, type2) "{\"" #objName "\":{\"type\":\"object\",\"properties\":{" REQUIRED(p1, type1) "," REQUIRED(p2, type2) "," SYSTEM_PARAMETERS "},\"additionalProperties\":false}}"
83 
84 #define NAKED_OBJECT_OPTIONAL_2(objName, p1, type1, p2, type2) "\"" #objName "\":{\"type\":\"object\",\"properties\":{" OPTIONAL(p1, type1) "," OPTIONAL(p2, type2) "," SYSTEM_PARAMETERS "},\"additionalProperties\":false}"
85 #define OBJECT_OPTIONAL_2(objName, p1, type1, p2, type2) "{\"" #objName "\":{\"type\":\"object\",\"properties\":{" OPTIONAL(p1, type1) "," OPTIONAL(p2, type2) "," SYSTEM_PARAMETERS "},\"additionalProperties\":false}}"
86 
87 #define NAKED_OBJECT_REQUIRED_3(objName, p1, type1, p2, type2, p3, type3) "\"" #objName "\":{\"type\":\"object\",\"properties\":{" REQUIRED(p1, type1) "," REQUIRED(p2, type2) "," REQUIRED(p3, type3) "," SYSTEM_PARAMETERS "},\"additionalProperties\":false}"
88 #define OBJECT_REQUIRED_3(objName, p1, type1, p2, type2, p3, type3) "{\"" #objName "\":{\"type\":\"object\",\"properties\":{" REQUIRED(p1, type1) "," REQUIRED(p2, type2) "," REQUIRED(p3, type3) "," SYSTEM_PARAMETERS "},\"additionalProperties\":false}}"
89 
90 #define NAKED_OBJECT_OPTIONAL_3(objName, p1, type1, p2, type2, p3, type3) "\"" #objName "\":{\"type\":\"object\",\"properties\":{" OPTIONAL(p1, type1) "," OPTIONAL(p2, type2) "," OPTIONAL(p3, type3) "," SYSTEM_PARAMETERS "},\"additionalProperties\":false}"
91 #define OBJECT_OPTIONAL_3(objName, p1, type1, p2, type2, p3, type3) "{\"" #objName "\":{\"type\":\"object\",\"properties\":{" OPTIONAL(p1, type1) "," OPTIONAL(p2, type2) "," OPTIONAL(p3, type3) "," SYSTEM_PARAMETERS "},\"additionalProperties\":false}}"
92 
93 // Deprecated Macro comments
94 #define DEPRECATED_SERVICE_MSG() g_critical("THIS METHOD IS DEPRECATED. PLEASE REVISIT THE CODE.")
95 
96 class JsonValue
97 {
98 public:
99  JsonValue(const pbnjson::JValue & value) : mValue(value) {}
100 
101  pbnjson::JValue & get() { return mValue; }
102 
103  bool get(const char * name, std::string & str) { return mValue[name].asString(str) == CONV_OK; }
104  bool get(const char * name, bool & boolean) { return mValue[name].asBool(boolean) == CONV_OK; }
105  template <class T> bool get(const char * name, T & number) { return mValue[name].asNumber<T>(number) == CONV_OK; }
106  pbnjson::JValue get(const char * name) { return mValue[name]; }
107 
108 private:
109  pbnjson::JValue mValue;
110 };
111 
112 /*
113  * Helper class to parse a json message using a schema (if specified)
114  */
116 {
117 public:
118  JsonMessageParser(const char * json, const char * schema) : mJson(json), mSchema(schema) {}
119 
120  bool parse(const char * callerFunction);
121  pbnjson::JValue get() { return mParser.getDom(); }
122 
123  // convenience functions to get a parameter directly.
124  bool get(const char * name, std::string & str) { return get()[name].asString(str) == CONV_OK; }
125  bool get(const char * name, bool & boolean) { return get()[name].asBool(boolean) == CONV_OK; }
126  template <class T> bool get(const char * name, T & number) { return get()[name].asNumber<T>(number) == CONV_OK; }
127  pbnjson::JValue get(const char * name) { return get()[name]; }
128 
129 private:
130  const char * mJson;
131  pbnjson::JSchemaFragment mSchema;
132  pbnjson::JDomParser mParser;
133 };
134 
135 
140 {
141  EIgnore = 0,
145 };
146 
147 /*
148  * Small wrapper around LSError. User is responsible for calling Print or Free after the error has been set.
149  */
150 struct CLSError : public LSError
151 {
153  {
154  LSErrorInit(this);
155  }
156  void Print(const char * where, int line, GLogLevelFlags logLevel = G_LOG_LEVEL_WARNING);
157  void Free()
158  {
159  LSErrorFree(this);
160  }
161 };
162 
163 /*
164  * Helper class to parse json messages coming from an LS service using pbnjson
165  */
167 {
168 public:
169  // Default using any specific schema. Will simply validate that the message is a valid json message.
170  LSMessageJsonParser(LSMessage * message, const char * schema);
171 
179  bool parse(const char * callerFunction, LSHandle * sender = 0, ESchemaErrorOptions errOption = EIgnore);
180 
185  std::string getMsgCategoryMethod();
186 
191  std::string getSender();
192 
193  pbnjson::JValue get() { return mParser.getDom(); }
194  const char * getPayload() { return LSMessageGetPayload(mMessage); }
195 
196  // convenience functions to get a parameter directly.
197  bool get(const char * name, std::string & str) { return get()[name].asString(str) == CONV_OK; }
198  bool get(const char * name, bool & boolean) { return get()[name].asBool(boolean) == CONV_OK; }
199  template <class T> bool get(const char * name, T & number) { return get()[name].asNumber<T>(number) == CONV_OK; }
200 
201 private:
202  LSMessage * mMessage;
203  const char * mSchemaText;
204  pbnjson::JSchemaFragment mSchema;
205  pbnjson::JDomParser mParser;
206 };
207 
215 #define VALIDATE_SCHEMA_AND_RETURN_OPTION(lsHandle, message, schema, schErrOption) {\
216  LSMessageJsonParser jsonParser(message, schema); \
217  \
218  if (EDefault == schErrOption) \
219  schErrOption = static_cast<ESchemaErrorOptions>(Settings::LunaSettings()->schemaValidationOption); \
220  \
221  if (!jsonParser.parse(__FUNCTION__, lsHandle, schErrOption)) \
222  return true; \
223  }
224 
225 #define VALIDATE_SCHEMA_AND_RETURN(lsHandle, message, schema) {\
226  ESchemaErrorOptions schErrOption = EDefault; \
227  VALIDATE_SCHEMA_AND_RETURN_OPTION(lsHandle, message, schema, schErrOption); \
228  }
229 
233 #define SUBSCRIBE_SCHEMA_RETURN(lsHandle, message) VALIDATE_SCHEMA_AND_RETURN(lsHandle, message, SCHEMA_1(OPTIONAL(subscribe, boolean)))
234 
238 #define EMPTY_SCHEMA_RETURN(lsHandle, message) VALIDATE_SCHEMA_AND_RETURN(lsHandle, message, SCHEMA_ANY)
239 
240 // build a standard reply returnValue & errorCode/errorText if defined
241 pbnjson::JValue createJsonReply(bool returnValue = true, int errorCode = 0, const char * errorText = 0);
242 
243 // build a standard json reply string without the overhead of using json schema
244 std::string createJsonReplyString(bool returnValue = true, int errorCode = 0, const char * errorText = 0);
245 
246 // serialize a reply
247 std::string jsonToString(pbnjson::JValue & reply, const char * schema = SCHEMA_ANY);
248 
249 #endif // JSONUTILS_H