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