Updated copyright headers. Omit CVS ID.
[metaproxy-moved-to-github.git] / src / router_flexml.cpp
1 /* This file is part of Metaproxy.
2    Copyright (C) 2005-2008 Index Data
3
4 Metaproxy is free software; you can redistribute it and/or modify it under
5 the terms of the GNU General Public License as published by the Free
6 Software Foundation; either version 2, or (at your option) any later
7 version.
8
9 Metaproxy is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17 */
18
19 #include "config.hpp"
20 #include "xmlutil.hpp"
21 #include "router_flexml.hpp"
22 #include "factory_filter.hpp"
23 #include "factory_static.hpp"
24
25 #include <iostream>
26 #include <map>
27 #include <list>
28
29 #include <boost/shared_ptr.hpp>
30
31 #include <libxml/xmlversion.h>
32 #include <libxml/parser.h>
33 #include <libxml/tree.h>
34
35 namespace mp = metaproxy_1;
36
37 namespace metaproxy_1 {
38     class RouterFleXML::Route {
39         friend class RouterFleXML::Rep;
40         friend class RouterFleXML::Pos;
41         friend class RouterFleXML;
42         std::list<boost::shared_ptr<const mp::filter::Base> > m_list;
43     };
44     class RouterFleXML::Rep {
45         friend class RouterFleXML;
46         friend class RouterFleXML::Pos;
47         Rep();
48
49         void base(xmlDocPtr doc, mp::FactoryFilter &factory, bool test_only);
50
51         typedef std::map<std::string,
52                          boost::shared_ptr<const mp::filter::Base > >
53                          IdFilterMap ;
54
55         IdFilterMap m_id_filter_map;
56
57         std::map<std::string,RouterFleXML::Route> m_routes;
58
59         std::string m_start_route;
60
61         std::string m_dl_path;
62
63         void parse_xml_config_dom(xmlDocPtr doc, bool test_only);
64
65         void parse_xml_filters(xmlDocPtr doc, const xmlNode *node,
66             bool test_only);
67         void parse_xml_routes(xmlDocPtr doc, const xmlNode *node,
68             bool test_only);
69
70         bool m_xinclude;
71     private:
72         FactoryFilter *m_factory; // TODO shared_ptr
73     };
74
75     class RouterFleXML::Pos : public RoutePos {
76     public:
77         virtual const filter::Base *move(const char *route);
78         virtual RoutePos *clone();
79         virtual ~Pos();
80         mp::RouterFleXML::Rep *m_p;
81
82         std::map<std::string, 
83                  RouterFleXML::Route>::iterator m_route_it;
84         std::list<boost::shared_ptr <const mp::filter::Base> >::iterator m_filter_it;
85     };
86 }
87
88 void mp::RouterFleXML::Rep::parse_xml_filters(xmlDocPtr doc,
89                                               const xmlNode *node,
90                                               bool test_only)
91 {
92     unsigned int filter_nr = 0;
93     while(node && mp::xml::check_element_mp(node, "filter"))
94     {
95         filter_nr++;
96
97         const struct _xmlAttr *attr;
98         std::string id_value;
99         std::string type_value;
100         for (attr = node->properties; attr; attr = attr->next)
101         {
102             std::string name = std::string((const char *) attr->name);
103             std::string value;
104
105             if (attr->children && attr->children->type == XML_TEXT_NODE)
106                 value = std::string((const char *)attr->children->content);
107
108             if (name == "id")
109                 id_value = value;
110             else if (name == "type")
111                 type_value = value;
112             else
113                 throw mp::XMLError("Only attribute id or type allowed"
114                                     " in filter element. Got " + name);
115         }
116
117         if (!m_factory->exist(type_value))
118         {
119             std::cout << "about to load " << type_value << ", path=" << 
120                 m_dl_path << "\n";
121             m_factory->add_creator_dl(type_value, m_dl_path);
122         }
123         mp::filter::Base* filter_base = m_factory->create(type_value);
124
125         filter_base->configure(node, test_only);
126
127         if (m_id_filter_map.find(id_value) != m_id_filter_map.end())
128             throw mp::XMLError("Filter " + id_value + " already defined");
129
130         m_id_filter_map[id_value] =
131             boost::shared_ptr<mp::filter::Base>(filter_base);
132
133         node = mp::xml::jump_to_next(node, XML_ELEMENT_NODE);
134     }
135 }
136
137 void mp::RouterFleXML::Rep::parse_xml_routes(xmlDocPtr doc,
138                                              const xmlNode *node,
139                                              bool test_only)
140 {
141     mp::xml::check_element_mp(node, "route");
142
143     unsigned int route_nr = 0;
144     while(mp::xml::is_element_mp(node, "route"))
145     {
146         route_nr++;
147
148         const struct _xmlAttr *attr;
149         std::string id_value;
150         for (attr = node->properties; attr; attr = attr->next)
151         {
152             std::string name = std::string((const char *) attr->name);
153             std::string value;
154             
155             if (attr->children && attr->children->type == XML_TEXT_NODE)
156                 value = std::string((const char *)attr->children->content);
157             
158             if (name == "id")
159                 id_value = value;
160             else
161                 throw mp::XMLError("Only attribute 'id' allowed for"
162                                     " element 'route'."
163                                     " Got " + name);
164         }
165
166         Route route;
167
168         // process <filter> nodes in third level
169         const xmlNode* node3 = mp::xml::jump_to_children(node, XML_ELEMENT_NODE);
170
171         unsigned int filter3_nr = 0;
172         while(node3 && mp::xml::check_element_mp(node3, "filter"))
173         {
174             filter3_nr++;
175             
176             const struct _xmlAttr *attr;
177             std::string refid_value;
178             std::string type_value;
179             for (attr = node3->properties; attr; attr = attr->next)
180             {
181                 std::string name = std::string((const char *) attr->name);
182                 std::string value;
183                 
184                 if (attr->children && attr->children->type == XML_TEXT_NODE)
185                     value = std::string((const char *)attr->children->content);
186                 
187                 if (name == "refid")
188                     refid_value = value;
189                 else if (name == "type")
190                     type_value = value;
191                 else
192                     throw mp::XMLError("Only attribute 'refid' or 'type'"
193                                         " allowed for element 'filter'."
194                                         " Got " + name);
195             }
196             if (refid_value.length())
197             {
198                 std::map<std::string,
199                     boost::shared_ptr<const mp::filter::Base > >::iterator it;
200                 it = m_id_filter_map.find(refid_value);
201                 if (it == m_id_filter_map.end())
202                     throw mp::XMLError("Unknown filter refid "
203                                         + refid_value);
204                 else
205                     route.m_list.push_back(it->second);
206             }
207             else if (type_value.length())
208             {
209                 if (!m_factory->exist(type_value))
210                 {
211                     std::cout << "about to load " << type_value << ", path=" << 
212                         m_dl_path << "\n";
213                     m_factory->add_creator_dl(type_value, m_dl_path);
214                 }
215                 mp::filter::Base* filter_base = m_factory->create(type_value);
216
217                 filter_base->configure(node3, test_only);
218                 
219                 route.m_list.push_back(
220                     boost::shared_ptr<mp::filter::Base>(filter_base));
221             }
222             node3 = mp::xml::jump_to_next(node3, XML_ELEMENT_NODE);
223             
224         }
225         std::map<std::string,RouterFleXML::Route>::iterator it;
226         it = m_routes.find(id_value);
227         if (it != m_routes.end())
228             throw mp::XMLError("Route id='" + id_value
229                                 + "' already exist");
230         else
231             m_routes[id_value] = route;
232         node = mp::xml::jump_to_next(node, XML_ELEMENT_NODE);
233     }
234 }
235
236 void mp::RouterFleXML::Rep::parse_xml_config_dom(xmlDocPtr doc,
237                                                  bool test_only)
238 {
239     if (!doc)
240         throw mp::XMLError("Empty XML Document");
241     
242     const xmlNode* root = xmlDocGetRootElement(doc);
243     
244     mp::xml::check_element_mp(root,  "metaproxy");
245
246     const xmlNode* node = mp::xml::jump_to_children(root, XML_ELEMENT_NODE);
247
248     if (mp::xml::is_element_mp(node, "dlpath"))
249     {
250         m_dl_path = mp::xml::get_text(node);
251         node = mp::xml::jump_to_next(node, XML_ELEMENT_NODE);
252     }
253     // process <start> node which is expected first element node
254     if (mp::xml::check_element_mp(node, "start"))
255     {
256         const struct _xmlAttr *attr;
257         std::string id_value;
258         for (attr = node->properties; attr; attr = attr->next)
259         {
260             std::string name = std::string((const char *) attr->name);
261             std::string value;
262
263             if (attr->children && attr->children->type == XML_TEXT_NODE)
264                 value = std::string((const char *)attr->children->content);
265
266             if (name == "route")
267                 m_start_route = value;
268             else
269                 throw mp::XMLError("Only attribute start allowed"
270                                     " in element 'start'. Got " + name);
271         }
272         node = mp::xml::jump_to_next(node, XML_ELEMENT_NODE);
273     }
274     // process <filters> node if given
275     if (mp::xml::is_element_mp(node, "filters"))
276     {
277         parse_xml_filters(doc, mp::xml::jump_to_children(node,
278                                                          XML_ELEMENT_NODE),
279             test_only);
280                       
281         node = mp::xml::jump_to_next(node, XML_ELEMENT_NODE);
282     }
283     // process <routes> node which is expected third element node
284     mp::xml::check_element_mp(node, "routes");
285     
286     parse_xml_routes(doc, mp::xml::jump_to_children(node, XML_ELEMENT_NODE),
287         test_only);
288
289     node = mp::xml::jump_to_next(node, XML_ELEMENT_NODE);
290     if (node)
291     {
292         throw mp::XMLError("Unexpected element " 
293                             + std::string((const char *)node->name));
294     }
295 }        
296
297 mp::RouterFleXML::Rep::Rep() : m_xinclude(false)
298 {
299 }
300
301 void mp::RouterFleXML::Rep::base(xmlDocPtr doc, mp::FactoryFilter &factory,
302     bool test_only)
303 {
304     m_factory = &factory;
305     parse_xml_config_dom(doc, test_only);
306     m_start_route = "start";
307 }
308
309 mp::RouterFleXML::RouterFleXML(xmlDocPtr doc, mp::FactoryFilter &factory,
310     bool test_only)
311     : m_p(new Rep)
312 {
313     m_p->base(doc, factory, test_only);
314 }
315
316 mp::RouterFleXML::RouterFleXML(std::string xmlconf, mp::FactoryFilter &factory,
317     bool test_only) 
318     : m_p(new Rep)
319 {            
320     LIBXML_TEST_VERSION;
321     
322     xmlDocPtr doc = xmlParseMemory(xmlconf.c_str(),
323                                    xmlconf.size());
324     if (!doc)
325         throw mp::XMLError("xmlParseMemory failed");
326     else
327     {
328         m_p->base(doc, factory, test_only);
329         xmlFreeDoc(doc);
330     }
331 }
332
333 mp::RouterFleXML::~RouterFleXML()
334 {
335 }
336
337 const mp::filter::Base *mp::RouterFleXML::Pos::move(const char *route)
338 {
339     if (route && *route)
340     {
341         //std::cout << "move to " << route << "\n";
342         m_route_it = m_p->m_routes.find(route);
343         if (m_route_it == m_p->m_routes.end())
344         {
345             std::cout << "no such route " << route << "\n";
346             throw mp::XMLError("bad route " + std::string(route));
347         }
348         m_filter_it = m_route_it->second.m_list.begin();
349     }
350     if (m_filter_it == m_route_it->second.m_list.end())
351         return 0;
352     const mp::filter::Base *f = (*m_filter_it).get();
353     m_filter_it++;
354     return f;
355 }
356
357 mp::RoutePos *mp::RouterFleXML::createpos() const
358 {
359     mp::RouterFleXML::Pos *p = new mp::RouterFleXML::Pos;
360
361     p->m_route_it = m_p->m_routes.find(m_p->m_start_route);
362     if (p->m_route_it == m_p->m_routes.end())
363     {
364         delete p;
365         return 0;
366     }
367     p->m_filter_it = p->m_route_it->second.m_list.begin();
368     p->m_p = m_p.get();
369     return p;
370 }
371
372 mp::RoutePos *mp::RouterFleXML::Pos::clone()
373 {
374     mp::RouterFleXML::Pos *p = new mp::RouterFleXML::Pos;
375     p->m_filter_it = m_filter_it;
376     p->m_route_it = m_route_it;
377     p->m_p = m_p;
378     return p;
379 }
380
381 mp::RouterFleXML::Pos::~Pos()
382 {
383 }
384
385
386 /*
387  * Local variables:
388  * c-basic-offset: 4
389  * indent-tabs-mode: nil
390  * c-file-style: "stroustrup"
391  * End:
392  * vim: shiftwidth=4 tabstop=8 expandtab
393  */