metaproxy 1.22.1
router_flexml.cpp
Go to the documentation of this file.
1/* This file is part of Metaproxy.
2 Copyright (C) Index Data
3
4Metaproxy is free software; you can redistribute it and/or modify it under
5the terms of the GNU General Public License as published by the Free
6Software Foundation; either version 2, or (at your option) any later
7version.
8
9Metaproxy is distributed in the hope that it will be useful, but WITHOUT ANY
10WARRANTY; without even the implied warranty of MERCHANTABILITY or
11FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program; if not, write to the Free Software
16Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17*/
18
19#include "config.hpp"
20#include <metaproxy/xmlutil.hpp>
21#include <string.h>
22#include "router_flexml.hpp"
23#include "factory_filter.hpp"
24#include "factory_static.hpp"
25
26#include <iostream>
27#include <map>
28#include <list>
29#include <yaz/log.h>
30#include <yaz/xml_include.h>
31
32#include <boost/shared_ptr.hpp>
33
34#include <libxml/xmlversion.h>
35#include <libxml/parser.h>
36#include <libxml/tree.h>
37
38namespace mp = metaproxy_1;
39
40namespace metaproxy_1 {
42 friend class RouterFleXML::Rep;
43 friend class RouterFleXML::Pos;
44 friend class RouterFleXML;
45 std::list<boost::shared_ptr<const mp::filter::Base> > m_list;
46 };
48 friend class RouterFleXML;
49 friend class RouterFleXML::Pos;
50 Rep();
51
53 const char *file_include_path);
54
55 typedef std::map<std::string,
56 boost::shared_ptr<const mp::filter::Base > >
58
60
61 std::map<std::string,RouterFleXML::Route> m_routes;
62
63 std::string m_start_route;
64
65 std::string m_dl_path;
66
68 const char *file_include_path);
69
71 bool test_only, const char *file_include_path);
73 bool test_only, const char *file_include_path,
74 Route &route);
76 bool test_only, const char *file_include_path);
78
80 private:
81 FactoryFilter *m_factory; // TODO shared_ptr
82 };
83
84 class RouterFleXML::Pos : public RoutePos {
85 public:
86 virtual const filter::Base *move(const char *route);
87 virtual RoutePos *clone();
88 virtual ~Pos();
89 mp::RouterFleXML::Rep *m_p;
90
91 std::map<std::string,
93 std::list<boost::shared_ptr <const mp::filter::Base> >::iterator m_filter_it;
94 };
95}
96
97void mp::RouterFleXML::Rep::parse_xml_filters(xmlDocPtr doc,
98 const xmlNode *node,
99 bool test_only,
100 const char *file_include_path)
101{
102 unsigned int filter_nr = 0;
103 while (node && mp::xml::check_element_mp(node, "filter"))
104 {
105 filter_nr++;
106
107 const struct _xmlAttr *attr;
108 std::string id_value;
109 std::string type_value;
110 for (attr = node->properties; attr; attr = attr->next)
111 {
112 std::string name = std::string((const char *) attr->name);
113 std::string value;
114
115 if (attr->children && attr->children->type == XML_TEXT_NODE)
116 value = std::string((const char *)attr->children->content);
117
118 if (name == "id")
119 id_value = value;
120 else if (name == "type")
121 type_value = value;
122 else if (name == "base")
123 ;// Ignore XInclude base attribute.
124 else
125 throw mp::XMLError("Only attribute id or type allowed"
126 " in filter element. Got " + name);
127 }
128
129 if (!m_factory->exist(type_value))
130 {
131 yaz_log(YLOG_LOG, "Loading %s (dlpath %s)",
132 type_value.c_str(), m_dl_path.c_str());
133 m_factory->add_creator_dl(type_value, m_dl_path);
134 }
135 boost::shared_ptr<mp::filter::Base> fb(m_factory->create(type_value));
136
137 fb->configure(node, test_only, file_include_path);
138
139 if (m_id_filter_map.find(id_value) != m_id_filter_map.end())
140 throw mp::XMLError("Filter " + id_value + " already defined");
141
142 m_id_filter_map[id_value] = fb;
143
144 node = mp::xml::jump_to_next(node, XML_ELEMENT_NODE);
145 }
146}
147
148void mp::RouterFleXML::Rep::parse_xml_filters1(xmlDocPtr doc,
149 const xmlNode *node,
150 bool test_only,
151 const char *file_include_path,
152 Route &route)
153{
154 while (node)
155 {
156 if (mp::xml::is_element_mp(node, "filters"))
157 {
158 const xmlNode* node1 =
159 mp::xml::jump_to_children(node, XML_ELEMENT_NODE);
160
161 parse_xml_filters1(doc, node1, test_only, file_include_path, route);
162 }
163 else if (mp::xml::check_element_mp(node, "filter"))
164 {
165 const struct _xmlAttr *attr;
166 std::string refid_value;
167 std::string type_value;
168 for (attr = node->properties; attr; attr = attr->next)
169 {
170 std::string name = std::string((const char *) attr->name);
171 std::string value;
172
173 if (attr->children && attr->children->type == XML_TEXT_NODE)
174 value = std::string((const char *)attr->children->content);
175
176 if (name == "refid")
177 refid_value = value;
178 else if (name == "type")
179 type_value = value;
180 else if (name == "base")
181 ;// Ignore XInclude base attribute.
182 else
183 throw mp::XMLError("Only attribute 'refid' or 'type'"
184 " allowed for element 'filter'."
185 " Got " + name);
186 }
187 if (refid_value.length())
188 {
189 std::map<std::string,
190 boost::shared_ptr<const mp::filter::Base > >::iterator it;
191 it = m_id_filter_map.find(refid_value);
192 if (it == m_id_filter_map.end())
193 throw mp::XMLError("Unknown filter refid "
194 + refid_value);
195 else
196 route.m_list.push_back(it->second);
197 }
198 else if (type_value.length())
199 {
200 if (!m_factory->exist(type_value))
201 {
202 yaz_log(YLOG_LOG, "Loading %s (dlpath %s)",
203 type_value.c_str(), m_dl_path.c_str());
204 m_factory->add_creator_dl(type_value, m_dl_path);
205 }
206 boost::shared_ptr<mp::filter::Base>
207 filter_base(m_factory->create(type_value));
208
209 filter_base->configure(node, test_only, file_include_path);
210
211 route.m_list.push_back(filter_base);
212 }
213
214 }
215 node = mp::xml::jump_to_next(node, XML_ELEMENT_NODE);
216 }
217}
218
219
220void mp::RouterFleXML::Rep::parse_xml_routes(xmlDocPtr doc,
221 const xmlNode *node,
222 bool test_only,
223 const char *file_include_path)
224{
225 mp::xml::check_element_mp(node, "route");
226
227 unsigned int route_nr = 0;
228 while (mp::xml::is_element_mp(node, "route"))
229 {
230 route_nr++;
231
232 const struct _xmlAttr *attr;
233 std::string id_value;
234 for (attr = node->properties; attr; attr = attr->next)
235 {
236 std::string name = std::string((const char *) attr->name);
237 std::string value;
238
239 if (attr->children && attr->children->type == XML_TEXT_NODE)
240 value = std::string((const char *)attr->children->content);
241
242 if (name == "id")
243 id_value = value;
244 else if (name == "base")
245 ;// Ignore XInclude base attribute.
246 else
247 throw mp::XMLError("Only attribute 'id' allowed for"
248 " element 'route'."
249 " Got " + name);
250 }
251
252 Route route;
253
254 // process <filter> / <filters> nodes in third level
255 const xmlNode* node3 = mp::xml::jump_to_children(node, XML_ELEMENT_NODE);
256
257
258
259 parse_xml_filters1(doc, node3, test_only, file_include_path, route);
260
261 std::map<std::string,RouterFleXML::Route>::iterator it;
262 it = m_routes.find(id_value);
263 if (it != m_routes.end())
264 throw mp::XMLError("Route id='" + id_value
265 + "' already exist");
266 else
267 m_routes[id_value] = route;
268 node = mp::xml::jump_to_next(node, XML_ELEMENT_NODE);
269 }
270}
271
272void mp::RouterFleXML::Rep::check_routes_in_filters(const xmlNode *node)
273{
274 while (node)
275 {
276 if (mp::xml::is_element_mp(node, "filters"))
277 {
278 const xmlNode *n =
279 mp::xml::jump_to_children(node, XML_ELEMENT_NODE);
280 check_routes_in_filters(n);
281 }
282 else if (mp::xml::is_element_mp(node, "filter"))
283 {
284 const xmlNode *n =
285 mp::xml::jump_to_children(node, XML_ELEMENT_NODE);
286 while (n)
287 {
288 const struct _xmlAttr *attr;
289 // we assume thar that route attribute is only at one level
290 // below filter.. At least that works for multi and virt_db.
291 for (attr = n->properties; attr; attr = attr->next)
292 {
293 if (!strcmp((const char *) attr->name, "route"))
294 {
295 std::string value;
296
297 if (attr->children && attr->children->type == XML_TEXT_NODE)
298 value = std::string((const char *)attr->children->content);
299
300 std::map<std::string,RouterFleXML::Route>::iterator it;
301 it = m_routes.find(value);
302 if (it == m_routes.end())
303 {
304 throw mp::XMLError("Route '" + value + "' does not exist");
305 }
306 }
307 }
308 n = mp::xml::jump_to_next(n, XML_ELEMENT_NODE);
309 }
310 }
311 node = mp::xml::jump_to_next(node, XML_ELEMENT_NODE);
312 }
313}
314
315void mp::RouterFleXML::Rep::parse_xml_config_dom(xmlDocPtr doc,
316 bool test_only,
317 const char *file_include_path)
318{
319 if (!doc)
320 throw mp::XMLError("Empty XML Document");
321
322 const xmlNode* root = xmlDocGetRootElement(doc);
323
324 if (file_include_path)
325 {
326 int r = yaz_xml_include_glob((xmlNode *) root, file_include_path,
327 YAZ_FILE_GLOB_FAIL_NOTEXIST);
328 if (r)
329 throw mp::XMLError("YAZ XML Include failed");
330 }
331
332 mp::xml::check_element_mp(root, "metaproxy");
333
334 const xmlNode* node = mp::xml::jump_to_children(root, XML_ELEMENT_NODE);
335
336 if (mp::xml::is_element_mp(node, "dlpath"))
337 {
338 m_dl_path = mp::xml::get_text(node);
339 node = mp::xml::jump_to_next(node, XML_ELEMENT_NODE);
340 }
341 // process <start> node which is expected first element node
342 if (mp::xml::check_element_mp(node, "start"))
343 {
344 const struct _xmlAttr *attr;
345 for (attr = node->properties; attr; attr = attr->next)
346 {
347 std::string name = std::string((const char *) attr->name);
348 std::string value;
349
350 if (attr->children && attr->children->type == XML_TEXT_NODE)
351 value = std::string((const char *)attr->children->content);
352
353 if (name == "route")
354 m_start_route = value;
355 else if (name == "base")
356 ;// Ignore XInclude base attribute.
357 else
358 throw mp::XMLError("Only attribute route allowed"
359 " in element 'start'. Got " + name);
360 }
361 node = mp::xml::jump_to_next(node, XML_ELEMENT_NODE);
362 }
363 // process <filters> node if given
364 if (mp::xml::is_element_mp(node, "filters"))
365 {
366 parse_xml_filters(doc, mp::xml::jump_to_children(node,
367 XML_ELEMENT_NODE),
368 test_only, file_include_path);
369
370 node = mp::xml::jump_to_next(node, XML_ELEMENT_NODE);
371 }
372 // process <routes> node which is expected third element node
373 mp::xml::check_element_mp(node, "routes");
374
375 parse_xml_routes(doc, mp::xml::jump_to_children(node, XML_ELEMENT_NODE),
376 test_only, file_include_path);
377
378 node = mp::xml::jump_to_next(node, XML_ELEMENT_NODE);
379 if (node)
380 {
381 throw mp::XMLError("Unexpected element "
382 + std::string((const char *)node->name));
383 }
384
385 node = mp::xml::jump_to_children(root, XML_ELEMENT_NODE);
386 while (node)
387 {
388 if (mp::xml::is_element_mp(node, "filters"))
389 check_routes_in_filters(
390 mp::xml::jump_to_children(node,
391 XML_ELEMENT_NODE));
392 else if (mp::xml::is_element_mp(node, "routes"))
393 {
394 const xmlNode* n = mp::xml::jump_to_children(node,
395 XML_ELEMENT_NODE);
396 while (n)
397 {
398 if (mp::xml::is_element_mp(n, "route"))
399 {
400 check_routes_in_filters(
401 mp::xml::jump_to_children(n, XML_ELEMENT_NODE));
402
403 }
404 n = mp::xml::jump_to_next(n, XML_ELEMENT_NODE);
405 }
406 }
407 node = mp::xml::jump_to_next(node, XML_ELEMENT_NODE);
408 }
409 std::map<std::string,RouterFleXML::Route>::iterator it;
410 it = m_routes.find(m_start_route);
411 if (it == m_routes.end())
412 throw mp::XMLError("Start route '" + m_start_route + "' not found");
413}
414
415mp::RouterFleXML::Rep::Rep() : m_xinclude(false)
416{
417}
418
419void mp::RouterFleXML::Rep::base(xmlDocPtr doc, mp::FactoryFilter &factory,
420 bool test_only, const char *file_include_path)
421{
422 m_factory = &factory;
423 m_start_route = "start";
424 parse_xml_config_dom(doc, test_only, file_include_path);
425}
426
427mp::RouterFleXML::RouterFleXML(xmlDocPtr doc, mp::FactoryFilter &factory,
428 bool test_only, const char *file_include_path)
429 : m_p(new Rep)
430{
432}
433
434mp::RouterFleXML::RouterFleXML(std::string xmlconf, mp::FactoryFilter &factory,
435 bool test_only)
436 : m_p(new Rep)
437{
439 xmlconf.size());
440 if (!doc)
441 throw mp::XMLError("xmlParseMemory failed");
442 else
443 {
444 m_p->base(doc, factory, test_only, 0);
446 }
447}
448
449mp::RouterFleXML::~RouterFleXML()
450{
451}
452
453const mp::filter::Base *mp::RouterFleXML::Pos::move(const char *route)
454{
455 if (route && *route)
456 {
457 m_route_it = m_p->m_routes.find(route);
458 if (m_route_it == m_p->m_routes.end())
459 {
460 yaz_log(YLOG_FATAL, "no such route %s", route);
461 return 0;
462 }
463 m_filter_it = m_route_it->second.m_list.begin();
464 }
465 if (m_filter_it == m_route_it->second.m_list.end())
466 return 0;
467 const mp::filter::Base *f = (*m_filter_it).get();
468 m_filter_it++;
469 return f;
470}
471
472mp::RoutePos *mp::RouterFleXML::createpos() const
473{
474 mp::RouterFleXML::Pos *p = new mp::RouterFleXML::Pos;
475
476 p->m_route_it = m_p->m_routes.find(m_p->m_start_route);
477 if (p->m_route_it == m_p->m_routes.end())
478 {
479 delete p;
480 return 0;
481 }
482 p->m_filter_it = p->m_route_it->second.m_list.begin();
483 p->m_p = m_p.get();
484 return p;
485}
486
487mp::RoutePos *mp::RouterFleXML::Pos::clone()
488{
489 mp::RouterFleXML::Pos *p = new mp::RouterFleXML::Pos;
490 p->m_filter_it = m_filter_it;
491 p->m_route_it = m_route_it;
492 p->m_p = m_p;
493 return p;
494}
495
496mp::RouterFleXML::Pos::~Pos()
497{
498}
499
500
501void mp::RouterFleXML::start()
502{
503 std::map<std::string,RouterFleXML::Route>::iterator route_it;
504
505 route_it = m_p->m_routes.begin();
506 while (route_it != m_p->m_routes.end())
507 {
508 RouterFleXML::Route route = route_it->second;
509
510 std::list<boost::shared_ptr<const mp::filter::Base> >::iterator it;
511
512 for (it = route.m_list.begin(); it != route.m_list.end(); it++)
513 (*it)->start();
514 route_it++;
515 }
516}
517
518void mp::RouterFleXML::stop(int signo)
519{
520 std::map<std::string,RouterFleXML::Route>::iterator route_it;
521
522 route_it = m_p->m_routes.begin();
523 while (route_it != m_p->m_routes.end())
524 {
525 RouterFleXML::Route route = route_it->second;
526
527 std::list<boost::shared_ptr<const mp::filter::Base> >::iterator it;
528
529 for (it = route.m_list.begin(); it != route.m_list.end(); it++)
530 (*it)->stop(signo);
531 route_it++;
532 }
533}
534
535
536/*
537 * Local variables:
538 * c-basic-offset: 4
539 * c-file-style: "Stroustrup"
540 * indent-tabs-mode: nil
541 * End:
542 * vim: shiftwidth=4 tabstop=8 expandtab
543 */
544
mp::RouterFleXML::Rep * m_p
virtual const filter::Base * move(const char *route)
std::list< boost::shared_ptr< constmp::filter::Base > >::iterator m_filter_it
std::map< std::string, RouterFleXML::Route >::iterator m_route_it
void base(xmlDocPtr doc, mp::FactoryFilter &factory, bool test_only, const char *file_include_path)
void check_routes_in_filters(const xmlNode *n)
void parse_xml_filters(xmlDocPtr doc, const xmlNode *node, bool test_only, const char *file_include_path)
void parse_xml_filters1(xmlDocPtr doc, const xmlNode *node, bool test_only, const char *file_include_path, Route &route)
void parse_xml_routes(xmlDocPtr doc, const xmlNode *node, bool test_only, const char *file_include_path)
std::map< std::string, boost::shared_ptr< const mp::filter::Base > > IdFilterMap
void parse_xml_config_dom(xmlDocPtr doc, bool test_only, const char *file_include_path)
std::map< std::string, RouterFleXML::Route > m_routes
std::list< boost::shared_ptr< const mp::filter::Base > > m_list
boost::scoped_ptr< Rep > m_p