Flow123d  jenkins-Flow123d-windows32-release-multijob-51
json_to_storage.hh
Go to the documentation of this file.
1 /*
2  * json_to_storage.hh
3  *
4  * Created on: May 7, 2012
5  * Author: jb
6  *
7  * TODO:
8  * EI_InputType - passing pointer is not save. The object can be deleted during stack unfolding.
9  * Error_info can not be used for abstract types (of course), the only save way is to
10  * use boost::shared_ptr, so make the copy our self by make_shared and then only pass the pointer.
11  *
12  * These problems can be eliminated, when all Type instances are static.
13  *
14  * TODO:
15  * - check cyclic references, drop const for json_spirit pointers and modify REF keys
16  * when dereferenced and modify it back when we return.
17  * (e.g. add a new entry into map
18  * TODO:
19  * Find deleting of a null pointer in json_spirit library. Possibly implement
20  * output of true stack for GNU.
21  */
22 
23 #ifndef JSON_TO_STORAGE_HH_
24 #define JSON_TO_STORAGE_HH_
25 
26 
27 #include <sstream>
28 
30 #include "input/input_type.hh"
31 
32 #include "input/accessors.hh"
33 #include "input/storage.hh"
34 
35 
36 namespace Input {
37 
38 
39 
40 /**
41  * @brief Class used by JSONToStorage class to iterate over the JSON tree provided by json_spirit library.
42  *
43  * This class keeps whole path from the root of the JSON tree to the current node. We store nodes along path in \p nodes_
44  * and address of the node in \p path_.
45  *
46  * The class also contains methods for processing of special keys 'REF' and 'TYPE'. The reference is record with only one key
47  * 'REF' with a string value that contains address of the reference. The string with the address is extracted by \p JSONToStorage::get_ref_from_head
48  * then the JSONPath corresponding to the address is provided by method \p JSONtoStorage::find_ref_node.
49  */
50 class JSONPath {
51 public:
52  /**
53  * Thrown if a reference in the input file
54  */
55 
56  TYPEDEF_ERR_INFO(EI_ErrorAddress, JSONPath);
57  TYPEDEF_ERR_INFO(EI_RefAddress, JSONPath);
58  TYPEDEF_ERR_INFO(EI_JsonFile, const string);
59  TYPEDEF_ERR_INFO(EI_RefStr, const string);
60  TYPEDEF_ERR_INFO(EI_Specification, const string);
61  DECLARE_INPUT_EXCEPTION(ExcRefOfWrongType,
62  << "Reference at address "
63  << EI_ErrorAddress::qval << " has wrong type, should by string.");
64  DECLARE_INPUT_EXCEPTION(ExcReferenceNotFound,
65  << "Error in input file: " << EI_JsonFile::qval << "\nReference {REF=\"" << EI_RefStr::val << "\"} at address " << EI_RefAddress::qval << " not found.\n"
66  << "failed to follow at address: " << EI_ErrorAddress::qval << " because " << EI_Specification::val);
67 
68 
69 
71 
72  JSONPath(const Node& root_node);
73 
74  /**
75  * Dive into json_spirit hierarchy. Store current path and returns pointer to new json_spirit node.
76  * If the json_spirit type do not match returns NULL.
77  */
78  const Node * down(unsigned int index);
79  const Node * down(const string& key);
80 
81  /**
82  * Return one level up in the hierrarchy.
83  */
84  void up();
85 
86  /**
87  * Move to root node.
88  */
89  void go_to_root();
90 
91  /**
92  * Pointer to JSON Value object at current path.
93  */
94  inline const Node * head() const
95  { return nodes_.back(); }
96 
97  /**
98  * Returns level of actual path. Root has level == 0.
99  */
100  inline int level() const
101  { return nodes_.size() - 1; }
102 
103  /**
104  * Check if current head node is a JSON Object containing one key REF of type string.
105  * If yes, returns the string through reference @p ref_address.
106  */
107  bool get_ref_from_head(string & ref_address);
108 
109  /**
110  * Creates a new JSONPath object given by address string possibly relative to the current
111  * path.
112  */
113  JSONPath find_ref_node(const string& ref_address);
114 
115  /**
116  * Output to the given stream.
117  */
118  void output(ostream &stream) const;
119 
120  /**
121  * Returns string address of current position.
122  */
123  string str();
124 
125  /**
126  * Put actual address to previous_references_ set
127  */
128  void put_address();
129 
130 private:
131  /**
132  * One level of the @p path_ is either index (nonnegative int) in array or string key in a json object.
133  * For the first type we save index into first part of the pair and empty string to the second.
134  * For the later type of level, we save -1 for index and the key into the secodn part of the pair.
135  */
138  std::set<string> previous_references_;
139 
140 
141 };
142 
143 /**
144  * Output operator for JSONPath. Mainly for debugging purposes and error messages.
145  */
146 std::ostream& operator<<(std::ostream& stream, const JSONPath& path);
147 
148 
149 /**
150  * @brief Reader for (slightly) modified JSON files.
151  *
152  * This class implements a reader of modified JSON file format. The modifications include
153  * shell-like comments (using hash '#' character), this is implemented in comment_filter.hh, optional quoting of
154  * keys in JSON objects that do not contain spaces, and possibility to use '=' instead of ':'. So you can write:
155  * @code
156  * { key1="text", key2=2, "key 3"=4 }
157  * @endcode
158  * Note, however, that our input interface allows only C identifiers for keys. The reader use json_spirit library
159  * (based on Spirit parser from Boost) with slightly modified grammar.
160  *
161  * The input file is at first read and parsed by json_spirit. Then JSONToStorage pass through tree with parsed data along
162  * with passing through declaration tree. The input data are check against declaration and stored in the Storage tree.
163  *
164  * Accessor to the root record is provided by JSONToStorage::get_root_interface<T> method template.
165  *
166  * @ingroup input
167  */
169 public:
170  /*
171  * Exceptions.
172  */
173  /// General exception during conversion from JSON tree to storage.
174  TYPEDEF_ERR_INFO(EI_InputType, string );
175  TYPEDEF_ERR_INFO(EI_File, const string);
176  TYPEDEF_ERR_INFO(EI_Specification, const string);
177  TYPEDEF_ERR_INFO(EI_JSON_Type, const string);
178  TYPEDEF_ERR_INFO( EI_ErrorAddress, JSONPath);
179  DECLARE_INPUT_EXCEPTION( ExcInputError, << "Error in input file: " << EI_File::qval << " at address: " << EI_ErrorAddress::qval <<"\n"
180  << EI_Specification::val << "\n"
181  << "JSON type: " << EI_JSON_Type::qval << "\n"
182  << "Expected type:\n" << EI_InputType::val );
183 
184 
185  TYPEDEF_ERR_INFO( EI_JSONLine, unsigned int);
186  TYPEDEF_ERR_INFO( EI_JSONColumn, unsigned int);
187  TYPEDEF_ERR_INFO( EI_JSONReason, string);
188  DECLARE_INPUT_EXCEPTION( ExcNotJSONFormat, << "Not valid JSON file " << EI_File::qval << ". Error at line "
189  << EI_JSONLine::val << " : col " << EI_JSONColumn::val
190  << " ; reason: " << EI_JSONReason::val << "\n" );
191 
192 
193  /**
194  * Read a storage from input stream. Parameter @p root_type
195  * provides input type tree declaration. See @p read_from_stream for details.
196  */
197  JSONToStorage(istream &in, const Type::TypeBase &root_type);
198 
199  /**
200  * Read a storage from string (e.g. complex default value).
201  */
202  JSONToStorage( const string &default_str, const Type::TypeBase &root_type);
203 
204  /**
205  * Returns the root accessor. The template type \p T should correspond
206  * to the kind of the input type at root of the declaration tree.
207  */
208  template <class T>
209  T get_root_interface() const;
210 
211 
212 protected:
213 
214  /**
215  * Default constructor.
216  * Provides common initialization for public constructors.
217  */
218  JSONToStorage();
219 
220  /**
221  * This method actually reads the given stream \p in, checks the data just read against the declaration tree given by \p root_type, and
222  * store the data into private storage tree using \p StorageBase classes.
223  */
224  void read_stream(istream &in, const Type::TypeBase &root_type);
225 
226  /**
227  * Getter for root of the storage tree.
228  */
230  { return storage_;}
231 
232 
233  /**
234  * Check correctness of the input given by json_spirit node at head() of JSONPath @p p
235  * against type specification @p type. Die on input error (and return NULL).
236  * For correct input, creates the storage tree and returns pointer to its root node.
237  */
238  StorageBase * make_storage(JSONPath &p, const Type::TypeBase *type);
239 
240  StorageBase * make_storage(JSONPath &p, const Type::Record *record);
241  StorageBase * make_storage(JSONPath &p, const Type::AbstractRecord *abstr_rec);
242  StorageBase * make_storage(JSONPath &p, const Type::Array *array);
243 
245  StorageBase * make_storage(JSONPath &p, const Type::Selection *selection);
248  StorageBase * make_storage(JSONPath &p, const Type::Double *double_type);
249  StorageBase * make_storage(JSONPath &p, const Type::String *string_type);
250 
251  /**
252  * Dispatch according to @p type and create corresponding storage from the given string.
253  */
254  StorageBase * make_storage_from_default( const string &dflt_str, const Type::TypeBase *type);
255 
256 
257  /// Storage of the read and checked input data
259 
260  /// Root of the declaration tree of the data in the storage.
262 
263  /**
264  * Names of all possible node types in parsed JSON tree provided by JSON Spirit library.
265  * Initialized in constructor.
266  *
267  */
269 
270 };
271 
272 
273 
274 
275 
276 
277 
278 /********************************************88
279  * Implementation
280  */
281 
282 template <class T>
284 {
285  ASSERT(storage_, "NULL pointer to storage !!! \n");
286 
287  Address addr(storage_, root_type_);
288  // try to create an iterator just to check type
289  Iterator<T>( *root_type_, addr, 0);
290 
291  auto tmp_root_type = static_cast<const typename T::InputType &>(*root_type_);
292  return T( addr, tmp_root_type );
293 }
294 
295 
296 
297 
298 } // namespace Input
299 
300 
301 
302 #endif /* JSON_TO_STORAGE_HH_ */
StorageBase * make_selection_storage_without_catch(JSONPath &p, const Type::Selection *selection)
Base of classes for declaring structure of the input data.
Definition: type_base.hh:63
Base class for nodes of a data storage tree.
Definition: storage.hh:57
StorageBase * make_storage_from_default(const string &dflt_str, const Type::TypeBase *type)
std::set< string > previous_references_
bool get_ref_from_head(string &ref_address)
DECLARE_INPUT_EXCEPTION(ExcInputError,<< "Error in input file: "<< EI_File::qval<< " at address: "<< EI_ErrorAddress::qval<<"\n"<< EI_Specification::val<< "\n"<< "JSON type: "<< EI_JSON_Type::qval<< "\n"<< "Expected type:\n"<< EI_InputType::val)
vector< string > json_type_names
std::ostream & operator<<(std::ostream &stream, const Address &address)
Definition: accessors.hh:269
JSONPath(const Node &root_node)
Class for declaration of the input of type Bool.
Definition: type_base.hh:321
void output(ostream &stream) const
vector< pair< int, string > > path_
vector< const Node * > nodes_
const StorageBase * get_storage()
JSONPath find_ref_node(const string &ref_address)
json_spirit::mValue Node
Class for declaration of the integral input data.
Definition: type_base.hh:341
Class for declaration of inputs sequences.
Definition: type_base.hh:230
int level() const
const Type::TypeBase * root_type_
Root of the declaration tree of the data in the storage.
#define ASSERT(...)
Definition: global_defs.h:121
Class for declaration of the input data that are floating point numbers.
Definition: type_base.hh:376
StorageBase * storage_
Storage of the read and checked input data.
StorageBase * make_storage(JSONPath &p, const Type::TypeBase *type)
Class for declaration of polymorphic Record.
Definition: type_record.hh:463
TYPEDEF_ERR_INFO(EI_ErrorAddress, JSONPath)
DECLARE_INPUT_EXCEPTION(ExcRefOfWrongType,<< "Reference at address "<< EI_ErrorAddress::qval<< " has wrong type, should by string.")
const Node * down(unsigned int index)
const Node * head() const
TYPEDEF_ERR_INFO(EI_InputType, string)
General exception during conversion from JSON tree to storage.
Record type proxy class.
Definition: type_record.hh:161
Reader for (slightly) modified JSON files.
Template for classes storing finite set of named values.
Class used by JSONToStorage class to iterate over the JSON tree provided by json_spirit library...
void read_stream(istream &in, const Type::TypeBase &root_type)