1 /* $Id: filter_record_transform.cpp,v 1.12 2007-05-09 21:23:09 adam Exp $
2 Copyright (c) 2005-2007, Index Data.
4 This file is part of Metaproxy.
6 Metaproxy is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 2, or (at your option) any later
11 Metaproxy is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 You should have received a copy of the GNU General Public License
17 along with Metaproxy; see the file LICENSE. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
24 #include "filter_record_transform.hpp"
25 #include "package.hpp"
27 #include "gduutil.hpp"
28 #include "xmlutil.hpp"
30 #include <yaz/diagbib1.h>
32 #include <yaz/retrieval.h>
34 //#include <boost/thread/mutex.hpp>
38 namespace mp = metaproxy_1;
39 namespace yf = mp::filter;
40 namespace mp_util = metaproxy_1::util;
42 namespace metaproxy_1 {
44 class RecordTransform::Impl {
48 void process(metaproxy_1::Package & package) const;
49 void configure(const xmlNode * xml_node);
51 yaz_retrieval_t m_retrieval;
56 // define Pimpl wrapper forwarding to Impl
58 yf::RecordTransform::RecordTransform() : m_p(new Impl)
62 yf::RecordTransform::~RecordTransform()
63 { // must have a destructor because of boost::scoped_ptr
66 void yf::RecordTransform::configure(const xmlNode *xmlnode)
68 m_p->configure(xmlnode);
71 void yf::RecordTransform::process(mp::Package &package) const
73 m_p->process(package);
77 // define Implementation stuff
81 yf::RecordTransform::Impl::Impl()
83 m_retrieval = yaz_retrieval_create();
87 yf::RecordTransform::Impl::~Impl()
90 yaz_retrieval_destroy(m_retrieval);
93 void yf::RecordTransform::Impl::configure(const xmlNode *xml_node)
95 //const char *srcdir = getenv("srcdir");
97 // yaz_retrieval_set_path(m_retrieval, srcdir);
100 throw mp::XMLError("RecordTransform filter config: empty XML DOM");
102 // parsing down to retrieval node, which can be any of the children nodes
103 xmlNode *retrieval_node;
104 for (retrieval_node = xml_node->children;
106 retrieval_node = retrieval_node->next)
108 if (retrieval_node->type != XML_ELEMENT_NODE)
110 if (0 == strcmp((const char *) retrieval_node->name, "retrievalinfo"))
114 // read configuration
115 if ( 0 != yaz_retrieval_configure(m_retrieval, retrieval_node)){
116 std::string msg("RecordTransform filter config: ");
117 msg += yaz_retrieval_get_error(m_retrieval);
118 throw mp::XMLError(msg);
122 void yf::RecordTransform::Impl::process(mp::Package &package) const
125 Z_GDU *gdu_req = package.request().get();
127 // only working on z3950 present packages
129 || !(gdu_req->which == Z_GDU_Z3950)
130 || !(gdu_req->u.z3950->which == Z_APDU_presentRequest))
136 // getting original present request
137 Z_PresentRequest *pr_req = gdu_req->u.z3950->u.presentRequest;
139 // setting up ODR's for memory during encoding/decoding
140 //mp::odr odr_de(ODR_DECODE);
141 mp::odr odr_en(ODR_ENCODE);
143 // setting up variables for conversion state
144 yaz_record_conv_t rc = 0;
147 const char *input_schema = 0;
148 Odr_oid *input_syntax = 0;
150 if(pr_req->recordComposition){
152 = mp_util::record_composition_to_esn(pr_req->recordComposition);
154 if(pr_req->preferredRecordSyntax){
155 input_syntax = pr_req->preferredRecordSyntax;
158 const char *match_schema = 0;
159 Odr_oid *match_syntax = 0;
161 const char *backend_schema = 0;
162 Odr_oid *backend_syntax = 0;
165 = yaz_retrieval_request(m_retrieval,
166 input_schema, input_syntax,
167 &match_schema, &match_syntax,
169 &backend_schema, &backend_syntax);
174 // need to construct present error package and send back
178 const char *details = 0;
179 if (ret_code == -1) /* error ? */
181 details = yaz_retrieval_get_error(m_retrieval);
182 apdu = odr_en.create_presentResponse(
184 YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS, details);
186 else if (ret_code == 1 || ret_code == 3)
188 details = input_schema;
189 apdu = odr_en.create_presentResponse(
191 YAZ_BIB1_ELEMENT_SET_NAMES_UNSUPP, details);
193 else if (ret_code == 2)
195 char oidbuf[OID_STR_MAX];
196 oid_oid_to_dotstring(input_syntax, oidbuf);
197 details = odr_strdup(odr_en, oidbuf);
199 apdu = odr_en.create_presentResponse(
201 YAZ_BIB1_RECORD_SYNTAX_UNSUPP, details);
203 package.response() = apdu;
207 // now re-coding the z3950 backend present request
210 pr_req->preferredRecordSyntax = odr_oiddup(odr_en, backend_syntax);
212 pr_req->preferredRecordSyntax = 0;
215 // z3950'fy record schema
218 pr_req->recordComposition
219 = (Z_RecordComposition *)
220 odr_malloc(odr_en, sizeof(Z_RecordComposition));
221 pr_req->recordComposition->which
222 = Z_RecordComp_simple;
223 pr_req->recordComposition->u.simple
224 = (Z_ElementSetNames *)
225 odr_malloc(odr_en, sizeof(Z_ElementSetNames));
226 pr_req->recordComposition->u.simple->which = Z_ElementSetNames_generic;
227 pr_req->recordComposition->u.simple->u.generic
228 = odr_strdup(odr_en, backend_schema);
231 // attaching Z3950 package to filter chain
232 package.request() = gdu_req;
236 //check successful Z3950 present response
237 Z_GDU *gdu_res = package.response().get();
238 if (!gdu_res || gdu_res->which != Z_GDU_Z3950
239 || gdu_res->u.z3950->which != Z_APDU_presentResponse
240 || !gdu_res->u.z3950->u.presentResponse)
243 std::cout << "record-transform: error back present\n";
244 package.session().close();
249 // everything fine, continuing
250 // std::cout << "z3950_present_request OK\n";
251 // std::cout << "back z3950 " << *gdu_res << "\n";
253 Z_PresentResponse * pr_res = gdu_res->u.z3950->u.presentResponse;
255 // let non surrogate dioagnostics in Z3950 present response package
256 // pass to frontend - just return
258 && pr_res->records->which == Z_Records_NSD
259 && pr_res->records->u.nonSurrogateDiagnostic)
261 // we might do more clever tricks to "reverse"
264 //*pr_res->records->u.nonSurrogateDiagnostic->condition =
265 // YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS;
268 // record transformation must take place
270 && pr_res->numberOfRecordsReturned
271 && *(pr_res->numberOfRecordsReturned) > 0
273 && pr_res->records->which == Z_Records_DBOSD
274 && pr_res->records->u.databaseOrSurDiagnostics->num_records)
276 //transform all records
278 i < pr_res->records->u.databaseOrSurDiagnostics->num_records;
281 Z_NamePlusRecord *npr
282 = pr_res->records->u.databaseOrSurDiagnostics->records[i];
283 if (npr->which == Z_NamePlusRecord_databaseRecord)
285 Z_External *r = npr->u.databaseRecord;
286 //oident *ent = oid_getentbyoid(r->direct_reference);
287 if (r->which == Z_External_octet)
289 WRBUF output_record = wrbuf_alloc();
291 = yaz_record_conv_record(rc,
293 r->u.octet_aligned->buf,
294 r->u.octet_aligned->len,
298 npr->u.databaseRecord =
299 z_ext_record_oid(odr_en, match_syntax,
300 wrbuf_buf(output_record),
301 wrbuf_len(output_record));
306 u.databaseOrSurDiagnostics->records[i]
307 = zget_surrogateDiagRec(
308 odr_en, npr->databaseName,
309 YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS,
310 yaz_record_conv_get_error(rc));
312 wrbuf_destroy(output_record);
317 package.response() = gdu_res;
322 static mp::filter::Base* filter_creator()
324 return new mp::filter::RecordTransform;
328 struct metaproxy_1_filter_struct metaproxy_1_filter_record_transform = {
339 * indent-tabs-mode: nil
340 * c-file-style: "stroustrup"
342 * vim: shiftwidth=4 tabstop=8 expandtab