Fix Metaproxy stops logging after check config failed MP-590
[metaproxy-moved-to-github.git] / src / filter_sort.cpp
index 5f09492..ce0db12 100644 (file)
@@ -1,5 +1,5 @@
 /* This file is part of Metaproxy.
-   Copyright (C) 2005-2012 Index Data
+   Copyright (C) Index Data
 
 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
@@ -51,6 +51,7 @@ namespace metaproxy_1 {
             std::string m_xpath_expr;
             std::string m_namespaces;
             bool m_ascending;
+            bool m_debug;
             boost::mutex m_mutex;
             boost::condition m_cond_session_ready;
             std::map<mp::Session, FrontendPtr> m_clients;
@@ -62,14 +63,14 @@ namespace metaproxy_1 {
             Z_NamePlusRecord *npr;
             std::string score;
             void get_xpath(xmlDoc *doc, const char *namespaces,
-                           const char *expr);
+                           const char *expr, bool debug);
             bool register_namespaces(xmlXPathContextPtr xpathCtx,
                                      const char *nsList);
         public:
             Record(Z_NamePlusRecord *n, const char *namespaces,
-                   const char *expr);
+                   const char *expr, bool debug);
             ~Record();
-            bool operator < (const Record &rhs);
+            bool operator < (const Record &rhs) const;
         };
         class Sort::RecordList : boost::noncopyable {
             Odr_oid *syntax;
@@ -77,6 +78,7 @@ namespace metaproxy_1 {
             mp::odr m_odr;
             std::string namespaces;
             std::string xpath_expr;
+            bool debug;
         public:
             bool cmp(Odr_oid *syntax);
             void add(Z_NamePlusRecord *s);
@@ -84,7 +86,7 @@ namespace metaproxy_1 {
             Z_NamePlusRecord *get(int i, bool ascending);
             void sort();
             RecordList(Odr_oid *, std::string namespaces,
-                       std::string xpath_expr);
+                       std::string xpath_expr, bool debug);
             ~RecordList();
         };
         class Sort::ResultSet : boost::noncopyable {
@@ -109,6 +111,7 @@ namespace metaproxy_1 {
                                 Odr_int start_pos,
                                 ResultSetPtr s,
                                 Odr_oid *syntax,
+                                Z_RecordComposition *comp,
                                 const char *resultSetId);
         public:
             Frontend(Impl *impl);
@@ -122,37 +125,37 @@ static void print_xpath_nodes(xmlNodeSetPtr nodes, FILE* output)
     xmlNodePtr cur;
     int size;
     int i;
-    
+
     assert(output);
     size = nodes ? nodes->nodeNr : 0;
-    
+
     fprintf(output, "Result (%d nodes):\n", size);
     for (i = 0; i < size; ++i) {
        assert(nodes->nodeTab[i]);
-       
+
        if (nodes->nodeTab[i]->type == XML_NAMESPACE_DECL)
         {
            xmlNsPtr ns = (xmlNsPtr)nodes->nodeTab[i];
            cur = (xmlNodePtr)ns->next;
            if (cur->ns)
-               fprintf(output, "= namespace \"%s\"=\"%s\" for node %s:%s\n", 
+               fprintf(output, "= namespace \"%s\"=\"%s\" for node %s:%s\n",
                         ns->prefix, ns->href, cur->ns->href, cur->name);
             else
-                fprintf(output, "= namespace \"%s\"=\"%s\" for node %s\n", 
+                fprintf(output, "= namespace \"%s\"=\"%s\" for node %s\n",
                         ns->prefix, ns->href, cur->name);
        }
         else if (nodes->nodeTab[i]->type == XML_ELEMENT_NODE)
         {
-           cur = nodes->nodeTab[i];        
+           cur = nodes->nodeTab[i];
            if (cur->ns)
-               fprintf(output, "= element node \"%s:%s\"\n", 
+               fprintf(output, "= element node \"%s:%s\"\n",
                         cur->ns->href, cur->name);
             else
                fprintf(output, "= element node \"%s\"\n",  cur->name);
        }
         else
         {
-           cur = nodes->nodeTab[i];    
+           cur = nodes->nodeTab[i];
            fprintf(output, "= node \"%s\": type %d\n", cur->name, cur->type);
        }
     }
@@ -165,15 +168,15 @@ bool yf::Sort::Record::register_namespaces(xmlXPathContextPtr xpathCtx,
     xmlChar* prefix;
     xmlChar* href;
     xmlChar* next;
-    
+
     assert(xpathCtx);
     assert(nsList);
 
     nsListDup = xmlStrdup((const xmlChar *) nsList);
     if (!nsListDup)
         return false;
-    
-    next = nsListDup; 
+
+    next = nsListDup;
     while (next)
     {
        /* skip spaces */
@@ -190,13 +193,13 @@ bool yf::Sort::Record::register_namespaces(xmlXPathContextPtr xpathCtx,
            xmlFree(nsListDup);
            return false;
        }
-       *next++ = '\0'; 
-       
+       *next++ = '\0';
+
        /* find href */
        href = next;
        next = (xmlChar*)xmlStrchr(next, ' ');
        if (next)
-           *next++ = '\0';     
+           *next++ = '\0';
 
        /* do register namespace */
        if (xmlXPathRegisterNs(xpathCtx, prefix, href) != 0)
@@ -205,7 +208,7 @@ bool yf::Sort::Record::register_namespaces(xmlXPathContextPtr xpathCtx,
            return false;
        }
     }
-    
+
     xmlFree(nsListDup);
     return true;
 }
@@ -213,17 +216,19 @@ bool yf::Sort::Record::register_namespaces(xmlXPathContextPtr xpathCtx,
 
 
 void yf::Sort::Record::get_xpath(xmlDoc *doc, const char *namespaces,
-                                 const char *expr)
+                                 const char *expr, bool debug)
 {
     xmlXPathContextPtr xpathCtx = xmlXPathNewContext(doc);
     if (xpathCtx)
-    { 
+    {
         register_namespaces(xpathCtx, namespaces);
         xmlXPathObjectPtr xpathObj =
             xmlXPathEvalExpression((const xmlChar *) expr, xpathCtx);
         if (xpathObj)
         {
             xmlNodeSetPtr nodes = xpathObj->nodesetval;
+            if (debug)
+                print_xpath_nodes(nodes, yaz_log_file());
             if (nodes)
             {
                 int i;
@@ -240,7 +245,7 @@ void yf::Sort::Record::get_xpath(xmlDoc *doc, const char *namespaces,
                     {
                         content = mp::xml::get_text(ptr);
                     }
-                    if (content.c_str())
+                    if (content.length())
                     {
                         score = content;
                         break;
@@ -255,7 +260,8 @@ void yf::Sort::Record::get_xpath(xmlDoc *doc, const char *namespaces,
 
 yf::Sort::Record::Record(Z_NamePlusRecord *n,
                          const char *namespaces,
-                         const char *expr) : npr(n) 
+                         const char *expr,
+                         bool debug) : npr(n)
 {
     if (npr->which == Z_NamePlusRecord_databaseRecord)
     {
@@ -269,7 +275,7 @@ yf::Sort::Record::Record(Z_NamePlusRecord *n,
                 ext->u.octet_aligned->len);
             if (doc)
             {
-                get_xpath(doc, namespaces, expr);
+                get_xpath(doc, namespaces, expr, debug);
                 xmlFreeDoc(doc);
             }
         }
@@ -280,7 +286,7 @@ yf::Sort::Record::~Record()
 {
 }
 
-bool yf::Sort::Record::operator < (const Record &rhs)
+bool yf::Sort::Record::operator < (const Record &rhs) const
 {
     if (strcmp(this->score.c_str(), rhs.score.c_str()) < 0)
         return true;
@@ -289,8 +295,9 @@ bool yf::Sort::Record::operator < (const Record &rhs)
 
 yf::Sort::RecordList::RecordList(Odr_oid *syntax,
                                  std::string a_namespaces,
-                                 std::string a_xpath_expr)
-    : namespaces(a_namespaces), xpath_expr(a_xpath_expr)
+                                 std::string a_xpath_expr,
+                                 bool a_debug)
+    : namespaces(a_namespaces), xpath_expr(a_xpath_expr), debug(a_debug)
 
 {
     if (syntax)
@@ -301,9 +308,9 @@ yf::Sort::RecordList::RecordList(Odr_oid *syntax,
 
 yf::Sort::RecordList::~RecordList()
 {
-    
+
 }
+
 bool yf::Sort::RecordList::cmp(Odr_oid *syntax)
 {
     if ((!this->syntax && !syntax)
@@ -322,7 +329,7 @@ void yf::Sort::RecordList::add(Z_NamePlusRecord *s)
 {
     ODR oi = m_odr;
     Z_NamePlusRecord *npr = yaz_clone_z_NamePlusRecord(s, oi->mem);
-    Record record(npr, namespaces.c_str(), xpath_expr.c_str());
+    Record record(npr, namespaces.c_str(), xpath_expr.c_str(), debug);
     npr_list.push_back(record);
 }
 
@@ -365,7 +372,7 @@ void yf::Sort::process(mp::Package &package) const
 }
 
 
-yf::Sort::Frontend::Frontend(Impl *impl) : 
+yf::Sort::Frontend::Frontend(Impl *impl) :
     m_p(impl), m_is_virtual(false), m_in_use(true)
 {
 }
@@ -375,12 +382,12 @@ yf::Sort::Frontend::~Frontend()
 }
 
 
-yf::Sort::Impl::Impl() : m_prefetch(20), m_ascending(true)
+yf::Sort::Impl::Impl() : m_prefetch(20), m_ascending(true), m_debug(false)
 {
 }
 
 yf::Sort::Impl::~Impl()
-{ 
+{
 }
 
 yf::Sort::FrontendPtr yf::Sort::Impl::get_frontend(mp::Package &package)
@@ -388,13 +395,13 @@ yf::Sort::FrontendPtr yf::Sort::Impl::get_frontend(mp::Package &package)
     boost::mutex::scoped_lock lock(m_mutex);
 
     std::map<mp::Session,yf::Sort::FrontendPtr>::iterator it;
-    
+
     while(true)
     {
         it = m_clients.find(package.session());
         if (it == m_clients.end())
             break;
-        
+
         if (!it->second->m_in_use)
         {
             it->second->m_in_use = true;
@@ -412,7 +419,7 @@ void yf::Sort::Impl::release_frontend(mp::Package &package)
 {
     boost::mutex::scoped_lock lock(m_mutex);
     std::map<mp::Session,yf::Sort::FrontendPtr>::iterator it;
-    
+
     it = m_clients.find(package.session());
     if (it != m_clients.end())
     {
@@ -435,8 +442,8 @@ void yf::Sort::Impl::configure(const xmlNode *ptr, bool test_only,
     {
         if (ptr->type != XML_ELEMENT_NODE)
             continue;
-        if (!strcmp((const char *) ptr->name, "config"))
-        {            
+        if (!strcmp((const char *) ptr->name, "sort"))
+        {
             const struct _xmlAttr *attr;
             for (attr = ptr->properties; attr; attr = attr->next)
             {
@@ -446,7 +453,7 @@ void yf::Sort::Impl::configure(const xmlNode *ptr, bool test_only,
                     if (m_prefetch < 0)
                     {
                         throw mp::filter::FilterException(
-                            "Bad or missing value for attribute " + 
+                            "Bad or missing value for attribute " +
                             std::string((const char *) attr->name));
                     }
                 }
@@ -458,18 +465,13 @@ void yf::Sort::Impl::configure(const xmlNode *ptr, bool test_only,
                 {
                     m_namespaces = mp::xml::get_text(attr->children);
                 }
-                else if (!strcmp((const char *) attr->name, "sortorder"))
+                else if (!strcmp((const char *) attr->name, "ascending"))
                 {
-                    std::string t = mp::xml::get_text(attr->children);
-                    if (t == "ascending")
-                        m_ascending = true;
-                    else if (t == "descending")
-                        m_ascending = false;
-                    else
-                        throw mp::filter::FilterException(
-                            "Bad attribute value " + t + " for attribute " +
-                            std::string((const char *) attr->name));
-
+                    m_ascending = mp::xml::get_bool(attr->children, true);
+                }
+                else if (!strcmp((const char *) attr->name, "debug"))
+                {
+                    m_debug = mp::xml::get_bool(attr->children, false);
                 }
                 else
                     throw mp::filter::FilterException(
@@ -480,7 +482,7 @@ void yf::Sort::Impl::configure(const xmlNode *ptr, bool test_only,
         else
         {
             throw mp::filter::FilterException
-                ("Bad element " 
+                ("Bad element "
                  + std::string((const char *) ptr->name)
                  + " in sort filter");
         }
@@ -499,6 +501,7 @@ void yf::Sort::Frontend::handle_records(mp::Package &package,
                                         Odr_int start_pos,
                                         ResultSetPtr s,
                                         Odr_oid *syntax,
+                                        Z_RecordComposition *comp,
                                         const char *resultSetId)
 {
     if (records && records->which == Z_Records_DBOSD && start_pos == 1)
@@ -515,7 +518,8 @@ void yf::Sort::Frontend::handle_records(mp::Package &package,
         int pos = 1;
         RecordListPtr rlp(new RecordList(syntax,
                                          m_p->m_namespaces.c_str(),
-                                         m_p->m_xpath_expr.c_str()));
+                                         m_p->m_xpath_expr.c_str(),
+                                         m_p->m_debug));
         for (i = 0; i < nprl->num_records; i++, pos++)
             rlp->add(nprl->records[i]);
 
@@ -537,6 +541,7 @@ void yf::Sort::Frontend::handle_records(mp::Package &package,
             *p_req->numberOfRecordsRequested = end_pos - pos + 1;
             p_req->preferredRecordSyntax = syntax;
             p_req->resultSetId = odr_strdup(odr, resultSetId);
+            p_req->recordComposition = comp;
 
             present_package.request() = p_apdu;
             present_package.move();
@@ -566,57 +571,74 @@ void yf::Sort::Frontend::handle_records(mp::Package &package,
 
 void yf::Sort::Frontend::handle_search(mp::Package &package, Z_APDU *apdu_req)
 {
-    Z_SearchRequest *req = apdu_req->u.searchRequest;    
+    Z_SearchRequest *req = apdu_req->u.searchRequest;
     std::string resultSetId = req->resultSetName;
-    Package b_package(package.session(), package.origin());
     mp::odr odr;
+    Odr_oid *syntax = 0;
+
+    if (req->preferredRecordSyntax)
+        syntax = odr_oiddup(odr, req->preferredRecordSyntax);
 
-    b_package.copy_filter(package);
     Sets_it sets_it = m_sets.find(req->resultSetName);
     if (sets_it != m_sets.end())
     {
-        // result set already exist 
+        // result set already exist
         // if replace indicator is off: we return diagnostic if
         // result set already exist.
         if (*req->replaceIndicator == 0)
         {
-            Z_APDU *apdu = 
+            Z_APDU *apdu =
                 odr.create_searchResponse(
                     apdu_req,
                     YAZ_BIB1_RESULT_SET_EXISTS_AND_REPLACE_INDICATOR_OFF,
                     0);
             package.response() = apdu;
             return;
-        } 
+        }
         m_sets.erase(resultSetId);
     }
     ResultSetPtr s(new ResultSet);
     m_sets[resultSetId] = s;
-    package.move();
-    Z_GDU *gdu_res = package.response().get();
+
+    Package b_package(package.session(), package.origin());
+    b_package.copy_filter(package);
+    b_package.request() = apdu_req;
+    b_package.move();
+
+    Z_GDU *gdu_res = b_package.response().get();
     if (gdu_res && gdu_res->which == Z_GDU_Z3950 && gdu_res->u.z3950->which ==
         Z_APDU_searchResponse)
     {
         Z_SearchResponse *res = gdu_res->u.z3950->u.searchResponse;
+        Z_RecordComposition *record_comp =
+            mp::util::piggyback_to_RecordComposition(odr,
+                                                     *res->resultCount, req);
         s->hit_count = *res->resultCount;
         handle_records(b_package, apdu_req, res->records, 1, s,
-                       req->preferredRecordSyntax, resultSetId.c_str());
+                       syntax, record_comp, resultSetId.c_str());
         package.response() = gdu_res;
     }
+    else
+        package.response() = b_package.response();
+    if (b_package.session().is_closed())
+        b_package.session().close();
 }
 
 void yf::Sort::Frontend::handle_present(mp::Package &package, Z_APDU *apdu_req)
 {
-    Z_PresentRequest *req = apdu_req->u.presentRequest;    
+    Z_PresentRequest *req = apdu_req->u.presentRequest;
     std::string resultSetId = req->resultSetId;
-    Package b_package(package.session(), package.origin());
     mp::odr odr;
+    Odr_oid *syntax = 0;
+    Odr_int start = *req->resultSetStartPoint;
+
+    if (req->preferredRecordSyntax)
+        syntax = odr_oiddup(odr, req->preferredRecordSyntax);
 
-    b_package.copy_filter(package);
     Sets_it sets_it = m_sets.find(resultSetId);
     if (sets_it == m_sets.end())
     {
-        Z_APDU *apdu = 
+        Z_APDU *apdu =
             odr.create_presentResponse(
                 apdu_req,
                 YAZ_BIB1_SPECIFIED_RESULT_SET_DOES_NOT_EXIST,
@@ -629,7 +651,7 @@ void yf::Sort::Frontend::handle_present(mp::Package &package, Z_APDU *apdu_req)
     for (; it != rset->record_lists.end(); it++)
         if ((*it)->cmp(req->preferredRecordSyntax))
         {
-            if (*req->resultSetStartPoint - 1 + *req->numberOfRecordsRequested 
+            if (*req->resultSetStartPoint - 1 + *req->numberOfRecordsRequested
                 <= (*it)->size())
             {
                 int i;
@@ -638,9 +660,9 @@ void yf::Sort::Frontend::handle_present(mp::Package &package, Z_APDU *apdu_req)
 
                 *p_res->nextResultSetPosition = *req->resultSetStartPoint +
                     *req->numberOfRecordsRequested;
-                *p_res->numberOfRecordsReturned = 
+                *p_res->numberOfRecordsReturned =
                     *req->numberOfRecordsRequested;
-                p_res->records = (Z_Records *) 
+                p_res->records = (Z_Records *)
                     odr_malloc(odr, sizeof(*p_res->records));
                 p_res->records->which = Z_Records_DBOSD;
                 Z_NamePlusRecordList *nprl =  (Z_NamePlusRecordList *)
@@ -659,17 +681,26 @@ void yf::Sort::Frontend::handle_present(mp::Package &package, Z_APDU *apdu_req)
             }
             break;
         }
-    package.move();
+
+
+    Package b_package(package.session(), package.origin());
+    b_package.copy_filter(package);
+    b_package.request() = apdu_req;
+    b_package.move();
     Z_GDU *gdu_res = package.response().get();
     if (gdu_res && gdu_res->which == Z_GDU_Z3950 && gdu_res->u.z3950->which ==
         Z_APDU_presentResponse)
     {
         Z_PresentResponse *res = gdu_res->u.z3950->u.presentResponse;
-        handle_records(b_package, apdu_req, res->records, 
-                       *req->resultSetStartPoint, rset,
-                       req->preferredRecordSyntax, resultSetId.c_str());
+        handle_records(b_package, apdu_req, res->records,
+                       start, rset, syntax, req->recordComposition,
+                       resultSetId.c_str());
         package.response() = gdu_res;
     }
+    else
+        package.response() = b_package.response();
+    if (b_package.session().is_closed())
+        b_package.session().close();
 }
 
 void yf::Sort::Frontend::handle_package(mp::Package &package)