d4e24d7e559b15ec9bc253b312e72186efe50ac3
[metaproxy-moved-to-github.git] / src / router_flexml.cpp
1 /* $Id: router_flexml.cpp,v 1.10 2006-01-05 16:39:37 adam Exp $
2    Copyright (c) 2005, Index Data.
3
4 %LICENSE%
5  */
6
7 #include "config.hpp"
8 #include "router_flexml.hpp"
9 #include "factory_filter.hpp"
10 #include "factory_static.hpp"
11
12 #include <iostream>
13 #include <map>
14 #include <list>
15
16 #include <boost/shared_ptr.hpp>
17
18 #include <libxml/xmlversion.h>
19 #include <libxml/parser.h>
20 #include <libxml/tree.h>
21
22
23 namespace yp2 {
24     class RouterFleXML::Route {
25         friend class RouterFleXML::Rep;
26         std::list<boost::shared_ptr<const yp2::filter::Base> > m_list;
27     };
28     class RouterFleXML::Rep {
29         friend class RouterFleXML;
30         Rep();
31
32         typedef std::map<std::string,
33                          boost::shared_ptr<const yp2::filter::Base > >
34                          IdFilterMap ;
35
36         IdFilterMap m_id_filter_map;
37
38         std::map<std::string,RouterFleXML::Route> m_routes;
39
40         void parse_xml_config_dom(xmlDocPtr doc);
41
42         bool is_element(const xmlNode *ptr, 
43                         const std::string &ns,
44                         const std::string &name);
45         
46         bool is_element_yp2(const xmlNode *ptr, 
47                             const std::string &name);
48
49         bool check_element_yp2(const xmlNode *ptr, 
50                                const std::string &name);
51         
52         const xmlNode* jump_to(const xmlNode* node, int xml_node_type);
53
54         const xmlNode* jump_to_next(const xmlNode* node, int xml_node_type);
55         
56         const xmlNode* jump_to_children(const xmlNode* node, int xml_node_type);
57         void parse_xml_filters(xmlDocPtr doc, const xmlNode *node);
58         void parse_xml_routes(xmlDocPtr doc, const xmlNode *node);
59
60         bool m_xinclude;
61     private:
62         FactoryFilter *m_factory; // TODO shared_ptr
63     };
64 }
65
66 const xmlNode* yp2::RouterFleXML::Rep::jump_to_children(const xmlNode* node,
67                                                         int xml_node_type)
68 {
69     node = node->children;
70     for (; node && node->type != xml_node_type; node = node->next)
71         ;
72     return node;
73 }
74         
75 const xmlNode* yp2::RouterFleXML::Rep::jump_to_next(const xmlNode* node,
76                                                     int xml_node_type)
77 {
78     node = node->next;
79     for (; node && node->type != xml_node_type; node = node->next)
80         ;
81     return node;
82 }
83         
84 const xmlNode* yp2::RouterFleXML::Rep::jump_to(const xmlNode* node,
85                                                int xml_node_type)
86 {
87     for (; node && node->type != xml_node_type; node = node->next)
88         ;
89     return node;
90 }
91
92 bool yp2::RouterFleXML::Rep::is_element(const xmlNode *ptr, 
93                                         const std::string &ns,
94                                         const std::string &name)
95 {
96     if (ptr && ptr->type == XML_ELEMENT_NODE && ptr->ns && ptr->ns->href 
97         && !xmlStrcmp(BAD_CAST ns.c_str(), ptr->ns->href)
98         && !xmlStrcmp(BAD_CAST name.c_str(), ptr->name))
99         return true;
100     return false;
101 }
102
103 bool yp2::RouterFleXML::Rep::is_element_yp2(const xmlNode *ptr, 
104                                             const std::string &name)
105 {
106     return is_element(ptr, "http://indexdata.dk/yp2/config/1", name);
107 }
108
109 bool yp2::RouterFleXML::Rep::check_element_yp2(const xmlNode *ptr, 
110                                                const std::string &name)
111 {
112     if (!is_element_yp2(ptr, name))
113         throw XMLError("Expected element name " + name);
114     return true;
115 }
116
117
118 void yp2::RouterFleXML::Rep::parse_xml_filters(xmlDocPtr doc,
119                                                const xmlNode *node)
120 {
121     unsigned int filter_nr = 0;
122     while(node && check_element_yp2(node, "filter"))
123     {
124         filter_nr++;
125         std::cout << "processing /yp2/filters/filter[" 
126                   << filter_nr << "]" << std::endl;
127
128         const struct _xmlAttr *attr;
129         std::string id_value;
130         std::string type_value;
131         for (attr = node->properties; attr; attr = attr->next)
132         {
133             std::string name = std::string((const char *) attr->name);
134             std::string value;
135
136             if (attr->children && attr->children->type == XML_TEXT_NODE)
137                 value = std::string((const char *)attr->children->content);
138
139             if (name == "id")
140                 id_value = value;
141             else if (name == "type")
142                 type_value = value;
143             else
144                 throw XMLError("Only attribute id or type allowed"
145                                " in filter element. Got " + name);
146                 
147             std::cout << "attr " << name << "=" << value << "\n";
148         }
149
150         yp2::filter::Base* filter_base = m_factory->create(type_value);
151
152         filter_base->configure(node);
153
154         if (m_id_filter_map.find(id_value) != m_id_filter_map.end())
155             throw XMLError("Filter " + id_value + " already defined");
156
157         m_id_filter_map[id_value] =
158             boost::shared_ptr<yp2::filter::Base>(filter_base);
159
160         node = jump_to_next(node, XML_ELEMENT_NODE);
161     }
162 }
163
164 void yp2::RouterFleXML::Rep::parse_xml_routes(xmlDocPtr doc,
165                                               const xmlNode *node)
166 {
167     check_element_yp2(node, "route");
168
169     unsigned int route_nr = 0;
170     while(is_element_yp2(node, "route"))
171     {
172         route_nr++;
173
174         const struct _xmlAttr *attr;
175         std::string id_value;
176         for (attr = node->properties; attr; attr = attr->next)
177         {
178             std::string name = std::string((const char *) attr->name);
179             std::string value;
180             
181             if (attr->children && attr->children->type == XML_TEXT_NODE)
182                 value = std::string((const char *)attr->children->content);
183             
184             if (name == "id")
185                 id_value = value;
186             else
187                 throw XMLError("Only attribute refid allowed route element. Got " + name);
188             
189             std::cout << "attr " << name << "=" << value << "\n";
190         }
191
192         Route route;
193
194         std::cout << "processing /yp2/routes/route[" 
195                   << route_nr << "]" << std::endl;
196         
197         // process <filter> nodes in third level
198
199         const xmlNode* node3 = jump_to_children(node, XML_ELEMENT_NODE);
200
201         unsigned int filter3_nr = 0;
202         while(node3 && check_element_yp2(node3, "filter"))
203         {
204             filter3_nr++;
205             
206             const struct _xmlAttr *attr;
207             std::string refid_value;
208             std::string type_value;
209             for (attr = node3->properties; attr; attr = attr->next)
210             {
211                 std::string name = std::string((const char *) attr->name);
212                 std::string value;
213                 
214                 if (attr->children && attr->children->type == XML_TEXT_NODE)
215                     value = std::string((const char *)attr->children->content);
216                 
217                 if (name == "refid")
218                     refid_value = value;
219                 else if (name == "type")
220                     type_value = value;
221                 else
222                     throw XMLError("Only attribute refid or type"
223                                    " allowed in filter element. Got " + name);
224                 
225                 std::cout << "attr " << name << "=" << value << "\n";
226             }
227             if (refid_value.length())
228             {
229                 std::map<std::string,
230                     boost::shared_ptr<const yp2::filter::Base > >::iterator it;
231                 it = m_id_filter_map.find(refid_value);
232                 if (it == m_id_filter_map.end())
233                     throw XMLError("Unknown filter refid " + refid_value);
234                 else
235                     route.m_list.push_back(it->second);
236             }
237             else if (type_value.length())
238             {
239                 yp2::filter::Base* filter_base = m_factory->create(type_value);
240
241                 filter_base->configure(node3);
242                 
243                 route.m_list.push_back(
244                     boost::shared_ptr<yp2::filter::Base>(filter_base));
245             }
246             std::cout << "processing /yp2/routes/route[" 
247                       << route_nr << "]/filter[" 
248                       << filter3_nr << "]" << std::endl;
249             
250             node3 = jump_to_next(node3, XML_ELEMENT_NODE);
251             
252         }
253         std::map<std::string,RouterFleXML::Route>::iterator it;
254         it = m_routes.find(id_value);
255         if (it != m_routes.end())
256             throw XMLError("Route id='" + id_value + "' already exist");
257         else
258             m_routes[id_value] = route;
259         node = jump_to_next(node, XML_ELEMENT_NODE);
260     }
261 }
262
263 void yp2::RouterFleXML::Rep::parse_xml_config_dom(xmlDocPtr doc)
264 {
265     if (!doc)
266         throw XMLError("Empty XML Document");
267     
268     const xmlNode* root = xmlDocGetRootElement(doc);
269     
270     check_element_yp2(root,  "yp2");
271
272     std::cout << "processing /yp2" << std::endl;
273     
274     // process <start> node which is expected first element node
275     const xmlNode* node = jump_to_children(root, XML_ELEMENT_NODE);
276     //for (; node && node->type != XML_ELEMENT_NODE; node = node->next)
277     //    ;
278
279     check_element_yp2(node, "start");
280
281     std::cout << "processing /yp2/start" << std::endl;
282     
283     // process <filters> node which is expected second element node
284     node = jump_to_next(node, XML_ELEMENT_NODE);
285     check_element_yp2(node, "filters");
286     std::cout << "processing /yp2/filters" << std::endl;
287     
288     parse_xml_filters(doc, jump_to_children(node, XML_ELEMENT_NODE));
289                       
290     // process <routes> node which is expected third element node
291     node = jump_to_next(node, XML_ELEMENT_NODE);
292     check_element_yp2(node, "routes");
293     std::cout << "processing /yp2/routes" << std::endl;
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 yp2::RouterFleXML::RouterFleXML(std::string xmlconf, yp2::FactoryFilter &factory) 
303     : m_p(new Rep)
304 {            
305
306     m_p->m_factory = &factory;
307
308     LIBXML_TEST_VERSION;
309     
310     xmlDocPtr doc = xmlParseMemory(xmlconf.c_str(),
311                                    xmlconf.size());
312     if (!doc)
313         throw XMLError("xmlParseMemory failed");
314     else
315     {
316         m_p->parse_xml_config_dom(doc);
317         xmlFreeDoc(doc);
318     }
319 }
320
321 yp2::RouterFleXML::~RouterFleXML()
322 {
323 }
324
325 const yp2::filter::Base *
326 yp2::RouterFleXML::move(const yp2::filter::Base *filter,
327                         const yp2::Package *package) const 
328 {
329     return 0;
330 }
331         
332
333 /*
334  * Local variables:
335  * c-basic-offset: 4
336  * indent-tabs-mode: nil
337  * c-file-style: "stroustrup"
338  * End:
339  * vim: shiftwidth=4 tabstop=8 expandtab
340  */