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 // define Implementation stuff
75 yf::RecordTransform::Impl::Impl()
77 m_retrieval = yaz_retrieval_create();
81 yf::RecordTransform::Impl::~Impl()
84 yaz_retrieval_destroy(m_retrieval);
87 void yf::RecordTransform::Impl::configure(const xmlNode *xml_node,
90 yaz_retrieval_set_path(m_retrieval, path);
93 throw mp::XMLError("RecordTransform filter config: empty XML DOM");
95 // parsing down to retrieval node, which can be any of the children nodes
96 xmlNode *retrieval_node;
97 for (retrieval_node = xml_node->children;
99 retrieval_node = retrieval_node->next)
101 if (retrieval_node->type != XML_ELEMENT_NODE)
103 if (0 == strcmp((const char *) retrieval_node->name, "retrievalinfo"))
107 // read configuration
108 if (0 != yaz_retrieval_configure(m_retrieval, retrieval_node))
110 std::string msg("RecordTransform filter config: ");
111 msg += yaz_retrieval_get_error(m_retrieval);
112 throw mp::XMLError(msg);
116 void yf::RecordTransform::Impl::process(mp::Package &package) const
119 Z_GDU *gdu_req = package.request().get();
121 // only working on z3950 present packages
123 || !(gdu_req->which == Z_GDU_Z3950)
124 || !(gdu_req->u.z3950->which == Z_APDU_presentRequest))
130 // getting original present request
131 Z_PresentRequest *pr_req = gdu_req->u.z3950->u.presentRequest;
133 // setting up ODR's for memory during encoding/decoding
134 //mp::odr odr_de(ODR_DECODE);
135 mp::odr odr_en(ODR_ENCODE);
137 // setting up variables for conversion state
138 yaz_record_conv_t rc = 0;
141 const char *input_schema = 0;
142 Odr_oid *input_syntax = 0;
144 if (pr_req->recordComposition)
147 = mp_util::record_composition_to_esn(pr_req->recordComposition);
149 if (pr_req->preferredRecordSyntax)
151 input_syntax = pr_req->preferredRecordSyntax;
154 const char *match_schema = 0;
155 Odr_oid *match_syntax = 0;
157 const char *backend_schema = 0;
158 Odr_oid *backend_syntax = 0;
161 = yaz_retrieval_request(m_retrieval,
162 input_schema, input_syntax,
163 &match_schema, &match_syntax,
165 &backend_schema, &backend_syntax);
170 // need to construct present error package and send back
174 const char *details = 0;
175 if (ret_code == -1) /* error ? */
177 details = yaz_retrieval_get_error(m_retrieval);
178 apdu = odr_en.create_presentResponse(
180 YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS, details);
182 else if (ret_code == 1 || ret_code == 3)
184 details = input_schema;
185 apdu = odr_en.create_presentResponse(
187 YAZ_BIB1_ELEMENT_SET_NAMES_UNSUPP, details);
189 else if (ret_code == 2)
191 char oidbuf[OID_STR_MAX];
192 oid_oid_to_dotstring(input_syntax, oidbuf);
193 details = odr_strdup(odr_en, oidbuf);
195 apdu = odr_en.create_presentResponse(
197 YAZ_BIB1_RECORD_SYNTAX_UNSUPP, details);
199 package.response() = apdu;
203 // now re-coding the z3950 backend present request
206 pr_req->preferredRecordSyntax = odr_oiddup(odr_en, backend_syntax);
208 pr_req->preferredRecordSyntax = 0;
211 // z3950'fy record schema
214 pr_req->recordComposition
215 = (Z_RecordComposition *)
216 odr_malloc(odr_en, sizeof(Z_RecordComposition));
217 pr_req->recordComposition->which
218 = Z_RecordComp_simple;
219 pr_req->recordComposition->u.simple
220 = (Z_ElementSetNames *)
221 odr_malloc(odr_en, sizeof(Z_ElementSetNames));
222 pr_req->recordComposition->u.simple->which = Z_ElementSetNames_generic;
223 pr_req->recordComposition->u.simple->u.generic
224 = odr_strdup(odr_en, backend_schema);
227 // attaching Z3950 package to filter chain
228 package.request() = gdu_req;
232 //check successful Z3950 present response
233 Z_GDU *gdu_res = package.response().get();
234 if (!gdu_res || gdu_res->which != Z_GDU_Z3950
235 || gdu_res->u.z3950->which != Z_APDU_presentResponse
236 || !gdu_res->u.z3950->u.presentResponse)
239 package.session().close();
244 // everything fine, continuing
245 // std::cout << "z3950_present_request OK\n";
246 // std::cout << "back z3950 " << *gdu_res << "\n";
248 Z_PresentResponse * pr_res = gdu_res->u.z3950->u.presentResponse;
250 // let non surrogate dioagnostics in Z3950 present response package
251 // pass to frontend - just return
253 && pr_res->records->which == Z_Records_NSD
254 && pr_res->records->u.nonSurrogateDiagnostic)
256 // we might do more clever tricks to "reverse"
259 //*pr_res->records->u.nonSurrogateDiagnostic->condition =
260 // YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS;
263 // record transformation must take place
265 && pr_res->numberOfRecordsReturned
266 && *(pr_res->numberOfRecordsReturned) > 0
268 && pr_res->records->which == Z_Records_DBOSD
269 && pr_res->records->u.databaseOrSurDiagnostics->num_records)
271 //transform all records
273 i < pr_res->records->u.databaseOrSurDiagnostics->num_records;
276 Z_NamePlusRecord *npr
277 = pr_res->records->u.databaseOrSurDiagnostics->records[i];
278 if (npr->which == Z_NamePlusRecord_databaseRecord)
280 WRBUF output_record = wrbuf_alloc();
281 Z_External *r = npr->u.databaseRecord;
283 if (r->which == Z_External_OPAC)
285 #if YAZ_VERSIONL >= 0x030011
287 yaz_record_conv_opac_record(rc, r->u.opac,
293 else if (r->which == Z_External_octet)
296 yaz_record_conv_record(rc, (const char *)
297 r->u.octet_aligned->buf,
298 r->u.octet_aligned->len,
303 npr->u.databaseRecord =
304 z_ext_record_oid(odr_en, match_syntax,
305 wrbuf_buf(output_record),
306 wrbuf_len(output_record));
311 u.databaseOrSurDiagnostics->records[i]
312 = zget_surrogateDiagRec(
313 odr_en, npr->databaseName,
314 YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS,
315 yaz_record_conv_get_error(rc));
317 wrbuf_destroy(output_record);
321 package.response() = gdu_res;
326 static mp::filter::Base* filter_creator()
328 return new mp::filter::RecordTransform;
332 struct metaproxy_1_filter_struct metaproxy_1_filter_record_transform = {
343 * c-file-style: "Stroustrup"
344 * indent-tabs-mode: nil
346 * vim: shiftwidth=4 tabstop=8 expandtab