Ruleset functional MP-469
[metaproxy-moved-to-github.git] / src / filter_session_shared.cpp
index 229c99b..e3833e1 100644 (file)
@@ -1,5 +1,5 @@
 /* This file is part of Metaproxy.
-   Copyright (C) 2005-2012 Index Data
+   Copyright (C) 2005-2013 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
@@ -31,6 +31,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 #include <metaproxy/util.hpp>
 #include "filter_session_shared.hpp"
 
+#include <yaz/copy_types.h>
 #include <yaz/log.h>
 #include <yaz/zgdu.h>
 #include <yaz/otherinfo.h>
@@ -125,11 +126,15 @@ namespace metaproxy_1 {
             time_t m_backend_set_ttl;
             time_t m_backend_expiry_ttl;
             size_t m_backend_set_max;
+            Odr_int m_preferredMessageSize;
+            Odr_int m_maximumRecordSize;
         public:
             BackendClass(const yazpp_1::GDU &init_request,
                          int resultset_ttl,
                          int resultset_max,
-                         int session_ttl);
+                         int session_ttl,
+                         Odr_int preferredRecordSize,
+                         Odr_int maximumRecordSize);
             ~BackendClass();
         };
         // frontend result set
@@ -155,6 +160,9 @@ namespace metaproxy_1 {
             void present(Package &package, Z_APDU *apdu);
             void scan(Package &package, Z_APDU *apdu);
 
+            int result_set_ref(ODR o,
+                               const Databases &databases,
+                               Z_RPNStructure *s, std::string &rset);
             void get_set(mp::Package &package,
                          const Z_APDU *apdu_req,
                          const Databases &databases,
@@ -197,6 +205,8 @@ namespace metaproxy_1 {
             bool m_optimize_search;
             bool m_restart;
             int m_session_max;
+            Odr_int m_preferredMessageSize;
+            Odr_int m_maximumRecordSize;
         };
     }
 }
@@ -382,6 +392,11 @@ yf::SessionShared::BackendInstancePtr yf::SessionShared::BackendClass::create_ba
     ODR_MASK_SET(req->protocolVersion, Z_ProtocolVersion_2);
     ODR_MASK_SET(req->protocolVersion, Z_ProtocolVersion_3);
 
+    if (m_preferredMessageSize)
+        *req->preferredMessageSize = m_preferredMessageSize;
+    if (m_maximumRecordSize)
+        *req->maximumRecordSize = m_maximumRecordSize;
+
     init_package.request() = init_pdu;
 
     init_package.move();
@@ -430,10 +445,14 @@ yf::SessionShared::BackendInstancePtr yf::SessionShared::BackendClass::create_ba
 yf::SessionShared::BackendClass::BackendClass(const yazpp_1::GDU &init_request,
                                               int resultset_ttl,
                                               int resultset_max,
-                                              int session_ttl)
+                                              int session_ttl,
+                                              Odr_int preferredMessageSize,
+                                              Odr_int maximumRecordSize)
     : m_named_result_sets(false), m_init_request(init_request),
       m_sequence_top(0), m_backend_set_ttl(resultset_ttl),
-      m_backend_expiry_ttl(session_ttl), m_backend_set_max(resultset_max)
+      m_backend_expiry_ttl(session_ttl), m_backend_set_max(resultset_max),
+      m_preferredMessageSize(preferredMessageSize),
+      m_maximumRecordSize(maximumRecordSize)
 {}
 
 yf::SessionShared::BackendClass::~BackendClass()
@@ -456,7 +475,9 @@ void yf::SessionShared::Rep::init(mp::Package &package, const Z_GDU *gdu,
             BackendClassPtr b(new BackendClass(gdu->u.z3950,
                                                m_resultset_ttl,
                                                m_resultset_max,
-                                               m_session_ttl));
+                                               m_session_ttl,
+                                               m_preferredMessageSize,
+                                               m_maximumRecordSize));
             m_backend_map[k] = b;
             frontend->m_backend_class = b;
         }
@@ -474,7 +495,6 @@ void yf::SessionShared::Rep::init(mp::Package &package, const Z_GDU *gdu,
     if (bc->m_backend_list.size() == 0)
     {
         BackendInstancePtr backend = bc->create_backend(package);
-
         if (backend)
             bc->release_backend(backend);
     }
@@ -491,13 +511,22 @@ void yf::SessionShared::Rep::init(mp::Package &package, const Z_GDU *gdu,
         Z_GDU *response_gdu = init_response.get();
         mp::util::transfer_referenceId(odr, gdu->u.z3950,
                                        response_gdu->u.z3950);
-        Z_Options *server_options =
-            response_gdu->u.z3950->u.initResponse->options;
+        Z_InitResponse *init_res = response_gdu->u.z3950->u.initResponse;
+        Z_Options *server_options = init_res->options;
         Z_Options *client_options = &frontend->m_init_options;
         int i;
         for (i = 0; i < 30; i++)
             if (!ODR_MASK_GET(client_options, i))
                 ODR_MASK_CLEAR(server_options, i);
+
+        if (!m_preferredMessageSize ||
+            *init_res->preferredMessageSize > *req->preferredMessageSize)
+            *init_res->preferredMessageSize = *req->preferredMessageSize;
+
+        if (!m_maximumRecordSize ||
+            *init_res->maximumRecordSize > *req->maximumRecordSize)
+            *init_res->maximumRecordSize = *req->maximumRecordSize;
+
         package.response() = init_response;
         if (!*response_gdu->u.z3950->u.initResponse->result)
             package.session().close();
@@ -819,6 +848,54 @@ restart:
     found_backend->m_sets.push_back(found_set);
 }
 
+int yf::SessionShared::Frontend::result_set_ref(ODR o,
+                                                const Databases &databases,
+                                                Z_RPNStructure *s,
+                                                std::string &rset)
+{
+    int ret = 0;
+    switch (s->which)
+    {
+    case Z_RPNStructure_simple:
+        if (s->u.simple->which == Z_Operand_resultSetId)
+        {
+            const char *id = s->u.simple->u.resultSetId;
+            rset = id;
+
+            FrontendSets::iterator fset_it = m_frontend_sets.find(id);
+            if (fset_it == m_frontend_sets.end())
+            {
+                ret = YAZ_BIB1_SPECIFIED_RESULT_SET_DOES_NOT_EXIST;
+            }
+            else if (fset_it->second->get_databases() != databases)
+            {
+                ret = YAZ_BIB1_SPECIFIED_RESULT_SET_DOES_NOT_EXIST;
+            }
+            else
+            {
+                yazpp_1::Yaz_Z_Query query = fset_it->second->get_query();
+                Z_Query *q = yaz_copy_Z_Query(query.get_Z_Query(), o);
+                if (q->which == Z_Query_type_1 || q->which == Z_Query_type_101)
+                {
+                    s->which = q->u.type_1->RPNStructure->which;
+                    s->u.simple = q->u.type_1->RPNStructure->u.simple;
+                }
+                else
+                {
+                    ret = YAZ_BIB1_SPECIFIED_RESULT_SET_DOES_NOT_EXIST;
+                }
+            }
+        }
+        break;
+    case Z_RPNStructure_complex:
+        ret = result_set_ref(o, databases, s->u.complex->s1, rset);
+        if (!ret)
+            ret = result_set_ref(o, databases, s->u.complex->s2, rset);
+        break;
+    }
+    return ret;
+}
+
 void yf::SessionShared::Frontend::search(mp::Package &package,
                                          Z_APDU *apdu_req)
 {
@@ -839,19 +916,40 @@ void yf::SessionShared::Frontend::search(mp::Package &package,
                     YAZ_BIB1_RESULT_SET_EXISTS_AND_REPLACE_INDICATOR_OFF,
                     0);
             package.response() = apdu;
-
             return;
         }
         m_frontend_sets.erase(fset_it);
     }
 
-    yazpp_1::Yaz_Z_Query query;
-    query.set_Z_Query(req->query);
     Databases databases;
     int i;
     for (i = 0; i < req->num_databaseNames; i++)
         databases.push_back(req->databaseNames[i]);
 
+
+    yazpp_1::Yaz_Z_Query query;
+    query.set_Z_Query(req->query);
+
+    Z_Query *q = query.get_Z_Query();
+    if (q->which == Z_Query_type_1 || q->which == Z_Query_type_101)
+    {
+        mp::odr odr;
+        std::string rset;
+        int diag = result_set_ref(odr, databases, q->u.type_1->RPNStructure,
+                                  rset);
+        if (diag)
+        {
+            Z_APDU *apdu =
+                odr.create_searchResponse(
+                    apdu_req,
+                    diag,
+                    rset.c_str());
+            package.response() = apdu;
+            return;
+        }
+        query.set_Z_Query(q);
+    }
+
     BackendSetPtr found_set; // null
     BackendInstancePtr found_backend; // null
 
@@ -1091,6 +1189,8 @@ yf::SessionShared::Rep::Rep()
     m_optimize_search = true;
     m_restart = false;
     m_session_max = 100;
+    m_preferredMessageSize = 0;
+    m_maximumRecordSize = 0;
 }
 
 void yf::SessionShared::Rep::start()
@@ -1279,6 +1379,24 @@ void yf::SessionShared::configure(const xmlNode *ptr, bool test_only,
                                                        attr->name));
             }
         }
+        else if (!strcmp((const char *) ptr->name, "init"))
+        {
+            const struct _xmlAttr *attr;
+            for (attr = ptr->properties; attr; attr = attr->next)
+            {
+                if (!strcmp((const char *) attr->name, "maximum-record-size"))
+                    m_p->m_maximumRecordSize =
+                        mp::xml::get_int(attr->children, 0);
+                else if (!strcmp((const char *) attr->name,
+                                 "preferred-message-size"))
+                    m_p->m_preferredMessageSize =
+                        mp::xml::get_int(attr->children, 0);
+                else
+                    throw mp::filter::FilterException(
+                        "Bad attribute " + std::string((const char *)
+                                                       attr->name));
+            }
+        }
         else
         {
             throw mp::filter::FilterException("Bad element "