Version 1.3.38
[metaproxy-moved-to-github.git] / src / filter_sort.cpp
index c91d8a8..784c6f9 100644 (file)
@@ -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,12 +63,12 @@ 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);
         };
@@ -77,12 +78,15 @@ 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);
-            Z_NamePlusRecord *get(int i);
+            int size();
+            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 {
@@ -211,7 +215,7 @@ 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)
@@ -222,6 +226,8 @@ void yf::Sort::Record::get_xpath(xmlDoc *doc, const char *namespaces,
         if (xpathObj)
         {
             xmlNodeSetPtr nodes = xpathObj->nodesetval;
+            if (debug)
+                print_xpath_nodes(nodes, yaz_log_file());
             if (nodes)
             {
                 int i;
@@ -238,7 +244,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;
@@ -253,7 +259,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)
     {
@@ -267,7 +274,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);
             }
         }
@@ -287,8 +294,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)
@@ -302,21 +310,39 @@ yf::Sort::RecordList::~RecordList()
     
 }
  
+bool yf::Sort::RecordList::cmp(Odr_oid *syntax)
+{
+    if ((!this->syntax && !syntax)
+        ||
+        (this->syntax && syntax && !oid_oidcmp(this->syntax, syntax)))
+        return true;
+    return false;
+}
+
+int yf::Sort::RecordList::size()
+{
+    return npr_list.size();
+}
+
 void yf::Sort::RecordList::add(Z_NamePlusRecord *s)
 {
     ODR oi = m_odr;
-    Record record(yaz_clone_z_NamePlusRecord(s, oi->mem),
-                  namespaces.c_str(),
-                  xpath_expr.c_str());
+    Z_NamePlusRecord *npr = yaz_clone_z_NamePlusRecord(s, oi->mem);
+    Record record(npr, namespaces.c_str(), xpath_expr.c_str(), debug);
     npr_list.push_back(record);
 }
 
-Z_NamePlusRecord *yf::Sort::RecordList::get(int i)
+Z_NamePlusRecord *yf::Sort::RecordList::get(int pos, bool ascending)
 {
     std::list<Record>::const_iterator it = npr_list.begin();
+    int i = pos;
+    if (!ascending)
+        i = npr_list.size() - pos - 1;
     for (; it != npr_list.end(); it++, --i)
         if (i <= 0)
+        {
             return it->npr;
+        }
     return 0;
 }
 
@@ -355,7 +381,7 @@ 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)
 {
 }
 
@@ -415,7 +441,7 @@ 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)
@@ -438,18 +464,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(
@@ -483,13 +504,20 @@ void yf::Sort::Frontend::handle_records(mp::Package &package,
 {
     if (records && records->which == Z_Records_DBOSD && start_pos == 1)
     {
+        std::list<RecordListPtr>::const_iterator it = s->record_lists.begin();
+
+        for (; it != s->record_lists.end(); it++)
+            if ((*it)->cmp(syntax))
+                return;
+
         Z_NamePlusRecordList *nprl = records->u.databaseOrSurDiagnostics;
         int i;    // i is number of records fetched in last response
 
         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]);
 
@@ -534,10 +562,7 @@ void yf::Sort::Frontend::handle_records(mp::Package &package,
         rlp->sort();
 
         for (i = 0; i < nprl->num_records; i++)
-            if (m_p->m_ascending)
-                nprl->records[i] = rlp->get(i);
-            else
-                nprl->records[nprl->num_records - i - 1] = rlp->get(i);
+            nprl->records[i] = rlp->get(i, m_p->m_ascending);
     }
 }
 
@@ -547,6 +572,10 @@ void yf::Sort::Frontend::handle_search(mp::Package &package, Z_APDU *apdu_req)
     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);
@@ -577,7 +606,8 @@ void yf::Sort::Frontend::handle_search(mp::Package &package, Z_APDU *apdu_req)
         Z_SearchResponse *res = gdu_res->u.z3950->u.searchResponse;
         s->hit_count = *res->resultCount;
         handle_records(b_package, apdu_req, res->records, 1, s,
-                       req->preferredRecordSyntax, resultSetId.c_str());
+                       syntax, resultSetId.c_str());
+        package.response() = gdu_res;
     }
 }
 
@@ -587,6 +617,11 @@ void yf::Sort::Frontend::handle_present(mp::Package &package, Z_APDU *apdu_req)
     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);
@@ -600,6 +635,41 @@ void yf::Sort::Frontend::handle_present(mp::Package &package, Z_APDU *apdu_req)
         package.response() = apdu;
         return;
     }
+    ResultSetPtr rset = sets_it->second;
+    std::list<RecordListPtr>::const_iterator it = rset->record_lists.begin();
+    for (; it != rset->record_lists.end(); it++)
+        if ((*it)->cmp(req->preferredRecordSyntax))
+        {
+            if (*req->resultSetStartPoint - 1 + *req->numberOfRecordsRequested 
+                <= (*it)->size())
+            {
+                int i;
+                Z_APDU *p_apdu = zget_APDU(odr, Z_APDU_presentResponse);
+                Z_PresentResponse *p_res = p_apdu->u.presentResponse;
+
+                *p_res->nextResultSetPosition = *req->resultSetStartPoint +
+                    *req->numberOfRecordsRequested;
+                *p_res->numberOfRecordsReturned = 
+                    *req->numberOfRecordsRequested;
+                p_res->records = (Z_Records *) 
+                    odr_malloc(odr, sizeof(*p_res->records));
+                p_res->records->which = Z_Records_DBOSD;
+                Z_NamePlusRecordList *nprl =  (Z_NamePlusRecordList *)
+                    odr_malloc(odr, sizeof(*nprl));
+                p_res->records->u.databaseOrSurDiagnostics = nprl;
+                nprl->num_records = *req->numberOfRecordsRequested;
+                nprl->records = (Z_NamePlusRecord **)
+                    odr_malloc(odr, nprl->num_records * sizeof(*nprl->records));
+                for (i = 0; i < nprl->num_records; i++)
+                {
+                    int pos = i + *req->resultSetStartPoint - 1;
+                    nprl->records[i] = (*it)->get(pos, m_p->m_ascending);
+                }
+                package.response() = p_apdu;
+                return;
+            }
+            break;
+        }
     package.move();
     Z_GDU *gdu_res = package.response().get();
     if (gdu_res && gdu_res->which == Z_GDU_Z3950 && gdu_res->u.z3950->which ==
@@ -607,8 +677,8 @@ void yf::Sort::Frontend::handle_present(mp::Package &package, Z_APDU *apdu_req)
     {
         Z_PresentResponse *res = gdu_res->u.z3950->u.presentResponse;
         handle_records(b_package, apdu_req, res->records, 
-                       *req->resultSetStartPoint, sets_it->second,
-                       req->preferredRecordSyntax, resultSetId.c_str());
+                       start, rset, syntax, resultSetId.c_str());
+        package.response() = gdu_res;
     }
 }