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;
140 const char *input_schema = 0;
141 Odr_oid *input_syntax = 0;
143 if (pr_req->recordComposition)
146 = mp_util::record_composition_to_esn(pr_req->recordComposition);
148 if (pr_req->preferredRecordSyntax)
150 input_syntax = pr_req->preferredRecordSyntax;
153 const char *match_schema = 0;
154 Odr_oid *match_syntax = 0;
156 const char *backend_schema = 0;
157 Odr_oid *backend_syntax = 0;
160 = yaz_retrieval_request(m_retrieval,
161 input_schema, input_syntax,
162 &match_schema, &match_syntax,
164 &backend_schema, &backend_syntax);
169 // need to construct present error package and send back
173 const char *details = 0;
174 if (ret_code == -1) /* error ? */
176 details = yaz_retrieval_get_error(m_retrieval);
177 apdu = odr_en.create_presentResponse(
179 YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS, details);
181 else if (ret_code == 1 || ret_code == 3)
183 details = input_schema;
184 apdu = odr_en.create_presentResponse(
186 YAZ_BIB1_ELEMENT_SET_NAMES_UNSUPP, details);
188 else if (ret_code == 2)
190 char oidbuf[OID_STR_MAX];
191 oid_oid_to_dotstring(input_syntax, oidbuf);
192 details = odr_strdup(odr_en, oidbuf);
194 apdu = odr_en.create_presentResponse(
196 YAZ_BIB1_RECORD_SYNTAX_UNSUPP, details);
198 package.response() = apdu;
202 // now re-coding the z3950 backend present request
204 pr_req->preferredRecordSyntax = odr_oiddup(odr_en, backend_syntax);
206 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();
240 Z_PresentResponse * pr_res = gdu_res->u.z3950->u.presentResponse;
242 // record transformation must take place
244 && pr_res->numberOfRecordsReturned
245 && *(pr_res->numberOfRecordsReturned) > 0
247 && pr_res->records->which == Z_Records_DBOSD
248 && pr_res->records->u.databaseOrSurDiagnostics->num_records)
250 // transform all records
252 i < pr_res->records->u.databaseOrSurDiagnostics->num_records;
255 Z_NamePlusRecord *npr
256 = pr_res->records->u.databaseOrSurDiagnostics->records[i];
257 if (npr->which == Z_NamePlusRecord_databaseRecord)
259 WRBUF output_record = wrbuf_alloc();
260 Z_External *r = npr->u.databaseRecord;
262 if (r->which == Z_External_OPAC)
265 yaz_record_conv_opac_record(rc, r->u.opac,
268 else if (r->which == Z_External_octet)
271 yaz_record_conv_record(rc, (const char *)
272 r->u.octet_aligned->buf,
273 r->u.octet_aligned->len,
278 npr->u.databaseRecord =
279 z_ext_record_oid(odr_en, match_syntax,
280 wrbuf_buf(output_record),
281 wrbuf_len(output_record));
286 u.databaseOrSurDiagnostics->records[i]
287 = zget_surrogateDiagRec(
288 odr_en, npr->databaseName,
289 YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS,
290 yaz_record_conv_get_error(rc));
292 wrbuf_destroy(output_record);
296 package.response() = gdu_res;
301 static mp::filter::Base* filter_creator()
303 return new mp::filter::RecordTransform;
307 struct metaproxy_1_filter_struct metaproxy_1_filter_record_transform = {
318 * c-file-style: "Stroustrup"
319 * indent-tabs-mode: nil
321 * vim: shiftwidth=4 tabstop=8 expandtab