1 /* This file is part of Metaproxy.
2 Copyright (C) 2005-2012 Index Data
4 Metaproxy is free software; you can redistribute it and/or modify it under
5 the terms of the GNU General Public License as published by the Free
6 Software Foundation; either version 2, or (at your option) any later
9 Metaproxy is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 #include "filter_record_transform.hpp"
21 #include <metaproxy/package.hpp>
22 #include <metaproxy/util.hpp>
23 #include "gduutil.hpp"
25 #include <yaz/diagbib1.h>
27 #include <yaz/retrieval.h>
31 namespace mp = metaproxy_1;
32 namespace yf = mp::filter;
33 namespace mp_util = metaproxy_1::util;
35 namespace metaproxy_1 {
37 class RecordTransform::Impl {
41 void process(metaproxy_1::Package & package) const;
42 void configure(const xmlNode * xml_node, const char *path);
44 yaz_retrieval_t m_retrieval;
49 // define Pimpl wrapper forwarding to Impl
51 yf::RecordTransform::RecordTransform() : m_p(new Impl)
55 yf::RecordTransform::~RecordTransform()
56 { // must have a destructor because of boost::scoped_ptr
59 void yf::RecordTransform::configure(const xmlNode *xmlnode, bool test_only,
62 m_p->configure(xmlnode, path);
65 void yf::RecordTransform::process(mp::Package &package) const
67 m_p->process(package);
71 yf::RecordTransform::Impl::Impl()
73 m_retrieval = yaz_retrieval_create();
77 yf::RecordTransform::Impl::~Impl()
80 yaz_retrieval_destroy(m_retrieval);
83 void yf::RecordTransform::Impl::configure(const xmlNode *xml_node,
86 yaz_retrieval_set_path(m_retrieval, path);
89 throw mp::XMLError("RecordTransform filter config: empty XML DOM");
91 // parsing down to retrieval node, which can be any of the children nodes
92 xmlNode *retrieval_node;
93 for (retrieval_node = xml_node->children;
95 retrieval_node = retrieval_node->next)
97 if (retrieval_node->type != XML_ELEMENT_NODE)
99 if (0 == strcmp((const char *) retrieval_node->name, "retrievalinfo"))
103 // read configuration
104 if (0 != yaz_retrieval_configure(m_retrieval, retrieval_node))
106 std::string msg("RecordTransform filter config: ");
107 msg += yaz_retrieval_get_error(m_retrieval);
108 throw mp::XMLError(msg);
112 void yf::RecordTransform::Impl::process(mp::Package &package) const
115 Z_GDU *gdu_req = package.request().get();
116 Z_PresentRequest *pr_req = 0;
117 Z_SearchRequest *sr_req = 0;
119 const char *input_schema = 0;
120 Odr_oid *input_syntax = 0;
122 if (gdu_req && gdu_req->which == Z_GDU_Z3950 &&
123 gdu_req->u.z3950->which == Z_APDU_presentRequest)
125 pr_req = gdu_req->u.z3950->u.presentRequest;
128 mp_util::record_composition_to_esn(pr_req->recordComposition);
129 input_syntax = pr_req->preferredRecordSyntax;
131 else if (gdu_req && gdu_req->which == Z_GDU_Z3950 &&
132 gdu_req->u.z3950->which == Z_APDU_searchRequest)
134 sr_req = gdu_req->u.z3950->u.searchRequest;
136 input_syntax = sr_req->preferredRecordSyntax;
138 // we don't know how many hits we're going to get and therefore
139 // the effective element set name.. Therefore we can only allow
140 // two cases.. Both equal or absent.. If not, we'll just have to
141 // disable the piggyback!
142 if (sr_req->smallSetElementSetNames
144 sr_req->mediumSetElementSetNames
146 sr_req->smallSetElementSetNames->which == Z_ElementSetNames_generic
148 sr_req->mediumSetElementSetNames->which == Z_ElementSetNames_generic
150 !strcmp(sr_req->smallSetElementSetNames->u.generic,
151 sr_req->mediumSetElementSetNames->u.generic))
153 input_schema = sr_req->smallSetElementSetNames->u.generic;
155 else if (!sr_req->smallSetElementSetNames &&
156 !sr_req->mediumSetElementSetNames)
157 ; // input_schema is 0 already
160 // disable piggyback (perhaps it was disabled already)
161 *sr_req->smallSetUpperBound = 0;
162 *sr_req->largeSetLowerBound = 0;
163 *sr_req->mediumSetPresentNumber = 0;
167 // we can handle it in record_transform.
175 mp::odr odr_en(ODR_ENCODE);
177 // setting up variables for conversion state
178 yaz_record_conv_t rc = 0;
180 const char *match_schema = 0;
181 Odr_oid *match_syntax = 0;
183 const char *backend_schema = 0;
184 Odr_oid *backend_syntax = 0;
187 = yaz_retrieval_request(m_retrieval,
188 input_schema, input_syntax,
189 &match_schema, &match_syntax,
191 &backend_schema, &backend_syntax);
196 const char *details = 0;
198 if (ret_code == -1) /* error ? */
200 details = yaz_retrieval_get_error(m_retrieval);
201 error_code = YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS;
203 else if (ret_code == 1 || ret_code == 3)
205 details = input_schema;
206 error_code = YAZ_BIB1_ELEMENT_SET_NAMES_UNSUPP;
208 else if (ret_code == 2)
210 char oidbuf[OID_STR_MAX];
211 oid_oid_to_dotstring(input_syntax, oidbuf);
212 details = odr_strdup(odr_en, oidbuf);
213 error_code = YAZ_BIB1_RECORD_SYNTAX_UNSUPP;
217 char *tmp = (char*) odr_malloc(odr_en, 80);
219 "record_transform: yaz_retrieval_get_error returned %d",
222 error_code = YAZ_BIB1_UNSPECIFIED_ERROR;
227 apdu = odr_en.create_searchResponse(
228 gdu_req->u.z3950, error_code, details);
232 apdu = odr_en.create_presentResponse(
233 gdu_req->u.z3950, error_code, details);
235 package.response() = apdu;
242 sr_req->preferredRecordSyntax = odr_oiddup(odr_en, backend_syntax);
244 sr_req->preferredRecordSyntax = 0;
248 sr_req->smallSetElementSetNames
249 = (Z_ElementSetNames *)
250 odr_malloc(odr_en, sizeof(Z_ElementSetNames));
251 sr_req->smallSetElementSetNames->which = Z_ElementSetNames_generic;
252 sr_req->smallSetElementSetNames->u.generic
253 = odr_strdup(odr_en, backend_schema);
254 sr_req->mediumSetElementSetNames = sr_req->smallSetElementSetNames;
258 sr_req->smallSetElementSetNames = 0;
259 sr_req->mediumSetElementSetNames = 0;
265 pr_req->preferredRecordSyntax = odr_oiddup(odr_en, backend_syntax);
267 pr_req->preferredRecordSyntax = 0;
271 pr_req->recordComposition
272 = (Z_RecordComposition *)
273 odr_malloc(odr_en, sizeof(Z_RecordComposition));
274 pr_req->recordComposition->which
275 = Z_RecordComp_simple;
276 pr_req->recordComposition->u.simple
277 = (Z_ElementSetNames *)
278 odr_malloc(odr_en, sizeof(Z_ElementSetNames));
279 pr_req->recordComposition->u.simple->which = Z_ElementSetNames_generic;
280 pr_req->recordComposition->u.simple->u.generic
281 = odr_strdup(odr_en, backend_schema);
284 pr_req->recordComposition = 0;
287 // attaching Z3950 package to filter chain
288 package.request() = gdu_req;
292 Z_GDU *gdu_res = package.response().get();
294 // see if we have a records list to patch!
295 Z_NamePlusRecordList *records = 0;
296 if (gdu_res && gdu_res->which == Z_GDU_Z3950 &&
297 gdu_res->u.z3950->which == Z_APDU_presentResponse)
299 Z_PresentResponse * pr_res = gdu_res->u.z3950->u.presentResponse;
302 && pr_res->numberOfRecordsReturned
303 && *(pr_res->numberOfRecordsReturned) > 0
305 && pr_res->records->which == Z_Records_DBOSD)
307 records = pr_res->records->u.databaseOrSurDiagnostics;
310 if (gdu_res && gdu_res->which == Z_GDU_Z3950 &&
311 gdu_res->u.z3950->which == Z_APDU_searchResponse)
313 Z_SearchResponse *sr_res = gdu_res->u.z3950->u.searchResponse;
316 && sr_res->numberOfRecordsReturned
317 && *(sr_res->numberOfRecordsReturned) > 0
319 && sr_res->records->which == Z_Records_DBOSD)
321 records = sr_res->records->u.databaseOrSurDiagnostics;
328 for (i = 0; i < records->num_records; i++)
330 Z_NamePlusRecord *npr = records->records[i];
331 if (npr->which == Z_NamePlusRecord_databaseRecord)
333 WRBUF output_record = wrbuf_alloc();
334 Z_External *r = npr->u.databaseRecord;
336 if (r->which == Z_External_OPAC)
339 yaz_record_conv_opac_record(rc, r->u.opac,
342 else if (r->which == Z_External_octet)
345 yaz_record_conv_record(rc, (const char *)
346 r->u.octet_aligned->buf,
347 r->u.octet_aligned->len,
352 npr->u.databaseRecord =
353 z_ext_record_oid(odr_en, match_syntax,
354 wrbuf_buf(output_record),
355 wrbuf_len(output_record));
359 records->records[i] =
360 zget_surrogateDiagRec(
361 odr_en, npr->databaseName,
362 YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS,
363 yaz_record_conv_get_error(rc));
365 wrbuf_destroy(output_record);
368 package.response() = gdu_res;
373 static mp::filter::Base* filter_creator()
375 return new mp::filter::RecordTransform;
379 struct metaproxy_1_filter_struct metaproxy_1_filter_record_transform = {
390 * c-file-style: "Stroustrup"
391 * indent-tabs-mode: nil
393 * vim: shiftwidth=4 tabstop=8 expandtab