progressing slowly
[metaproxy-moved-to-github.git] / src / filter_record_transform.cpp
1 /* $Id: filter_record_transform.cpp,v 1.5 2006-10-05 20:19:50 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_req = 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_req->recordComposition){
135         input_schema 
136             = mp_util::record_composition_to_esn(pr_req->recordComposition);
137     }
138     if(pr_req->preferredRecordSyntax){
139         input_syntax = pr_req->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     ret_code 
149         = yaz_retrieval_request(m_retrieval,
150                                 input_schema, input_syntax,
151                                 &match_schema, &match_syntax,
152                                 &rc,
153                                 &backend_schema, &backend_syntax);
154
155     // debug output - to be removed later
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)
216             //{
217             //    char oidbuf[OID_STR_MAX];
218             //    oid_to_dotstring(input_syntax, 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)  // TODO: this seems not to work - why ??
233          pr_req->preferredRecordSyntax
234              = yaz_oidval_to_z3950oid(odr_en, CLASS_RECSYN, *backend_syntax);
235      else
236          pr_req->preferredRecordSyntax
237              = yaz_oidval_to_z3950oid(odr_en, CLASS_RECSYN, VAL_NONE);
238
239      //pr_req->preferredRecordSyntax 
240      //    = yaz_oidval_to_z3950oid (odr_en, CLASS_RECSYN, VAL_TEXT_XML);
241         
242
243     //Odr_oid odr_oid;   
244         // = yaz_oidval_to_z3950oid (odr_en, CLASS_RECSYN, VAL_TEXT_XML);
245     // }
246     // Odr_oid *yaz_str_to_z3950oid (ODR o, int oid_class,
247     //                                         const char *str);
248     // const char *yaz_z3950oid_to_str (Odr_oid *oid, int *oid_class);
249
250          //   oident *oident_syntax = oid_getentbyoid(backend_syntax);
251          //
252          //   rr->request_format_raw = backend_syntax;
253          //   
254          //   if (oident_syntax)
255          //       rr->request_format = oident_syntax->value;
256          //   else
257          //       rr->request_format = VAL_NONE;
258          
259
260
261
262     // z3950'fy record schema
263     if (backend_schema)
264     {
265         pr_req->recordComposition 
266             = (Z_RecordComposition *) 
267               odr_malloc(odr_en, sizeof(Z_RecordComposition));
268         pr_req->recordComposition->which 
269             = Z_RecordComp_simple;
270         pr_req->recordComposition->u.simple 
271             = (Z_ElementSetNames *)
272                odr_malloc(odr_en, sizeof(Z_ElementSetNames));
273         pr_req->recordComposition->u.simple->which = Z_ElementSetNames_generic;
274         pr_req->recordComposition->u.simple->u.generic 
275             = odr_strdup(odr_en, backend_schema);
276     }
277
278     // attaching Z3950 package to filter chain
279     package.request() = gdu_req;
280
281     // std::cout << "z3950_present_request " << *apdu << "\n";   
282
283     // sending package
284     package.move();
285
286    //check successful Z3950 present response
287     Z_GDU *gdu_res = package.response().get();
288     if (!gdu_res || gdu_res->which != Z_GDU_Z3950 
289         || gdu_res->u.z3950->which != Z_APDU_presentResponse
290         || !gdu_res->u.z3950->u.presentResponse)
291
292     {
293         std::cout << "record-transform: error back present\n";
294         package.session().close();
295         return;
296     }
297     
298
299     // everything fine, continuing
300     // std::cout << "z3950_present_request OK\n";
301     // std::cout << "back z3950 " << *gdu_res << "\n";
302
303     Z_PresentResponse * pr_res = gdu_res->u.z3950->u.presentResponse;
304
305     // let non surrogate dioagnostics in Z3950 present response package
306     // pass to frontend - just return
307     if (pr_res->records 
308         && pr_res->records->which == Z_Records_NSD
309         && pr_res->records->u.nonSurrogateDiagnostic)
310         return;
311
312     // record transformation must take place 
313     if (rc && pr_res 
314         && pr_res->numberOfRecordsReturned 
315         && *(pr_res->numberOfRecordsReturned)
316         && pr_res->records
317         && pr_res->records->which == Z_Records_DBOSD
318         && pr_res->records->u.databaseOrSurDiagnostics->num_records)
319     {
320         //transform all records
321          for (int i = 0; 
322               i < pr_res->records->u.databaseOrSurDiagnostics->num_records; 
323               i++)
324          {
325              Z_NamePlusRecord *npr 
326                  = pr_res->records->u.databaseOrSurDiagnostics->records[i];
327              if (npr->which != Z_NamePlusRecord_databaseRecord)
328              {
329                  std::cout  << "TODO: surrogate diag to be set\n";
330              }
331              else
332              {
333                  std::cout  << "TODO: record transform to be done\n";
334                  WRBUF output_record = wrbuf_alloc();
335                  Z_External *r = npr->u.databaseRecord;
336                  //oident *ent = oid_getentbyoid(r->direct_reference);
337                  std::cout 
338                      << "database record type: " << r->which << "\n";
339                  if (r->which == Z_External_octet) 
340                      //&& ent->value == *backend_schema)
341                  {
342                      int ret_trans 
343                          =  yaz_record_conv_record(rc, 
344                                                    (const char *)
345                                                    r->u.octet_aligned->buf, 
346                                                    r->u.octet_aligned->len,
347                                                    output_record);
348                      std::cout 
349                          << "TODO: record transformation error checking\n";
350                 }
351                 
352              }
353          }
354 //&& rr->record && rr->errcode == 0 && rr->len > 0)
355     }
356     
357 //         WRBUF output_record = wrbuf_alloc();
358 //         int r = yaz_record_conv_record(rc, rr->record, rr->len, output_record);
359 //         if (r)
360 //         {
361 //             const char *details = yaz_record_conv_get_error(rc);
362 //             rr->errcode = YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS;
363 //             if (details)
364 //                 rr->errstring = odr_strdup(rr->stream, details);
365 //         }
366 //         else
367 //         {
368 //             rr->len = wrbuf_len(output_record);
369 //             rr->record = odr_malloc(rr->stream, rr->len);
370 //             memcpy(rr->record, wrbuf_buf(output_record), rr->len);
371 //         }
372 //         wrbuf_free(output_record, 1);
373 //     }
374 //     if (match_syntax)
375 //     {
376 //         struct oident *oi = oid_getentbyoid(match_syntax);
377 //         rr->output_format = oi ? oi->value : VAL_NONE;
378 //         rr->output_format_raw = match_syntax;
379 //     }
380 //     if (match_schema)
381 //         rr->schema = odr_strdup(rr->stream, match_schema);
382 //     return 0;
383
384     return;
385 }
386
387
388 static mp::filter::Base* filter_creator()
389 {
390     return new mp::filter::RecordTransform;
391 }
392
393 extern "C" {
394     struct metaproxy_1_filter_struct metaproxy_1_filter_record_transform = {
395         0,
396         "record_transform",
397         filter_creator
398     };
399 }
400
401
402 /*
403  * Local variables:
404  * c-basic-offset: 4
405  * indent-tabs-mode: nil
406  * c-file-style: "stroustrup"
407  * End:
408  * vim: shiftwidth=4 tabstop=8 expandtab
409  */