record_transform: remove some dead code
[metaproxy-moved-to-github.git] / src / filter_record_transform.cpp
1 /* This file is part of Metaproxy.
2    Copyright (C) 2005-2012 Index Data
3
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
7 version.
8
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
12 for more details.
13
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
17 */
18
19 #include "config.hpp"
20 #include "filter_record_transform.hpp"
21 #include <metaproxy/package.hpp>
22 #include <metaproxy/util.hpp>
23 #include "gduutil.hpp"
24
25 #include <yaz/diagbib1.h>
26 #include <yaz/zgdu.h>
27 #include <yaz/retrieval.h>
28
29 #include <iostream>
30
31 namespace mp = metaproxy_1;
32 namespace yf = mp::filter;
33 namespace mp_util = metaproxy_1::util;
34
35 namespace metaproxy_1 {
36     namespace filter {
37         class RecordTransform::Impl {
38         public:
39             Impl();
40             ~Impl();
41             void process(metaproxy_1::Package & package) const;
42             void configure(const xmlNode * xml_node, const char *path);
43         private:
44             yaz_retrieval_t m_retrieval;
45         };
46     }
47 }
48
49 // define Pimpl wrapper forwarding to Impl
50  
51 yf::RecordTransform::RecordTransform() : m_p(new Impl)
52 {
53 }
54
55 yf::RecordTransform::~RecordTransform()
56 {  // must have a destructor because of boost::scoped_ptr
57 }
58
59 void yf::RecordTransform::configure(const xmlNode *xmlnode, bool test_only,
60                                     const char *path)
61 {
62     m_p->configure(xmlnode, path);
63 }
64
65 void yf::RecordTransform::process(mp::Package &package) const
66 {
67     m_p->process(package);
68 }
69
70
71 // define Implementation stuff
72
73
74
75 yf::RecordTransform::Impl::Impl() 
76 {
77     m_retrieval = yaz_retrieval_create();
78     assert(m_retrieval);
79 }
80
81 yf::RecordTransform::Impl::~Impl()
82
83     if (m_retrieval)
84         yaz_retrieval_destroy(m_retrieval);
85 }
86
87 void yf::RecordTransform::Impl::configure(const xmlNode *xml_node,
88                                           const char *path)
89 {
90     yaz_retrieval_set_path(m_retrieval, path);
91
92     if (!xml_node)
93         throw mp::XMLError("RecordTransform filter config: empty XML DOM");
94
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; 
98          retrieval_node; 
99          retrieval_node = retrieval_node->next)
100     {
101         if (retrieval_node->type != XML_ELEMENT_NODE)
102             continue;
103         if (0 == strcmp((const char *) retrieval_node->name, "retrievalinfo"))
104             break;
105     }
106
107     // read configuration
108     if (0 != yaz_retrieval_configure(m_retrieval, retrieval_node))
109     {
110         std::string msg("RecordTransform filter config: ");
111         msg += yaz_retrieval_get_error(m_retrieval);
112         throw mp::XMLError(msg);
113     }
114 }
115
116 void yf::RecordTransform::Impl::process(mp::Package &package) const
117 {
118
119     Z_GDU *gdu_req = package.request().get();
120     
121     // only working on z3950 present packages
122     if (!gdu_req 
123         || !(gdu_req->which == Z_GDU_Z3950) 
124         || !(gdu_req->u.z3950->which == Z_APDU_presentRequest))
125     {
126         package.move();
127         return;
128     }
129     
130     // getting original present request
131     Z_PresentRequest *pr_req = gdu_req->u.z3950->u.presentRequest;
132
133     // setting up ODR's for memory during encoding/decoding
134     //mp::odr odr_de(ODR_DECODE);  
135     mp::odr odr_en(ODR_ENCODE);
136
137     // setting up variables for conversion state
138     yaz_record_conv_t rc = 0;
139
140     const char *input_schema = 0;
141     Odr_oid *input_syntax = 0;
142
143     if (pr_req->recordComposition)
144     {
145         input_schema 
146             = mp_util::record_composition_to_esn(pr_req->recordComposition);
147     }
148     if (pr_req->preferredRecordSyntax)
149     {
150         input_syntax = pr_req->preferredRecordSyntax;
151     }
152     
153     const char *match_schema = 0;
154     Odr_oid *match_syntax = 0;
155
156     const char *backend_schema = 0;
157     Odr_oid *backend_syntax = 0;
158
159     int ret_code 
160         = yaz_retrieval_request(m_retrieval,
161                                 input_schema, input_syntax,
162                                 &match_schema, &match_syntax,
163                                 &rc,
164                                 &backend_schema, &backend_syntax);
165
166     // error handling
167     if (ret_code != 0)
168     {
169         // need to construct present error package and send back
170
171         Z_APDU *apdu = 0;
172
173         const char *details = 0;
174         if (ret_code == -1) /* error ? */
175         {
176            details = yaz_retrieval_get_error(m_retrieval);
177            apdu = odr_en.create_presentResponse(
178                gdu_req->u.z3950,
179                YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS, details);
180         }
181         else if (ret_code == 1 || ret_code == 3)
182         {
183             details = input_schema;
184             apdu = odr_en.create_presentResponse(
185                 gdu_req->u.z3950,
186                 YAZ_BIB1_ELEMENT_SET_NAMES_UNSUPP, details);
187         }
188         else if (ret_code == 2)
189         {
190             char oidbuf[OID_STR_MAX];
191             oid_oid_to_dotstring(input_syntax, oidbuf);
192             details = odr_strdup(odr_en, oidbuf);
193             
194             apdu = odr_en.create_presentResponse(
195                 gdu_req->u.z3950,
196                 YAZ_BIB1_RECORD_SYNTAX_UNSUPP, details);
197         }
198         package.response() = apdu;
199         return;
200     }
201
202     // now re-coding the z3950 backend present request
203     if (backend_syntax) 
204         pr_req->preferredRecordSyntax = odr_oiddup(odr_en, backend_syntax);
205     else
206         pr_req->preferredRecordSyntax = 0;
207     
208     // z3950'fy record schema
209     if (backend_schema)
210     {
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);
222     }
223
224     // attaching Z3950 package to filter chain
225     package.request() = gdu_req;
226
227     package.move();
228
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)
234
235     {
236         package.session().close();
237         return;
238     }
239     
240     Z_PresentResponse * pr_res = gdu_res->u.z3950->u.presentResponse;
241
242     // record transformation must take place 
243     if (rc && pr_res 
244         && pr_res->numberOfRecordsReturned 
245         && *(pr_res->numberOfRecordsReturned) > 0
246         && pr_res->records
247         && pr_res->records->which == Z_Records_DBOSD
248         && pr_res->records->u.databaseOrSurDiagnostics->num_records)
249     {
250          // transform all records
251          for (int i = 0; 
252               i < pr_res->records->u.databaseOrSurDiagnostics->num_records; 
253               i++)
254          {
255              Z_NamePlusRecord *npr 
256                  = pr_res->records->u.databaseOrSurDiagnostics->records[i];
257              if (npr->which == Z_NamePlusRecord_databaseRecord)
258              {
259                  WRBUF output_record = wrbuf_alloc();
260                  Z_External *r = npr->u.databaseRecord;
261                  int ret_trans = 0;
262                  if (r->which == Z_External_OPAC)
263                  {
264                      ret_trans = 
265                          yaz_record_conv_opac_record(rc, r->u.opac,
266                                                      output_record);
267                  }
268                  else if (r->which == Z_External_octet) 
269                  {
270                      ret_trans =
271                          yaz_record_conv_record(rc, (const char *)
272                                                 r->u.octet_aligned->buf, 
273                                                 r->u.octet_aligned->len,
274                                                 output_record);
275                  }
276                  if (ret_trans == 0)
277                  {
278                      npr->u.databaseRecord =
279                          z_ext_record_oid(odr_en, match_syntax,
280                                           wrbuf_buf(output_record),
281                                           wrbuf_len(output_record));
282                  }
283                  else
284                  {
285                      pr_res->records->
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));
291                  }
292                  wrbuf_destroy(output_record);
293              }
294          }
295     }
296     package.response() = gdu_res;
297     return;
298 }
299
300
301 static mp::filter::Base* filter_creator()
302 {
303     return new mp::filter::RecordTransform;
304 }
305
306 extern "C" {
307     struct metaproxy_1_filter_struct metaproxy_1_filter_record_transform = {
308         0,
309         "record_transform",
310         filter_creator
311     };
312 }
313
314
315 /*
316  * Local variables:
317  * c-basic-offset: 4
318  * c-file-style: "Stroustrup"
319  * indent-tabs-mode: nil
320  * End:
321  * vim: shiftwidth=4 tabstop=8 expandtab
322  */
323