record transformation - encoding of z3950 present package schema and elemname
[metaproxy-moved-to-github.git] / src / filter_record_transform.cpp
1 /* $Id: filter_record_transform.cpp,v 1.4 2006-10-05 12:17:24 marc Exp $
2    Copyright (c) 2005-2006, Index Data.
3
4    See the LICENSE file for details
5  */
6
7 #include "config.hpp"
8 #include "filter.hpp"
9 #include "filter_record_transform.hpp"
10 #include "package.hpp"
11 #include "util.hpp"
12 #include "gduutil.hpp"
13 #include "xmlutil.hpp"
14
15 #include <yaz/zgdu.h>
16 #include <yaz/retrieval.h>
17
18 //#include <boost/thread/mutex.hpp>
19
20 #include <iostream>
21
22 namespace mp = metaproxy_1;
23 namespace yf = mp::filter;
24 namespace mp_util = metaproxy_1::util;
25
26 namespace metaproxy_1 {
27     namespace filter {
28         class RecordTransform::Impl {
29         public:
30             Impl();
31             ~Impl();
32             void process(metaproxy_1::Package & package) const;
33             void configure(const xmlNode * xml_node);
34         private:
35             yaz_retrieval_t m_retrieval;
36         };
37     }
38 }
39
40 // define Pimpl wrapper forwarding to Impl
41  
42 yf::RecordTransform::RecordTransform() : m_p(new Impl)
43 {
44 }
45
46 yf::RecordTransform::~RecordTransform()
47 {  // must have a destructor because of boost::scoped_ptr
48 }
49
50 void yf::RecordTransform::configure(const xmlNode *xmlnode)
51 {
52     m_p->configure(xmlnode);
53 }
54
55 void yf::RecordTransform::process(mp::Package &package) const
56 {
57     m_p->process(package);
58 }
59
60
61 // define Implementation stuff
62
63
64
65 yf::RecordTransform::Impl::Impl() 
66 {
67     m_retrieval = yaz_retrieval_create();
68     assert(m_retrieval);
69 }
70
71 yf::RecordTransform::Impl::~Impl()
72
73     if (m_retrieval)
74         yaz_retrieval_destroy(m_retrieval);
75 }
76
77 void yf::RecordTransform::Impl::configure(const xmlNode *xml_node)
78 {
79     //const char *srcdir = getenv("srcdir");
80     //if (srcdir)
81     //    yaz_retrieval_set_path(m_retrieval, srcdir);
82
83     if (!xml_node)
84         throw mp::XMLError("RecordTransform filter config: empty XML DOM");
85
86     // parsing down to retrieval node, which can be any of the children nodes
87     xmlNode *retrieval_node;
88     for (retrieval_node = xml_node->children; 
89          retrieval_node; 
90          retrieval_node = retrieval_node->next)
91     {
92         if (retrieval_node->type != XML_ELEMENT_NODE)
93             continue;
94         if (0 == strcmp((const char *) retrieval_node->name, "retrievalinfo"))
95             break;
96     }
97     
98     // read configuration
99     if ( 0 != yaz_retrieval_configure(m_retrieval, retrieval_node)){
100         std::string msg("RecordTransform filter config: ");
101         msg += yaz_retrieval_get_error(m_retrieval);
102         throw mp::XMLError(msg);
103     }
104 }
105
106 void yf::RecordTransform::Impl::process(mp::Package &package) const
107 {
108
109     Z_GDU *gdu_req = package.request().get();
110     
111     // only working on z3950 present packages
112     if (!gdu_req 
113         || !(gdu_req->which == Z_GDU_Z3950) 
114         || !(gdu_req->u.z3950->which == Z_APDU_presentRequest))
115     {
116         package.move();
117         return;
118     }
119     
120     // getting original present request
121     Z_PresentRequest *pr = gdu_req->u.z3950->u.presentRequest;
122
123     // setting up ODR's for memory during encoding/decoding
124     //mp::odr odr_de(ODR_DECODE);  
125     mp::odr odr_en(ODR_ENCODE);
126
127     // setting up variables for conversion state
128     yaz_record_conv_t rc = 0;
129     int ret_code;
130
131     const char *input_schema = 0;
132     Odr_oid *input_syntax = 0;
133
134     if(pr->recordComposition){
135         input_schema 
136             = mp_util::record_composition_to_esn(pr->recordComposition);
137     }
138     if(pr->preferredRecordSyntax){
139         input_syntax = pr->preferredRecordSyntax;
140     }
141     
142     const char *match_schema = 0;
143     int *match_syntax = 0;
144
145     const char *backend_schema = 0;
146     Odr_oid *backend_syntax = 0;
147
148     std::cout << "yaz_retrieval_request" << "\n";
149     ret_code 
150         = yaz_retrieval_request(m_retrieval,
151                                 input_schema, input_syntax,
152                                 &match_schema, &match_syntax,
153                                 &rc,
154                                 &backend_schema, &backend_syntax);
155
156     std::cout << "ret_code " <<  ret_code << "\n";
157     std::cout << "input   " << input_syntax << " ";
158     if (input_syntax)
159         std::cout << (oid_getentbyoid(input_syntax))->desc << " ";
160     else
161         std::cout << "- ";
162     if (input_schema)
163         std::cout   <<  input_schema << "\n";
164     else
165         std::cout   <<  "-\n";
166     std::cout << "match   " << match_syntax << " ";
167     if (match_syntax)
168         std::cout << (oid_getentbyoid(match_syntax))->desc << " ";
169     else
170         std::cout << "- ";
171     if (match_schema)
172         std::cout   <<  match_schema << "\n";
173     else
174         std::cout   <<  "-\n";
175     std::cout << "backend " << backend_syntax << " ";
176     if (backend_syntax)
177         std::cout << (oid_getentbyoid(backend_syntax))->desc << " ";
178     else
179         std::cout << "- ";
180     if (backend_schema)
181         std::cout   <<  backend_schema << "\n";
182     else
183         std::cout   <<  "-\n";
184     
185     // error handeling
186     if (ret_code != 0)
187     {
188
189         // need to construct present error package and send back
190
191         const char *details = 0;
192         if (ret_code == -1) /* error ? */
193         {
194            details = yaz_retrieval_get_error(m_retrieval);
195            std::cout << "ERROR: YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS"
196                      << details << "\n";
197            //rr->errcode = YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS;
198            // if (details)
199            //     rr->errstring = odr_strdup(rr->stream, details);
200         }
201         else if (ret_code == 1 || ret_code == 3)
202         {
203             details = input_schema;
204             std::cout << "ERROR: YAZ_BIB1_ELEMENT_SET_NAMES_UNSUPP"
205                       << details << "\n";
206             //rr->errcode =  YAZ_BIB1_ELEMENT_SET_NAMES_UNSUPP;
207             //if (details)
208             //    rr->errstring = odr_strdup(rr->stream, details);
209         }
210         else if (ret_code == 2)
211         {
212             std::cout << "ERROR: YAZ_BIB1_RECORD_SYNTAX_UNSUPP"
213                       << details << "\n";
214             //rr->errcode = YAZ_BIB1_RECORD_SYNTAX_UNSUPP;
215             //if (input_syntax_raw)
216             //{
217             //    char oidbuf[OID_STR_MAX];
218             //    oid_to_dotstring(input_syntax_raw, oidbuf);
219             //    rr->errstring = odr_strdup(rr->stream, oidbuf);
220             //}
221         }
222         //package.session().close();
223         return;
224     }
225
226
227
228     // now re-coding the z3950 backend present request
229      
230     // z3950'fy record syntax
231
232      if (backend_syntax)
233          pr->preferredRecordSyntax
234              = yaz_oidval_to_z3950oid(odr_en, CLASS_RECSYN, *backend_syntax);
235      else
236          pr->preferredRecordSyntax
237              = yaz_oidval_to_z3950oid(odr_en, CLASS_RECSYN, VAL_NONE);
238
239         
240     //Odr_oid odr_oid;
241
242         
243         // = yaz_oidval_to_z3950oid (odr_en, CLASS_RECSYN, VAL_TEXT_XML);
244     // }
245     // Odr_oid *yaz_str_to_z3950oid (ODR o, int oid_class,
246     //                                         const char *str);
247     // const char *yaz_z3950oid_to_str (Odr_oid *oid, int *oid_class);
248
249          //   oident *oident_syntax = oid_getentbyoid(backend_syntax);
250          //
251          //   rr->request_format_raw = backend_syntax;
252          //   
253          //   if (oident_syntax)
254          //       rr->request_format = oident_syntax->value;
255          //   else
256          //       rr->request_format = VAL_NONE;
257          
258
259
260
261     // z3950'fy record schema
262     if (backend_schema)
263     {
264         pr->recordComposition 
265             = (Z_RecordComposition *) 
266               odr_malloc(odr_en, sizeof(Z_RecordComposition));
267         pr->recordComposition->which 
268             = Z_RecordComp_simple;
269         pr->recordComposition->u.simple 
270             = (Z_ElementSetNames *)
271                odr_malloc(odr_en, sizeof(Z_ElementSetNames));
272         pr->recordComposition->u.simple->which = Z_ElementSetNames_generic;
273         pr->recordComposition->u.simple->u.generic 
274             = odr_strdup(odr_en, backend_schema);
275     }
276
277     // attaching Z3950 package to filter chain
278     package.request() = gdu_req;
279
280     // std::cout << "z3950_present_request " << *apdu << "\n";   
281
282     // sending package
283     package.move();
284
285    //check successful Z3950 present response
286     Z_GDU *gdu_res = package.response().get();
287     if (!gdu_res || gdu_res->which != Z_GDU_Z3950 
288         || gdu_res->u.z3950->which != Z_APDU_presentResponse
289         || !gdu_res->u.z3950->u.presentResponse)
290
291     {
292         std::cout << "record-transform: error back present\n";
293         package.session().close();
294         return;
295     }
296     
297
298     // everything fine, continuing
299     // std::cout << "z3950_present_request OK\n";
300     // std::cout << "back z3950 " << *gdu_res << "\n";
301
302 //         if (backend_schema)
303 //         {
304 //             set_esn(&rr->comp, backend_schema, rr->stream->mem);
305 //         }
306 //         if (backend_syntax)
307 //         {
308 //             oident *oident_syntax = oid_getentbyoid(backend_syntax);
309
310 //             rr->request_format_raw = backend_syntax;
311             
312 //             if (oident_syntax)
313 //                 rr->request_format = oident_syntax->value;
314 //             else
315 //                 rr->request_format = VAL_NONE;
316
317 //        }
318 //     }
319 //     (*assoc->init->bend_fetch)(assoc->backend, rr);
320 //     if (rc && rr->record && rr->errcode == 0 && rr->len > 0)
321 //     {   /* post conversion must take place .. */
322 //         WRBUF output_record = wrbuf_alloc();
323 //         int r = yaz_record_conv_record(rc, rr->record, rr->len, output_record);
324 //         if (r)
325 //         {
326 //             const char *details = yaz_record_conv_get_error(rc);
327 //             rr->errcode = YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS;
328 //             if (details)
329 //                 rr->errstring = odr_strdup(rr->stream, details);
330 //         }
331 //         else
332 //         {
333 //             rr->len = wrbuf_len(output_record);
334 //             rr->record = odr_malloc(rr->stream, rr->len);
335 //             memcpy(rr->record, wrbuf_buf(output_record), rr->len);
336 //         }
337 //         wrbuf_free(output_record, 1);
338 //     }
339 //     if (match_syntax)
340 //     {
341 //         struct oident *oi = oid_getentbyoid(match_syntax);
342 //         rr->output_format = oi ? oi->value : VAL_NONE;
343 //         rr->output_format_raw = match_syntax;
344 //     }
345 //     if (match_schema)
346 //         rr->schema = odr_strdup(rr->stream, match_schema);
347 //     return 0;
348
349     return;
350 }
351
352
353 static mp::filter::Base* filter_creator()
354 {
355     return new mp::filter::RecordTransform;
356 }
357
358 extern "C" {
359     struct metaproxy_1_filter_struct metaproxy_1_filter_record_transform = {
360         0,
361         "record_transform",
362         filter_creator
363     };
364 }
365
366
367 /*
368  * Local variables:
369  * c-basic-offset: 4
370  * indent-tabs-mode: nil
371  * c-file-style: "stroustrup"
372  * End:
373  * vim: shiftwidth=4 tabstop=8 expandtab
374  */