The configure method takes test_only flag so we can avoid
[metaproxy-moved-to-github.git] / src / filter_virt_db.cpp
index 67b6750..bd142a0 100644 (file)
@@ -1,7 +1,27 @@
-/* $Id: filter_virt_db.cpp,v 1.39 2006-05-15 13:22:02 adam Exp $
-   Copyright (c) 2005-2006, Index Data.
+/* $Id: filter_virt_db.cpp,v 1.54 2008-02-20 15:07:52 adam Exp $
+   Copyright (c) 2005-2007, Index Data.
 
-%LICENSE%
+This file is part of Metaproxy.
+
+Metaproxy is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+Metaproxy is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Metaproxy; see the file LICENSE.  If not, write to the
+Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+ */
+/* $Id: filter_virt_db.cpp,v 1.54 2008-02-20 15:07:52 adam Exp $
+   Copyright (c) 2005-2007, Index Data.
+
+   See the LICENSE file for details
  */
 
 #include "config.hpp"
@@ -29,7 +49,7 @@ namespace yf = mp::filter;
 namespace metaproxy_1 {
     namespace filter {
 
-        struct Virt_db::Set {
+        struct VirtualDB::Set {
             Set(BackendPtr b, std::string setname);
             Set();
             ~Set();
@@ -37,13 +57,13 @@ namespace metaproxy_1 {
             BackendPtr m_backend;
             std::string m_setname;
         };
-        struct Virt_db::Map {
+        struct VirtualDB::Map {
             Map(std::list<std::string> targets, std::string route);
             Map();
             std::list<std::string> m_targets;
             std::string m_route;
         };
-        struct Virt_db::Backend {
+        struct VirtualDB::Backend {
             mp::Session m_backend_session;
             std::list<std::string> m_frontend_databases;
             std::list<std::string> m_targets;
@@ -51,7 +71,7 @@ namespace metaproxy_1 {
             bool m_named_result_sets;
             int m_number_of_sets;
         };
-        struct Virt_db::Frontend {
+        struct VirtualDB::Frontend {
             Frontend(Rep *rep);
             ~Frontend();
             mp::Session m_session;
@@ -59,20 +79,21 @@ namespace metaproxy_1 {
             bool m_in_use;
             yazpp_1::GDU m_init_gdu;
             std::list<BackendPtr> m_backend_list;
-            std::map<std::string,Virt_db::Set> m_sets;
+            std::map<std::string,VirtualDB::Set> m_sets;
 
             void search(Package &package, Z_APDU *apdu);
             void present(Package &package, Z_APDU *apdu);
             void scan(Package &package, Z_APDU *apdu);
 
             void close(Package &package);
-            typedef std::map<std::string,Virt_db::Set>::iterator Sets_it;
-
-            void fixup_npr(Package &p, BackendPtr b);
-
-            void fixup_npr(Z_Records *records, std::string database,
-                           ODR odr);
+            typedef std::map<std::string,VirtualDB::Set>::iterator Sets_it;
 
+            void fixup_package(Package &p, BackendPtr b);
+            void fixup_npr_record(ODR odr, Z_NamePlusRecord *npr,
+                                  BackendPtr b);
+            void fixup_npr_records(ODR odr, Z_Records *records,
+                                   BackendPtr b);
+    
             BackendPtr lookup_backend_from_databases(
                 std::list<std::string> databases);
             BackendPtr create_backend_from_databases(
@@ -85,15 +106,15 @@ namespace metaproxy_1 {
                                     int &error_code, std::string &addinfo);
             Rep *m_p;
         };            
-        class Virt_db::Rep {
-            friend class Virt_db;
+        class VirtualDB::Rep {
+            friend class VirtualDB;
             friend struct Frontend;
             
             FrontendPtr get_frontend(Package &package);
             void release_frontend(Package &package);
         private:
-            std::map<std::string, Virt_db::Map>m_maps;
-            typedef std::map<std::string,Virt_db::Set>::iterator Sets_it;
+            std::map<std::string, VirtualDB::Map>m_maps;
+            typedef std::map<std::string,VirtualDB::Set>::iterator Sets_it;
             boost::mutex m_mutex;
             boost::condition m_cond_session_ready;
             std::map<mp::Session, FrontendPtr> m_clients;
@@ -101,7 +122,7 @@ namespace metaproxy_1 {
     }
 }
 
-yf::Virt_db::BackendPtr yf::Virt_db::Frontend::lookup_backend_from_databases(
+yf::VirtualDB::BackendPtr yf::VirtualDB::Frontend::lookup_backend_from_databases(
     std::list<std::string> databases)
 {
     std::list<BackendPtr>::const_iterator map_it;
@@ -113,7 +134,7 @@ yf::Virt_db::BackendPtr yf::Virt_db::Frontend::lookup_backend_from_databases(
     return null;
 }
 
-yf::Virt_db::BackendPtr yf::Virt_db::Frontend::create_backend_from_databases(
+yf::VirtualDB::BackendPtr yf::VirtualDB::Frontend::create_backend_from_databases(
     std::list<std::string> databases, int &error_code, std::string &addinfo)
 {
     BackendPtr b(new Backend);
@@ -128,19 +149,24 @@ yf::Virt_db::BackendPtr yf::Virt_db::Frontend::create_backend_from_databases(
     std::map<std::string,bool> targets_dedup;
     for (; db_it != databases.end(); db_it++)
     {
-        std::map<std::string, Virt_db::Map>::iterator map_it;
+        std::map<std::string, VirtualDB::Map>::iterator map_it;
         map_it = m_p->m_maps.find(mp::util::database_name_normalize(*db_it));
         if (map_it == m_p->m_maps.end())  // database not found
         {
-            error_code = YAZ_BIB1_DATABASE_UNAVAILABLE;
+            error_code = YAZ_BIB1_DATABASE_DOES_NOT_EXIST;
             addinfo = *db_it;
             BackendPtr ptr;
             return ptr;
         }
         std::list<std::string>::const_iterator t_it =
             map_it->second.m_targets.begin();
-        for (; t_it != map_it->second.m_targets.end(); t_it++)
-            targets_dedup[*t_it] = true;
+        for (; t_it != map_it->second.m_targets.end(); t_it++) {
+            if (!targets_dedup[*t_it])
+            {
+                targets_dedup[*t_it] = true;
+                b->m_targets.push_back(*t_it);
+            }
+        }
 
         // see if we have a route conflict.
         if (!first_route && b->m_route != map_it->second.m_route)
@@ -153,15 +179,11 @@ yf::Virt_db::BackendPtr yf::Virt_db::Frontend::create_backend_from_databases(
         b->m_route = map_it->second.m_route;
         first_route = false;
     }
-    std::map<std::string,bool>::const_iterator tm_it = targets_dedup.begin();
-    for (; tm_it != targets_dedup.end(); tm_it++)
-        b->m_targets.push_back(tm_it->first);
-
     return b;
 }
 
-yf::Virt_db::BackendPtr yf::Virt_db::Frontend::init_backend(
-    std::list<std::string> databases, Package &package,
+yf::VirtualDB::BackendPtr yf::VirtualDB::Frontend::init_backend(
+    std::list<std::string> databases, mp::Package &package,
     int &error_code, std::string &addinfo)
 {
     BackendPtr b = create_backend_from_databases(databases, error_code,
@@ -213,6 +235,7 @@ yf::Virt_db::BackendPtr yf::Virt_db::Frontend::init_backend(
         }
         if (!*res->result)
         {
+            error_code = YAZ_BIB1_DATABASE_UNAVAILABLE;
             mp::util::get_init_diagnostics(res, error_code, addinfo);
             BackendPtr null;
             return null; 
@@ -237,7 +260,7 @@ yf::Virt_db::BackendPtr yf::Virt_db::Frontend::init_backend(
     return b;
 }
 
-void yf::Virt_db::Frontend::search(Package &package, Z_APDU *apdu_req)
+void yf::VirtualDB::Frontend::search(mp::Package &package, Z_APDU *apdu_req)
 {
     Z_SearchRequest *req = apdu_req->u.searchRequest;
     std::string vhost;
@@ -356,18 +379,18 @@ void yf::Virt_db::Frontend::search(Package &package, Z_APDU *apdu_req)
     }
     b->m_number_of_sets++;
 
-    m_sets[resultSetId] = Virt_db::Set(b, backend_setname);
-    fixup_npr(search_package, b);
+    m_sets[resultSetId] = VirtualDB::Set(b, backend_setname);
+    fixup_package(search_package, b);
     package.response() = search_package.response();
 }
 
-yf::Virt_db::Frontend::Frontend(Rep *rep)
+yf::VirtualDB::Frontend::Frontend(Rep *rep)
 {
     m_p = rep;
     m_is_virtual = false;
 }
 
-void yf::Virt_db::Frontend::close(Package &package)
+void yf::VirtualDB::Frontend::close(mp::Package &package)
 {
     std::list<BackendPtr>::const_iterator b_it;
     
@@ -381,15 +404,15 @@ void yf::Virt_db::Frontend::close(Package &package)
     m_backend_list.clear();
 }
 
-yf::Virt_db::Frontend::~Frontend()
+yf::VirtualDB::Frontend::~Frontend()
 {
 }
 
-yf::Virt_db::FrontendPtr yf::Virt_db::Rep::get_frontend(Package &package)
+yf::VirtualDB::FrontendPtr yf::VirtualDB::Rep::get_frontend(mp::Package &package)
 {
     boost::mutex::scoped_lock lock(m_mutex);
 
-    std::map<mp::Session,yf::Virt_db::FrontendPtr>::iterator it;
+    std::map<mp::Session,yf::VirtualDB::FrontendPtr>::iterator it;
     
     while(true)
     {
@@ -410,10 +433,10 @@ yf::Virt_db::FrontendPtr yf::Virt_db::Rep::get_frontend(Package &package)
     return f;
 }
 
-void yf::Virt_db::Rep::release_frontend(Package &package)
+void yf::VirtualDB::Rep::release_frontend(mp::Package &package)
 {
     boost::mutex::scoped_lock lock(m_mutex);
-    std::map<mp::Session,yf::Virt_db::FrontendPtr>::iterator it;
+    std::map<mp::Session,yf::VirtualDB::FrontendPtr>::iterator it;
     
     it = m_clients.find(package.session());
     if (it != m_clients.end())
@@ -431,40 +454,80 @@ void yf::Virt_db::Rep::release_frontend(Package &package)
     }
 }
 
-yf::Virt_db::Set::Set(BackendPtr b, std::string setname)
+yf::VirtualDB::Set::Set(BackendPtr b, std::string setname)
     :  m_backend(b), m_setname(setname)
 {
 }
 
 
-yf::Virt_db::Set::Set()
+yf::VirtualDB::Set::Set()
 {
 }
 
 
-yf::Virt_db::Set::~Set()
+yf::VirtualDB::Set::~Set()
 {
 }
 
-yf::Virt_db::Map::Map(std::list<std::string> targets, std::string route)
+yf::VirtualDB::Map::Map(std::list<std::string> targets, std::string route)
     : m_targets(targets), m_route(route) 
 {
 }
 
-yf::Virt_db::Map::Map()
+yf::VirtualDB::Map::Map()
 {
 }
 
-yf::Virt_db::Virt_db() : m_p(new Virt_db::Rep)
+yf::VirtualDB::VirtualDB() : m_p(new VirtualDB::Rep)
 {
 }
 
-yf::Virt_db::~Virt_db() {
+yf::VirtualDB::~VirtualDB() {
 }
 
+void yf::VirtualDB::Frontend::fixup_npr_record(ODR odr, Z_NamePlusRecord *npr,
+                                             BackendPtr b)
+{
+    if (npr->databaseName)
+    {
+        std::string b_database = std::string(npr->databaseName);
+
+        // consider each of the frontend databases..
+        std::list<std::string>::const_iterator db_it;
+        for (db_it = b->m_frontend_databases.begin(); 
+             db_it != b->m_frontend_databases.end(); db_it++)
+        {
+            // see which target it corresponds to.. (if any)
+            std::map<std::string,VirtualDB::Map>::const_iterator map_it;
 
-void yf::Virt_db::Frontend::fixup_npr(Z_Records *records, std::string database,
-                                      ODR odr)
+            map_it = m_p->m_maps.find(mp::util::database_name_normalize(*db_it));
+            if (map_it != m_p->m_maps.end())
+            { 
+                VirtualDB::Map m = map_it->second;
+                
+                std::list<std::string>::const_iterator t;
+                for (t = m.m_targets.begin(); t != m.m_targets.end(); t++)
+                {
+                    if (*t == b_database)
+                    {
+                        npr->databaseName = odr_strdup(odr, (*db_it).c_str());
+                        return;
+                    }
+                }
+            }
+            
+        }
+        db_it = b->m_frontend_databases.begin();
+        if (db_it != b->m_frontend_databases.end())
+        {
+            std::string database = *db_it;
+            npr->databaseName = odr_strdup(odr, database.c_str());
+        }
+    }
+}
+
+void yf::VirtualDB::Frontend::fixup_npr_records(ODR odr, Z_Records *records,
+                                              BackendPtr b)
 {
     if (records && records->which == Z_Records_DBOSD)
     {
@@ -472,37 +535,33 @@ void yf::Virt_db::Frontend::fixup_npr(Z_Records *records, std::string database,
         int i;
         for (i = 0; i < nprlist->num_records; i++)
         {
-            Z_NamePlusRecord *npr = nprlist->records[i];
-            npr->databaseName = odr_strdup(odr, database.c_str());
+            fixup_npr_record(odr, nprlist->records[i], b);
         }
     }
 }
 
-void yf::Virt_db::Frontend::fixup_npr(Package &p, BackendPtr b)
+void yf::VirtualDB::Frontend::fixup_package(mp::Package &p, BackendPtr b)
 {
     Z_GDU *gdu = p.response().get();
     mp::odr odr;
-    std::string database = "dummy";
-    std::list<std::string>::const_iterator db_it =
-        b->m_frontend_databases.begin();
-    if (db_it != b->m_frontend_databases.end())
-        database = *db_it;
 
-    if (gdu && gdu->which == Z_GDU_Z3950 && gdu->u.z3950->which ==
-        Z_APDU_presentResponse)
-    {
-        fixup_npr(gdu->u.z3950->u.presentResponse->records, database, odr);
-        p.response() = gdu;
-    }
-    if (gdu && gdu->which == Z_GDU_Z3950 && gdu->u.z3950->which ==
-        Z_APDU_searchResponse)
+    if (gdu && gdu->which == Z_GDU_Z3950)
     {
-        fixup_npr(gdu->u.z3950->u.searchResponse->records, database, odr);
-        p.response() = gdu;
+        Z_APDU *apdu = gdu->u.z3950;
+        if (apdu->which == Z_APDU_presentResponse)
+        {
+            fixup_npr_records(odr, apdu->u.presentResponse->records, b);
+            p.response() = gdu;
+        }
+        else if (apdu->which == Z_APDU_searchResponse)
+        {
+            fixup_npr_records(odr,  apdu->u.searchResponse->records, b);
+            p.response() = gdu;
+        }
     }
 }
 
-void yf::Virt_db::Frontend::present(Package &package, Z_APDU *apdu_req)
+void yf::VirtualDB::Frontend::present(mp::Package &package, Z_APDU *apdu_req)
 {
     Z_PresentRequest *req = apdu_req->u.presentRequest;
     std::string resultSetId = req->resultSetId;
@@ -532,7 +591,7 @@ void yf::Virt_db::Frontend::present(Package &package, Z_APDU *apdu_req)
 
     present_package.move(sets_it->second.m_backend->m_route);
 
-    fixup_npr(present_package, sets_it->second.m_backend);
+    fixup_package(present_package, sets_it->second.m_backend);
 
     if (present_package.session().is_closed())
     {
@@ -547,7 +606,7 @@ void yf::Virt_db::Frontend::present(Package &package, Z_APDU *apdu_req)
     delete id;
 }
 
-void yf::Virt_db::Frontend::scan(Package &package, Z_APDU *apdu_req)
+void yf::VirtualDB::Frontend::scan(mp::Package &package, Z_APDU *apdu_req)
 {
     Z_ScanRequest *req = apdu_req->u.scanRequest;
     std::string vhost;
@@ -613,16 +672,16 @@ void yf::Virt_db::Frontend::scan(Package &package, Z_APDU *apdu_req)
 }
 
 
-void yf::Virt_db::add_map_db2targets(std::string db, 
+void yf::VirtualDB::add_map_db2targets(std::string db, 
                                      std::list<std::string> targets,
                                      std::string route)
 {
     m_p->m_maps[mp::util::database_name_normalize(db)] 
-        = Virt_db::Map(targets, route);
+        = VirtualDB::Map(targets, route);
 }
 
 
-void yf::Virt_db::add_map_db2target(std::string db, 
+void yf::VirtualDB::add_map_db2target(std::string db, 
                                     std::string target,
                                     std::string route)
 {
@@ -630,10 +689,10 @@ void yf::Virt_db::add_map_db2target(std::string db,
     targets.push_back(target);
 
     m_p->m_maps[mp::util::database_name_normalize(db)]
-        = Virt_db::Map(targets, route);
+        = VirtualDB::Map(targets, route);
 }
 
-void yf::Virt_db::process(Package &package) const
+void yf::VirtualDB::process(mp::Package &package) const
 {
     FrontendPtr f = m_p->get_frontend(package);
 
@@ -645,7 +704,7 @@ void yf::Virt_db::process(Package &package) const
         Z_InitRequest *req = gdu->u.z3950->u.initRequest;
         
         std::list<std::string> vhosts;
-        mp::util::get_vhost_otherinfo(&req->otherInfo, false, vhosts);
+        mp::util::get_vhost_otherinfo(req->otherInfo, vhosts);
         if (vhosts.size() == 0)
         {
             f->m_init_gdu = gdu;
@@ -712,6 +771,10 @@ void yf::Virt_db::process(Package &package) const
         {
             f->scan(package, apdu);
         }
+        else if (apdu->which == Z_APDU_close)
+        {
+            package.session().close();
+        }
         else
         {
             mp::odr odr;
@@ -727,7 +790,7 @@ void yf::Virt_db::process(Package &package) const
 }
 
 
-void mp::filter::Virt_db::configure(const xmlNode * ptr)
+void mp::filter::VirtualDB::configure(const xmlNode * ptr, bool test_only)
 {
     for (ptr = ptr->children; ptr; ptr = ptr->next)
     {
@@ -743,9 +806,9 @@ void mp::filter::Virt_db::configure(const xmlNode * ptr)
                 if (v_node->type != XML_ELEMENT_NODE)
                     continue;
                 
-                if (mp::xml::is_element_yp2(v_node, "database"))
+                if (mp::xml::is_element_mp(v_node, "database"))
                     database = mp::xml::get_text(v_node);
-                else if (mp::xml::is_element_yp2(v_node, "target"))
+                else if (mp::xml::is_element_mp(v_node, "target"))
                     targets.push_back(mp::xml::get_text(v_node));
                 else
                     throw mp::filter::FilterException
@@ -769,7 +832,7 @@ void mp::filter::Virt_db::configure(const xmlNode * ptr)
 
 static mp::filter::Base* filter_creator()
 {
-    return new mp::filter::Virt_db;
+    return new mp::filter::VirtualDB;
 }
 
 extern "C" {