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