1 /* This file is part of Metaproxy.
2 Copyright (C) 2005-2008 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
21 #include "filter_record_transform.hpp"
22 #include "package.hpp"
24 #include "gduutil.hpp"
25 #include "xmlutil.hpp"
27 #include <yaz/diagbib1.h>
29 #include <yaz/retrieval.h>
31 //#include <boost/thread/mutex.hpp>
35 namespace mp = metaproxy_1;
36 namespace yf = mp::filter;
37 namespace mp_util = metaproxy_1::util;
39 namespace metaproxy_1 {
41 class RecordTransform::Impl {
45 void process(metaproxy_1::Package & package) const;
46 void configure(const xmlNode * xml_node);
48 yaz_retrieval_t m_retrieval;
53 // define Pimpl wrapper forwarding to Impl
55 yf::RecordTransform::RecordTransform() : m_p(new Impl)
59 yf::RecordTransform::~RecordTransform()
60 { // must have a destructor because of boost::scoped_ptr
63 void yf::RecordTransform::configure(const xmlNode *xmlnode, bool test_only)
65 m_p->configure(xmlnode);
68 void yf::RecordTransform::process(mp::Package &package) const
70 m_p->process(package);
74 // define Implementation stuff
78 yf::RecordTransform::Impl::Impl()
80 m_retrieval = yaz_retrieval_create();
84 yf::RecordTransform::Impl::~Impl()
87 yaz_retrieval_destroy(m_retrieval);
90 void yf::RecordTransform::Impl::configure(const xmlNode *xml_node)
92 //const char *srcdir = getenv("srcdir");
94 // yaz_retrieval_set_path(m_retrieval, srcdir);
97 throw mp::XMLError("RecordTransform filter config: empty XML DOM");
99 // parsing down to retrieval node, which can be any of the children nodes
100 xmlNode *retrieval_node;
101 for (retrieval_node = xml_node->children;
103 retrieval_node = retrieval_node->next)
105 if (retrieval_node->type != XML_ELEMENT_NODE)
107 if (0 == strcmp((const char *) retrieval_node->name, "retrievalinfo"))
111 // read configuration
112 if ( 0 != yaz_retrieval_configure(m_retrieval, retrieval_node)){
113 std::string msg("RecordTransform filter config: ");
114 msg += yaz_retrieval_get_error(m_retrieval);
115 throw mp::XMLError(msg);
119 void yf::RecordTransform::Impl::process(mp::Package &package) const
122 Z_GDU *gdu_req = package.request().get();
124 // only working on z3950 present packages
126 || !(gdu_req->which == Z_GDU_Z3950)
127 || !(gdu_req->u.z3950->which == Z_APDU_presentRequest))
133 // getting original present request
134 Z_PresentRequest *pr_req = gdu_req->u.z3950->u.presentRequest;
136 // setting up ODR's for memory during encoding/decoding
137 //mp::odr odr_de(ODR_DECODE);
138 mp::odr odr_en(ODR_ENCODE);
140 // setting up variables for conversion state
141 yaz_record_conv_t rc = 0;
144 const char *input_schema = 0;
145 Odr_oid *input_syntax = 0;
147 if(pr_req->recordComposition){
149 = mp_util::record_composition_to_esn(pr_req->recordComposition);
151 if(pr_req->preferredRecordSyntax){
152 input_syntax = pr_req->preferredRecordSyntax;
155 const char *match_schema = 0;
156 Odr_oid *match_syntax = 0;
158 const char *backend_schema = 0;
159 Odr_oid *backend_syntax = 0;
162 = yaz_retrieval_request(m_retrieval,
163 input_schema, input_syntax,
164 &match_schema, &match_syntax,
166 &backend_schema, &backend_syntax);
171 // need to construct present error package and send back
175 const char *details = 0;
176 if (ret_code == -1) /* error ? */
178 details = yaz_retrieval_get_error(m_retrieval);
179 apdu = odr_en.create_presentResponse(
181 YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS, details);
183 else if (ret_code == 1 || ret_code == 3)
185 details = input_schema;
186 apdu = odr_en.create_presentResponse(
188 YAZ_BIB1_ELEMENT_SET_NAMES_UNSUPP, details);
190 else if (ret_code == 2)
192 char oidbuf[OID_STR_MAX];
193 oid_oid_to_dotstring(input_syntax, oidbuf);
194 details = odr_strdup(odr_en, oidbuf);
196 apdu = odr_en.create_presentResponse(
198 YAZ_BIB1_RECORD_SYNTAX_UNSUPP, details);
200 package.response() = apdu;
204 // now re-coding the z3950 backend present request
207 pr_req->preferredRecordSyntax = odr_oiddup(odr_en, backend_syntax);
209 pr_req->preferredRecordSyntax = 0;
212 // z3950'fy record schema
215 pr_req->recordComposition
216 = (Z_RecordComposition *)
217 odr_malloc(odr_en, sizeof(Z_RecordComposition));
218 pr_req->recordComposition->which
219 = Z_RecordComp_simple;
220 pr_req->recordComposition->u.simple
221 = (Z_ElementSetNames *)
222 odr_malloc(odr_en, sizeof(Z_ElementSetNames));
223 pr_req->recordComposition->u.simple->which = Z_ElementSetNames_generic;
224 pr_req->recordComposition->u.simple->u.generic
225 = odr_strdup(odr_en, backend_schema);
228 // attaching Z3950 package to filter chain
229 package.request() = gdu_req;
233 //check successful Z3950 present response
234 Z_GDU *gdu_res = package.response().get();
235 if (!gdu_res || gdu_res->which != Z_GDU_Z3950
236 || gdu_res->u.z3950->which != Z_APDU_presentResponse
237 || !gdu_res->u.z3950->u.presentResponse)
240 std::cout << "record-transform: error back present\n";
241 package.session().close();
246 // everything fine, continuing
247 // std::cout << "z3950_present_request OK\n";
248 // std::cout << "back z3950 " << *gdu_res << "\n";
250 Z_PresentResponse * pr_res = gdu_res->u.z3950->u.presentResponse;
252 // let non surrogate dioagnostics in Z3950 present response package
253 // pass to frontend - just return
255 && pr_res->records->which == Z_Records_NSD
256 && pr_res->records->u.nonSurrogateDiagnostic)
258 // we might do more clever tricks to "reverse"
261 //*pr_res->records->u.nonSurrogateDiagnostic->condition =
262 // YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS;
265 // record transformation must take place
267 && pr_res->numberOfRecordsReturned
268 && *(pr_res->numberOfRecordsReturned) > 0
270 && pr_res->records->which == Z_Records_DBOSD
271 && pr_res->records->u.databaseOrSurDiagnostics->num_records)
273 //transform all records
275 i < pr_res->records->u.databaseOrSurDiagnostics->num_records;
278 Z_NamePlusRecord *npr
279 = pr_res->records->u.databaseOrSurDiagnostics->records[i];
280 if (npr->which == Z_NamePlusRecord_databaseRecord)
282 WRBUF output_record = wrbuf_alloc();
283 Z_External *r = npr->u.databaseRecord;
285 if (r->which == Z_External_OPAC)
287 #if YAZ_VERSIONL >= 0x030011
289 yaz_record_conv_opac_record(rc, r->u.opac,
295 else if (r->which == Z_External_octet)
298 yaz_record_conv_record(rc, (const char *)
299 r->u.octet_aligned->buf,
300 r->u.octet_aligned->len,
305 npr->u.databaseRecord =
306 z_ext_record_oid(odr_en, match_syntax,
307 wrbuf_buf(output_record),
308 wrbuf_len(output_record));
313 u.databaseOrSurDiagnostics->records[i]
314 = zget_surrogateDiagRec(
315 odr_en, npr->databaseName,
316 YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS,
317 yaz_record_conv_get_error(rc));
319 wrbuf_destroy(output_record);
323 package.response() = gdu_res;
328 static mp::filter::Base* filter_creator()
330 return new mp::filter::RecordTransform;
334 struct metaproxy_1_filter_struct metaproxy_1_filter_record_transform = {
345 * indent-tabs-mode: nil
346 * c-file-style: "stroustrup"
348 * vim: shiftwidth=4 tabstop=8 expandtab