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>
30 #include <usemarconlib.h>
36 namespace mp = metaproxy_1;
37 namespace yf = mp::filter;
38 namespace mp_util = metaproxy_1::util;
40 namespace metaproxy_1 {
42 class RecordTransform::Impl {
46 void process(metaproxy_1::Package & package) const;
47 void configure(const xmlNode * xml_node, const char *path);
49 yaz_retrieval_t m_retrieval;
55 struct info_usemarcon {
59 Usemarcon *usemarcon1;
60 Usemarcon *usemarcon2;
63 static int convert_usemarcon(void *info, WRBUF record, WRBUF wr_error)
65 struct info_usemarcon *p = (struct info_usemarcon *) info;
73 p->usemarcon1->SetMarcRecord(wrbuf_buf(record), wrbuf_len(record));
74 res = p->usemarcon1->Convert();
77 wrbuf_printf(wr_error, "usemarcon stage1 failed res=%d", res);
80 p->usemarcon1->GetMarcRecord(converted, convlen);
84 p->usemarcon2->SetMarcRecord(converted, convlen);
86 res = p->usemarcon2->Convert();
90 wrbuf_printf(wr_error, "usemarcon stage2 failed res=%d",
94 p->usemarcon2->GetMarcRecord(converted, convlen);
97 wrbuf_write(record, converted, convlen);
103 static void destroy_usemarcon(void *info)
105 struct info_usemarcon *p = (struct info_usemarcon *) info;
107 delete p->usemarcon1;
108 delete p->usemarcon2;
114 static void *construct_usemarcon(const xmlNode *ptr, const char *path,
117 struct _xmlAttr *attr;
118 if (strcmp((const char *) ptr->name, "usemarcon"))
121 struct info_usemarcon *p = (struct info_usemarcon *) xmalloc(sizeof(*p));
127 for (attr = ptr->properties; attr; attr = attr->next)
129 if (!xmlStrcmp(attr->name, BAD_CAST "stage1") &&
130 attr->children && attr->children->type == XML_TEXT_NODE)
131 p->stage1 = xstrdup((const char *) attr->children->content);
132 else if (!xmlStrcmp(attr->name, BAD_CAST "stage2") &&
133 attr->children && attr->children->type == XML_TEXT_NODE)
134 p->stage2 = xstrdup((const char *) attr->children->content);
137 wrbuf_printf(wr_error, "Bad attribute '%s'"
138 "Expected stage1 or stage2.", attr->name);
139 destroy_usemarcon(p);
146 p->usemarcon1 = new Usemarcon();
147 p->usemarcon1->SetIniFileName(p->stage1);
151 p->usemarcon2 = new Usemarcon();
152 p->usemarcon2->SetIniFileName(p->stage2);
157 static void type_usemarcon(struct yaz_record_conv_type *t)
160 t->construct = construct_usemarcon;
161 t->convert = convert_usemarcon;
162 t->destroy = destroy_usemarcon;
166 // define Pimpl wrapper forwarding to Impl
168 yf::RecordTransform::RecordTransform() : m_p(new Impl)
172 yf::RecordTransform::~RecordTransform()
173 { // must have a destructor because of boost::scoped_ptr
176 void yf::RecordTransform::configure(const xmlNode *xmlnode, bool test_only,
179 m_p->configure(xmlnode, path);
182 void yf::RecordTransform::process(mp::Package &package) const
184 m_p->process(package);
188 yf::RecordTransform::Impl::Impl()
190 m_retrieval = yaz_retrieval_create();
194 yf::RecordTransform::Impl::~Impl()
197 yaz_retrieval_destroy(m_retrieval);
200 void yf::RecordTransform::Impl::configure(const xmlNode *xml_node,
203 yaz_retrieval_set_path(m_retrieval, path);
206 throw mp::XMLError("RecordTransform filter config: empty XML DOM");
208 // parsing down to retrieval node, which can be any of the children nodes
209 xmlNode *retrieval_node;
210 for (retrieval_node = xml_node->children;
212 retrieval_node = retrieval_node->next)
214 if (retrieval_node->type != XML_ELEMENT_NODE)
216 if (0 == strcmp((const char *) retrieval_node->name, "retrievalinfo"))
221 struct yaz_record_conv_type mt;
223 struct yaz_record_conv_type *t = &mt;
225 struct yaz_record_conv_type *t = 0;
228 // read configuration
229 if (0 != yaz_retrieval_configure_t(m_retrieval, retrieval_node, t))
231 std::string msg("RecordTransform filter config: ");
232 msg += yaz_retrieval_get_error(m_retrieval);
233 throw mp::XMLError(msg);
237 void yf::RecordTransform::Impl::process(mp::Package &package) const
240 Z_GDU *gdu_req = package.request().get();
241 Z_PresentRequest *pr_req = 0;
242 Z_SearchRequest *sr_req = 0;
244 const char *input_schema = 0;
245 Odr_oid *input_syntax = 0;
247 if (gdu_req && gdu_req->which == Z_GDU_Z3950 &&
248 gdu_req->u.z3950->which == Z_APDU_presentRequest)
250 pr_req = gdu_req->u.z3950->u.presentRequest;
253 mp_util::record_composition_to_esn(pr_req->recordComposition);
254 input_syntax = pr_req->preferredRecordSyntax;
256 else if (gdu_req && gdu_req->which == Z_GDU_Z3950 &&
257 gdu_req->u.z3950->which == Z_APDU_searchRequest)
259 sr_req = gdu_req->u.z3950->u.searchRequest;
261 input_syntax = sr_req->preferredRecordSyntax;
263 // we don't know how many hits we're going to get and therefore
264 // the effective element set name.. Therefore we can only allow
265 // two cases.. Both equal or absent.. If not, we'll just have to
266 // disable the piggyback!
267 if (sr_req->smallSetElementSetNames
269 sr_req->mediumSetElementSetNames
271 sr_req->smallSetElementSetNames->which == Z_ElementSetNames_generic
273 sr_req->mediumSetElementSetNames->which == Z_ElementSetNames_generic
275 !strcmp(sr_req->smallSetElementSetNames->u.generic,
276 sr_req->mediumSetElementSetNames->u.generic))
278 input_schema = sr_req->smallSetElementSetNames->u.generic;
280 else if (!sr_req->smallSetElementSetNames &&
281 !sr_req->mediumSetElementSetNames)
282 ; // input_schema is 0 already
285 // disable piggyback (perhaps it was disabled already)
286 *sr_req->smallSetUpperBound = 0;
287 *sr_req->largeSetLowerBound = 0;
288 *sr_req->mediumSetPresentNumber = 0;
292 // we can handle it in record_transform.
300 mp::odr odr_en(ODR_ENCODE);
302 // setting up variables for conversion state
303 yaz_record_conv_t rc = 0;
305 const char *match_schema = 0;
306 Odr_oid *match_syntax = 0;
308 const char *backend_schema = 0;
309 Odr_oid *backend_syntax = 0;
312 = yaz_retrieval_request(m_retrieval,
313 input_schema, input_syntax,
314 &match_schema, &match_syntax,
316 &backend_schema, &backend_syntax);
321 const char *details = 0;
323 if (ret_code == -1) /* error ? */
325 details = yaz_retrieval_get_error(m_retrieval);
326 error_code = YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS;
328 else if (ret_code == 1 || ret_code == 3)
330 details = input_schema;
331 error_code = YAZ_BIB1_ELEMENT_SET_NAMES_UNSUPP;
333 else if (ret_code == 2)
335 char oidbuf[OID_STR_MAX];
336 oid_oid_to_dotstring(input_syntax, oidbuf);
337 details = odr_strdup(odr_en, oidbuf);
338 error_code = YAZ_BIB1_RECORD_SYNTAX_UNSUPP;
342 char *tmp = (char*) odr_malloc(odr_en, 80);
344 "record_transform: yaz_retrieval_get_error returned %d",
347 error_code = YAZ_BIB1_UNSPECIFIED_ERROR;
352 apdu = odr_en.create_searchResponse(
353 gdu_req->u.z3950, error_code, details);
357 apdu = odr_en.create_presentResponse(
358 gdu_req->u.z3950, error_code, details);
360 package.response() = apdu;
367 sr_req->preferredRecordSyntax = odr_oiddup(odr_en, backend_syntax);
369 sr_req->preferredRecordSyntax = 0;
373 sr_req->smallSetElementSetNames
374 = (Z_ElementSetNames *)
375 odr_malloc(odr_en, sizeof(Z_ElementSetNames));
376 sr_req->smallSetElementSetNames->which = Z_ElementSetNames_generic;
377 sr_req->smallSetElementSetNames->u.generic
378 = odr_strdup(odr_en, backend_schema);
379 sr_req->mediumSetElementSetNames = sr_req->smallSetElementSetNames;
383 sr_req->smallSetElementSetNames = 0;
384 sr_req->mediumSetElementSetNames = 0;
390 pr_req->preferredRecordSyntax = odr_oiddup(odr_en, backend_syntax);
392 pr_req->preferredRecordSyntax = 0;
396 pr_req->recordComposition
397 = (Z_RecordComposition *)
398 odr_malloc(odr_en, sizeof(Z_RecordComposition));
399 pr_req->recordComposition->which
400 = Z_RecordComp_simple;
401 pr_req->recordComposition->u.simple
402 = (Z_ElementSetNames *)
403 odr_malloc(odr_en, sizeof(Z_ElementSetNames));
404 pr_req->recordComposition->u.simple->which = Z_ElementSetNames_generic;
405 pr_req->recordComposition->u.simple->u.generic
406 = odr_strdup(odr_en, backend_schema);
409 pr_req->recordComposition = 0;
412 // attaching Z3950 package to filter chain
413 package.request() = gdu_req;
417 Z_GDU *gdu_res = package.response().get();
419 // see if we have a records list to patch!
420 Z_NamePlusRecordList *records = 0;
421 if (gdu_res && gdu_res->which == Z_GDU_Z3950 &&
422 gdu_res->u.z3950->which == Z_APDU_presentResponse)
424 Z_PresentResponse * pr_res = gdu_res->u.z3950->u.presentResponse;
427 && pr_res->numberOfRecordsReturned
428 && *(pr_res->numberOfRecordsReturned) > 0
430 && pr_res->records->which == Z_Records_DBOSD)
432 records = pr_res->records->u.databaseOrSurDiagnostics;
435 if (gdu_res && gdu_res->which == Z_GDU_Z3950 &&
436 gdu_res->u.z3950->which == Z_APDU_searchResponse)
438 Z_SearchResponse *sr_res = gdu_res->u.z3950->u.searchResponse;
441 && sr_res->numberOfRecordsReturned
442 && *(sr_res->numberOfRecordsReturned) > 0
444 && sr_res->records->which == Z_Records_DBOSD)
446 records = sr_res->records->u.databaseOrSurDiagnostics;
453 for (i = 0; i < records->num_records; i++)
455 Z_NamePlusRecord *npr = records->records[i];
456 if (npr->which == Z_NamePlusRecord_databaseRecord)
458 WRBUF output_record = wrbuf_alloc();
459 Z_External *r = npr->u.databaseRecord;
461 if (r->which == Z_External_OPAC)
464 yaz_record_conv_opac_record(rc, r->u.opac,
467 else if (r->which == Z_External_octet)
470 yaz_record_conv_record(rc, (const char *)
471 r->u.octet_aligned->buf,
472 r->u.octet_aligned->len,
477 npr->u.databaseRecord =
478 z_ext_record_oid(odr_en, match_syntax,
479 wrbuf_buf(output_record),
480 wrbuf_len(output_record));
484 records->records[i] =
485 zget_surrogateDiagRec(
486 odr_en, npr->databaseName,
487 YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS,
488 yaz_record_conv_get_error(rc));
490 wrbuf_destroy(output_record);
493 package.response() = gdu_res;
498 static mp::filter::Base* filter_creator()
500 return new mp::filter::RecordTransform;
504 struct metaproxy_1_filter_struct metaproxy_1_filter_record_transform = {
515 * c-file-style: "Stroustrup"
516 * indent-tabs-mode: nil
518 * vim: shiftwidth=4 tabstop=8 expandtab