e24fa192f69d3c5d1f0d323d0a00813a7211e32e
[metaproxy-moved-to-github.git] / src / router_flexml.cpp
1 /* $Id: router_flexml.cpp,v 1.12 2006-01-09 13:53:13 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         void parse_xml_config_dom(xmlDocPtr doc);
49
50         bool check_element_yp2(const xmlNode *ptr, 
51                                const std::string &name);
52         
53         const xmlNode* jump_to(const xmlNode* node, int xml_node_type);
54
55         const xmlNode* jump_to_next(const xmlNode* node, int xml_node_type);
56         
57         const xmlNode* jump_to_children(const xmlNode* node, int xml_node_type);
58         void parse_xml_filters(xmlDocPtr doc, const xmlNode *node);
59         void parse_xml_routes(xmlDocPtr doc, const xmlNode *node);
60
61         bool m_xinclude;
62     private:
63         FactoryFilter *m_factory; // TODO shared_ptr
64     };
65
66     class RouterFleXML::Pos : public RoutePos {
67     public:
68         virtual const filter::Base *move();
69         virtual RoutePos *clone();
70         virtual ~Pos();
71         yp2::RouterFleXML::Rep *m_p;
72
73         std::map<std::string, 
74                  RouterFleXML::Route>::iterator m_route_it;
75         std::list<boost::shared_ptr <const yp2::filter::Base> >::iterator m_filter_it;
76     };
77 }
78
79 const xmlNode* yp2::RouterFleXML::Rep::jump_to_children(const xmlNode* node,
80                                                         int xml_node_type)
81 {
82     node = node->children;
83     for (; node && node->type != xml_node_type; node = node->next)
84         ;
85     return node;
86 }
87         
88 const xmlNode* yp2::RouterFleXML::Rep::jump_to_next(const xmlNode* node,
89                                                     int xml_node_type)
90 {
91     node = node->next;
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(const xmlNode* node,
98                                                int xml_node_type)
99 {
100     for (; node && node->type != xml_node_type; node = node->next)
101         ;
102     return node;
103 }
104
105 bool yp2::RouterFleXML::Rep::check_element_yp2(const xmlNode *ptr, 
106                                                const std::string &name)
107 {
108     if (!yp2::xml::is_element_yp2(ptr, name))
109         throw XMLError("Expected element name " + name);
110     return true;
111 }
112
113
114 void yp2::RouterFleXML::Rep::parse_xml_filters(xmlDocPtr doc,
115                                                const xmlNode *node)
116 {
117     unsigned int filter_nr = 0;
118     while(node && check_element_yp2(node, "filter"))
119     {
120         filter_nr++;
121
122         const struct _xmlAttr *attr;
123         std::string id_value;
124         std::string type_value;
125         for (attr = node->properties; attr; attr = attr->next)
126         {
127             std::string name = std::string((const char *) attr->name);
128             std::string value;
129
130             if (attr->children && attr->children->type == XML_TEXT_NODE)
131                 value = std::string((const char *)attr->children->content);
132
133             if (name == "id")
134                 id_value = value;
135             else if (name == "type")
136                 type_value = value;
137             else
138                 throw XMLError("Only attribute id or type allowed"
139                                " in filter element. Got " + name);
140         }
141
142         yp2::filter::Base* filter_base = m_factory->create(type_value);
143
144         filter_base->configure(node);
145
146         if (m_id_filter_map.find(id_value) != m_id_filter_map.end())
147             throw XMLError("Filter " + id_value + " already defined");
148
149         m_id_filter_map[id_value] =
150             boost::shared_ptr<yp2::filter::Base>(filter_base);
151
152         node = jump_to_next(node, XML_ELEMENT_NODE);
153     }
154 }
155
156 void yp2::RouterFleXML::Rep::parse_xml_routes(xmlDocPtr doc,
157                                               const xmlNode *node)
158 {
159     check_element_yp2(node, "route");
160
161     unsigned int route_nr = 0;
162     while(yp2::xml::is_element_yp2(node, "route"))
163     {
164         route_nr++;
165
166         const struct _xmlAttr *attr;
167         std::string id_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 == "id")
177                 id_value = value;
178             else
179                 throw XMLError("Only attribute 'id' allowed for element"
180                                "'route'."
181                                " Got " + name);
182         }
183
184         Route route;
185
186         // process <filter> nodes in third level
187         const xmlNode* node3 = jump_to_children(node, XML_ELEMENT_NODE);
188
189         unsigned int filter3_nr = 0;
190         while(node3 && check_element_yp2(node3, "filter"))
191         {
192             filter3_nr++;
193             
194             const struct _xmlAttr *attr;
195             std::string refid_value;
196             std::string type_value;
197             for (attr = node3->properties; attr; attr = attr->next)
198             {
199                 std::string name = std::string((const char *) attr->name);
200                 std::string value;
201                 
202                 if (attr->children && attr->children->type == XML_TEXT_NODE)
203                     value = std::string((const char *)attr->children->content);
204                 
205                 if (name == "refid")
206                     refid_value = value;
207                 else if (name == "type")
208                     type_value = value;
209                 else
210                     throw XMLError("Only attribute 'refid' or 'type'"
211                                    " allowed for element 'filter'."
212                                    " Got " + name);
213             }
214             if (refid_value.length())
215             {
216                 std::map<std::string,
217                     boost::shared_ptr<const yp2::filter::Base > >::iterator it;
218                 it = m_id_filter_map.find(refid_value);
219                 if (it == m_id_filter_map.end())
220                     throw XMLError("Unknown filter refid " + refid_value);
221                 else
222                     route.m_list.push_back(it->second);
223             }
224             else if (type_value.length())
225             {
226                 yp2::filter::Base* filter_base = m_factory->create(type_value);
227
228                 filter_base->configure(node3);
229                 
230                 route.m_list.push_back(
231                     boost::shared_ptr<yp2::filter::Base>(filter_base));
232             }
233             node3 = jump_to_next(node3, XML_ELEMENT_NODE);
234             
235         }
236         std::map<std::string,RouterFleXML::Route>::iterator it;
237         it = m_routes.find(id_value);
238         if (it != m_routes.end())
239             throw XMLError("Route id='" + id_value + "' already exist");
240         else
241             m_routes[id_value] = route;
242         node = jump_to_next(node, XML_ELEMENT_NODE);
243     }
244 }
245
246 void yp2::RouterFleXML::Rep::parse_xml_config_dom(xmlDocPtr doc)
247 {
248     if (!doc)
249         throw XMLError("Empty XML Document");
250     
251     const xmlNode* root = xmlDocGetRootElement(doc);
252     
253     check_element_yp2(root,  "yp2");
254
255     // process <start> node which is expected first element node
256     const xmlNode* node = jump_to_children(root, XML_ELEMENT_NODE);
257     if (check_element_yp2(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 XMLError("Only attribute start allowed"
273                                " in element 'start'. Got " + name);
274         }
275         node = jump_to_next(node, XML_ELEMENT_NODE);
276     }
277     // process <filters> node which is expected second element node
278     check_element_yp2(node, "filters");
279     
280     parse_xml_filters(doc, jump_to_children(node, XML_ELEMENT_NODE));
281                       
282     // process <routes> node which is expected third element node
283     node = jump_to_next(node, XML_ELEMENT_NODE);
284     check_element_yp2(node, "routes");
285     
286     parse_xml_routes(doc, jump_to_children(node, XML_ELEMENT_NODE));
287 }        
288
289 yp2::RouterFleXML::Rep::Rep() : m_xinclude(false)
290 {
291 }
292
293 void yp2::RouterFleXML::Rep::base(xmlDocPtr doc, yp2::FactoryFilter &factory)
294 {
295     m_factory = &factory;
296     parse_xml_config_dom(doc);
297     m_start_route = "start";
298 }
299
300 yp2::RouterFleXML::RouterFleXML(xmlDocPtr doc, yp2::FactoryFilter &factory)
301     : m_p(new Rep)
302 {
303     m_p->base(doc, factory);
304 }
305
306 yp2::RouterFleXML::RouterFleXML(std::string xmlconf, yp2::FactoryFilter &factory) 
307     : m_p(new Rep)
308 {            
309     LIBXML_TEST_VERSION;
310     
311     xmlDocPtr doc = xmlParseMemory(xmlconf.c_str(),
312                                    xmlconf.size());
313     if (!doc)
314         throw XMLError("xmlParseMemory failed");
315     else
316     {
317         m_p->base(doc, factory);
318         xmlFreeDoc(doc);
319     }
320 }
321
322 yp2::RouterFleXML::~RouterFleXML()
323 {
324 }
325
326 const yp2::filter::Base *yp2::RouterFleXML::Pos::move()
327 {
328     if (m_filter_it == m_route_it->second.m_list.end())
329         return 0;
330     const yp2::filter::Base *f = (*m_filter_it).get();
331     m_filter_it++;
332     return f;
333 }
334
335 yp2::RoutePos *yp2::RouterFleXML::createpos() const
336 {
337     yp2::RouterFleXML::Pos *p = new yp2::RouterFleXML::Pos;
338
339     p->m_route_it = m_p->m_routes.find(m_p->m_start_route);
340     if (p->m_route_it == m_p->m_routes.end())
341     {
342         delete p;
343         return 0;
344     }
345     p->m_filter_it = p->m_route_it->second.m_list.begin();
346     p->m_p = m_p.get();
347     return p;
348 }
349
350 yp2::RoutePos *yp2::RouterFleXML::Pos::clone()
351 {
352     yp2::RouterFleXML::Pos *p = new yp2::RouterFleXML::Pos;
353     p->m_filter_it = m_filter_it;
354     p->m_route_it = m_route_it;
355     p->m_p = m_p;
356     return p;
357 }
358
359 yp2::RouterFleXML::Pos::~Pos()
360 {
361 }
362
363
364 /*
365  * Local variables:
366  * c-basic-offset: 4
367  * indent-tabs-mode: nil
368  * c-file-style: "stroustrup"
369  * End:
370  * vim: shiftwidth=4 tabstop=8 expandtab
371  */