ChimeraTK-DeviceAccess-DoocsBackend 01.11.02
Loading...
Searching...
No Matches
CatalogueCache.cc
Go to the documentation of this file.
1#include "CatalogueCache.h"
2
3#include "RegisterInfo.h"
4#include "StringUtility.h"
5
6#include <doocs/EqCall.h>
7#include <libxml++/libxml++.h>
8
9#include <boost/algorithm/string.hpp>
10#include <boost/filesystem.hpp>
11
12#include <eq_types.h>
13
14#include <cerrno>
15#include <cstdlib>
16#include <cstring>
17#include <fstream>
18
19/********************************************************************************************************************/
20
21namespace Cache {
22
23 static std::unique_ptr<xmlpp::DomParser> createDomParser(const std::string& xmlfile);
24 static xmlpp::Element* getRootNode(xmlpp::DomParser& parser);
25 static unsigned int convertToUint(const std::string& s, int line);
26 static int convertToInt(const std::string& s, int line);
27 static void parseRegister(xmlpp::Element const* registerNode, DoocsBackendRegisterCatalogue& catalogue);
28 static unsigned int parseLength(xmlpp::Element const* c);
29 static int parseTypeId(xmlpp::Element const* c);
30 static ChimeraTK::AccessModeFlags parseAccessMode(xmlpp::Element const* c);
31 static void addRegInfoXmlNode(const DoocsBackendRegisterInfo& r, xmlpp::Node* rootNode);
32
33 /********************************************************************************************************************/
34
35 DoocsBackendRegisterCatalogue readCatalogue(const std::string& xmlfile) {
37 auto parser = createDomParser(xmlfile);
38 auto registerList = getRootNode(*parser);
39
40 for(auto const node : registerList->get_children()) {
41 auto reg = dynamic_cast<const xmlpp::Element*>(node);
42 if(reg == nullptr) {
43 continue;
44 }
45 parseRegister(reg, catalogue);
46 }
47 return catalogue;
48 }
49
50 /********************************************************************************************************************/
51 bool is_empty(std::ifstream& f) {
52 return f.peek() == std::ifstream::traits_type::eof();
53 }
54
55 bool is_empty(std::ifstream&& f) {
56 return is_empty(f);
57 }
58
59 /********************************************************************************************************************/
60
61 void saveCatalogue(const DoocsBackendRegisterCatalogue& c, const std::string& xmlfile) {
62 xmlpp::Document doc;
63
64 auto rootNode = doc.create_root_node("catalogue");
65 rootNode->set_attribute("version", "1.0");
66
67 for(auto& doocsRegInfo : c) {
68 addRegInfoXmlNode(doocsRegInfo, rootNode);
69 }
70
71 const std::string pathTemplate = "%%%%%%-doocs-backend-cache-%%%%%%.tmp";
72 boost::filesystem::path temporaryName;
73
74 try {
75 temporaryName = boost::filesystem::unique_path(boost::filesystem::path(pathTemplate));
76 }
77 catch(boost::filesystem::filesystem_error& e) {
78 throw ChimeraTK::runtime_error(std::string{"Failed to generate temporary path: "} + e.what());
79 }
80
81 {
82 auto stream = std::ofstream(temporaryName);
83 doc.write_to_stream_formatted(stream);
84 }
85
86 // check for empty tmp file:
87 // xmlpp::Document::write_to_file_formatted sometimes misbehaves on exceptions, creating
88 // empty files.
89 if(is_empty(std::ifstream(temporaryName))) {
90 throw ChimeraTK::runtime_error(std::string{"Failed to save cache File"});
91 }
92
93 try {
94 boost::filesystem::rename(temporaryName, xmlfile);
95 }
96 catch(boost::filesystem::filesystem_error& e) {
97 throw ChimeraTK::runtime_error(std::string{"Failed to replace cache file: "} + e.what());
98 }
99 }
100
101 /********************************************************************************************************************/
102
103 void parseRegister(xmlpp::Element const* registerNode, DoocsBackendRegisterCatalogue& catalogue) {
104 std::string name;
105 unsigned int len{};
106 int doocsTypeId{};
107 ChimeraTK::DataDescriptor descriptor{};
108 ChimeraTK::AccessModeFlags flags{};
109
110 for(auto& node : registerNode->get_children()) {
111 auto e = dynamic_cast<const xmlpp::Element*>(node);
112 if(e == nullptr) {
113 continue;
114 }
115 std::string nodeName = e->get_name();
116
117 if(nodeName == "name") {
118 name = e->get_child_text()->get_content();
119 }
120 else if(nodeName == "length") {
121 len = parseLength(e);
122 }
123 else if(nodeName == "access_mode") {
124 flags = parseAccessMode(e);
125 }
126 else if(nodeName == "doocs_type_id") {
127 doocsTypeId = parseTypeId(e);
128 }
129 }
130
131 bool is_ifff = (doocsTypeId == DATA_IFFF);
132
133 if(is_ifff) {
134 auto pattern = detail::endsWith(name, {"/I", "/F1", "/F2", "/F3"}).second;
135 // remove pattern from name for getRegInfo to work correctly;
136 // precondition: patten is contained in name.
137 name.erase(name.end() - pattern.length(), name.end());
138 }
139
140 // add corresponding registers (note: only registers not yet being in the catalogue will be added)
141 catalogue.addProperty(name, len, doocsTypeId, flags);
142 }
143
144 /********************************************************************************************************************/
145
146 unsigned int parseLength(xmlpp::Element const* c) {
147 return convertToUint(c->get_child_text()->get_content(), c->get_line());
148 }
149
150 /********************************************************************************************************************/
151
152 int parseTypeId(xmlpp::Element const* c) {
153 return convertToInt(c->get_child_text()->get_content(), c->get_line());
154 }
155
156 /********************************************************************************************************************/
157
158 ChimeraTK::AccessModeFlags parseAccessMode(xmlpp::Element const* c) {
159 std::string accessMode{};
160 auto t = c->get_child_text();
161 if(t != nullptr) {
162 accessMode = t->get_content();
163 }
164 return ChimeraTK::AccessModeFlags::deserialize(accessMode);
165 }
166
167 /********************************************************************************************************************/
168
169 std::unique_ptr<xmlpp::DomParser> createDomParser(const std::string& xmlfile) {
170 try {
171 return std::make_unique<xmlpp::DomParser>(xmlfile);
172 }
173 catch(std::exception& e) {
174 throw ChimeraTK::logic_error("Error opening " + xmlfile + ": " + e.what());
175 }
176 }
177
178 /********************************************************************************************************************/
179
180 xmlpp::Element* getRootNode(xmlpp::DomParser& parser) {
181 try {
182 auto root = parser.get_document()->get_root_node();
183 if(root->get_name() != "catalogue") {
184 ChimeraTK::logic_error("Expected tag 'catalog' got: " + root->get_name());
185 }
186 return root;
187 }
188 catch(std::exception& e) {
189 throw ChimeraTK::logic_error(e.what());
190 }
191 }
192
193 /********************************************************************************************************************/
194
195 unsigned int convertToUint(const std::string& s, int line) {
196 try {
197 return std::stoul(s);
198 }
199 catch(std::invalid_argument& e) {
200 throw ChimeraTK::logic_error("Failed to parse node at line " + std::to_string(line) + ":" + e.what());
201 }
202 catch(std::out_of_range& e) {
203 throw ChimeraTK::logic_error("Failed to parse node at line " + std::to_string(line) + ":" + e.what());
204 }
205 }
206 /********************************************************************************************************************/
207
208 int convertToInt(const std::string& s, int line) {
209 try {
210 return std::stol(s);
211 }
212 catch(std::invalid_argument& e) {
213 throw ChimeraTK::logic_error("Failed to parse node at line " + std::to_string(line) + ":" + e.what());
214 }
215 catch(std::out_of_range& e) {
216 throw ChimeraTK::logic_error("Failed to parse node at line " + std::to_string(line) + ":" + e.what());
217 }
218 }
219
220 /********************************************************************************************************************/
221
222 void addRegInfoXmlNode(const DoocsBackendRegisterInfo& r, xmlpp::Node* rootNode) {
223 auto registerTag = rootNode->add_child("register");
224
225 auto nameTag = registerTag->add_child("name");
226 nameTag->set_child_text(static_cast<std::string>(r.getRegisterName()));
227
228 auto lengthTag = registerTag->add_child("length");
229 lengthTag->set_child_text(std::to_string(r.getNumberOfElements()));
230
231 auto accessMode = registerTag->add_child("access_mode");
232 accessMode->set_child_text(r.accessModeFlags.serialize());
233
234 auto typeId = registerTag->add_child("doocs_type_id");
235 typeId->set_child_text(std::to_string(r.doocsTypeId));
236
237 std::string comment_text = std::string("doocs id: ") + doocs::EqData().type_string(r.doocsTypeId);
238 registerTag->add_child_comment(comment_text);
239 }
240
241} // namespace Cache
void addProperty(const std::string &name, unsigned int length, int doocsType, ChimeraTK::AccessModeFlags flags)
ChimeraTK::RegisterPath getRegisterName() const override
ChimeraTK::AccessModeFlags accessModeFlags
unsigned int getNumberOfElements() const override
bool is_empty(std::ifstream &f)
DoocsBackendRegisterCatalogue readCatalogue(const std::string &xmlfile)
void saveCatalogue(const DoocsBackendRegisterCatalogue &c, const std::string &xmlfile)
std::pair< bool, std::string > endsWith(std::string const &s, const std::vector< std::string > &patterns)