1 /* This file is part of Metaproxy.
2 Copyright (C) 2005-2011 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)){
109 std::string msg("RecordTransform filter config: ");
110 msg += yaz_retrieval_get_error(m_retrieval);
111 throw mp::XMLError(msg);
115 void yf::RecordTransform::Impl::process(mp::Package &package) const
118 Z_GDU *gdu_req = package.request().get();
120 // only working on z3950 present packages
122 || !(gdu_req->which == Z_GDU_Z3950)
123 || !(gdu_req->u.z3950->which == Z_APDU_presentRequest))
129 // getting original present request
130 Z_PresentRequest *pr_req = gdu_req->u.z3950->u.presentRequest;
132 // setting up ODR's for memory during encoding/decoding
133 //mp::odr odr_de(ODR_DECODE);
134 mp::odr odr_en(ODR_ENCODE);
136 // setting up variables for conversion state
137 yaz_record_conv_t rc = 0;
140 const char *input_schema = 0;
141 Odr_oid *input_syntax = 0;
143 if(pr_req->recordComposition){
145 = mp_util::record_composition_to_esn(pr_req->recordComposition);
147 if(pr_req->preferredRecordSyntax){
148 input_syntax = pr_req->preferredRecordSyntax;
151 const char *match_schema = 0;
152 Odr_oid *match_syntax = 0;
154 const char *backend_schema = 0;
155 Odr_oid *backend_syntax = 0;
158 = yaz_retrieval_request(m_retrieval,
159 input_schema, input_syntax,
160 &match_schema, &match_syntax,
162 &backend_schema, &backend_syntax);
167 // need to construct present error package and send back
171 const char *details = 0;
172 if (ret_code == -1) /* error ? */
174 details = yaz_retrieval_get_error(m_retrieval);
175 apdu = odr_en.create_presentResponse(
177 YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS, details);
179 else if (ret_code == 1 || ret_code == 3)
181 details = input_schema;
182 apdu = odr_en.create_presentResponse(
184 YAZ_BIB1_ELEMENT_SET_NAMES_UNSUPP, details);
186 else if (ret_code == 2)
188 char oidbuf[OID_STR_MAX];
189 oid_oid_to_dotstring(input_syntax, oidbuf);
190 details = odr_strdup(odr_en, oidbuf);
192 apdu = odr_en.create_presentResponse(
194 YAZ_BIB1_RECORD_SYNTAX_UNSUPP, details);
196 package.response() = apdu;
200 // now re-coding the z3950 backend present request
203 pr_req->preferredRecordSyntax = odr_oiddup(odr_en, backend_syntax);
205 pr_req->preferredRecordSyntax = 0;
208 // z3950'fy record schema
211 pr_req->recordComposition
212 = (Z_RecordComposition *)
213 odr_malloc(odr_en, sizeof(Z_RecordComposition));
214 pr_req->recordComposition->which
215 = Z_RecordComp_simple;
216 pr_req->recordComposition->u.simple
217 = (Z_ElementSetNames *)
218 odr_malloc(odr_en, sizeof(Z_ElementSetNames));
219 pr_req->recordComposition->u.simple->which = Z_ElementSetNames_generic;
220 pr_req->recordComposition->u.simple->u.generic
221 = odr_strdup(odr_en, backend_schema);
224 // attaching Z3950 package to filter chain
225 package.request() = gdu_req;
229 //check successful Z3950 present response
230 Z_GDU *gdu_res = package.response().get();
231 if (!gdu_res || gdu_res->which != Z_GDU_Z3950
232 || gdu_res->u.z3950->which != Z_APDU_presentResponse
233 || !gdu_res->u.z3950->u.presentResponse)
236 package.session().close();
241 // everything fine, continuing
242 // std::cout << "z3950_present_request OK\n";
243 // std::cout << "back z3950 " << *gdu_res << "\n";
245 Z_PresentResponse * pr_res = gdu_res->u.z3950->u.presentResponse;
247 // let non surrogate dioagnostics in Z3950 present response package
248 // pass to frontend - just return
250 && pr_res->records->which == Z_Records_NSD
251 && pr_res->records->u.nonSurrogateDiagnostic)
253 // we might do more clever tricks to "reverse"
256 //*pr_res->records->u.nonSurrogateDiagnostic->condition =
257 // YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS;
260 // record transformation must take place
262 && pr_res->numberOfRecordsReturned
263 && *(pr_res->numberOfRecordsReturned) > 0
265 && pr_res->records->which == Z_Records_DBOSD
266 && pr_res->records->u.databaseOrSurDiagnostics->num_records)
268 //transform all records
270 i < pr_res->records->u.databaseOrSurDiagnostics->num_records;
273 Z_NamePlusRecord *npr
274 = pr_res->records->u.databaseOrSurDiagnostics->records[i];
275 if (npr->which == Z_NamePlusRecord_databaseRecord)
277 WRBUF output_record = wrbuf_alloc();
278 Z_External *r = npr->u.databaseRecord;
280 if (r->which == Z_External_OPAC)
282 #if YAZ_VERSIONL >= 0x030011
284 yaz_record_conv_opac_record(rc, r->u.opac,
290 else if (r->which == Z_External_octet)
293 yaz_record_conv_record(rc, (const char *)
294 r->u.octet_aligned->buf,
295 r->u.octet_aligned->len,
300 npr->u.databaseRecord =
301 z_ext_record_oid(odr_en, match_syntax,
302 wrbuf_buf(output_record),
303 wrbuf_len(output_record));
308 u.databaseOrSurDiagnostics->records[i]
309 = zget_surrogateDiagRec(
310 odr_en, npr->databaseName,
311 YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS,
312 yaz_record_conv_get_error(rc));
314 wrbuf_destroy(output_record);
318 package.response() = gdu_res;
323 static mp::filter::Base* filter_creator()
325 return new mp::filter::RecordTransform;
329 struct metaproxy_1_filter_struct metaproxy_1_filter_record_transform = {
340 * c-file-style: "Stroustrup"
341 * indent-tabs-mode: nil
343 * vim: shiftwidth=4 tabstop=8 expandtab