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