-/* $Id: filter_sru_to_z3950.cpp,v 1.36 2008-01-29 16:51:12 adam Exp $
- Copyright (c) 2005-2007, Index Data.
-
-This file is part of Metaproxy.
+/* This file is part of Metaproxy.
+ Copyright (C) 2005-2008 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
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.
- */
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
#include "config.hpp"
#include "filter.hpp"
#include <yaz/srw.h>
#include <yaz/pquery.h>
#include <yaz/oid_db.h>
+#include <yaz/log.h>
#include <boost/thread/mutex.hpp>
+#include <boost/thread/condition.hpp>
#include <iostream>
#include <sstream>
namespace mp_util = metaproxy_1::util;
namespace yf = mp::filter;
-
namespace metaproxy_1 {
namespace filter {
class SRUtoZ3950::Impl {
union SRW_query {char * cql; char * xcql; char * pqf;};
typedef const int& SRW_query_type;
std::map<std::string, const xmlNode *> m_database_explain;
- private:
+ typedef std::map<std::string, int> ActiveUrlMap;
+
+ boost::mutex m_mutex;
+ boost::condition m_cond_url_ready;
+ ActiveUrlMap m_active_urls;
+ private:
+ void sru(metaproxy_1::Package &package, Z_GDU *zgdu_req);
bool z3950_build_query(mp::odr &odr_en, Z_Query *z_query,
const SRW_query &query,
SRW_query_type query_type) const;
bool z3950_init_request(mp::Package &package,
mp::odr &odr_en,
- Z_SRW_PDU *sru_pdu_req,
+ std::string zurl,
Z_SRW_PDU *sru_pdu_res) const;
bool z3950_close_request(mp::Package &package) const;
mp::Package &package,
mp::odr &odr_en,
Z_SRW_PDU *sru_pdu_res,
- Z_SRW_searchRetrieveRequest const *sr_req) const;
+ Z_SRW_searchRetrieveRequest const *sr_req,
+ std::string zurl) const;
bool z3950_present_request(
mp::Package &package,
int z3950_to_srw_diag(mp::odr &odr_en,
Z_SRW_searchRetrieveResponse *srw_res,
Z_DefaultDiagFormat *ddf) const;
+
+
};
}
}
{ // must have a destructor because of boost::scoped_ptr
}
-void yf::SRUtoZ3950::configure(const xmlNode *xmlnode)
+void yf::SRUtoZ3950::configure(const xmlNode *xmlnode, bool test_only)
{
m_p->configure(xmlnode);
}
}
}
-void yf::SRUtoZ3950::Impl::process(mp::Package &package)
+void yf::SRUtoZ3950::Impl::sru(mp::Package &package, Z_GDU *zgdu_req)
{
- Z_GDU *zgdu_req = package.request().get();
-
- // ignoring all non HTTP_Request packages
- if (!zgdu_req || !(zgdu_req->which == Z_GDU_HTTP_Request)){
- package.move();
- return;
- }
-
- // only working on HTTP_Request packages now
-
bool ok = true;
mp::odr odr_de(ODR_DECODE);
return;
}
+ std::string zurl;
+ Z_SRW_extra_arg *arg;
+
+ for ( arg = sru_pdu_req->extra_args; arg; arg = arg->next)
+ if (!strcmp(arg->name, "x-target"))
+ {
+ zurl = std::string(arg->value);
+ }
+ else if (!strcmp(arg->name, "x-max-sockets"))
+ {
+ package.origin().set_max_sockets(atoi(arg->value));
+ }
+
+
// filter acts as sink for SRU explain requests
if (sru_pdu_req && sru_pdu_req->which == Z_SRW_explain_request)
{
ok = mp_util::check_sru_query_exists(package, odr_en,
sru_pdu_res, sr_req);
- if (ok && z3950_init_request(package, odr_en, sru_pdu_req, sru_pdu_res))
+ if (ok && z3950_init_request(package, odr_en, zurl, sru_pdu_res))
{
- {
- ok = z3950_search_request(package, odr_en,
- sru_pdu_res, sr_req);
-
- if (ok
- && sru_pdu_res->u.response->numberOfRecords
- && *(sru_pdu_res->u.response->numberOfRecords)
- && sr_req->maximumRecords
- && *(sr_req->maximumRecords))
-
- ok = z3950_present_request(package, odr_en,
- sru_pdu_res,
- sr_req);
- z3950_close_request(package);
- }
+ ok = z3950_search_request(package, odr_en,
+ sru_pdu_res, sr_req, zurl);
+
+ if (ok
+ && sru_pdu_res->u.response->numberOfRecords
+ && *(sru_pdu_res->u.response->numberOfRecords)
+ && sr_req->maximumRecords
+ && *(sr_req->maximumRecords))
+
+ ok = z3950_present_request(package, odr_en,
+ sru_pdu_res,
+ sr_req);
+ z3950_close_request(package);
}
}
yaz_add_srw_diagnostic(odr_en,
&(sru_pdu_res->u.scan_response->diagnostics),
&(sru_pdu_res->u.scan_response->num_diagnostics),
- 4, "scan");
+ YAZ_SRW_UNSUPP_OPERATION, "scan");
// to be used when we do scan
- if (false && z3950_init_request(package, odr_en, sru_pdu_req,
- sru_pdu_res))
+ if (false && z3950_init_request(package, odr_en, zurl, sru_pdu_res))
{
z3950_scan_request(package, odr_en, sru_pdu_res, sr_req);
z3950_close_request(package);
}
+void yf::SRUtoZ3950::Impl::process(mp::Package &package)
+{
+ Z_GDU *zgdu_req = package.request().get();
+
+ // ignoring all non HTTP_Request packages
+ if (!zgdu_req || !(zgdu_req->which == Z_GDU_HTTP_Request)){
+ package.move();
+ return;
+ }
+
+ // only working on HTTP_Request packages now
+
+ // see if HTTP request is already being executed..
+ // we consider only the SRU - GET case..
+ if (zgdu_req->u.HTTP_Request->content_len == 0)
+ {
+ const char *path = zgdu_req->u.HTTP_Request->path;
+ boost::mutex::scoped_lock lock(m_mutex);
+ while (1)
+ {
+ ActiveUrlMap::iterator it = m_active_urls.find(path);
+ if (it == m_active_urls.end())
+ {
+ m_active_urls[path] = 1;
+ break;
+ }
+ yaz_log(YLOG_LOG, "Waiting for %s to complete", path);
+ m_cond_url_ready.wait(lock);
+ }
+ }
+ sru(package, zgdu_req);
+ if (zgdu_req->u.HTTP_Request->content_len == 0)
+ {
+ const char *path = zgdu_req->u.HTTP_Request->path;
+ boost::mutex::scoped_lock lock(m_mutex);
+
+ ActiveUrlMap::iterator it = m_active_urls.find(path);
+
+ m_active_urls.erase(it);
+ m_cond_url_ready.notify_all();
+ }
+}
+
bool
yf::SRUtoZ3950::Impl::z3950_init_request(mp::Package &package,
mp::odr &odr_en,
- Z_SRW_PDU *sru_pdu_req,
+ std::string zurl,
Z_SRW_PDU *sru_pdu_res) const
{
// prepare Z3950 package
ODR_MASK_SET(init_req->protocolVersion, Z_ProtocolVersion_2);
ODR_MASK_SET(init_req->protocolVersion, Z_ProtocolVersion_3);
- Z_SRW_extra_arg *arg;
- for ( arg = sru_pdu_req->extra_args; arg; arg = arg->next)
- if (!strcmp(arg->name, "x-target"))
- {
- std::string target(arg->value);
- mp_util::set_vhost_otherinfo(&init_req->otherInfo,
- odr_en, target, 1);
-
- }
+ if (zurl.length())
+ {
+ std::string host;
+ std::list<std::string> dblist;
+ mp_util::split_zurl(zurl, host, dblist);
+ mp_util::set_vhost_otherinfo(&init_req->otherInfo, odr_en, host, 1);
+ }
z3950_package.request() = apdu;
yaz_add_srw_diagnostic(odr_en,
&(sru_pdu_res->u.response->diagnostics),
&(sru_pdu_res->u.response->num_diagnostics),
- 2, 0);
+ YAZ_SRW_SYSTEM_TEMPORARILY_UNAVAILABLE, 0);
return false;
}
yaz_add_srw_diagnostic(odr_en,
&(sru_pdu_res->u.response->diagnostics),
&(sru_pdu_res->u.response->num_diagnostics),
- 2, 0);
+ YAZ_SRW_SYSTEM_TEMPORARILY_UNAVAILABLE, 0);
return false;
}
mp::odr &odr_en,
Z_SRW_PDU *sru_pdu_res,
Z_SRW_searchRetrieveRequest
- const *sr_req) const
+ const *sr_req,
+ std::string zurl) const
{
assert(sru_pdu_res->u.response);
Z_APDU *apdu = zget_APDU(odr_en, Z_APDU_searchRequest);
Z_SearchRequest *z_searchRequest = apdu->u.searchRequest;
- // z3950'fy database
- z_searchRequest->num_databaseNames = 1;
- z_searchRequest->databaseNames = (char**)
- odr_malloc(odr_en, sizeof(char *));
- if (sr_req->database)
- z_searchRequest->databaseNames[0]
- = odr_strdup(odr_en, const_cast<char *>(sr_req->database));
- else
- z_searchRequest->databaseNames[0]
- = odr_strdup(odr_en, "Default");
+ if (!mp_util::set_databases_from_zurl(odr_en, zurl,
+ &z_searchRequest->num_databaseNames,
+ &z_searchRequest->databaseNames))
+ {
+ z_searchRequest->num_databaseNames = 1;
+ z_searchRequest->databaseNames = (char**)
+ odr_malloc(odr_en, sizeof(char *));
+ if (sr_req->database)
+ z_searchRequest->databaseNames[0]
+ = odr_strdup(odr_en, const_cast<char *>(sr_req->database));
+ else
+ z_searchRequest->databaseNames[0]
+ = odr_strdup(odr_en, "Default");
+ }
// z3950'fy query
Z_Query *z_query = (Z_Query *) odr_malloc(odr_en, sizeof(Z_Query));
bool
yf::SRUtoZ3950::Impl::z3950_present_request(mp::Package &package,
- mp::odr &odr_en,
- Z_SRW_PDU *sru_pdu_res,
- Z_SRW_searchRetrieveRequest
- const *sr_req)
+ mp::odr &odr_en,
+ Z_SRW_PDU *sru_pdu_res,
+ Z_SRW_searchRetrieveRequest
+ const *sr_req)
const
{
assert(sru_pdu_res->u.response);
+ int start = 1;
+ int max_recs = 0;
if (!sr_req)
return false;
-
+ if (sr_req->maximumRecords)
+ max_recs = *sr_req->maximumRecords;
+ if (sr_req->startRecord)
+ start = *sr_req->startRecord;
+
// no need to work if nobody wants record ..
- if (!(sr_req->maximumRecords) || 0 == *(sr_req->maximumRecords))
+ if (max_recs == 0)
return true;
bool send_z3950_present = true;
yaz_add_srw_diagnostic(odr_en,
&(sru_pdu_res->u.response->diagnostics),
&(sru_pdu_res->u.response->num_diagnostics),
- 72, 0);
+ YAZ_SRW_XPATH_RETRIEVAL_UNSUPP, 0);
}
// resultSetTTL unsupported.
yaz_add_srw_diagnostic(odr_en,
&(sru_pdu_res->u.response->diagnostics),
&(sru_pdu_res->u.response->num_diagnostics),
- 50, 0);
+ YAZ_SRW_RESULT_SETS_UNSUPP, 0);
}
// sort unsupported
yaz_add_srw_diagnostic(odr_en,
&(sru_pdu_res->u.response->diagnostics),
&(sru_pdu_res->u.response->num_diagnostics),
- 80, 0);
+ YAZ_SRW_SORT_UNSUPP, 0);
}
// start record requested negative, or larger than number of records
- if (sr_req->startRecord
- &&
- ((*(sr_req->startRecord) < 0) // negative
- ||
- (sru_pdu_res->u.response->numberOfRecords //out of range
- && *(sr_req->startRecord)
- > *(sru_pdu_res->u.response->numberOfRecords))
- ))
+ if (start < 0 || start > *sru_pdu_res->u.response->numberOfRecords)
{
send_z3950_present = false;
yaz_add_srw_diagnostic(odr_en,
&(sru_pdu_res->u.response->diagnostics),
&(sru_pdu_res->u.response->num_diagnostics),
- 61, 0);
+ YAZ_SRW_FIRST_RECORD_POSITION_OUT_OF_RANGE, 0);
}
-
+
// maximumRecords requested negative
- if (sr_req->maximumRecords
- && *(sr_req->maximumRecords) < 0)
-
+ if (max_recs < 0)
{
send_z3950_present = false;
yaz_add_srw_diagnostic(odr_en,
&(sru_pdu_res->u.response->diagnostics),
&(sru_pdu_res->u.response->num_diagnostics),
- 6, "maximumRecords");
+ YAZ_SRW_UNSUPP_PARAMETER_VALUE,
+ "maximumRecords");
}
// exit on all these above diagnostics
assert(apdu->u.presentRequest);
// z3950'fy start record position
- if (sr_req->startRecord)
- *(apdu->u.presentRequest->resultSetStartPoint)
- = *(sr_req->startRecord);
- else
- *(apdu->u.presentRequest->resultSetStartPoint) = 1;
+ *apdu->u.presentRequest->resultSetStartPoint = start;
// z3950'fy number of records requested
// protect against requesting records out of range
- if (sr_req->maximumRecords)
- *(apdu->u.presentRequest->numberOfRecordsRequested)
- = std::min(*(sr_req->maximumRecords),
- *(sru_pdu_res->u.response->numberOfRecords)
- - *(apdu->u.presentRequest->resultSetStartPoint)
- + 1);
-
+ *apdu->u.presentRequest->numberOfRecordsRequested
+ = std::min(max_recs,
+ *sru_pdu_res->u.response->numberOfRecords - start + 1);
+
// z3950'fy recordPacking
int record_packing = Z_SRW_recordPacking_XML;
if (sr_req->recordPacking && 's' == *(sr_req->recordPacking))
record_packing = Z_SRW_recordPacking_string;
-
+
// RecordSyntax will always be XML
apdu->u.presentRequest->preferredRecordSyntax
= odr_oiddup(odr_en, yaz_oid_recsyn_xml);
// z3950'fy record schema
- if (sr_req->recordSchema)
- {
- apdu->u.presentRequest->recordComposition
- = (Z_RecordComposition *)
- odr_malloc(odr_en, sizeof(Z_RecordComposition));
- apdu->u.presentRequest->recordComposition->which
- = Z_RecordComp_simple;
- apdu->u.presentRequest->recordComposition->u.simple
- = mp_util::build_esn_from_schema(odr_en,
- (const char *) sr_req->recordSchema);
- }
+ if (sr_req->recordSchema)
+ {
+ apdu->u.presentRequest->recordComposition
+ = (Z_RecordComposition *)
+ odr_malloc(odr_en, sizeof(Z_RecordComposition));
+ apdu->u.presentRequest->recordComposition->which
+ = Z_RecordComp_simple;
+ apdu->u.presentRequest->recordComposition->u.simple
+ = mp_util::build_esn_from_schema(odr_en,
+ (const char *)
+ sr_req->recordSchema);
+ }
// z3950'fy time to live - flagged as diagnostics above
//if (sr_req->resultSetTTL)
yaz_add_srw_diagnostic(odr_en,
&(sru_pdu_res->u.response->diagnostics),
&(sru_pdu_res->u.response->num_diagnostics),
- 2, 0);
+ YAZ_SRW_SYSTEM_TEMPORARILY_UNAVAILABLE, 0);
return false;
}
// inserting all records
for (int i = 0; i < sru_res->num_records; i++)
{
+ int position = i + *apdu->u.presentRequest->resultSetStartPoint;
Z_NamePlusRecord *npr
= pr->records->u.databaseOrSurDiagnostics->records[i];
- sru_res->records[i].recordPosition
- = odr_intdup(odr_en,
- i + *(apdu->u.presentRequest->resultSetStartPoint));
-
sru_res->records[i].recordPacking = record_packing;
- if (npr->which != Z_NamePlusRecord_databaseRecord)
+ if (npr->which == Z_NamePlusRecord_databaseRecord &&
+ npr->u.databaseRecord->direct_reference
+ && !oid_oidcmp(npr->u.databaseRecord->direct_reference,
+ yaz_oid_recsyn_xml))
{
- sru_res->records[i].recordSchema = "diagnostic";
- sru_res->records[i].recordData_buf = "67";
- sru_res->records[i].recordData_len = 2;
+ // got XML record back
+ Z_External *r = npr->u.databaseRecord;
+ sru_res->records[i].recordPosition =
+ odr_intdup(odr_en, position);
+ sru_res->records[i].recordSchema = sr_req->recordSchema;
+ sru_res->records[i].recordData_buf
+ = odr_strdupn(odr_en,
+ (const char *)r->u.octet_aligned->buf,
+ r->u.octet_aligned->len);
+ sru_res->records[i].recordData_len
+ = r->u.octet_aligned->len;
}
else
{
- Z_External *r = npr->u.databaseRecord;
- if (r->direct_reference
- && !oid_oidcmp(r->direct_reference, yaz_oid_recsyn_xml))
- {
- sru_res->records[i].recordSchema = "dc";
- sru_res->records[i].recordData_buf
- = odr_strdupn(odr_en,
- (const char *)r->u.octet_aligned->buf,
- r->u.octet_aligned->len);
- sru_res->records[i].recordData_len
- = r->u.octet_aligned->len;
- }
- else
- {
- sru_res->records[i].recordSchema = "diagnostic";
- sru_res->records[i].recordData_buf = "67";
- sru_res->records[i].recordData_len = 2;
- }
- }
- }
+ // not XML or no database record at all
+ yaz_mk_sru_surrogate(
+ odr_en, sru_res->records + i, position,
+ YAZ_SRW_RECORD_NOT_AVAILABLE_IN_THIS_SCHEMA, 0);
+ }
+ }
}
return true;