2 ==================================================================================
4 Copyright (c) 2018-2019 AT&T Intellectual Property.
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
10 http://www.apache.org/licenses/LICENSE-2.0
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License for the specific language governing permissions and
16 limitations under the License.
17 ==================================================================================
20 Author : Ashwin Sridharan
25 #include <json_handler.hpp>
28 TrieNode::TrieNode(int val): val_type(-1){
29 _id.tag = DataContainer::Types::integer;
33 TrieNode::TrieNode( std::string val) : val_type(-1){
34 _id.tag = DataContainer::Types::str;
35 _id.value.s.assign(val);
38 void TrieNode::set_value(const char * val){
39 _val.tag = DataContainer::Types::str;
40 _val.value.s.assign(val);
44 void TrieNode::set_value(bool val){
45 _val.tag = DataContainer::Types::boolean;
50 void TrieNode::set_value(int val){
51 _val.tag = DataContainer::Types::integer;
53 //std::cout <<"Assigned integer " << val << std::endl;
58 void TrieNode::set_value(unsigned int val){
59 _val.tag = DataContainer::Types::uinteger;
64 void TrieNode::set_value( long int val){
65 _val.tag = DataContainer::Types::big_integer;
69 void TrieNode::set_value(unsigned long int val){
70 _val.tag = DataContainer::Types::ubig_integer;
74 void TrieNode::set_value(double val){
75 _val.tag = DataContainer::Types::real;
81 void TrieNode::set_value(std::string val){
82 _val.tag = DataContainer::Types::str;
83 _val.value.s.assign(val);
86 void TrieNode::set_value(const char * c, size_t len){
87 _val.tag = DataContainer::Types::str;
88 _val.value.s.assign(c, len);
91 void TrieNode::add_child(TrieNode * node){
92 _children.push_back(node);
97 void TrieNode::print_id(void){
100 case DataContainer::Types::integer :
101 std::cout <<"Type = " << _id.tag << " Value = " << _id.value.i << std::endl;
103 case DataContainer::Types::str :
104 std::cout <<"Type = " << _id.tag << " Value = " << _id.value.s << std::endl;
107 std::cerr<< "Error ! ID not set or unknown type " << _id.tag;
111 void TrieNode::print_value(void){
114 case DataContainer::Types::boolean :
115 std::cout <<"Type = " << _val.tag << " Value = " << _val.value.b << std::endl;
117 case DataContainer::Types::integer :
118 std::cout <<"Type = " << _val.tag << " Value = " << _val.value.i << std::endl;
120 case DataContainer::Types::uinteger :
121 std::cout <<"Type = " << _val.tag << " Value = " << _val.value.ui << std::endl;
123 case DataContainer::Types::big_integer :
124 std::cout <<"Type = " << _val.tag << " Value = " << _val.value.l << std::endl;
126 case DataContainer::Types::ubig_integer :
127 std::cout <<"Type = " << _val.tag << " Value = " << _val.value.ul << std::endl;
129 case DataContainer::Types::real :
130 std::cout <<"Type = " << _val.tag << " Value = " << _val.value.f << std::endl;
132 case DataContainer::Types::str :
133 std::cout <<"Type = " << _val.tag << " Value = " << _val.value.s << std::endl;
136 std::cerr<< "Error ! Value not set or unknown type " << _val.tag;
141 jsonHandler::jsonHandler(void):_is_root(false), _is_schema(false), _is_buffer(false){
148 void jsonHandler::load_file(std::string input_file, std::string & contents ){
152 fp = std::fopen(input_file.c_str(), "rb");
154 catch(std::exception &e){
155 std::string error_string = "Error opening input schema file " + input_file;
156 throw std::runtime_error(error_string);
160 std::fseek(fp, 0, SEEK_END);
161 contents.resize(std::ftell(fp));
163 std::fread(&contents[0], 1, contents.size(), fp);
168 std::string error_string = "Error opening input file " + input_file;
169 throw std::runtime_error(error_string);
176 void jsonHandler::load_schema(std::string input_file){
178 load_file(input_file, _contents);
180 if (_doc.Parse(_contents.c_str()).HasParseError()){
181 std::string error_string = input_file + " is invalid JSON" ;
182 throw std::runtime_error(error_string);
185 _ref_schema_doc= std::make_unique<SchemaDocument>(_doc);
191 void jsonHandler::load_schema(std::string input_file, TrieNode * root){
193 load_file(input_file, _contents);
194 std::string response;
196 if (_doc.Parse(_contents.c_str()).HasParseError()){
197 std::string error_string = input_file + " is invalid JSON" ;
198 throw std::runtime_error(error_string);
201 // Get message schema
205 res = find_member(_root, response, root, _schema_root);
207 throw std::runtime_error(response);
210 _ref_schema_doc= std::make_unique<SchemaDocument>(_schema_root);
215 void jsonHandler::load_buffer(std::string input_file){
217 load_file(input_file, _buffer);
219 if (_doc.Parse(_buffer.c_str()).HasParseError()){
220 std::string error_string = input_file + " is invalid JSON" ;
221 throw std::runtime_error(error_string);
227 void jsonHandler::load_buffer(std::string input_file, TrieNode * root){
229 load_file(input_file, _buffer);
231 std::string response;
233 if (_doc.Parse(_buffer.c_str()).HasParseError()){
234 std::string error_string = input_file + " is invalid JSON" ;
235 throw std::runtime_error(error_string);
240 res = find_member(_doc, response, root, _buffer_root);
242 throw std::runtime_error(response);
245 StringBuffer out_buffer;
246 Writer<StringBuffer> writer(out_buffer);
247 _buffer_root.Accept(writer);
248 _buffer.assign(out_buffer.GetString(), out_buffer.GetLength());
253 std::string jsonHandler::get_buffer(void){
254 std::string response;
256 response.assign(_buffer);
270 bool jsonHandler::find_member(const std::string schema, std::string & response, TrieNode * root, Value & TargetVal){
273 std::string contents(schema);
275 if(doc.Parse(contents.c_str()).HasParseError()){
276 response.assign("Error Parsing JSON File");
280 return find_member(doc, response, root, TargetVal);
285 bool jsonHandler::find_member(Value & doc_root, std::string & response, TrieNode * root, Value & TargetVal){
288 response.assign("Null Trie root node");
291 //std::cout <<"LOoking for schema root" << std::endl;
293 Value & json_node = doc_root;
294 TrieNode * trie_node = root;
295 Value::MemberIterator itr;
299 DataContainer const * d = trie_node->get_id();
301 response.assign("Error could not find any id for trie node ");
305 if (d->tag == DataContainer::Types::integer && json_node.IsArray()){
306 if (json_node.Size() < d->value.i){
307 response.assign("Error json array size ");
308 response += std::to_string(json_node.Size()) + " is smaller than trie node index " + std::to_string( d->value.i);
312 if (trie_node->is_child()){
313 response.assign("Error child trie points to an array ? ");
317 trie_node = trie_node->get_children()[0];
318 json_node = json_node[d->value.i];
320 else if (d->tag == DataContainer::Types::str && json_node.IsObject()){
322 itr = json_node.FindMember(d->value.s.c_str());
323 if (itr == json_node.MemberEnd()){
324 response.assign("Error ! Could not find key = ");
325 response += d->value.s;
328 if (trie_node->is_child()){
329 // reached end of trie
330 if (itr->value.IsObject()){
331 TargetVal = itr->value.GetObject();
332 //std::cout <<"Reached root = " << itr->name.GetString() << std::endl;
334 else if (itr->value.IsArray()){
335 TargetVal = itr->value.GetArray();
338 response.assign("Error ! JSON node selected must be object or array in current version");
339 std::cerr << response << std::endl;
345 trie_node = trie_node->get_children()[0];
346 trie_node->print_id();
348 if (itr->value.IsObject()){
349 json_node = itr->value.GetObject();
351 else if (itr->value.IsArray()){
352 json_node = itr->value.GetArray();
355 std::string error_string= " Path must be an object or array";
356 response.assign(error_string);
362 std::string error_string = "Mismatch when setting root : Trie node is of type = " + std::to_string (d->tag) + " and json node is of type = " + std::to_string(json_node.GetType());
363 response.assign(error_string);
373 bool jsonHandler::is_valid(const char *message, int message_length, std::string & response){
380 SchemaValidator validator(*(_ref_schema_doc.get()));
382 // ensure message has terminator by translating to string ?
383 std::string message_s(message, message_length);
387 if (doc.Parse(message_s.c_str()).HasParseError()){
389 // return error message
390 std::string failed_message = "\"message\": \"Invalid JSON\"";
391 response.assign( failed_message );
396 // Validate against our JSON input schema
397 if (!doc.Accept(validator)){
400 validator.GetInvalidSchemaPointer().StringifyUriFragment(sb);
401 std::string failed_message = std::string("\"message\": \"Schema Violation:") + std::string(sb.GetString());
402 failed_message += std::string(" Invalid keyword :") + std::string(validator.GetInvalidSchemaKeyword()) + " \"";
403 response.assign(failed_message);
407 response.assign("SUCCESS");
415 // should be thread safe since it can be expected to be called from multiple threads
416 // only static external variable referenced is the schema (which should be read-only and hence ok ?)
418 // Returns 0 if success
419 // -1 if invalid json
420 // -2 if invalid schema (assuming schema provided)
422 // -4 no buffer available
424 int jsonHandler::get_values(const char *message, int message_length, std::string & response, TrieNode * root, std::vector<TrieNode *> & response_list){
428 // ensure message has terminator by translating to string ?
429 std::string message_s(message, message_length);
432 if (doc.Parse(message_s.c_str()).HasParseError()){
434 // return error message
435 response.assign("Invalid JSON");
439 // Validate against our JSON input schema
441 SchemaValidator validator(*(_ref_schema_doc.get()));
443 if (!doc.Accept(validator)){
446 validator.GetInvalidSchemaPointer().StringifyUriFragment(sb);
447 response = std::string("Schema Violation ") + std::string(sb.GetString()) ;
448 response += std::string(" Invalid keyword = ") + std::string(validator.GetInvalidSchemaKeyword()) + " \"";
454 Value & doc_root = doc;
455 bool res = traverse_doc(doc_root, root, true, response, response_list);
460 response.assign("SUCCESS");
465 int jsonHandler::get_values( std::string & response, TrieNode * root, std::vector<TrieNode *> & response_list){
469 _doc.Parse(_buffer.c_str());
470 Value & _buffer_root = _doc;
472 res = traverse_doc(_buffer_root, root, true, response, response_list);
476 response = "Error ! No buffer loaded in json object for get";
482 // If in get mode, return all values we can get
483 // If in set mode, return false if we cannot set a value
484 bool jsonHandler::traverse_doc(Value & json_node, TrieNode * trie_node, bool get, std::string & response, std::vector<TrieNode* > & response_list ){
487 response.assign(" Null Trie node ");
493 DataContainer const * d = trie_node->get_id();
495 response.assign(" Error could not find any id for trie node");
499 Value::MemberIterator itr;
502 if (d->tag == DataContainer::Types::integer && json_node.IsArray()){
503 if (json_node.Size() < d->value.i){
504 response = "Error json array size " + std::to_string( json_node.Size()) + " is smaller than trie node index " + std::to_string( d->value.i);
508 if (trie_node->is_child()){
509 response.assign("Error child trie points to an array ? ");
513 for (auto & e: trie_node->get_children()){
514 res = traverse_doc(json_node[d->value.i], e, get, response, response_list);
516 // if not in get mode and we hit a not found
517 // don't go any further, else move to next ...
523 else if (d->tag == DataContainer::Types::str && json_node.IsObject()){
524 itr = json_node.FindMember(d->value.s.c_str());
526 if (itr == json_node.MemberEnd()){
527 response = "Error ! Could not find key " + d->value.s;
531 if (trie_node->is_child()){
532 // end of the line : do we get or set values ?
535 if (itr->value.IsBool()){
536 trie_node->set_value(itr->value.GetBool());
539 else if (itr->value.IsInt()){
540 trie_node->set_value(itr->value.GetInt());
543 else if(itr->value.IsUint()){
544 trie_node->set_value(static_cast<unsigned int>(itr->value.GetUint()));
547 else if(itr->value.IsUint64()){
548 trie_node->set_value(static_cast<unsigned long int>(itr->value.GetUint64()));
551 else if (itr->value.IsInt64()){
552 trie_node->set_value(static_cast<long int>(itr->value.GetInt64()));
555 else if ( itr->value.IsDouble()){
556 trie_node->set_value(itr->value.GetDouble());
559 else if ( itr->value.IsString()){
560 trie_node->set_value(itr->value.GetString(), itr->value.GetStringLength());
564 response = " json node corresponding to child node key must of type bool, int or string. Is of type = " + std::to_string(itr->value.GetType());
569 response_list.push_back(trie_node);
572 //std::cout <<"Set value of child node with key = " << d->value.s.c_str() << " Type = " << trie_node->get_type() << std::endl;
576 DataContainer const * d_val = trie_node->get_value();
577 if (d_val->tag == DataContainer::Types::boolean){
578 itr->value.SetBool(d_val->value.b);
580 else if (d_val->tag == DataContainer::Types::integer){
581 itr->value.SetInt(d_val->value.i);
584 else if (d_val->tag == DataContainer::Types::uinteger){
585 itr->value.SetUint(d_val->value.ui);
588 else if (d_val->tag == DataContainer::Types::big_integer){
589 itr->value.SetInt64(d_val->value.l);
591 else if (d_val->tag == DataContainer::Types::ubig_integer){
592 itr->value.SetUint64(d_val->value.ul);
594 else if (d_val->tag == DataContainer::Types::real){
595 itr->value.SetDouble(d_val->value.f);
597 else if (d_val->tag == DataContainer::Types::str){
598 itr->value.SetString(d_val->value.s.c_str(), d_val->value.s.length());
601 response = " unknown type for child node value = " + std::to_string(d_val->tag) + " cannot set json node key = " + d->value.s;
608 for (auto & e: trie_node->get_children()){
609 res = traverse_doc(itr->value, e, get, response, response_list);
610 if(res == false && ! get){
618 response = "Mismatch : Trie node is of type = " + std::to_string(d->tag) + " while json node is of type = " + std::to_string( json_node.GetType());
628 int jsonHandler::set_values(const char * buffer, int len, std::string & response, std::vector<TrieNode *> root_nodes){
631 std::string message_s(buffer, len);
634 if (doc.Parse(message_s.c_str()).HasParseError()){
635 // return error message
636 response.assign("Invalid JSON");
641 Value & doc_root = doc;
642 // fake list to maintain signature for re-using traverse_doc
643 // since we don't return trie nodes when setting ...
644 std::vector<TrieNode *> fake_list;
645 for(auto const & e: root_nodes){
646 bool res = traverse_doc(doc_root, e, false, response, fake_list);
652 StringBuffer out_buffer;
653 Writer<StringBuffer> writer(out_buffer);
654 doc_root.Accept(writer);
655 response.assign(out_buffer.GetString(), out_buffer.GetLength());
660 // wrapper if instead of providing buffer, we simply use stored json object and use it
661 int jsonHandler::set_values(std::string & response, std::vector<TrieNode *> root_nodes){
663 std::vector<TrieNode *> fake_list;
665 _doc.Parse(_buffer.c_str());
666 Value & _buffer_root = _doc;
668 for(auto const & e: root_nodes){
669 bool res = traverse_doc(_buffer_root, e, false, response, fake_list);
675 StringBuffer out_buffer;
676 Writer<StringBuffer> writer(out_buffer);
677 _buffer_root.Accept(writer);
678 response.assign(out_buffer.GetString(), out_buffer.GetLength());
682 response = "Error ! " + std::string( __FILE__) + "," + std::to_string(__LINE__) + " : No buffer loaded in json object to set";