RouterFleXML now stores routes and filters internally.
authorAdam Dickmeiss <adam@indexdata.dk>
Thu, 5 Jan 2006 16:39:37 +0000 (16:39 +0000)
committerAdam Dickmeiss <adam@indexdata.dk>
Thu, 5 Jan 2006 16:39:37 +0000 (16:39 +0000)
src/factory_filter.cpp
src/factory_filter.hpp
src/router.hpp
src/router_flexml.cpp
src/router_flexml.hpp
src/test_router_flexml.cpp

index de786ff..d48d2dd 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: factory_filter.cpp,v 1.1 2006-01-04 14:30:51 adam Exp $
+/* $Id: factory_filter.cpp,v 1.2 2006-01-05 16:39:37 adam Exp $
    Copyright (c) 2005, Index Data.
 
 %LICENSE%
@@ -29,8 +29,8 @@ namespace yp2 {
     };
 }
 
-yp2::FactoryFilterException::FactoryFilterException(const std::string message)
-    : std::runtime_error("FilterException: " + message)
+yp2::FactoryFilter::NotFound::NotFound(const std::string message)
+    : std::runtime_error(message)
 {
 }
 
@@ -70,7 +70,7 @@ yp2::filter::Base* yp2::FactoryFilter::create(std::string fi)
     
     if (it == m_p->m_fcm.end()){
         std::string msg = "filter type '" + fi + "' not found";
-            throw yp2::FactoryFilterException(msg);
+            throw NotFound(msg);
     }
     // call create function
     return (it->second());
index ab2acd8..7ecb706 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: factory_filter.hpp,v 1.1 2006-01-04 14:30:51 adam Exp $
+/* $Id: factory_filter.hpp,v 1.2 2006-01-05 16:39:37 adam Exp $
    Copyright (c) 2005, Index Data.
 
 %LICENSE%
 #include "filter.hpp"
 
 namespace yp2 {
-    class FactoryFilterException : public std::runtime_error {
-    public:
-        FactoryFilterException(const std::string message);
-    };
-    
     class FactoryFilter : public boost::noncopyable
     {
         typedef yp2::filter::Base* (*CreateFilterCallback)();
@@ -41,6 +36,12 @@ namespace yp2 {
         yp2::filter::Base* create(std::string fi);
 
         bool add_creator_dyn(const std::string &fi, const std::string &path);
+
+
+        class NotFound : public std::runtime_error {
+        public:
+            NotFound(const std::string msg);
+        };
     private:
         boost::scoped_ptr<Rep> m_p;
     };
index 28279de..31836ae 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: router.hpp,v 1.6 2005-11-10 23:10:42 adam Exp $
+/* $Id: router.hpp,v 1.7 2006-01-05 16:39:37 adam Exp $
    Copyright (c) 2005, Index Data.
 
 %LICENSE%
@@ -23,8 +23,7 @@ namespace yp2
         RouterException(const std::string message)
             : std::runtime_error("RouterException: " + message){};
     };
-  
-    
+      
     class Router : boost::noncopyable {
     public:
         Router(){};
@@ -33,14 +32,6 @@ namespace yp2
         /// determines next Filter to use from current Filter and Package
         virtual const filter::Base *move(const filter::Base *filter,
                                          const Package *package) const = 0;
-        
-        /// re-read configuration of routing tables
-        //virtual void configure(){};
-
-        /// add routing rule expressed as Filter to Router
-        //virtual Router & rule(const filter::Base &filter){
-        //    return *this;
-        //}
     };
 }
 #endif
index 2abdfa8..d4e24d7 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: router_flexml.cpp,v 1.9 2006-01-04 14:30:51 adam Exp $
+/* $Id: router_flexml.cpp,v 1.10 2006-01-05 16:39:37 adam Exp $
    Copyright (c) 2005, Index Data.
 
 %LICENSE%
 
 
 namespace yp2 {
+    class RouterFleXML::Route {
+        friend class RouterFleXML::Rep;
+        std::list<boost::shared_ptr<const yp2::filter::Base> > m_list;
+    };
     class RouterFleXML::Rep {
         friend class RouterFleXML;
         Rep();
@@ -31,9 +35,7 @@ namespace yp2 {
 
         IdFilterMap m_id_filter_map;
 
-        void create_filter(std::string type, 
-                           const xmlDoc * xmldoc,
-                           std::string id = "");
+        std::map<std::string,RouterFleXML::Route> m_routes;
 
         void parse_xml_config_dom(xmlDocPtr doc);
 
@@ -52,13 +54,17 @@ namespace yp2 {
         const xmlNode* jump_to_next(const xmlNode* node, int xml_node_type);
         
         const xmlNode* jump_to_children(const xmlNode* node, int xml_node_type);
+        void parse_xml_filters(xmlDocPtr doc, const xmlNode *node);
+        void parse_xml_routes(xmlDocPtr doc, const xmlNode *node);
+
         bool m_xinclude;
     private:
         FactoryFilter *m_factory; // TODO shared_ptr
     };
 }
 
-const xmlNode* yp2::RouterFleXML::Rep::jump_to_children(const xmlNode* node, int xml_node_type)
+const xmlNode* yp2::RouterFleXML::Rep::jump_to_children(const xmlNode* node,
+                                                        int xml_node_type)
 {
     node = node->children;
     for (; node && node->type != xml_node_type; node = node->next)
@@ -66,7 +72,8 @@ const xmlNode* yp2::RouterFleXML::Rep::jump_to_children(const xmlNode* node, int
     return node;
 }
         
-const xmlNode* yp2::RouterFleXML::Rep::jump_to_next(const xmlNode* node, int xml_node_type)
+const xmlNode* yp2::RouterFleXML::Rep::jump_to_next(const xmlNode* node,
+                                                    int xml_node_type)
 {
     node = node->next;
     for (; node && node->type != xml_node_type; node = node->next)
@@ -74,7 +81,8 @@ const xmlNode* yp2::RouterFleXML::Rep::jump_to_next(const xmlNode* node, int xml
     return node;
 }
         
-const xmlNode* yp2::RouterFleXML::Rep::jump_to(const xmlNode* node, int xml_node_type)
+const xmlNode* yp2::RouterFleXML::Rep::jump_to(const xmlNode* node,
+                                               int xml_node_type)
 {
     for (; node && node->type != xml_node_type; node = node->next)
         ;
@@ -102,40 +110,16 @@ bool yp2::RouterFleXML::Rep::check_element_yp2(const xmlNode *ptr,
                                                const std::string &name)
 {
     if (!is_element_yp2(ptr, name))
-        throw XMLError("Error. Expected element name " + name);
+        throw XMLError("Expected element name " + name);
     return true;
 }
 
-void yp2::RouterFleXML::Rep::parse_xml_config_dom(xmlDocPtr doc)
-{
-    if (!doc)
-        throw XMLError("Empty XML Document");
-    
-    const xmlNode* root = xmlDocGetRootElement(doc);
-    
-    check_element_yp2(root,  "yp2");
 
-    std::cout << "processing /yp2" << std::endl;
-    
-    // process <start> node which is expected first element node
-    const xmlNode* node = jump_to_children(root, XML_ELEMENT_NODE);
-    //for (; node && node->type != XML_ELEMENT_NODE; node = node->next)
-    //    ;
-
-    check_element_yp2(node, "start");
-
-    std::cout << "processing /yp2/start" << std::endl;
-    
-    // process <filters> node which is expected second element node
-    node = jump_to_next(node, XML_ELEMENT_NODE);
-    check_element_yp2(node, "filters");
-    std::cout << "processing /yp2/filters" << std::endl;
-    
-    // process <filter> nodes  in next level
-    const xmlNode* node2 = jump_to_children(node, XML_ELEMENT_NODE);
-    
+void yp2::RouterFleXML::Rep::parse_xml_filters(xmlDocPtr doc,
+                                               const xmlNode *node)
+{
     unsigned int filter_nr = 0;
-    while(node2 && check_element_yp2(node2, "filter"))
+    while(node && check_element_yp2(node, "filter"))
     {
         filter_nr++;
         std::cout << "processing /yp2/filters/filter[" 
@@ -144,7 +128,7 @@ void yp2::RouterFleXML::Rep::parse_xml_config_dom(xmlDocPtr doc)
         const struct _xmlAttr *attr;
         std::string id_value;
         std::string type_value;
-        for (attr = node2->properties; attr; attr = attr->next)
+        for (attr = node->properties; attr; attr = attr->next)
         {
             std::string name = std::string((const char *) attr->name);
             std::string value;
@@ -157,16 +141,15 @@ void yp2::RouterFleXML::Rep::parse_xml_config_dom(xmlDocPtr doc)
             else if (name == "type")
                 type_value = value;
             else
-                throw XMLError("Error. Only attribute id or type allowed in filter element. Got " + name);
+                throw XMLError("Only attribute id or type allowed"
+                               " in filter element. Got " + name);
                 
             std::cout << "attr " << name << "=" << value << "\n";
-
-            //const xmlNode *val;
         }
 
         yp2::filter::Base* filter_base = m_factory->create(type_value);
 
-        filter_base->configure(node2);
+        filter_base->configure(node);
 
         if (m_id_filter_map.find(id_value) != m_id_filter_map.end())
             throw XMLError("Filter " + id_value + " already defined");
@@ -174,33 +157,92 @@ void yp2::RouterFleXML::Rep::parse_xml_config_dom(xmlDocPtr doc)
         m_id_filter_map[id_value] =
             boost::shared_ptr<yp2::filter::Base>(filter_base);
 
-        node2 = jump_to_next(node2, XML_ELEMENT_NODE);
+        node = jump_to_next(node, XML_ELEMENT_NODE);
     }
-    
-    // process <routes> node which is expected third element node
-    node = jump_to_next(node, XML_ELEMENT_NODE);
-    check_element_yp2(node, "routes");
-    std::cout << "processing /yp2/routes" << std::endl;
-    
-    // process <route> nodes  in next level
-    node2 = jump_to_children(node, XML_ELEMENT_NODE);
-    check_element_yp2(node2, "route");
-    
+}
+
+void yp2::RouterFleXML::Rep::parse_xml_routes(xmlDocPtr doc,
+                                              const xmlNode *node)
+{
+    check_element_yp2(node, "route");
+
     unsigned int route_nr = 0;
-    while(is_element_yp2(node2, "router"))
+    while(is_element_yp2(node, "route"))
     {
         route_nr++;
+
+        const struct _xmlAttr *attr;
+        std::string id_value;
+        for (attr = node->properties; attr; attr = attr->next)
+        {
+            std::string name = std::string((const char *) attr->name);
+            std::string value;
+            
+            if (attr->children && attr->children->type == XML_TEXT_NODE)
+                value = std::string((const char *)attr->children->content);
+            
+            if (name == "id")
+                id_value = value;
+            else
+                throw XMLError("Only attribute refid allowed route element. Got " + name);
+            
+            std::cout << "attr " << name << "=" << value << "\n";
+        }
+
+        Route route;
+
         std::cout << "processing /yp2/routes/route[" 
                   << route_nr << "]" << std::endl;
         
         // process <filter> nodes in third level
-        const xmlNode* node3 = jump_to_children(node2, XML_ELEMENT_NODE);
-        
+
+        const xmlNode* node3 = jump_to_children(node, XML_ELEMENT_NODE);
+
         unsigned int filter3_nr = 0;
         while(node3 && check_element_yp2(node3, "filter"))
         {
             filter3_nr++;
             
+            const struct _xmlAttr *attr;
+            std::string refid_value;
+            std::string type_value;
+            for (attr = node3->properties; attr; attr = attr->next)
+            {
+                std::string name = std::string((const char *) attr->name);
+                std::string value;
+                
+                if (attr->children && attr->children->type == XML_TEXT_NODE)
+                    value = std::string((const char *)attr->children->content);
+                
+                if (name == "refid")
+                    refid_value = value;
+                else if (name == "type")
+                    type_value = value;
+                else
+                    throw XMLError("Only attribute refid or type"
+                                   " allowed in filter element. Got " + name);
+                
+                std::cout << "attr " << name << "=" << value << "\n";
+            }
+            if (refid_value.length())
+            {
+                std::map<std::string,
+                    boost::shared_ptr<const yp2::filter::Base > >::iterator it;
+                it = m_id_filter_map.find(refid_value);
+                if (it == m_id_filter_map.end())
+                    throw XMLError("Unknown filter refid " + refid_value);
+                else
+                    route.m_list.push_back(it->second);
+            }
+            else if (type_value.length())
+            {
+                yp2::filter::Base* filter_base = m_factory->create(type_value);
+
+                filter_base->configure(node3);
+                
+                route.m_list.push_back(
+                    boost::shared_ptr<yp2::filter::Base>(filter_base));
+            }
             std::cout << "processing /yp2/routes/route[" 
                       << route_nr << "]/filter[" 
                       << filter3_nr << "]" << std::endl;
@@ -208,20 +250,52 @@ void yp2::RouterFleXML::Rep::parse_xml_config_dom(xmlDocPtr doc)
             node3 = jump_to_next(node3, XML_ELEMENT_NODE);
             
         }
-        node2 = jump_to_next(node2, XML_ELEMENT_NODE);
+        std::map<std::string,RouterFleXML::Route>::iterator it;
+        it = m_routes.find(id_value);
+        if (it != m_routes.end())
+            throw XMLError("Route id='" + id_value + "' already exist");
+        else
+            m_routes[id_value] = route;
+        node = jump_to_next(node, XML_ELEMENT_NODE);
     }
-}        
+}
 
-void yp2::RouterFleXML::Rep::create_filter(std::string type, 
-                                           const xmlDoc * xmldoc,
-                                           std::string id)
+void yp2::RouterFleXML::Rep::parse_xml_config_dom(xmlDocPtr doc)
 {
-    std::cout << "Created Filter type='" << type 
-              << "' id='" << id << "'" << std::endl;
-}
+    if (!doc)
+        throw XMLError("Empty XML Document");
+    
+    const xmlNode* root = xmlDocGetRootElement(doc);
+    
+    check_element_yp2(root,  "yp2");
+
+    std::cout << "processing /yp2" << std::endl;
+    
+    // process <start> node which is expected first element node
+    const xmlNode* node = jump_to_children(root, XML_ELEMENT_NODE);
+    //for (; node && node->type != XML_ELEMENT_NODE; node = node->next)
+    //    ;
+
+    check_element_yp2(node, "start");
+
+    std::cout << "processing /yp2/start" << std::endl;
+    
+    // process <filters> node which is expected second element node
+    node = jump_to_next(node, XML_ELEMENT_NODE);
+    check_element_yp2(node, "filters");
+    std::cout << "processing /yp2/filters" << std::endl;
+    
+    parse_xml_filters(doc, jump_to_children(node, XML_ELEMENT_NODE));
+                      
+    // process <routes> node which is expected third element node
+    node = jump_to_next(node, XML_ELEMENT_NODE);
+    check_element_yp2(node, "routes");
+    std::cout << "processing /yp2/routes" << std::endl;
+    
+    parse_xml_routes(doc, jump_to_children(node, XML_ELEMENT_NODE));
+}        
 
-yp2::RouterFleXML::Rep::Rep() : 
-    m_xinclude(false)
+yp2::RouterFleXML::Rep::Rep() : m_xinclude(false)
 {
 }
 
index 814d4c1..be7b66d 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: router_flexml.hpp,v 1.9 2006-01-04 14:30:51 adam Exp $
+/* $Id: router_flexml.hpp,v 1.10 2006-01-05 16:39:37 adam Exp $
    Copyright (c) 2005, Index Data.
 
    %LICENSE%
@@ -17,6 +17,7 @@ namespace yp2
     class RouterFleXML : public yp2::Router 
     {
         class Rep;
+        class Route;
     public:
         RouterFleXML(std::string xmlconf, yp2::FactoryFilter &factory);
         
index 5cefd7a..5bed848 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: test_router_flexml.cpp,v 1.11 2006-01-04 14:30:51 adam Exp $
+/* $Id: test_router_flexml.cpp,v 1.12 2006-01-05 16:39:37 adam Exp $
    Copyright (c) 2005, Index Data.
 
 %LICENSE%
 
 using namespace boost::unit_test;
 
-static bool tfilter_destroyed = false;
+static int tfilter_ref = 0;
 class TFilter: public yp2::filter::Base {
 public:
     void process(yp2::Package & package) const {};
-    ~TFilter() { tfilter_destroyed = true; };
+    TFilter() { tfilter_ref++; };
+    ~TFilter() { tfilter_ref--; };
 };
 
 static yp2::filter::Base* filter_creator()
@@ -29,6 +30,7 @@ static yp2::filter::Base* filter_creator()
     return new TFilter;
 }
 
+// Pass well-formed XML and valid configuration to it (implicit NS)
 BOOST_AUTO_UNIT_TEST( test_router_flexml_1 )
 {
     try
@@ -53,7 +55,11 @@ BOOST_AUTO_UNIT_TEST( test_router_flexml_1 )
             "  <routes>\n"  
             "    <route id=\"start\">\n"
             "      <filter refid=\"front_default\"/>\n"
-            "      <filter refid=\"log_cout\"/>\n"
+            "      <filter refid=\"log_cout1\"/>\n"
+            "      <filter type=\"tfilter\">\n"
+            "      </filter>\n"
+            "      <filter type=\"z3950_client\">\n"
+            "      </filter>\n"
             "    </route>\n"
             "  </routes>\n"
             "</yp2>\n";
@@ -61,6 +67,7 @@ BOOST_AUTO_UNIT_TEST( test_router_flexml_1 )
         yp2::FactoryStatic factory;
         factory.add_creator("tfilter", filter_creator);
         yp2::RouterFleXML rflexml(xmlconf, factory);
+        BOOST_CHECK_EQUAL(tfilter_ref, 2);
     }
     catch ( std::runtime_error &e) {
         std::cout << "std::runtime error: " << e.what() << "\n";
@@ -69,12 +76,13 @@ BOOST_AUTO_UNIT_TEST( test_router_flexml_1 )
     catch ( ... ) {
         BOOST_CHECK (false);
     }
-    BOOST_CHECK(tfilter_destroyed == true);
+    BOOST_CHECK_EQUAL(tfilter_ref, 0);
 }
 
+// Pass non-wellformed XML
 BOOST_AUTO_UNIT_TEST( test_router_flexml_2 )
 {
-    bool got_xml_error = false;
+    bool got_error_as_expected = false;
     try
     {
         std::string xmlconf_invalid = "<?xml version=\"1.0\"?>\n"
@@ -88,18 +96,19 @@ BOOST_AUTO_UNIT_TEST( test_router_flexml_2 )
         yp2::RouterFleXML rflexml(xmlconf_invalid, factory);
     }
     catch ( yp2::RouterFleXML::XMLError &e) {
-        got_xml_error = true;
+        std::cout << "XMLError: " << e.what() << "\n";
+        got_error_as_expected = true;
     }
     catch ( std::runtime_error &e) {
         std::cout << "std::runtime error: " << e.what() << "\n";
-        BOOST_CHECK (false);
     }
     catch ( ... ) {
         ;
     }
-    BOOST_CHECK(got_xml_error);
+    BOOST_CHECK(got_error_as_expected);
 }
 
+// Pass well-formed XML with explicit NS
 BOOST_AUTO_UNIT_TEST( test_router_flexml_3 )
 {
     try
@@ -135,6 +144,41 @@ BOOST_AUTO_UNIT_TEST( test_router_flexml_3 )
     }
 }
 
+// Pass well-formed XML but bad filter type
+BOOST_AUTO_UNIT_TEST( test_router_flexml_4 )
+{
+    bool got_error_as_expected = false;
+    try
+    {
+        std::string xmlconf = "<?xml version=\"1.0\"?>\n"
+            "<yp2 xmlns=\"http://indexdata.dk/yp2/config/1\">\n"
+            "  <start route=\"start\"/>\n"
+            "  <filters>\n"
+            "    <filter id=\"front_default\" type=\"notknown\">\n"
+            "      <port>210</port>\n"
+            "    </filter>\n"
+            "  </filters>\n"
+            "  <routes>\n"  
+            "    <route id=\"start\">\n"
+            "      <filter refid=\"front_default\"/>\n"
+            "    </route>\n"
+            "  </routes>\n"
+            "</yp2>\n";
+
+        yp2::FactoryStatic factory;
+        factory.add_creator("tfilter", filter_creator);
+        yp2::RouterFleXML rflexml(xmlconf, factory);
+    }
+    catch ( yp2::FactoryFilter::NotFound &e) {
+        std::cout << "yp2::FactoryFilter::NotFound: " << e.what() << "\n";
+        got_error_as_expected = true;
+    }
+    catch ( std::runtime_error &e) {
+        std::cout << "std::runtime error: " << e.what() << "\n";
+    }
+    BOOST_CHECK(got_error_as_expected);
+}
+
 
 /*
  * Local variables: