persistent.hpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715
  1. /*
  2. * Copyright (C) 2013 Teluu Inc. (http://www.teluu.com)
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  17. */
  18. #ifndef __PJSUA2_PERSISTENT_HPP__
  19. #define __PJSUA2_PERSISTENT_HPP__
  20. /**
  21. * @file pjsua2/persistent.hpp
  22. * @brief PJSUA2 Persistent Services
  23. */
  24. #include <pjsua2/types.hpp>
  25. #include <string>
  26. #include <vector>
  27. /** PJSUA2 API is inside pj namespace */
  28. namespace pj
  29. {
  30. /**
  31. * @defgroup PJSUA2_PERSISTENT Persistent API
  32. * @ingroup PJSUA2_Ref
  33. * @{
  34. * The persistent API provides functionality to read/write data from/to
  35. * a document (string or file). The data can be simple data types such
  36. * as boolean, number, string, and string arrays, or a user defined object.
  37. * Currently the implementation supports reading and writing from/to JSON
  38. * document, but the framework allows application to extend the API to
  39. * support other document formats.
  40. */
  41. using std::string;
  42. using std::vector;
  43. /* Forward declaration for ContainerNode */
  44. class ContainerNode;
  45. /**
  46. * This is the abstract base class of objects that can be serialized to/from
  47. * persistent document.
  48. */
  49. class PersistentObject
  50. {
  51. public:
  52. /**
  53. * Virtual destructor
  54. */
  55. virtual ~PersistentObject()
  56. {}
  57. /**
  58. * Read this object from a container node.
  59. *
  60. * @param node Container to read values from.
  61. */
  62. virtual void readObject(const ContainerNode &node) PJSUA2_THROW(Error) = 0;
  63. /**
  64. * Write this object to a container node.
  65. *
  66. * @param node Container to write values to.
  67. */
  68. virtual void writeObject(ContainerNode &node) const PJSUA2_THROW(Error) = 0;
  69. };
  70. /**
  71. * This a the abstract base class for a persistent document. A document
  72. * is created either by loading from a string or a file, or by constructing
  73. * it manually when writing data to it. The document then can be saved
  74. * to either string or to a file. A document contains one root ContainerNode
  75. * where all data are stored under.
  76. *
  77. * Document is read and written serially, hence the order of reading must be
  78. * the same as the order of writing. The PersistentDocument class provides
  79. * API to read and write to the root node, but for more flexible operations
  80. * application can use the ContainerNode methods instead. Indeed the read
  81. * and write API in PersistentDocument is just a shorthand which calls the
  82. * relevant methods in the ContainerNode. As a tip, normally application only
  83. * uses the readObject() and writeObject() methods declared here to read/write
  84. * top level objects, and use the macros that are explained in ContainerNode
  85. * documentation to read/write more detailed data.
  86. */
  87. class PersistentDocument
  88. {
  89. public:
  90. /**
  91. * Virtual destructor
  92. */
  93. virtual ~PersistentDocument()
  94. {}
  95. /**
  96. * Load this document from a file.
  97. *
  98. * @param filename The file name.
  99. */
  100. virtual void loadFile(const string &filename)
  101. PJSUA2_THROW(Error) = 0;
  102. /**
  103. * Load this document from string.
  104. *
  105. * @param input The string.
  106. */
  107. virtual void loadString(const string &input)
  108. PJSUA2_THROW(Error) = 0;
  109. /**
  110. * Write this document to a file.
  111. *
  112. * @param filename The file name.
  113. */
  114. virtual void saveFile(const string &filename)
  115. PJSUA2_THROW(Error) = 0;
  116. /**
  117. * Write this document to string.
  118. *
  119. * @return The string document.
  120. */
  121. virtual string saveString() PJSUA2_THROW(Error) = 0;
  122. /**
  123. * Get the root container node for this document
  124. *
  125. * @return The root node.
  126. */
  127. virtual ContainerNode & getRootContainer() const = 0;
  128. /*
  129. * Shorthand functions for reading and writing from/to the root container
  130. */
  131. /**
  132. * Determine if there is unread element. If yes, then app can use one of
  133. * the readXxx() functions to read it.
  134. *
  135. * @return True if there is.
  136. */
  137. bool hasUnread() const;
  138. /**
  139. * Get the name of the next unread element. It will throw Error if there
  140. * is no more element to read.
  141. *
  142. * @return The name of the next element .
  143. */
  144. string unreadName() const PJSUA2_THROW(Error);
  145. /**
  146. * Read an integer value from the document and return the value.
  147. * This will throw Error if the current element is not a number.
  148. * The read position will be advanced to the next element.
  149. *
  150. * @param name If specified, then the function will check if the
  151. * name of the next element matches the specified
  152. * name and throw Error if it doesn't match.
  153. *
  154. * @return The value.
  155. */
  156. int readInt(const string &name="") const
  157. PJSUA2_THROW(Error);
  158. /**
  159. * Read a float value from the document and return the value.
  160. * This will throw Error if the current element is not a number.
  161. * The read position will be advanced to the next element.
  162. *
  163. * @param name If specified, then the function will check if the
  164. * name of the next element matches the specified
  165. * name and throw Error if it doesn't match.
  166. *
  167. * @return The value.
  168. */
  169. float readNumber(const string &name="") const
  170. PJSUA2_THROW(Error);
  171. /**
  172. * Read a boolean value from the container and return the value.
  173. * This will throw Error if the current element is not a boolean.
  174. * The read position will be advanced to the next element.
  175. *
  176. * @param name If specified, then the function will check if the
  177. * name of the next element matches the specified
  178. * name and throw Error if it doesn't match.
  179. *
  180. * @return The value.
  181. */
  182. bool readBool(const string &name="") const
  183. PJSUA2_THROW(Error);
  184. /**
  185. * Read a string value from the container and return the value.
  186. * This will throw Error if the current element is not a string.
  187. * The read position will be advanced to the next element.
  188. *
  189. * @param name If specified, then the function will check if the
  190. * name of the next element matches the specified
  191. * name and throw Error if it doesn't match.
  192. *
  193. * @return The value.
  194. */
  195. string readString(const string &name="") const
  196. PJSUA2_THROW(Error);
  197. /**
  198. * Read a string array from the container. This will throw Error
  199. * if the current element is not a string array. The read position
  200. * will be advanced to the next element.
  201. *
  202. * @param name If specified, then the function will check if the
  203. * name of the next element matches the specified
  204. * name and throw Error if it doesn't match.
  205. *
  206. * @return The value.
  207. */
  208. StringVector readStringVector(const string &name="") const
  209. PJSUA2_THROW(Error);
  210. /**
  211. * Read the specified object from the container. This is equal to
  212. * calling PersistentObject.readObject(ContainerNode);
  213. *
  214. * @param obj The object to read.
  215. */
  216. void readObject(PersistentObject &obj) const
  217. PJSUA2_THROW(Error);
  218. /**
  219. * Read a container from the container. This will throw Error if the
  220. * current element is not an object. The read position will be advanced
  221. * to the next element.
  222. *
  223. * @param name If specified, then the function will check if the
  224. * name of the next element matches the specified
  225. * name and throw Error if it doesn't match.
  226. *
  227. * @return Container object.
  228. */
  229. ContainerNode readContainer(const string &name="") const
  230. PJSUA2_THROW(Error);
  231. /**
  232. * Read array container from the container. This will throw Error if the
  233. * current element is not an array. The read position will be advanced
  234. * to the next element.
  235. *
  236. * @param name If specified, then the function will check if the
  237. * name of the next element matches the specified
  238. * name and throw Error if it doesn't match.
  239. *
  240. * @return Container object.
  241. */
  242. ContainerNode readArray(const string &name="") const
  243. PJSUA2_THROW(Error);
  244. /**
  245. * Write a number value to the container.
  246. *
  247. * @param name The name for the value in the container.
  248. * @param num The value to be written.
  249. */
  250. void writeNumber(const string &name,
  251. float num) PJSUA2_THROW(Error);
  252. /**
  253. * Write a number value to the container.
  254. *
  255. * @param name The name for the value in the container.
  256. * @param num The value to be written.
  257. */
  258. void writeInt(const string &name,
  259. int num) PJSUA2_THROW(Error);
  260. /**
  261. * Write a boolean value to the container.
  262. *
  263. * @param name The name for the value in the container.
  264. * @param value The value to be written.
  265. */
  266. void writeBool(const string &name,
  267. bool value) PJSUA2_THROW(Error);
  268. /**
  269. * Write a string value to the container.
  270. *
  271. * @param name The name for the value in the container.
  272. * @param value The value to be written.
  273. */
  274. void writeString(const string &name,
  275. const string &value) PJSUA2_THROW(Error);
  276. /**
  277. * Write string vector to the container.
  278. *
  279. * @param name The name for the value in the container.
  280. * @param arr The vector to be written.
  281. */
  282. void writeStringVector(const string &name,
  283. const StringVector &arr)
  284. PJSUA2_THROW(Error);
  285. /**
  286. * Write an object to the container. This is equal to calling
  287. * PersistentObject.writeObject(ContainerNode);
  288. *
  289. * @param obj The object to be written
  290. */
  291. void writeObject(const PersistentObject &obj)
  292. PJSUA2_THROW(Error);
  293. /**
  294. * Create and write an empty Object node that can be used as parent
  295. * for subsequent write operations.
  296. *
  297. * @param name The name for the new container in the container.
  298. *
  299. * @return A sub-container.
  300. */
  301. ContainerNode writeNewContainer(const string &name)
  302. PJSUA2_THROW(Error);
  303. /**
  304. * Create and write an empty array node that can be used as parent
  305. * for subsequent write operations.
  306. *
  307. * @param name The name for the array.
  308. *
  309. * @return A sub-container.
  310. */
  311. ContainerNode writeNewArray(const string &name)
  312. PJSUA2_THROW(Error);
  313. };
  314. /**
  315. * Forward declaration of container_node_op.
  316. */
  317. struct container_node_op;
  318. /**
  319. * Internal data for ContainerNode. See ContainerNode implementation notes
  320. * for more info.
  321. */
  322. struct container_node_internal_data
  323. {
  324. void *doc; /**< The document. */
  325. void *data1; /**< Internal data 1 */
  326. void *data2; /**< Internal data 2 */
  327. };
  328. /**
  329. * A container node is a placeholder for storing other data elements, which
  330. * could be boolean, number, string, array of strings, or another container.
  331. * Each data in the container is basically a name/value pair, with a type
  332. * internally associated with it so that written data can be read in the
  333. * correct type. Data is read and written serially, hence the order of
  334. * reading must be the same as the order of writing.
  335. *
  336. * Application can read data from it by using the various read methods, and
  337. * write data to it using the various write methods. Alternatively, it
  338. * may be more convenient to use the provided macros below to read and write
  339. * the data, because these macros set the name automatically:
  340. * - NODE_READ_BOOL(node,item)
  341. * - NODE_READ_UNSIGNED(node,item)
  342. * - NODE_READ_INT(node,item)
  343. * - NODE_READ_FLOAT(node,item)
  344. * - NODE_READ_NUM_T(node,type,item)
  345. * - NODE_READ_STRING(node,item)
  346. * - NODE_READ_STRINGV(node,item)
  347. * - NODE_READ_OBJ(node,item)
  348. * - NODE_WRITE_BOOL(node,item)
  349. * - NODE_WRITE_UNSIGNED(node,item)
  350. * - NODE_WRITE_INT(node,item)
  351. * - NODE_WRITE_FLOAT(node,item)
  352. * - NODE_WRITE_NUM_T(node,type,item)
  353. * - NODE_WRITE_STRING(node,item)
  354. * - NODE_WRITE_STRINGV(node,item)
  355. * - NODE_WRITE_OBJ(node,item)
  356. *
  357. * Implementation notes:
  358. *
  359. * The ContainerNode class is subclass-able, but not in the usual C++ way.
  360. * With the usual C++ inheritance, some methods will be made pure virtual
  361. * and must be implemented by the actual class. However, doing so will
  362. * require dynamic instantiation of the ContainerNode class, which means
  363. * we will need to pass around the class as pointer, for example as the
  364. * return value of readContainer() and writeNewContainer() methods. Then
  365. * we will need to establish who needs or how to delete these objects, or
  366. * use shared pointer mechanism, each of which is considered too inconvenient
  367. * or complicated for the purpose.
  368. *
  369. * So hence we use C style "inheritance", where the methods are declared in
  370. * container_node_op and the data in container_node_internal_data structures.
  371. * An implementation of ContainerNode class will need to set up these members
  372. * with values that makes sense to itself. The methods in container_node_op
  373. * contains the pointer to the actual implementation of the operation, which
  374. * would be specific according to the format of the document. The methods in
  375. * this ContainerNode class are just thin wrappers which call the
  376. * implementation in the container_node_op structure.
  377. *
  378. */
  379. class ContainerNode
  380. {
  381. public:
  382. /**
  383. * Determine if there is unread element. If yes, then app can use one of
  384. * the readXxx() functions to read it.
  385. */
  386. bool hasUnread() const;
  387. /**
  388. * Get the name of the next unread element.
  389. */
  390. string unreadName() const PJSUA2_THROW(Error);
  391. /**
  392. * Read an integer value from the document and return the value.
  393. * This will throw Error if the current element is not a number.
  394. * The read position will be advanced to the next element.
  395. *
  396. * @param name If specified, then the function will check if the
  397. * name of the next element matches the specified
  398. * name and throw Error if it doesn't match.
  399. *
  400. * @return The value.
  401. */
  402. int readInt(const string &name="") const
  403. PJSUA2_THROW(Error);
  404. /**
  405. * Read a number value from the document and return the value.
  406. * This will throw Error if the current element is not a number.
  407. * The read position will be advanced to the next element.
  408. *
  409. * @param name If specified, then the function will check if the
  410. * name of the next element matches the specified
  411. * name and throw Error if it doesn't match.
  412. *
  413. * @return The value.
  414. */
  415. float readNumber(const string &name="") const
  416. PJSUA2_THROW(Error);
  417. /**
  418. * Read a boolean value from the container and return the value.
  419. * This will throw Error if the current element is not a boolean.
  420. * The read position will be advanced to the next element.
  421. *
  422. * @param name If specified, then the function will check if the
  423. * name of the next element matches the specified
  424. * name and throw Error if it doesn't match.
  425. *
  426. * @return The value.
  427. */
  428. bool readBool(const string &name="") const
  429. PJSUA2_THROW(Error);
  430. /**
  431. * Read a string value from the container and return the value.
  432. * This will throw Error if the current element is not a string.
  433. * The read position will be advanced to the next element.
  434. *
  435. * @param name If specified, then the function will check if the
  436. * name of the next element matches the specified
  437. * name and throw Error if it doesn't match.
  438. *
  439. * @return The value.
  440. */
  441. string readString(const string &name="") const
  442. PJSUA2_THROW(Error);
  443. /**
  444. * Read a string array from the container. This will throw Error
  445. * if the current element is not a string array. The read position
  446. * will be advanced to the next element.
  447. *
  448. * @param name If specified, then the function will check if the
  449. * name of the next element matches the specified
  450. * name and throw Error if it doesn't match.
  451. *
  452. * @return The value.
  453. */
  454. StringVector readStringVector(const string &name="") const
  455. PJSUA2_THROW(Error);
  456. /**
  457. * Read the specified object from the container. This is equal to
  458. * calling PersistentObject.readObject(ContainerNode);
  459. *
  460. * @param obj The object to read.
  461. */
  462. void readObject(PersistentObject &obj) const
  463. PJSUA2_THROW(Error);
  464. /**
  465. * Read a container from the container. This will throw Error if the
  466. * current element is not a container. The read position will be advanced
  467. * to the next element.
  468. *
  469. * @param name If specified, then the function will check if the
  470. * name of the next element matches the specified
  471. * name and throw Error if it doesn't match.
  472. *
  473. * @return Container object.
  474. */
  475. ContainerNode readContainer(const string &name="") const
  476. PJSUA2_THROW(Error);
  477. /**
  478. * Read array container from the container. This will throw Error if the
  479. * current element is not an array. The read position will be advanced
  480. * to the next element.
  481. *
  482. * @param name If specified, then the function will check if the
  483. * name of the next element matches the specified
  484. * name and throw Error if it doesn't match.
  485. *
  486. * @return Container object.
  487. */
  488. ContainerNode readArray(const string &name="") const
  489. PJSUA2_THROW(Error);
  490. /**
  491. * Write a number value to the container.
  492. *
  493. * @param name The name for the value in the container.
  494. * @param num The value to be written.
  495. */
  496. void writeNumber(const string &name,
  497. float num) PJSUA2_THROW(Error);
  498. /**
  499. * Write a number value to the container.
  500. *
  501. * @param name The name for the value in the container.
  502. * @param num The value to be written.
  503. */
  504. void writeInt(const string &name,
  505. int num) PJSUA2_THROW(Error);
  506. /**
  507. * Write a boolean value to the container.
  508. *
  509. * @param name The name for the value in the container.
  510. * @param value The value to be written.
  511. */
  512. void writeBool(const string &name,
  513. bool value) PJSUA2_THROW(Error);
  514. /**
  515. * Write a string value to the container.
  516. *
  517. * @param name The name for the value in the container.
  518. * @param value The value to be written.
  519. */
  520. void writeString(const string &name,
  521. const string &value) PJSUA2_THROW(Error);
  522. /**
  523. * Write string vector to the container.
  524. *
  525. * @param name The name for the value in the container.
  526. * @param arr The vector to be written.
  527. */
  528. void writeStringVector(const string &name,
  529. const StringVector &arr)
  530. PJSUA2_THROW(Error);
  531. /**
  532. * Write an object to the container. This is equal to calling
  533. * PersistentObject.writeObject(ContainerNode);
  534. *
  535. * @param obj The object to be written
  536. */
  537. void writeObject(const PersistentObject &obj)
  538. PJSUA2_THROW(Error);
  539. /**
  540. * Create and write an empty Object node that can be used as parent
  541. * for subsequent write operations.
  542. *
  543. * @param name The name for the new container in the container.
  544. *
  545. * @return A sub-container.
  546. */
  547. ContainerNode writeNewContainer(const string &name)
  548. PJSUA2_THROW(Error);
  549. /**
  550. * Create and write an empty array node that can be used as parent
  551. * for subsequent write operations.
  552. *
  553. * @param name The name for the array.
  554. *
  555. * @return A sub-container.
  556. */
  557. ContainerNode writeNewArray(const string &name)
  558. PJSUA2_THROW(Error);
  559. public:
  560. /* internal data */
  561. container_node_op *op; /**< Method table. */
  562. container_node_internal_data data; /**< Internal data */
  563. ContainerNode()
  564. : op(NULL)
  565. {
  566. pj_bzero(&data, sizeof(data));
  567. }
  568. };
  569. /**
  570. * Pointer to actual ContainerNode implementation. See ContainerNode
  571. * implementation notes for more info.
  572. */
  573. //! @cond Doxygen_Suppress
  574. struct container_node_op
  575. {
  576. bool (*hasUnread)(const ContainerNode*);
  577. string (*unreadName)(const ContainerNode*)
  578. PJSUA2_THROW(Error);
  579. float (*readNumber)(const ContainerNode*,
  580. const string&)
  581. PJSUA2_THROW(Error);
  582. bool (*readBool)(const ContainerNode*,
  583. const string&)
  584. PJSUA2_THROW(Error);
  585. string (*readString)(const ContainerNode*,
  586. const string&)
  587. PJSUA2_THROW(Error);
  588. StringVector (*readStringVector)(const ContainerNode*,
  589. const string&)
  590. PJSUA2_THROW(Error);
  591. ContainerNode (*readContainer)(const ContainerNode*,
  592. const string &)
  593. PJSUA2_THROW(Error);
  594. ContainerNode (*readArray)(const ContainerNode*,
  595. const string &)
  596. PJSUA2_THROW(Error);
  597. void (*writeNumber)(ContainerNode*,
  598. const string &name,
  599. float num)
  600. PJSUA2_THROW(Error);
  601. void (*writeBool)(ContainerNode*,
  602. const string &name,
  603. bool value)
  604. PJSUA2_THROW(Error);
  605. void (*writeString)(ContainerNode*,
  606. const string &name,
  607. const string &value)
  608. PJSUA2_THROW(Error);
  609. void (*writeStringVector)(ContainerNode*,
  610. const string &name,
  611. const StringVector &value)
  612. PJSUA2_THROW(Error);
  613. ContainerNode (*writeNewContainer)(ContainerNode*,
  614. const string &name)
  615. PJSUA2_THROW(Error);
  616. ContainerNode (*writeNewArray)(ContainerNode*,
  617. const string &name)
  618. PJSUA2_THROW(Error);
  619. };
  620. /*
  621. * Convenient macros.
  622. */
  623. #define NODE_READ_BOOL(node,item) item = node.readBool(#item)
  624. #define NODE_READ_UNSIGNED(node,item) item = (unsigned)node.readNumber(#item)
  625. #define NODE_READ_INT(node,item) item = (int) node.readNumber(#item)
  626. #define NODE_READ_FLOAT(node,item) item = node.readNumber(#item)
  627. #define NODE_READ_NUM_T(node,T,item) item = (T)(int)node.readNumber(#item)
  628. #define NODE_READ_STRING(node,item) item = node.readString(#item)
  629. #define NODE_READ_STRINGV(node,item) item = node.readStringVector(#item)
  630. #define NODE_READ_OBJ(node,item) node.readObject(item)
  631. #define NODE_WRITE_BOOL(node,item) node.writeBool(#item, item)
  632. #define NODE_WRITE_UNSIGNED(node,item) node.writeNumber(#item, (float)item)
  633. #define NODE_WRITE_INT(node,item) node.writeNumber(#item, (float)item)
  634. #define NODE_WRITE_NUM_T(node,T,item) node.writeNumber(#item, (float)item)
  635. #define NODE_WRITE_FLOAT(node,item) node.writeNumber(#item, item)
  636. #define NODE_WRITE_STRING(node,item) node.writeString(#item, item)
  637. #define NODE_WRITE_STRINGV(node,item) node.writeStringVector(#item, item)
  638. #define NODE_WRITE_OBJ(node,item) node.writeObject(item)
  639. //! @endcond
  640. /**
  641. * @} PJSUA2
  642. */
  643. } // namespace pj
  644. #endif /* __PJSUA2_PERSISTENT_HPP__ */