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