Line data Source code
1 : #define _OksBuildDll_
2 :
3 : #include "oks/method.hpp"
4 : #include "oks/xml.hpp"
5 : #include "oks/class.hpp"
6 : #include "oks/cstring.hpp"
7 :
8 : #include <stdexcept>
9 : #include <sstream>
10 :
11 : namespace dunedaq {
12 : namespace oks {
13 :
14 : const char OksMethodImplementation::method_impl_xml_tag[] = "method-implementation";
15 : const char OksMethodImplementation::language_xml_attr[] = "language";
16 : const char OksMethodImplementation::prototype_xml_attr[] = "prototype";
17 : const char OksMethodImplementation::body_xml_attr[] = "body";
18 :
19 : const char OksMethod::method_xml_tag[] = "method";
20 : const char OksMethod::name_xml_attr[] = "name";
21 : const char OksMethod::description_xml_attr[] = "description";
22 :
23 :
24 0 : OksMethodImplementation::OksMethodImplementation(const std::string& language, const std::string& prototype, const std::string& body, OksMethod * p) :
25 0 : p_language (language),
26 0 : p_prototype (prototype),
27 0 : p_body (body),
28 0 : p_method (p)
29 : {
30 0 : oks::validate_not_empty(p_language, "method implementation language");
31 0 : oks::validate_not_empty(p_prototype, "method implementation prototype");
32 0 : }
33 :
34 : bool
35 0 : OksMethodImplementation::operator==(const class OksMethodImplementation &i) const
36 : {
37 0 : return (
38 0 : ( this == &i ) ||
39 0 : ( p_language == i.p_language && p_prototype == i.p_prototype && p_body == i.p_body )
40 0 : );
41 : }
42 :
43 : std::ostream&
44 0 : operator<<(std::ostream& s, const OksMethodImplementation& i)
45 : {
46 0 : s << " Method implementation:\n"
47 0 : " language: \"" << i.get_language() << "\"\n"
48 0 : " prototype: \"" << i.get_prototype() << "\"\n"
49 0 : " body: \"" << i.get_body() << "\"\n";
50 :
51 0 : return s;
52 : }
53 :
54 :
55 : void
56 0 : OksMethodImplementation::save(OksXmlOutputStream& s) const
57 : {
58 0 : s.put(" ");
59 :
60 0 : s.put_start_tag(method_impl_xml_tag, sizeof(method_impl_xml_tag)-1);
61 :
62 0 : s.put_attribute( language_xml_attr, sizeof(language_xml_attr)-1, get_language().c_str() );
63 0 : s.put_attribute( prototype_xml_attr, sizeof(prototype_xml_attr)-1, get_prototype().c_str() );
64 0 : s.put_attribute( body_xml_attr, sizeof(body_xml_attr)-1, get_body().c_str() );
65 :
66 0 : s.put_end_tag();
67 0 : }
68 :
69 :
70 2639 : OksMethodImplementation::OksMethodImplementation(OksXmlInputStream& s, OksMethod * parent) :
71 2639 : p_method (parent)
72 : {
73 10556 : try {
74 18473 : while(true) {
75 10556 : OksXmlAttribute attr(s);
76 :
77 : // check for close of tag
78 :
79 10556 : if(oks::cmp_str1(attr.name(), "/")) { break; }
80 :
81 : // check for known oks-method-implementation' attributes
82 :
83 7917 : else if( oks::cmp_str8(attr.name(), language_xml_attr) ) p_language.assign(attr.value(), attr.value_len());
84 5278 : else if( oks::cmp_str9(attr.name(), prototype_xml_attr) ) p_prototype.assign(attr.value(), attr.value_len());
85 2639 : else if( oks::cmp_str4(attr.name(), body_xml_attr) ) p_body.assign(attr.value(), attr.value_len());
86 : else {
87 0 : s.throw_unexpected_attribute(attr.name());
88 : }
89 7917 : }
90 : }
91 0 : catch(oks::exception & e) {
92 0 : throw oks::FailedRead("xml method implementation", e);
93 0 : }
94 0 : catch (std::exception & e) {
95 0 : throw oks::FailedRead("xml method implementation", e.what());
96 0 : }
97 :
98 2639 : try {
99 2639 : oks::validate_not_empty(p_language, "method implementation language");
100 2639 : oks::validate_not_empty(p_prototype, "method implementation prototype");
101 : }
102 0 : catch(std::exception& ex) {
103 0 : throw oks::FailedRead("oks method implementation", oks::BadFileData(ex.what(), s.get_line_no(), s.get_line_pos()));
104 0 : }
105 2639 : }
106 :
107 :
108 0 : OksMethod::OksMethod(const std::string& nm, OksClass * p) :
109 0 : p_class (p),
110 0 : p_name (nm),
111 0 : p_implementations (nullptr)
112 : {
113 0 : try {
114 0 : oks::validate_not_empty(p_name, "method name");
115 : }
116 0 : catch(std::exception& ex) {
117 0 : Oks::error_msg("OksMethod::OksMethod()") << ex.what() << std::endl;
118 0 : }
119 0 : }
120 :
121 0 : OksMethod::OksMethod(const std::string& nm, const std::string& desc, OksClass * p) :
122 0 : p_class (p),
123 0 : p_name (nm),
124 0 : p_description (desc),
125 0 : p_implementations (nullptr)
126 : {
127 0 : oks::validate_not_empty(p_name, "method name");
128 0 : }
129 :
130 2396 : OksMethod::~OksMethod()
131 : {
132 2396 : if(p_implementations) {
133 5035 : while(!p_implementations->empty()) {
134 2639 : OksMethodImplementation * i = p_implementations->front();
135 2639 : p_implementations->pop_front();
136 2639 : delete i;
137 : }
138 :
139 2396 : delete p_implementations;
140 : }
141 2396 : }
142 :
143 :
144 : bool
145 0 : OksMethod::operator==(const class OksMethod &m) const
146 : {
147 : // check if compare with self
148 :
149 0 : if(this == &m) return true;
150 :
151 :
152 : // check if attributes are different
153 :
154 0 : if(p_name != m.p_name || p_description != m.p_description) return false;
155 :
156 :
157 : // check if methods have no implementations
158 :
159 0 : if(p_implementations == 0 && m.p_implementations == 0) return true;
160 :
161 :
162 : // check if only one method has implementation
163 :
164 0 : if(p_implementations == 0 || m.p_implementations == 0) return false;
165 :
166 :
167 : // check if numbers of implementations are different
168 :
169 0 : if(p_implementations->size() != m.p_implementations->size()) return false;
170 :
171 :
172 : // check implementations
173 :
174 0 : std::list<OksMethodImplementation *>::const_iterator i1 = p_implementations->begin();
175 0 : std::list<OksMethodImplementation *>::const_iterator i2 = m.p_implementations->begin();
176 :
177 0 : for(;i1 != p_implementations->end(); ++i1, ++i2) {
178 0 : if( !(*(*i1) == *(*i2)) ) return false;
179 : }
180 :
181 : return true;
182 : }
183 :
184 : std::ostream&
185 0 : operator<<(std::ostream& s, const OksMethod& m)
186 : {
187 0 : s << "Method name: \"" << m.p_name << "\"\n"
188 0 : " description: \"" << m.p_description << "\"\n";
189 :
190 0 : if(m.p_implementations) {
191 0 : s << " implementations:\n";
192 :
193 0 : for(std::list<OksMethodImplementation *>::const_iterator i = m.p_implementations->begin(); i != m.p_implementations->end(); ++i)
194 0 : s << *(*i);
195 : }
196 : else
197 0 : s << " there are no implementation(s)\n";
198 :
199 0 : return s;
200 : }
201 :
202 :
203 : void
204 0 : OksMethod::save(OksXmlOutputStream& s) const
205 : {
206 0 : s.put_raw(' ');
207 0 : s.put_raw(' ');
208 :
209 0 : s.put_start_tag(method_xml_tag, sizeof(method_xml_tag)-1);
210 :
211 0 : s.put_attribute(name_xml_attr, sizeof(name_xml_attr)-1, p_name.c_str());
212 0 : s.put_attribute(description_xml_attr, sizeof(description_xml_attr)-1, p_description.c_str());
213 :
214 0 : s.put_raw('>');
215 0 : s.put_raw('\n');
216 :
217 0 : if(p_implementations) {
218 0 : for(std::list<OksMethodImplementation *>::iterator i = p_implementations->begin(); i != p_implementations->end(); ++i)
219 0 : (*i)->save(s);
220 : }
221 :
222 0 : s.put_raw(' ');
223 0 : s.put_raw(' ');
224 :
225 0 : s.put_last_tag(method_xml_tag, sizeof(method_xml_tag)-1);
226 0 : }
227 :
228 :
229 2396 : OksMethod::OksMethod(OksXmlInputStream& s, OksClass * parent) :
230 2396 : p_class (parent),
231 2396 : p_implementations (0)
232 : {
233 7188 : try {
234 11980 : while(true) {
235 7188 : OksXmlAttribute attr(s);
236 :
237 : // check for close of tag
238 :
239 7188 : if(oks::cmp_str1(attr.name(), ">")) { break; }
240 :
241 : // check for known oks-relationship' attributes
242 :
243 4792 : else if(oks::cmp_str4(attr.name(), name_xml_attr)) p_name.assign(attr.value(), attr.value_len());
244 2396 : else if(oks::cmp_str11(attr.name(), description_xml_attr)) p_description.assign(attr.value(), attr.value_len());
245 : else {
246 0 : s.throw_unexpected_attribute(attr.name());
247 : }
248 4792 : }
249 : }
250 0 : catch(oks::exception & e) {
251 0 : throw oks::FailedRead("xml method", e);
252 0 : }
253 0 : catch (std::exception & e) {
254 0 : throw oks::FailedRead("xml method", e.what());
255 0 : }
256 :
257 : // check validity of read values
258 :
259 2396 : try {
260 2396 : oks::validate_not_empty(p_name, "method name");
261 : }
262 0 : catch(std::exception& ex) {
263 0 : throw oks::FailedRead("oks method", oks::BadFileData(ex.what(), s.get_line_no(), s.get_line_pos()));
264 0 : }
265 :
266 :
267 : // read 'body' and 'method-actions'
268 :
269 5035 : {
270 7674 : while(true) try {
271 5035 : const char * tag_start = s.get_tag_start();
272 :
273 5035 : if(oks::cmp_str7(tag_start, "/method")) { break; }
274 :
275 2639 : else if(!strcmp(tag_start, "method-implementation")) {
276 2639 : if(!p_implementations) p_implementations = new std::list<OksMethodImplementation *>();
277 2639 : p_implementations->push_back(new OksMethodImplementation(s, this));
278 : }
279 :
280 : else {
281 0 : std::ostringstream text;
282 0 : text << "Unexpected tag \'" << tag_start << "\' inside method \'" << p_name << "\'\n";
283 0 : throw std::runtime_error( text.str().c_str() );
284 0 : }
285 :
286 : }
287 0 : catch (oks::exception & e) {
288 0 : throw oks::FailedRead("method tag", e);
289 0 : }
290 0 : catch (std::exception & e) {
291 0 : throw oks::FailedRead("method tag", e.what());
292 2639 : }
293 : }
294 2396 : }
295 :
296 :
297 : void
298 0 : OksMethod::set_name(const std::string& new_name)
299 : {
300 : // ignore when name is the same
301 :
302 0 : if(p_name == new_name) return;
303 :
304 :
305 : // additional checks are required,
306 : // if the method already belongs to some class
307 :
308 0 : if(p_class) {
309 :
310 : // check allowed length for attribute name
311 :
312 0 : try {
313 0 : oks::validate_not_empty(new_name, "name");
314 : }
315 0 : catch(std::exception& ex) {
316 0 : throw oks::SetOperationFailed("OksMethod::set_name", ex.what());
317 0 : }
318 :
319 :
320 : // having a direct method with the same name is an error
321 :
322 0 : if(p_class->find_direct_method(new_name) != 0) {
323 0 : std::ostringstream text;
324 0 : text << "Class \"" << p_class->get_name() << "\" already has direct method \"" << new_name << '\"';
325 0 : throw oks::SetOperationFailed("OksMethod::set_name", text.str());
326 0 : }
327 :
328 :
329 : // check that it is possible to lock the file
330 :
331 0 : p_class->lock_file("OksMethod::set_name");
332 :
333 :
334 : // probably a non-direct method already exists
335 :
336 0 : OksMethod * m = p_class->find_method(new_name);
337 :
338 :
339 : // change the name
340 :
341 0 : p_name = new_name;
342 :
343 :
344 : // registrate the change
345 :
346 0 : p_class->registrate_class_change(OksClass::ChangeMethodsList, (const void *)m);
347 : }
348 : else {
349 0 : p_name = new_name;
350 : }
351 : }
352 :
353 : OksMethodImplementation *
354 0 : OksMethod::find_implementation(const std::string& language) const
355 : {
356 0 : if(p_implementations) {
357 0 : for(std::list<OksMethodImplementation *>::iterator i = p_implementations->begin(); i != p_implementations->end(); ++i)
358 0 : if(language == (*i)->get_language()) return *i;
359 : }
360 :
361 : return 0;
362 : }
363 :
364 : void
365 0 : OksMethod::add_implementation(const std::string& language, const std::string& prototype, const std::string& body)
366 : {
367 0 : if(find_implementation(language)) {
368 0 : std::ostringstream text;
369 0 : text << "Cannot add implementation on language \"" << language << "\" since it already exists.";
370 0 : throw oks::SetOperationFailed("OksMethod::add_implementation", text.str());
371 0 : }
372 :
373 0 : if(p_class) p_class->lock_file("OksMethod::add_implementation");
374 :
375 0 : if(!p_implementations) {
376 0 : p_implementations = new std::list<OksMethodImplementation *>();
377 : }
378 :
379 0 : OksMethodImplementation * i = new OksMethodImplementation(language, prototype, body);
380 :
381 0 : p_implementations->push_back(i);
382 0 : i->p_method = this;
383 :
384 0 : if(p_class) p_class->registrate_class_change(OksClass::ChangeMethodImplementation, (const void *)this);
385 0 : }
386 :
387 : void
388 0 : OksMethod::remove_implementation(const std::string& language)
389 : {
390 0 : OksMethodImplementation * i = find_implementation(language);
391 :
392 0 : if(i == 0) {
393 0 : std::ostringstream text;
394 0 : text << "Cannot remove implementation on language \"" << language << "\" since it does not exist.";
395 0 : throw oks::SetOperationFailed("OksMethod::remove_implementation", text.str());
396 0 : }
397 :
398 0 : if(p_class) p_class->lock_file("OksMethod::remove_implementation");
399 :
400 0 : p_implementations->remove(i);
401 :
402 0 : if(p_implementations->empty()) {
403 0 : delete p_implementations;
404 0 : p_implementations = 0;
405 : }
406 :
407 0 : if(p_class) p_class->registrate_class_change(OksClass::ChangeMethodImplementation, (const void *)this);
408 0 : }
409 :
410 :
411 : void
412 0 : OksMethod::set_description(const std::string& desc)
413 : {
414 0 : if(p_description != desc) {
415 0 : if(p_class) p_class->lock_file("OksMethod::set_description");
416 :
417 0 : p_description = desc;
418 :
419 0 : if(p_class) p_class->registrate_class_change(OksClass::ChangeMethodDescription, (const void *)this);
420 : }
421 0 : }
422 :
423 : void
424 0 : OksMethodImplementation::set_language(const std::string& s)
425 : {
426 0 : if(p_language != s) {
427 0 : if(p_method) {
428 0 : if(p_method->find_implementation(s) != 0) {
429 0 : std::ostringstream text;
430 0 : text << "cannot rename \"" << p_method->p_name << "\" method implementation to language \"" << s << "\" "
431 0 : "since the method already has implementation with such language.";
432 0 : throw oks::SetOperationFailed("OksMethodImplementation::set_language", text.str());
433 0 : }
434 :
435 0 : try {
436 0 : oks::validate_not_empty(s, "language");
437 : }
438 0 : catch(std::exception& ex) {
439 0 : throw oks::SetOperationFailed("OksMethodImplementation::set_language", ex.what());
440 0 : }
441 :
442 0 : if(p_method->p_class) p_method->p_class->lock_file("OksMethodImplementation::set_language");
443 : }
444 :
445 0 : p_language = s;
446 :
447 0 : if(p_method && p_method->p_class) {
448 0 : p_method->p_class->registrate_class_change(OksClass::ChangeMethodImplementation, (const void *)this);
449 : }
450 : }
451 0 : }
452 :
453 : void
454 0 : OksMethodImplementation::set_prototype(const std::string& s)
455 : {
456 0 : if(p_prototype != s) {
457 0 : try {
458 0 : oks::validate_not_empty(s, "prototype");
459 : }
460 0 : catch(std::exception& ex) {
461 0 : throw oks::SetOperationFailed("OksMethodImplementation::set_prototype", ex.what());
462 0 : }
463 :
464 0 : if(p_method && p_method->p_class) p_method->p_class->lock_file("OksMethodImplementation::set_prototype");
465 :
466 0 : p_prototype = s;
467 :
468 0 : if(p_method && p_method->p_class) {
469 0 : p_method->p_class->registrate_class_change(OksClass::ChangeMethodImplementation, (const void *)this);
470 : }
471 : }
472 0 : }
473 :
474 : void
475 0 : OksMethodImplementation::set_body(const std::string& s)
476 : {
477 0 : if(p_body != s) {
478 0 : if(p_method && p_method->p_class) p_method->p_class->lock_file("OksMethodImplementation::set_body");
479 :
480 0 : p_body = s;
481 :
482 0 : if(p_method && p_method->p_class) {
483 0 : p_method->p_class->registrate_class_change(OksClass::ChangeMethodImplementation, (const void *)this);
484 : }
485 : }
486 0 : }
487 :
488 : } // namespace oks
489 : } // namespace dunedaq
|