Unused variable
[metaproxy-moved-to-github.git] / src / router_flexml.cpp
1 /* This file is part of Metaproxy.
2    Copyright (C) 2005-2011 Index Data
3
4 Metaproxy is free software; you can redistribute it and/or modify it under
5 the terms of the GNU General Public License as published by the Free
6 Software Foundation; either version 2, or (at your option) any later
7 version.
8
9 Metaproxy is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17 */
18
19 #include "config.hpp"
20 #include <metaproxy/xmlutil.hpp>
21 #include "router_flexml.hpp"
22 #include "factory_filter.hpp"
23 #include "factory_static.hpp"
24
25 #include <iostream>
26 #include <map>
27 #include <list>
28 #include <yaz/log.h>
29 #include <yaz/xml_include.h>
30
31 #include <boost/shared_ptr.hpp>
32
33 #include <libxml/xmlversion.h>
34 #include <libxml/parser.h>
35 #include <libxml/tree.h>
36
37 namespace mp = metaproxy_1;
38
39 namespace metaproxy_1 {
40     class RouterFleXML::Route {
41         friend class RouterFleXML::Rep;
42         friend class RouterFleXML::Pos;
43         friend class RouterFleXML;
44         std::list<boost::shared_ptr<const mp::filter::Base> > m_list;
45     };
46     class RouterFleXML::Rep {
47         friend class RouterFleXML;
48         friend class RouterFleXML::Pos;
49         Rep();
50
51         void base(xmlDocPtr doc, mp::FactoryFilter &factory, bool test_only,
52                   const char *file_include_path);
53
54         typedef std::map<std::string,
55                          boost::shared_ptr<const mp::filter::Base > >
56                          IdFilterMap ;
57
58         IdFilterMap m_id_filter_map;
59
60         std::map<std::string,RouterFleXML::Route> m_routes;
61
62         std::string m_start_route;
63
64         std::string m_dl_path;
65
66         void parse_xml_config_dom(xmlDocPtr doc, bool test_only,
67                                   const char *file_include_path);
68
69         void parse_xml_filters(xmlDocPtr doc, const xmlNode *node,
70                                bool test_only, const char *file_include_path);
71         void parse_xml_routes(xmlDocPtr doc, const xmlNode *node,
72                               bool test_only, const char *file_include_path);
73
74         bool m_xinclude;
75     private:
76         FactoryFilter *m_factory; // TODO shared_ptr
77     };
78
79     class RouterFleXML::Pos : public RoutePos {
80     public:
81         virtual const filter::Base *move(const char *route);
82         virtual RoutePos *clone();
83         virtual ~Pos();
84         mp::RouterFleXML::Rep *m_p;
85
86         std::map<std::string, 
87                  RouterFleXML::Route>::iterator m_route_it;
88         std::list<boost::shared_ptr <const mp::filter::Base> >::iterator m_filter_it;
89     };
90 }
91
92 void mp::RouterFleXML::Rep::parse_xml_filters(xmlDocPtr doc,
93                                               const xmlNode *node,
94                                               bool test_only,
95                                               const char *file_include_path)
96 {
97     unsigned int filter_nr = 0;
98     while (node && mp::xml::check_element_mp(node, "filter"))
99     {
100         filter_nr++;
101
102         const struct _xmlAttr *attr;
103         std::string id_value;
104         std::string type_value;
105         for (attr = node->properties; attr; attr = attr->next)
106         {
107             std::string name = std::string((const char *) attr->name);
108             std::string value;
109
110             if (attr->children && attr->children->type == XML_TEXT_NODE)
111                 value = std::string((const char *)attr->children->content);
112
113             if (name == "id")
114                 id_value = value;
115             else if (name == "type")
116                 type_value = value;
117             else
118                 throw mp::XMLError("Only attribute id or type allowed"
119                                     " in filter element. Got " + name);
120         }
121
122         if (!m_factory->exist(type_value))
123         {
124             yaz_log(YLOG_LOG, "Loading %s (dlpath %s)",
125                     type_value.c_str(), m_dl_path.c_str());
126             m_factory->add_creator_dl(type_value, m_dl_path);
127         }
128         mp::filter::Base* filter_base = m_factory->create(type_value);
129
130         filter_base->configure(node, test_only, file_include_path);
131
132         if (m_id_filter_map.find(id_value) != m_id_filter_map.end())
133             throw mp::XMLError("Filter " + id_value + " already defined");
134
135         m_id_filter_map[id_value] =
136             boost::shared_ptr<mp::filter::Base>(filter_base);
137
138         node = mp::xml::jump_to_next(node, XML_ELEMENT_NODE);
139     }
140 }
141
142 void mp::RouterFleXML::Rep::parse_xml_routes(xmlDocPtr doc,
143                                              const xmlNode *node,
144                                              bool test_only,
145                                              const char *file_include_path)
146 {
147     mp::xml::check_element_mp(node, "route");
148
149     unsigned int route_nr = 0;
150     while (mp::xml::is_element_mp(node, "route"))
151     {
152         route_nr++;
153
154         const struct _xmlAttr *attr;
155         std::string id_value;
156         for (attr = node->properties; attr; attr = attr->next)
157         {
158             std::string name = std::string((const char *) attr->name);
159             std::string value;
160             
161             if (attr->children && attr->children->type == XML_TEXT_NODE)
162                 value = std::string((const char *)attr->children->content);
163             
164             if (name == "id")
165                 id_value = value;
166             else
167                 throw mp::XMLError("Only attribute 'id' allowed for"
168                                     " element 'route'."
169                                     " Got " + name);
170         }
171
172         Route route;
173
174         // process <filter> nodes in third level
175         const xmlNode* node3 = mp::xml::jump_to_children(node, XML_ELEMENT_NODE);
176
177         unsigned int filter3_nr = 0;
178         while (node3 && mp::xml::check_element_mp(node3, "filter"))
179         {
180             filter3_nr++;
181             
182             const struct _xmlAttr *attr;
183             std::string refid_value;
184             std::string type_value;
185             for (attr = node3->properties; attr; attr = attr->next)
186             {
187                 std::string name = std::string((const char *) attr->name);
188                 std::string value;
189                 
190                 if (attr->children && attr->children->type == XML_TEXT_NODE)
191                     value = std::string((const char *)attr->children->content);
192                 
193                 if (name == "refid")
194                     refid_value = value;
195                 else if (name == "type")
196                     type_value = value;
197                 else
198                     throw mp::XMLError("Only attribute 'refid' or 'type'"
199                                         " allowed for element 'filter'."
200                                         " Got " + name);
201             }
202             if (refid_value.length())
203             {
204                 std::map<std::string,
205                     boost::shared_ptr<const mp::filter::Base > >::iterator it;
206                 it = m_id_filter_map.find(refid_value);
207                 if (it == m_id_filter_map.end())
208                     throw mp::XMLError("Unknown filter refid "
209                                         + refid_value);
210                 else
211                     route.m_list.push_back(it->second);
212             }
213             else if (type_value.length())
214             {
215                 if (!m_factory->exist(type_value))
216                 {
217                     yaz_log(YLOG_LOG, "Loading %s (dlpath %s)",
218                             type_value.c_str(), m_dl_path.c_str());
219                     m_factory->add_creator_dl(type_value, m_dl_path);
220                 }
221                 mp::filter::Base* filter_base = m_factory->create(type_value);
222
223                 filter_base->configure(node3, test_only, file_include_path);
224                 
225                 route.m_list.push_back(
226                     boost::shared_ptr<mp::filter::Base>(filter_base));
227             }
228             node3 = mp::xml::jump_to_next(node3, XML_ELEMENT_NODE);
229             
230         }
231         std::map<std::string,RouterFleXML::Route>::iterator it;
232         it = m_routes.find(id_value);
233         if (it != m_routes.end())
234             throw mp::XMLError("Route id='" + id_value
235                                 + "' already exist");
236         else
237             m_routes[id_value] = route;
238         node = mp::xml::jump_to_next(node, XML_ELEMENT_NODE);
239     }
240 }
241
242 void mp::RouterFleXML::Rep::parse_xml_config_dom(xmlDocPtr doc,
243                                                  bool test_only,
244                                                  const char *file_include_path)
245 {
246     if (!doc)
247         throw mp::XMLError("Empty XML Document");
248     
249     const xmlNode* root = xmlDocGetRootElement(doc);
250
251     if (file_include_path)
252     {
253         int r = yaz_xml_include_simple((xmlNode *) root, file_include_path);
254         if (r)
255             throw mp::XMLError("YAZ XML Include failed");
256     }
257     
258     mp::xml::check_element_mp(root,  "metaproxy");
259
260     const xmlNode* node = mp::xml::jump_to_children(root, XML_ELEMENT_NODE);
261
262     if (mp::xml::is_element_mp(node, "dlpath"))
263     {
264         m_dl_path = mp::xml::get_text(node);
265         node = mp::xml::jump_to_next(node, XML_ELEMENT_NODE);
266     }
267     // process <start> node which is expected first element node
268     if (mp::xml::check_element_mp(node, "start"))
269     {
270         const struct _xmlAttr *attr;
271         for (attr = node->properties; attr; attr = attr->next)
272         {
273             std::string name = std::string((const char *) attr->name);
274             std::string value;
275
276             if (attr->children && attr->children->type == XML_TEXT_NODE)
277                 value = std::string((const char *)attr->children->content);
278
279             if (name == "route")
280                 m_start_route = value;
281             else
282                 throw mp::XMLError("Only attribute start allowed"
283                                     " in element 'start'. Got " + name);
284         }
285         node = mp::xml::jump_to_next(node, XML_ELEMENT_NODE);
286     }
287     // process <filters> node if given
288     if (mp::xml::is_element_mp(node, "filters"))
289     {
290         parse_xml_filters(doc, mp::xml::jump_to_children(node,
291                                                          XML_ELEMENT_NODE),
292                           test_only, file_include_path);
293                       
294         node = mp::xml::jump_to_next(node, XML_ELEMENT_NODE);
295     }
296     // process <routes> node which is expected third element node
297     mp::xml::check_element_mp(node, "routes");
298     
299     parse_xml_routes(doc, mp::xml::jump_to_children(node, XML_ELEMENT_NODE),
300                      test_only, file_include_path);
301
302     node = mp::xml::jump_to_next(node, XML_ELEMENT_NODE);
303     if (node)
304     {
305         throw mp::XMLError("Unexpected element " 
306                             + std::string((const char *)node->name));
307     }
308 }        
309
310 mp::RouterFleXML::Rep::Rep() : m_xinclude(false)
311 {
312 }
313
314 void mp::RouterFleXML::Rep::base(xmlDocPtr doc, mp::FactoryFilter &factory,
315                                  bool test_only, const char *file_include_path)
316 {
317     m_factory = &factory;
318     parse_xml_config_dom(doc, test_only, file_include_path);
319     m_start_route = "start";
320 }
321
322 mp::RouterFleXML::RouterFleXML(xmlDocPtr doc, mp::FactoryFilter &factory,
323                                bool test_only, const char *file_include_path)
324     : m_p(new Rep)
325 {
326     m_p->base(doc, factory, test_only, file_include_path);
327 }
328
329 mp::RouterFleXML::RouterFleXML(std::string xmlconf, mp::FactoryFilter &factory,
330     bool test_only) 
331     : m_p(new Rep)
332 {            
333     LIBXML_TEST_VERSION;
334     
335     xmlDocPtr doc = xmlParseMemory(xmlconf.c_str(),
336                                    xmlconf.size());
337     if (!doc)
338         throw mp::XMLError("xmlParseMemory failed");
339     else
340     {
341         m_p->base(doc, factory, test_only, 0);
342         xmlFreeDoc(doc);
343     }
344 }
345
346 mp::RouterFleXML::~RouterFleXML()
347 {
348 }
349
350 const mp::filter::Base *mp::RouterFleXML::Pos::move(const char *route)
351 {
352     if (route && *route)
353     {
354         //std::cout << "move to " << route << "\n";
355         m_route_it = m_p->m_routes.find(route);
356         if (m_route_it == m_p->m_routes.end())
357         {
358             std::cout << "no such route " << route << "\n";
359             throw mp::XMLError("bad route " + std::string(route));
360         }
361         m_filter_it = m_route_it->second.m_list.begin();
362     }
363     if (m_filter_it == m_route_it->second.m_list.end())
364         return 0;
365     const mp::filter::Base *f = (*m_filter_it).get();
366     m_filter_it++;
367     return f;
368 }
369
370 mp::RoutePos *mp::RouterFleXML::createpos() const
371 {
372     mp::RouterFleXML::Pos *p = new mp::RouterFleXML::Pos;
373
374     p->m_route_it = m_p->m_routes.find(m_p->m_start_route);
375     if (p->m_route_it == m_p->m_routes.end())
376     {
377         delete p;
378         return 0;
379     }
380     p->m_filter_it = p->m_route_it->second.m_list.begin();
381     p->m_p = m_p.get();
382     return p;
383 }
384
385 mp::RoutePos *mp::RouterFleXML::Pos::clone()
386 {
387     mp::RouterFleXML::Pos *p = new mp::RouterFleXML::Pos;
388     p->m_filter_it = m_filter_it;
389     p->m_route_it = m_route_it;
390     p->m_p = m_p;
391     return p;
392 }
393
394 mp::RouterFleXML::Pos::~Pos()
395 {
396 }
397
398
399 void mp::RouterFleXML::start()
400 {
401     std::map<std::string,RouterFleXML::Route>::iterator route_it;
402
403     route_it = m_p->m_routes.begin();
404     while (route_it != m_p->m_routes.end())
405     {
406         RouterFleXML::Route route = route_it->second;
407
408         std::list<boost::shared_ptr<const mp::filter::Base> >::iterator it;
409
410         for (it = route.m_list.begin(); it != route.m_list.end(); it++)
411             (*it)->start();
412         route_it++;
413     }
414 }
415
416 /*
417  * Local variables:
418  * c-basic-offset: 4
419  * c-file-style: "Stroustrup"
420  * indent-tabs-mode: nil
421  * End:
422  * vim: shiftwidth=4 tabstop=8 expandtab
423  */
424