Further work on filter registration in RouterFleXML
[metaproxy-moved-to-github.git] / src / router_flexml.cpp
1 /* $Id: router_flexml.cpp,v 1.8 2006-01-04 14:15:45 adam Exp $
2    Copyright (c) 2005, Index Data.
3
4 %LICENSE%
5  */
6
7 #include "config.hpp"
8 #include "router_flexml.hpp"
9 #include "filter_factory.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::Rep {
25         friend class RouterFleXML;
26         Rep();
27
28         typedef std::map<std::string,
29                          boost::shared_ptr<const yp2::filter::Base > >
30                          IdFilterMap ;
31
32         IdFilterMap m_id_filter_map;
33
34         void create_filter(std::string type, 
35                            const xmlDoc * xmldoc,
36                            std::string id = "");
37
38         void parse_xml_config_dom(xmlDocPtr doc);
39
40         bool is_element(const xmlNode *ptr, 
41                         const std::string &ns,
42                         const std::string &name);
43         
44         bool is_element_yp2(const xmlNode *ptr, 
45                             const std::string &name);
46
47         bool check_element_yp2(const xmlNode *ptr, 
48                                const std::string &name);
49         
50         const xmlNode* jump_to(const xmlNode* node, int xml_node_type);
51
52         const xmlNode* jump_to_next(const xmlNode* node, int xml_node_type);
53         
54         const xmlNode* jump_to_children(const xmlNode* node, int xml_node_type);
55         bool m_xinclude;
56     private:
57         FilterFactory *m_factory; // TODO shared_ptr
58     };
59 }
60
61 const xmlNode* yp2::RouterFleXML::Rep::jump_to_children(const xmlNode* node, int xml_node_type)
62 {
63     node = node->children;
64     for (; node && node->type != xml_node_type; node = node->next)
65         ;
66     return node;
67 }
68         
69 const xmlNode* yp2::RouterFleXML::Rep::jump_to_next(const xmlNode* node, int xml_node_type)
70 {
71     node = node->next;
72     for (; node && node->type != xml_node_type; node = node->next)
73         ;
74     return node;
75 }
76         
77 const xmlNode* yp2::RouterFleXML::Rep::jump_to(const xmlNode* node, int xml_node_type)
78 {
79     for (; node && node->type != xml_node_type; node = node->next)
80         ;
81     return node;
82 }
83
84 bool yp2::RouterFleXML::Rep::is_element(const xmlNode *ptr, 
85                                         const std::string &ns,
86                                         const std::string &name)
87 {
88     if (ptr && ptr->type == XML_ELEMENT_NODE && ptr->ns && ptr->ns->href 
89         && !xmlStrcmp(BAD_CAST ns.c_str(), ptr->ns->href)
90         && !xmlStrcmp(BAD_CAST name.c_str(), ptr->name))
91         return true;
92     return false;
93 }
94
95 bool yp2::RouterFleXML::Rep::is_element_yp2(const xmlNode *ptr, 
96                                             const std::string &name)
97 {
98     return is_element(ptr, "http://indexdata.dk/yp2/config/1", name);
99 }
100
101 bool yp2::RouterFleXML::Rep::check_element_yp2(const xmlNode *ptr, 
102                                                const std::string &name)
103 {
104     if (!is_element_yp2(ptr, name))
105         throw XMLError("Error. Expected element name " + name);
106     return true;
107 }
108
109 void yp2::RouterFleXML::Rep::parse_xml_config_dom(xmlDocPtr doc)
110 {
111     if (!doc)
112         throw XMLError("Empty XML Document");
113     
114     const xmlNode* root = xmlDocGetRootElement(doc);
115     
116     check_element_yp2(root,  "yp2");
117
118     std::cout << "processing /yp2" << std::endl;
119     
120     // process <start> node which is expected first element node
121     const xmlNode* node = jump_to_children(root, XML_ELEMENT_NODE);
122     //for (; node && node->type != XML_ELEMENT_NODE; node = node->next)
123     //    ;
124
125     check_element_yp2(node, "start");
126
127     std::cout << "processing /yp2/start" << std::endl;
128     
129     // process <filters> node which is expected second element node
130     node = jump_to_next(node, XML_ELEMENT_NODE);
131     check_element_yp2(node, "filters");
132     std::cout << "processing /yp2/filters" << std::endl;
133     
134     // process <filter> nodes  in next level
135     const xmlNode* node2 = jump_to_children(node, XML_ELEMENT_NODE);
136     
137     unsigned int filter_nr = 0;
138     while(node2 && check_element_yp2(node2, "filter"))
139     {
140         filter_nr++;
141         std::cout << "processing /yp2/filters/filter[" 
142                   << filter_nr << "]" << std::endl;
143
144         const struct _xmlAttr *attr;
145         std::string id_value;
146         std::string type_value;
147         for (attr = node2->properties; attr; attr = attr->next)
148         {
149             std::string name = std::string((const char *) attr->name);
150             std::string value;
151
152             if (attr->children && attr->children->type == XML_TEXT_NODE)
153                 value = std::string((const char *)attr->children->content);
154
155             if (name == "id")
156                 id_value = value;
157             else if (name == "type")
158                 type_value = value;
159             else
160                 throw XMLError("Error. Only attribute id or type allowed in filter element. Got " + name);
161                 
162             std::cout << "attr " << name << "=" << value << "\n";
163
164             //const xmlNode *val;
165         }
166
167         yp2::filter::Base* filter_base = m_factory->create(type_value);
168
169         filter_base->configure(node2);
170
171         if (m_id_filter_map.find(id_value) != m_id_filter_map.end())
172             throw XMLError("Filter " + id_value + " already defined");
173
174         m_id_filter_map[id_value] =
175             boost::shared_ptr<yp2::filter::Base>(filter_base);
176
177         node2 = jump_to_next(node2, XML_ELEMENT_NODE);
178     }
179     
180     // process <routes> node which is expected third element node
181     node = jump_to_next(node, XML_ELEMENT_NODE);
182     check_element_yp2(node, "routes");
183     std::cout << "processing /yp2/routes" << std::endl;
184     
185     // process <route> nodes  in next level
186     node2 = jump_to_children(node, XML_ELEMENT_NODE);
187     check_element_yp2(node2, "route");
188     
189     unsigned int route_nr = 0;
190     while(is_element_yp2(node2, "router"))
191     {
192         route_nr++;
193         std::cout << "processing /yp2/routes/route[" 
194                   << route_nr << "]" << std::endl;
195         
196         // process <filter> nodes in third level
197         const xmlNode* node3 = jump_to_children(node2, XML_ELEMENT_NODE);
198         
199         unsigned int filter3_nr = 0;
200         while(node3 && check_element_yp2(node3, "filter"))
201         {
202             filter3_nr++;
203             
204             std::cout << "processing /yp2/routes/route[" 
205                       << route_nr << "]/filter[" 
206                       << filter3_nr << "]" << std::endl;
207             
208             node3 = jump_to_next(node3, XML_ELEMENT_NODE);
209             
210         }
211         node2 = jump_to_next(node2, XML_ELEMENT_NODE);
212     }
213 }        
214
215 void yp2::RouterFleXML::Rep::create_filter(std::string type, 
216                                            const xmlDoc * xmldoc,
217                                            std::string id)
218 {
219     std::cout << "Created Filter type='" << type 
220               << "' id='" << id << "'" << std::endl;
221 }
222
223 yp2::RouterFleXML::Rep::Rep() : 
224     m_xinclude(false)
225 {
226 }
227
228 yp2::RouterFleXML::RouterFleXML(std::string xmlconf, yp2::FilterFactory &factory) 
229     : m_p(new Rep)
230 {            
231
232     m_p->m_factory = &factory;
233
234     LIBXML_TEST_VERSION;
235     
236     xmlDocPtr doc = xmlParseMemory(xmlconf.c_str(),
237                                    xmlconf.size());
238     if (!doc)
239         throw XMLError("xmlParseMemory failed");
240     else
241     {
242         m_p->parse_xml_config_dom(doc);
243         xmlFreeDoc(doc);
244     }
245 }
246
247 yp2::RouterFleXML::~RouterFleXML()
248 {
249 }
250
251 const yp2::filter::Base *
252 yp2::RouterFleXML::move(const yp2::filter::Base *filter,
253                         const yp2::Package *package) const 
254 {
255     return 0;
256 }
257         
258
259 /*
260  * Local variables:
261  * c-basic-offset: 4
262  * indent-tabs-mode: nil
263  * c-file-style: "stroustrup"
264  * End:
265  * vim: shiftwidth=4 tabstop=8 expandtab
266  */