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);
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);
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)
89 //const char *srcdir = getenv("srcdir");
91 // yaz_retrieval_set_path(m_retrieval, srcdir);
94 throw mp::XMLError("RecordTransform filter config: empty XML DOM");
96 // parsing down to retrieval node, which can be any of the children nodes
97 xmlNode *retrieval_node;
98 for (retrieval_node = xml_node->children;
100 retrieval_node = retrieval_node->next)
102 if (retrieval_node->type != XML_ELEMENT_NODE)
104 if (0 == strcmp((const char *) retrieval_node->name, "retrievalinfo"))
108 // read configuration
109 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){
146 = mp_util::record_composition_to_esn(pr_req->recordComposition);
148 if(pr_req->preferredRecordSyntax){
149 input_syntax = pr_req->preferredRecordSyntax;
152 const char *match_schema = 0;
153 Odr_oid *match_syntax = 0;
155 const char *backend_schema = 0;
156 Odr_oid *backend_syntax = 0;
159 = yaz_retrieval_request(m_retrieval,
160 input_schema, input_syntax,
161 &match_schema, &match_syntax,
163 &backend_schema, &backend_syntax);
168 // need to construct present error package and send back
172 const char *details = 0;
173 if (ret_code == -1) /* error ? */
175 details = yaz_retrieval_get_error(m_retrieval);
176 apdu = odr_en.create_presentResponse(
178 YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS, details);
180 else if (ret_code == 1 || ret_code == 3)
182 details = input_schema;
183 apdu = odr_en.create_presentResponse(
185 YAZ_BIB1_ELEMENT_SET_NAMES_UNSUPP, details);
187 else if (ret_code == 2)
189 char oidbuf[OID_STR_MAX];
190 oid_oid_to_dotstring(input_syntax, oidbuf);
191 details = odr_strdup(odr_en, oidbuf);
193 apdu = odr_en.create_presentResponse(
195 YAZ_BIB1_RECORD_SYNTAX_UNSUPP, details);
197 package.response() = apdu;
201 // now re-coding the z3950 backend present request
204 pr_req->preferredRecordSyntax = odr_oiddup(odr_en, backend_syntax);
206 pr_req->preferredRecordSyntax = 0;
209 // z3950'fy record schema
212 pr_req->recordComposition
213 = (Z_RecordComposition *)
214 odr_malloc(odr_en, sizeof(Z_RecordComposition));
215 pr_req->recordComposition->which
216 = Z_RecordComp_simple;
217 pr_req->recordComposition->u.simple
218 = (Z_ElementSetNames *)
219 odr_malloc(odr_en, sizeof(Z_ElementSetNames));
220 pr_req->recordComposition->u.simple->which = Z_ElementSetNames_generic;
221 pr_req->recordComposition->u.simple->u.generic
222 = odr_strdup(odr_en, backend_schema);
225 // attaching Z3950 package to filter chain
226 package.request() = gdu_req;
230 //check successful Z3950 present response
231 Z_GDU *gdu_res = package.response().get();
232 if (!gdu_res || gdu_res->which != Z_GDU_Z3950
233 || gdu_res->u.z3950->which != Z_APDU_presentResponse
234 || !gdu_res->u.z3950->u.presentResponse)
237 package.session().close();
242 // everything fine, continuing
243 // std::cout << "z3950_present_request OK\n";
244 // std::cout << "back z3950 " << *gdu_res << "\n";
246 Z_PresentResponse * pr_res = gdu_res->u.z3950->u.presentResponse;
248 // let non surrogate dioagnostics in Z3950 present response package
249 // pass to frontend - just return
251 && pr_res->records->which == Z_Records_NSD
252 && pr_res->records->u.nonSurrogateDiagnostic)
254 // we might do more clever tricks to "reverse"
257 //*pr_res->records->u.nonSurrogateDiagnostic->condition =
258 // YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS;
261 // record transformation must take place
263 && pr_res->numberOfRecordsReturned
264 && *(pr_res->numberOfRecordsReturned) > 0
266 && pr_res->records->which == Z_Records_DBOSD
267 && pr_res->records->u.databaseOrSurDiagnostics->num_records)
269 //transform all records
271 i < pr_res->records->u.databaseOrSurDiagnostics->num_records;
274 Z_NamePlusRecord *npr
275 = pr_res->records->u.databaseOrSurDiagnostics->records[i];
276 if (npr->which == Z_NamePlusRecord_databaseRecord)
278 WRBUF output_record = wrbuf_alloc();
279 Z_External *r = npr->u.databaseRecord;
281 if (r->which == Z_External_OPAC)
283 #if YAZ_VERSIONL >= 0x030011
285 yaz_record_conv_opac_record(rc, r->u.opac,
291 else if (r->which == Z_External_octet)
294 yaz_record_conv_record(rc, (const char *)
295 r->u.octet_aligned->buf,
296 r->u.octet_aligned->len,
301 npr->u.databaseRecord =
302 z_ext_record_oid(odr_en, match_syntax,
303 wrbuf_buf(output_record),
304 wrbuf_len(output_record));
309 u.databaseOrSurDiagnostics->records[i]
310 = zget_surrogateDiagRec(
311 odr_en, npr->databaseName,
312 YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS,
313 yaz_record_conv_get_error(rc));
315 wrbuf_destroy(output_record);
319 package.response() = gdu_res;
324 static mp::filter::Base* filter_creator()
326 return new mp::filter::RecordTransform;
330 struct metaproxy_1_filter_struct metaproxy_1_filter_record_transform = {
341 * c-file-style: "Stroustrup"
342 * indent-tabs-mode: nil
344 * vim: shiftwidth=4 tabstop=8 expandtab