a14b341ae4a1ac6019d432f1c3ed05e4dfb64f14
[ric-app/admin.git] / src / json / json_handler.cc
1 /*
2 ==================================================================================
3
4         Copyright (c) 2018-2019 AT&T Intellectual Property.
5
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
9
10        http://www.apache.org/licenses/LICENSE-2.0
11
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 ==================================================================================
18 */
19 /*
20  Author : Ashwin Sridharan
21
22   
23 */
24
25 #include <json_handler.hpp>
26 #include <cstdio>
27
28 TrieNode::TrieNode(int val): val_type(-1){
29   _id.tag = DataContainer::Types::integer;
30   _id.value.i = val;
31 }
32
33 TrieNode::TrieNode( std::string val) : val_type(-1){
34   _id.tag = DataContainer::Types::str;
35   _id.value.s.assign(val);
36 }
37
38 void TrieNode::set_value(const char * val){
39   _val.tag = DataContainer::Types::str;
40   _val.value.s.assign(val);  
41 }
42
43
44 void TrieNode::set_value(bool val){
45   _val.tag = DataContainer::Types::boolean;
46   _val.value.b = val;
47   
48 }
49
50 void TrieNode::set_value(int val){
51   _val.tag = DataContainer::Types::integer;
52   _val.value.i = val;
53   //std::cout <<"Assigned integer " << val << std::endl;
54
55     
56 }
57
58 void TrieNode::set_value(unsigned int val){
59   _val.tag = DataContainer::Types::uinteger;
60   _val.value.ui = val;
61   
62 }
63
64 void TrieNode::set_value( long int val){
65   _val.tag = DataContainer::Types::big_integer;
66   _val.value.l = val;
67 }
68
69 void TrieNode::set_value(unsigned  long int val){
70   _val.tag = DataContainer::Types::ubig_integer;
71   _val.value.ul = val;
72 }
73
74 void TrieNode::set_value(double val){
75   _val.tag = DataContainer::Types::real;
76   _val.value.f = val;
77     
78 }
79
80
81 void TrieNode::set_value(std::string val){
82   _val.tag = DataContainer::Types::str;
83   _val.value.s.assign(val);
84 }
85
86 void TrieNode::set_value(const char * c, size_t len){
87   _val.tag = DataContainer::Types::str;
88   _val.value.s.assign(c, len);
89 }
90
91 void TrieNode::add_child(TrieNode * node){
92   _children.push_back(node);
93 };
94
95
96
97 void TrieNode::print_id(void){
98   switch(_id.tag){
99
100   case DataContainer::Types::integer :
101     std::cout <<"Type = " << _id.tag << " Value = " << _id.value.i << std::endl;
102     break;
103   case DataContainer::Types::str :
104     std::cout <<"Type = " << _id.tag << " Value = " << _id.value.s << std::endl;
105     break;
106   default:
107     std::cerr<< "Error ! ID  not set or unknown type " << _id.tag;
108   }
109 };
110
111 void TrieNode::print_value(void){
112   switch(_val.tag){
113
114   case DataContainer::Types::boolean :
115     std::cout <<"Type = " << _val.tag << " Value = " << _val.value.b << std::endl;
116     break;
117   case DataContainer::Types::integer :
118     std::cout <<"Type = " << _val.tag << " Value = " << _val.value.i << std::endl;
119     break;
120   case DataContainer::Types::uinteger :
121     std::cout <<"Type = " << _val.tag << " Value = " << _val.value.ui << std::endl;
122     break;
123   case DataContainer::Types::big_integer :
124     std::cout <<"Type = " << _val.tag << " Value = " << _val.value.l << std::endl;
125     break;
126   case DataContainer::Types::ubig_integer :
127     std::cout <<"Type = " << _val.tag << " Value = " << _val.value.ul << std::endl;
128     break;
129   case DataContainer::Types::real :
130     std::cout <<"Type = " << _val.tag << " Value = " << _val.value.f << std::endl;
131     break;
132   case DataContainer::Types::str :
133     std::cout <<"Type = " << _val.tag << " Value = " << _val.value.s << std::endl;
134     break;
135   default:
136     std::cerr<< "Error ! Value not set or unknown type " << _val.tag;
137   }
138 };
139     
140
141 jsonHandler::jsonHandler(void):_is_root(false), _is_schema(false), _is_buffer(false){
142  
143 };
144
145
146
147
148 void jsonHandler::load_file(std::string input_file, std::string &  contents ){
149
150   std::FILE *fp ;
151   try{
152     fp = std::fopen(input_file.c_str(), "rb");
153   }
154   catch(std::exception &e){
155     std::string error_string = "Error opening input schema file " + input_file;
156     throw std::runtime_error(error_string);
157   } 
158   
159   if (fp){
160     std::fseek(fp, 0, SEEK_END);
161     contents.resize(std::ftell(fp));
162     std::rewind(fp);
163     std::fread(&contents[0], 1, contents.size(), fp);
164     std::fclose(fp);
165   }
166   
167   else{
168     std::string error_string = "Error opening input  file " + input_file;
169     throw std::runtime_error(error_string);
170   }
171   
172 }
173
174
175
176 void jsonHandler::load_schema(std::string input_file){
177
178   load_file(input_file, _contents);
179   Document _doc;
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);
183   }
184   
185   _ref_schema_doc= std::make_unique<SchemaDocument>(_doc);
186   _is_schema = true;
187   
188   
189 }
190
191 void  jsonHandler::load_schema(std::string input_file, TrieNode * root){
192
193   load_file(input_file, _contents);
194   std::string response;
195   Document _doc;
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);
199   }
200   
201   // Get message schema
202   bool res;
203   Value  _schema_root;
204   Value &_root = _doc;
205   res = find_member(_root,  response, root, _schema_root);
206   if (res == false){
207     throw std::runtime_error(response);
208   }
209
210   _ref_schema_doc= std::make_unique<SchemaDocument>(_schema_root);
211   _is_schema = true;
212   
213 }
214
215 void jsonHandler::load_buffer(std::string input_file){
216   
217   load_file(input_file, _buffer);
218   Document _doc;
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);
222   }   
223   _is_buffer = true;
224   
225 }
226
227 void jsonHandler::load_buffer(std::string input_file, TrieNode * root){
228   
229   load_file(input_file, _buffer);
230   Document _doc;
231   std::string response;
232   
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);
236   }   
237
238   bool res;
239   Value _buffer_root;
240   res = find_member(_doc, response, root, _buffer_root);
241   if(res == false){
242     throw std::runtime_error(response);
243   }
244
245   StringBuffer out_buffer;
246   Writer<StringBuffer> writer(out_buffer);
247   _buffer_root.Accept(writer);
248   _buffer.assign(out_buffer.GetString(), out_buffer.GetLength());
249   _is_buffer = true;
250 }
251
252
253 std::string jsonHandler::get_buffer(void){
254   std::string response;  
255   if (_is_buffer){
256     response.assign(_buffer);
257   }
258   else{
259     response = "";
260   }
261   
262   return response;
263 }
264
265
266   
267
268
269
270 bool jsonHandler::find_member(const std::string schema, std::string & response, TrieNode * root, Value & TargetVal){
271
272   Document doc;
273   std::string contents(schema);
274   
275   if(doc.Parse(contents.c_str()).HasParseError()){
276     response.assign("Error Parsing JSON File");
277     return false;
278   }
279
280   return find_member(doc, response, root, TargetVal);
281   return true;
282 };
283
284
285 bool jsonHandler::find_member(Value & doc_root, std::string & response, TrieNode * root, Value & TargetVal){
286
287   if (!root){
288     response.assign("Null Trie root node");
289     return false;
290   }
291   //std::cout <<"LOoking for schema root" << std::endl;
292
293   Value & json_node = doc_root;
294   TrieNode * trie_node = root;  
295   Value::MemberIterator itr;
296   
297   while(1){
298
299     DataContainer const * d  = trie_node->get_id();
300     if (! d){
301       response.assign("Error could not find any id for trie node ");
302       return false;
303     }
304
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);
309         return false;
310       }
311       
312       if (trie_node->is_child()){
313         response.assign("Error child trie points to an array ? ");
314         return false;
315       }
316
317       trie_node = trie_node->get_children()[0];
318       json_node = json_node[d->value.i];
319     }
320     else if (d->tag == DataContainer::Types::str && json_node.IsObject()){
321       
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;
326         return false;
327       }
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;
333         }
334         else if (itr->value.IsArray()){
335           TargetVal = itr->value.GetArray();
336         }
337         else{
338           response.assign("Error ! JSON node selected  must be object or array in current version");
339           std::cerr << response << std::endl;
340           return false;
341         }
342         break;
343       }
344       else{
345         trie_node = trie_node->get_children()[0];
346         trie_node->print_id();
347         
348         if (itr->value.IsObject()){
349           json_node = itr->value.GetObject();
350         }
351         else if (itr->value.IsArray()){
352           json_node = itr->value.GetArray();
353         }
354         else{
355           std::string error_string= " Path must be an object or array";
356           response.assign(error_string);
357           return false;
358         }
359       }
360     }
361     else{
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);
364       return false;
365     }
366
367   }
368
369   return true;
370
371 }
372
373 bool jsonHandler::is_valid(const char *message, int message_length,  std::string & response){
374
375   Document doc;
376   if (! _is_schema){
377     return false;
378   }
379
380   SchemaValidator validator(*(_ref_schema_doc.get()));
381   
382   // ensure message has terminator by translating to string ?
383   std::string message_s(message, message_length);
384
385   
386   // validate json 
387   if (doc.Parse(message_s.c_str()).HasParseError()){
388     
389     // return error message
390     std::string failed_message = "\"message\": \"Invalid JSON\"";
391     response.assign( failed_message );
392     return false;
393   }
394
395   
396   // Validate against our JSON input schema
397   if (!doc.Accept(validator)){
398     
399     StringBuffer sb;
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);
404     return false;
405     
406   }
407   response.assign("SUCCESS");
408   return true;
409   
410   
411 }
412
413
414
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 ?)
417
418 // Returns 0 if success
419 // -1 if invalid json
420 // -2 if invalid schema (assuming schema provided)
421 // -3 unknown key
422 // -4 no buffer available
423
424 int jsonHandler::get_values(const  char *message, int message_length, std::string & response, TrieNode * root, std::vector<TrieNode *> & response_list){
425   
426   Document doc;
427
428   // ensure message has terminator by translating to string ?
429   std::string message_s(message, message_length);
430   
431   // validate json 
432   if (doc.Parse(message_s.c_str()).HasParseError()){
433     
434     // return error message
435     response.assign("Invalid JSON");
436     return -1;
437   }
438   
439   // Validate against our JSON input schema
440   if ( _is_schema){
441     SchemaValidator validator(*(_ref_schema_doc.get()));
442     
443     if (!doc.Accept(validator)){
444     
445       StringBuffer sb;
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()) + " \"";
449       return -2;
450     }
451
452   }
453   
454   Value & doc_root = doc;
455   bool res = traverse_doc(doc_root, root, true, response, response_list);
456   if (!res){
457     return -3;
458   }
459     
460   response.assign("SUCCESS");
461   return 0;
462 }
463
464
465 int jsonHandler::get_values( std::string & response, TrieNode * root, std::vector<TrieNode *> & response_list){
466   int res;
467   if (_is_buffer){
468     Document _doc;
469     _doc.Parse(_buffer.c_str());
470     Value & _buffer_root = _doc;
471     
472     res = traverse_doc(_buffer_root, root, true, response,  response_list);
473     return res;
474   }
475   else{
476     response = "Error !  No buffer loaded in json object for get";
477     return -4;
478   }
479 }
480
481
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 ){
485
486   if (!trie_node){
487     response.assign(" Null Trie node ");
488     return  false;
489   }
490
491   bool res;
492   
493   DataContainer const * d  = trie_node->get_id();
494   if (! d){
495     response.assign(" Error could not find any id for trie node");
496     return false;
497   }
498  
499   Value::MemberIterator itr;
500   
501
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);
505       return false;
506     }
507     
508     if (trie_node->is_child()){
509       response.assign("Error child trie points to an array ? ");
510       return false;
511     }
512     
513     for (auto & e: trie_node->get_children()){
514       res = traverse_doc(json_node[d->value.i], e, get, response, response_list);
515       if (!res && ! get){                               
516         // if not in get mode and we hit a not found
517         // don't go any further, else move to next ...
518         return res;
519       }
520     }
521   }
522   
523   else if (d->tag == DataContainer::Types::str  && json_node.IsObject()){
524     itr = json_node.FindMember(d->value.s.c_str());
525     
526     if (itr == json_node.MemberEnd()){
527       response = "Error ! Could not find key " + d->value.s;
528       return false;
529     }
530
531     if (trie_node->is_child()){
532       // end of the line : do we get or set values  ?
533       bool is_set = false;
534       if (get){
535         if (itr->value.IsBool()){
536           trie_node->set_value(itr->value.GetBool());
537           is_set = true;
538         }
539         else if (itr->value.IsInt()){
540           trie_node->set_value(itr->value.GetInt());
541           is_set = true;
542         }
543         else if(itr->value.IsUint()){
544           trie_node->set_value(static_cast<unsigned int>(itr->value.GetUint()));
545           is_set = true;
546         }
547         else if(itr->value.IsUint64()){
548           trie_node->set_value(static_cast<unsigned long int>(itr->value.GetUint64()));
549           is_set = true;
550         }
551         else if (itr->value.IsInt64()){
552           trie_node->set_value(static_cast<long int>(itr->value.GetInt64()));
553           is_set = true;
554         }
555         else if ( itr->value.IsDouble()){
556           trie_node->set_value(itr->value.GetDouble());
557           is_set = true;
558         }
559         else if ( itr->value.IsString()){
560           trie_node->set_value(itr->value.GetString(), itr->value.GetStringLength());
561           is_set = true;
562         }
563         else{
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());
565           return false;
566         }
567
568         if (is_set){
569           response_list.push_back(trie_node);
570         }
571         
572         //std::cout <<"Set value of child node with key = " << d->value.s.c_str() << " Type = " << trie_node->get_type()  << std::endl;
573         
574       }
575       else{
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);
579         }
580         else if (d_val->tag == DataContainer::Types::integer){
581           itr->value.SetInt(d_val->value.i);
582
583         }
584         else if (d_val->tag == DataContainer::Types::uinteger){
585           itr->value.SetUint(d_val->value.ui);
586
587         }
588         else if (d_val->tag == DataContainer::Types::big_integer){
589           itr->value.SetInt64(d_val->value.l);
590         }
591         else if (d_val->tag == DataContainer::Types::ubig_integer){
592           itr->value.SetUint64(d_val->value.ul);
593         }
594         else if (d_val->tag == DataContainer::Types::real){
595           itr->value.SetDouble(d_val->value.f);
596         }
597         else if (d_val->tag == DataContainer::Types::str){
598           itr->value.SetString(d_val->value.s.c_str(), d_val->value.s.length());                  
599         }
600         else{
601           response = " unknown type for child node value = " + std::to_string(d_val->tag) + " cannot set json node key = " +  d->value.s;
602           return false;
603         }
604       }      
605       return true;
606     }
607     else{
608       for (auto & e: trie_node->get_children()){
609         res = traverse_doc(itr->value, e, get, response, response_list);
610         if(res == false && ! get){
611           return false;
612         }
613       }
614     }
615   }
616  
617   else{
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());
619     return false;
620   }
621
622   return true;
623   
624  
625 }
626
627
628 int jsonHandler::set_values(const char * buffer, int len, std::string & response, std::vector<TrieNode *> root_nodes){
629  
630   Document doc;
631   std::string message_s(buffer, len);
632   
633   // validate json 
634   if (doc.Parse(message_s.c_str()).HasParseError()){  
635     // return error message
636     response.assign("Invalid JSON");
637     return -1;
638   }
639
640   
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);
647     if (!res){
648       return -3;
649     }
650   }
651   
652   StringBuffer out_buffer;
653   Writer<StringBuffer> writer(out_buffer);
654   doc_root.Accept(writer);
655   response.assign(out_buffer.GetString(), out_buffer.GetLength());
656    return 0;
657  }  
658
659
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){
662   if (_is_buffer){
663     std::vector<TrieNode *> fake_list;
664     Document _doc;
665     _doc.Parse(_buffer.c_str());
666     Value & _buffer_root = _doc;
667     
668     for(auto const & e: root_nodes){
669       bool res  = traverse_doc(_buffer_root, e,  false, response, fake_list);
670       if (!res){
671         return -3;
672       }
673     }
674     
675     StringBuffer out_buffer;
676     Writer<StringBuffer> writer(out_buffer);
677     _buffer_root.Accept(writer);
678     response.assign(out_buffer.GetString(), out_buffer.GetLength());
679     return 0;
680   }
681   else{
682     response = "Error ! " + std::string( __FILE__) + "," + std::to_string(__LINE__) + " :  No buffer loaded in json object to set";
683     return -1;
684   }
685   
686 }