Do not include router.hpp in filters
[metaproxy-moved-to-github.git] / src / filter_virt_db.cpp
1 /* $Id: filter_virt_db.cpp,v 1.19 2006-01-09 21:20:15 adam Exp $
2    Copyright (c) 2005, Index Data.
3
4 %LICENSE%
5  */
6
7 #include "config.hpp"
8
9 #include "xmlutil.hpp"
10 #include "filter.hpp"
11 #include "package.hpp"
12
13 #include <boost/thread/mutex.hpp>
14 #include <boost/thread/condition.hpp>
15
16 #include "util.hpp"
17 #include "filter_virt_db.hpp"
18
19 #include <yaz/zgdu.h>
20 #include <yaz/otherinfo.h>
21 #include <yaz/diagbib1.h>
22
23 #include <map>
24 #include <iostream>
25
26 namespace yf = yp2::filter;
27
28 namespace yp2 {
29     namespace filter {
30         struct Virt_db_set {
31             Virt_db_set(yp2::Session &id, std::string setname,
32                         std::string vhost, bool named_result_sets);
33             Virt_db_set();
34             ~Virt_db_set();
35
36             yp2::Session m_backend_session;
37             std::string m_backend_setname;
38             std::string m_vhost;
39             bool m_named_result_sets;
40         };
41         struct Virt_db_session {
42             Virt_db_session(yp2::Session &id, bool use_vhost);
43             Virt_db_session();
44             yp2::Session m_session;
45             bool m_use_vhost;
46             std::map<std::string,Virt_db_set> m_sets;
47         };
48         struct Virt_db_map {
49             Virt_db_map(std::string vhost);
50             Virt_db_map();
51             std::string m_vhost;
52         };
53         struct Frontend {
54             Frontend();
55             ~Frontend();
56             yp2::Session m_session;
57             bool m_use_vhost;
58             bool m_in_use;
59             std::map<std::string,Virt_db_set> m_sets;
60             void search(Package &package, Z_APDU *apdu,
61                         const std::map<std::string, Virt_db_map> &maps);
62             void present(Package &package, Z_APDU *apdu);
63             void close(Package &package);
64             typedef std::map<std::string,Virt_db_set>::iterator Sets_it;
65         };            
66         class Virt_db::Rep {
67             friend class Virt_db;
68             
69             void release_session(Package &package);
70             void init(Package &package, Z_APDU *apdu, bool &move_later);
71             void search(Package &package, Z_APDU *apdu, bool &move_later);
72             void present(Package &package, Z_APDU *apdu, bool &move_later);
73
74             Frontend *get_frontend(Package &package);
75             void release_frontend(Package &package);
76         private:
77             boost::mutex m_sessions_mutex;
78             std::map<yp2::Session,Virt_db_session>m_sessions;
79             std::map<std::string, Virt_db_map>m_maps;
80
81             typedef std::map<yp2::Session,Virt_db_session>::iterator Ses_it;
82             typedef std::map<std::string,Virt_db_set>::iterator Sets_it;
83
84             boost::mutex m_mutex;
85             boost::condition m_cond_session_ready;
86             std::map<yp2::Session,Frontend *> m_clients;
87         };
88     }
89 }
90
91 using namespace yp2;
92
93 yf::Frontend::Frontend()
94 {
95     m_use_vhost = false;
96 }
97
98 void yf::Frontend::close(Package &package)
99 {
100     Sets_it sit = m_sets.begin();
101     for (; sit != m_sets.end(); sit++)
102     {
103         sit->second.m_backend_session.close();
104         Package close_package(sit->second.m_backend_session, package.origin());
105         close_package.copy_filter(package);
106         
107         close_package.move();
108     }
109 }
110
111 yf::Frontend::~Frontend()
112 {
113 }
114
115 yf::Frontend *yf::Virt_db::Rep::get_frontend(Package &package)
116 {
117     boost::mutex::scoped_lock lock(m_mutex);
118
119     std::map<yp2::Session,yf::Frontend *>::iterator it;
120     
121     while(true)
122     {
123         it = m_clients.find(package.session());
124         if (it == m_clients.end())
125             break;
126         
127         if (!it->second->m_in_use)
128         {
129             it->second->m_in_use = true;
130             return it->second;
131         }
132         m_cond_session_ready.wait(lock);
133     }
134     Frontend *f = new Frontend;
135     m_clients[package.session()] = f;
136     f->m_in_use = true;
137     return f;
138 }
139
140
141 void yf::Virt_db::Rep::release_frontend(Package &package)
142 {
143     boost::mutex::scoped_lock lock(m_mutex);
144     std::map<yp2::Session,yf::Frontend *>::iterator it;
145     
146     it = m_clients.find(package.session());
147     if (it != m_clients.end())
148     {
149         if (package.session().is_closed())
150         {
151             std::cout << "Closing IT\n";
152             it->second->close(package);
153             delete it->second;
154             m_clients.erase(it);
155         }
156         else
157         {
158             it->second->m_in_use = false;
159         }
160         m_cond_session_ready.notify_all();
161     }
162 }
163
164 yf::Virt_db_set::Virt_db_set(yp2::Session &id, std::string setname,
165                              std::string vhost, bool named_result_sets)
166     :   m_backend_session(id), m_backend_setname(setname), m_vhost(vhost),
167         m_named_result_sets(named_result_sets)
168 {
169 }
170
171
172 yf::Virt_db_set::Virt_db_set()
173 {
174 }
175
176
177 yf::Virt_db_set::~Virt_db_set()
178 {
179 }
180
181 yf::Virt_db_map::Virt_db_map(std::string vhost)
182     : m_vhost(vhost) 
183 {
184 }
185
186 yf::Virt_db_map::Virt_db_map()
187 {
188 }
189
190 yf::Virt_db_session::Virt_db_session()
191     : m_use_vhost(false)
192 {
193
194 }
195
196 yf::Virt_db_session::Virt_db_session(yp2::Session &id,
197                                      bool use_vhost) :
198     m_session(id) , m_use_vhost(use_vhost)
199 {
200
201 }
202
203 yf::Virt_db::Virt_db() : m_p(new Virt_db::Rep)
204 {
205 }
206
207 yf::Virt_db::~Virt_db() {
208 }
209
210 void yf::Virt_db::Rep::release_session(Package &package)
211 {
212     boost::mutex::scoped_lock lock(m_sessions_mutex);
213     
214     Ses_it it = m_sessions.find(package.session());
215     
216     if (it != m_sessions.end())
217     {
218         Sets_it sit = it->second.m_sets.begin();
219         for (; sit != it->second.m_sets.end(); sit++)
220         {
221             sit->second.m_backend_session.close();
222             Package close_package(sit->second.m_backend_session, package.origin());
223             close_package.copy_filter(package);
224
225             close_package.move();
226         }
227     }
228     m_sessions.erase(package.session());
229 }
230
231 void yf::Virt_db::Rep::present(Package &package, Z_APDU *apdu, bool &move_later){
232     Session *id = 0;
233     Z_PresentRequest *req = apdu->u.presentRequest;
234     std::string resultSetId = req->resultSetId;
235     yp2::odr odr;
236     {
237         boost::mutex::scoped_lock lock(m_sessions_mutex);
238         
239         Ses_it it = m_sessions.find(package.session());
240         if (it == m_sessions.end())
241         {
242             package.response() = odr.create_close(
243                 Z_Close_protocolError,
244                 "no session for present request");
245             package.session().close();
246             return;
247         }
248         if (it->second.m_use_vhost)
249         {
250             move_later = true;
251             return;
252         }
253         Sets_it sets_it = it->second.m_sets.find(resultSetId);
254         if (sets_it == it->second.m_sets.end())
255         {
256             Z_APDU *apdu = zget_APDU(odr, Z_APDU_presentResponse);
257             
258             Z_Records *rec = (Z_Records *) odr_malloc(odr, sizeof(Z_Records));
259             apdu->u.presentResponse->records = rec;
260             rec->which = Z_Records_NSD;
261             rec->u.nonSurrogateDiagnostic =
262                 zget_DefaultDiagFormat(
263                     odr,
264                     YAZ_BIB1_SPECIFIED_RESULT_SET_DOES_NOT_EXIST,
265                     resultSetId.c_str());
266             package.response() = apdu;
267
268             return;
269         }
270         id = new yp2::Session(sets_it->second.m_backend_session);
271     }
272     
273     // sending present to backend
274     Package present_package(*id, package.origin());
275     present_package.copy_filter(package);
276     
277     req->resultSetId = odr_strdup(odr, "default");
278     present_package.request() = yazpp_1::GDU(apdu);
279
280     present_package.move();
281
282     if (present_package.session().is_closed())
283     {
284         Z_APDU *apdu = zget_APDU(odr, Z_APDU_presentResponse);
285         
286         Z_Records *rec = (Z_Records *) odr_malloc(odr, sizeof(Z_Records));
287         apdu->u.presentResponse->records = rec;
288         rec->which = Z_Records_NSD;
289         rec->u.nonSurrogateDiagnostic =
290             zget_DefaultDiagFormat(
291                 odr,
292                 YAZ_BIB1_RESULT_SET_NO_LONGER_EXISTS_UNILATERALLY_DELETED_BY_,
293                 resultSetId.c_str());
294         package.response() = apdu;
295         
296         boost::mutex::scoped_lock lock(m_sessions_mutex);
297         Ses_it it = m_sessions.find(package.session());
298         if (it != m_sessions.end())
299             it->second.m_sets.erase(resultSetId);
300     }
301     else
302     {
303         package.response() = present_package.response();
304     }
305     delete id;
306 }
307
308 void yf::Frontend::present(Package &package, Z_APDU *apdu)
309 {
310     Session *id = 0;
311     Z_PresentRequest *req = apdu->u.presentRequest;
312     std::string resultSetId = req->resultSetId;
313     yp2::odr odr;
314
315     Sets_it sets_it = m_sets.find(resultSetId);
316     if (sets_it == m_sets.end())
317     {
318         Z_APDU *apdu = zget_APDU(odr, Z_APDU_presentResponse);
319         
320         Z_Records *rec = (Z_Records *) odr_malloc(odr, sizeof(Z_Records));
321         apdu->u.presentResponse->records = rec;
322         rec->which = Z_Records_NSD;
323         rec->u.nonSurrogateDiagnostic =
324             zget_DefaultDiagFormat(
325                 odr,
326                 YAZ_BIB1_SPECIFIED_RESULT_SET_DOES_NOT_EXIST,
327                 resultSetId.c_str());
328         package.response() = apdu;
329         
330         return;
331     }
332     id = new yp2::Session(sets_it->second.m_backend_session);
333     
334     // sending present to backend
335     Package present_package(*id, package.origin());
336     present_package.copy_filter(package);
337     
338     req->resultSetId = odr_strdup(odr, "default");
339     present_package.request() = yazpp_1::GDU(apdu);
340
341     present_package.move();
342
343     if (present_package.session().is_closed())
344     {
345         Z_APDU *apdu = zget_APDU(odr, Z_APDU_presentResponse);
346         
347         Z_Records *rec = (Z_Records *) odr_malloc(odr, sizeof(Z_Records));
348         apdu->u.presentResponse->records = rec;
349         rec->which = Z_Records_NSD;
350         rec->u.nonSurrogateDiagnostic =
351             zget_DefaultDiagFormat(
352                 odr,
353                 YAZ_BIB1_RESULT_SET_NO_LONGER_EXISTS_UNILATERALLY_DELETED_BY_,
354                 resultSetId.c_str());
355         package.response() = apdu;
356         
357         m_sets.erase(resultSetId);
358     }
359     else
360     {
361         package.response() = present_package.response();
362     }
363     delete id;
364 }
365
366 void yf::Virt_db::Rep::search(Package &package, Z_APDU *apdu, bool &move_later)
367 {
368     Z_SearchRequest *req = apdu->u.searchRequest;
369     std::string vhost;
370     std::string database;
371     std::string resultSetId = req->resultSetName;
372     bool support_named_result_sets = false;  // whether backend supports it
373     yp2::odr odr;
374     {
375         boost::mutex::scoped_lock lock(m_sessions_mutex);
376
377         Ses_it it = m_sessions.find(package.session());
378         if (it == m_sessions.end())
379         {
380             package.response() = odr.create_close(
381                 Z_Close_protocolError,
382                 "no session for search request");
383             package.session().close();
384
385             return;
386         }
387         if (it->second.m_use_vhost)
388         {
389             move_later = true;
390             return;
391         }
392         if (req->num_databaseNames != 1)
393         {   // exactly one database must be specified
394             Z_APDU *apdu = zget_APDU(odr, Z_APDU_searchResponse);
395             
396             Z_Records *rec = (Z_Records *) odr_malloc(odr, sizeof(Z_Records));
397             apdu->u.searchResponse->records = rec;
398             rec->which = Z_Records_NSD;
399             rec->u.nonSurrogateDiagnostic =
400                 zget_DefaultDiagFormat(
401                     odr, YAZ_BIB1_TOO_MANY_DATABASES_SPECIFIED, 0);
402             package.response() = apdu;
403             
404             return;
405         }
406         database = req->databaseNames[0];
407         std::map<std::string, Virt_db_map>::iterator map_it;
408         map_it = m_maps.find(database);
409         if (map_it == m_maps.end()) 
410         {   // no map for database: return diagnostic
411             Z_APDU *apdu = zget_APDU(odr, Z_APDU_searchResponse);
412             
413             Z_Records *rec = (Z_Records *) odr_malloc(odr, sizeof(Z_Records));
414             apdu->u.searchResponse->records = rec;
415             rec->which = Z_Records_NSD;
416             rec->u.nonSurrogateDiagnostic =
417                 zget_DefaultDiagFormat(
418                     odr, YAZ_BIB1_DATABASE_DOES_NOT_EXIST, database.c_str());
419             package.response() = apdu;
420             
421             return;
422         }
423         if (*req->replaceIndicator == 0)
424         {
425             Sets_it sets_it = it->second.m_sets.find(req->resultSetName);
426             if (sets_it != it->second.m_sets.end())
427             {
428                 Z_APDU *apdu = zget_APDU(odr, Z_APDU_searchResponse);
429                 
430                 Z_Records *rec = (Z_Records *) odr_malloc(odr, sizeof(Z_Records));
431                 apdu->u.searchResponse->records = rec;
432                 rec->which = Z_Records_NSD;
433                 rec->u.nonSurrogateDiagnostic =
434                     zget_DefaultDiagFormat(
435                         odr,
436                         YAZ_BIB1_RESULT_SET_EXISTS_AND_REPLACE_INDICATOR_OFF,
437                         0);
438                 package.response() = apdu;
439                 
440                 return;
441             }
442         }
443         it->second.m_sets.erase(req->resultSetName);
444         vhost = map_it->second.m_vhost;
445     }
446     // we might look for an existing session with same vhost
447     Session id;
448     const char *vhost_cstr = vhost.c_str();
449     if (true)
450     {  // sending init to backend
451         Package init_package(id, package.origin());
452         init_package.copy_filter(package);
453         
454         Z_APDU *init_apdu = zget_APDU(odr, Z_APDU_initRequest);
455         
456         yaz_oi_set_string_oidval(&init_apdu->u.initRequest->otherInfo, odr,
457                                  VAL_PROXY, 1, vhost_cstr);
458         
459         init_package.request() = init_apdu;
460
461         init_package.move();  // sending init 
462
463         if (init_package.session().is_closed())
464         {
465             Z_APDU *apdu = zget_APDU(odr, Z_APDU_searchResponse);
466             
467             Z_Records *rec = (Z_Records *) odr_malloc(odr, sizeof(Z_Records));
468             apdu->u.searchResponse->records = rec;
469             rec->which = Z_Records_NSD;
470             rec->u.nonSurrogateDiagnostic =
471                 zget_DefaultDiagFormat(
472                     odr, YAZ_BIB1_DATABASE_UNAVAILABLE, database.c_str());
473             package.response() = apdu;
474         }
475         Z_GDU *gdu = init_package.response().get();
476         // we hope to get an init response
477         if (gdu && gdu->which == Z_GDU_Z3950 && gdu->u.z3950->which ==
478             Z_APDU_initResponse)
479         {
480             if (ODR_MASK_GET(gdu->u.z3950->u.initResponse->options,
481                              Z_Options_namedResultSets))
482                 support_named_result_sets = true;
483         }
484         else
485         {
486             Z_APDU *apdu = zget_APDU(odr, Z_APDU_searchResponse);
487             
488             Z_Records *rec = (Z_Records *) odr_malloc(odr, sizeof(Z_Records));
489             apdu->u.searchResponse->records = rec;
490             rec->which = Z_Records_NSD;
491             rec->u.nonSurrogateDiagnostic =
492                 zget_DefaultDiagFormat(
493                     odr, YAZ_BIB1_DATABASE_UNAVAILABLE, database.c_str());
494             package.response() = apdu;
495             
496             return;
497         }
498     }
499     // sending search to backend
500     Package search_package(id, package.origin());
501
502     search_package.copy_filter(package);
503     const char *sep = strchr(vhost_cstr, '/');
504     if (sep)
505         req->databaseNames[0] = odr_strdup(odr, sep+1);
506
507     *req->replaceIndicator = 1;
508
509     std::string backend_resultSetId = "default";
510     req->resultSetName = odr_strdup(odr, backend_resultSetId.c_str());
511     search_package.request() = yazpp_1::GDU(apdu);
512     
513     search_package.move();
514
515     if (search_package.session().is_closed())
516     {
517         Z_APDU *apdu = zget_APDU(odr, Z_APDU_searchResponse);
518         
519         Z_Records *rec = (Z_Records *) odr_malloc(odr, sizeof(Z_Records));
520         apdu->u.searchResponse->records = rec;
521         rec->which = Z_Records_NSD;
522         rec->u.nonSurrogateDiagnostic =
523             zget_DefaultDiagFormat(
524                 odr, YAZ_BIB1_DATABASE_UNAVAILABLE, database.c_str());
525         package.response() = apdu;
526         
527         return;
528     }
529     package.response() = search_package.response();
530     
531     boost::mutex::scoped_lock lock(m_sessions_mutex);
532     Ses_it it = m_sessions.find(package.session());
533     if (it != m_sessions.end())
534         it->second.m_sets[resultSetId] =
535             Virt_db_set(id, backend_resultSetId, vhost,
536                         support_named_result_sets);
537 }
538
539 void yf::Frontend::search(Package &package, Z_APDU *apdu,
540                           const std::map<std::string, Virt_db_map> &maps)
541 {
542     Z_SearchRequest *req = apdu->u.searchRequest;
543     std::string vhost;
544     std::string database;
545     std::string resultSetId = req->resultSetName;
546     bool support_named_result_sets = false;  // whether backend supports it
547     yp2::odr odr;
548     
549     if (req->num_databaseNames != 1)
550     {   // exactly one database must be specified
551         Z_APDU *apdu = zget_APDU(odr, Z_APDU_searchResponse);
552         
553         Z_Records *rec = (Z_Records *) odr_malloc(odr, sizeof(Z_Records));
554         apdu->u.searchResponse->records = rec;
555         rec->which = Z_Records_NSD;
556         rec->u.nonSurrogateDiagnostic =
557             zget_DefaultDiagFormat(
558                 odr, YAZ_BIB1_TOO_MANY_DATABASES_SPECIFIED, 0);
559         package.response() = apdu;
560         
561         return;
562     }
563     database = req->databaseNames[0];
564     std::map<std::string, Virt_db_map>::const_iterator map_it;
565     map_it = maps.find(database);
566     if (map_it == maps.end()) 
567     {   // no map for database: return diagnostic
568         Z_APDU *apdu = zget_APDU(odr, Z_APDU_searchResponse);
569         
570         Z_Records *rec = (Z_Records *) odr_malloc(odr, sizeof(Z_Records));
571         apdu->u.searchResponse->records = rec;
572         rec->which = Z_Records_NSD;
573         rec->u.nonSurrogateDiagnostic =
574             zget_DefaultDiagFormat(
575                 odr, YAZ_BIB1_DATABASE_DOES_NOT_EXIST, database.c_str());
576         package.response() = apdu;
577         
578         return;
579     }
580     if (*req->replaceIndicator == 0)
581     {
582         Sets_it sets_it = m_sets.find(req->resultSetName);
583         if (sets_it != m_sets.end())
584         {
585             Z_APDU *apdu = zget_APDU(odr, Z_APDU_searchResponse);
586             
587             Z_Records *rec = (Z_Records *) odr_malloc(odr, sizeof(Z_Records));
588             apdu->u.searchResponse->records = rec;
589             rec->which = Z_Records_NSD;
590             rec->u.nonSurrogateDiagnostic =
591                 zget_DefaultDiagFormat(
592                     odr,
593                     YAZ_BIB1_RESULT_SET_EXISTS_AND_REPLACE_INDICATOR_OFF,
594                     0);
595             package.response() = apdu;
596             
597             return;
598         }
599     }
600     m_sets.erase(req->resultSetName);
601     vhost = map_it->second.m_vhost;
602     // we might look for an existing session with same vhost
603     Session id;
604     const char *vhost_cstr = vhost.c_str();
605     if (true)
606     {  // sending init to backend
607         Package init_package(id, package.origin());
608         init_package.copy_filter(package);
609         
610         Z_APDU *init_apdu = zget_APDU(odr, Z_APDU_initRequest);
611         
612         yaz_oi_set_string_oidval(&init_apdu->u.initRequest->otherInfo, odr,
613                                  VAL_PROXY, 1, vhost_cstr);
614         
615         init_package.request() = init_apdu;
616
617         init_package.move();  // sending init 
618
619         if (init_package.session().is_closed())
620         {
621             Z_APDU *apdu = zget_APDU(odr, Z_APDU_searchResponse);
622             
623             Z_Records *rec = (Z_Records *) odr_malloc(odr, sizeof(Z_Records));
624             apdu->u.searchResponse->records = rec;
625             rec->which = Z_Records_NSD;
626             rec->u.nonSurrogateDiagnostic =
627                 zget_DefaultDiagFormat(
628                     odr, YAZ_BIB1_DATABASE_UNAVAILABLE, database.c_str());
629             package.response() = apdu;
630         }
631         Z_GDU *gdu = init_package.response().get();
632         // we hope to get an init response
633         if (gdu && gdu->which == Z_GDU_Z3950 && gdu->u.z3950->which ==
634             Z_APDU_initResponse)
635         {
636             if (ODR_MASK_GET(gdu->u.z3950->u.initResponse->options,
637                              Z_Options_namedResultSets))
638                 support_named_result_sets = true;
639         }
640         else
641         {
642             Z_APDU *apdu = zget_APDU(odr, Z_APDU_searchResponse);
643             
644             Z_Records *rec = (Z_Records *) odr_malloc(odr, sizeof(Z_Records));
645             apdu->u.searchResponse->records = rec;
646             rec->which = Z_Records_NSD;
647             rec->u.nonSurrogateDiagnostic =
648                 zget_DefaultDiagFormat(
649                     odr, YAZ_BIB1_DATABASE_UNAVAILABLE, database.c_str());
650             package.response() = apdu;
651             
652             return;
653         }
654     }
655     // sending search to backend
656     Package search_package(id, package.origin());
657
658     search_package.copy_filter(package);
659     const char *sep = strchr(vhost_cstr, '/');
660     if (sep)
661         req->databaseNames[0] = odr_strdup(odr, sep+1);
662
663     *req->replaceIndicator = 1;
664
665     std::string backend_resultSetId = "default";
666     req->resultSetName = odr_strdup(odr, backend_resultSetId.c_str());
667     search_package.request() = yazpp_1::GDU(apdu);
668     
669     search_package.move();
670
671     if (search_package.session().is_closed())
672     {
673         Z_APDU *apdu = zget_APDU(odr, Z_APDU_searchResponse);
674         
675         Z_Records *rec = (Z_Records *) odr_malloc(odr, sizeof(Z_Records));
676         apdu->u.searchResponse->records = rec;
677         rec->which = Z_Records_NSD;
678         rec->u.nonSurrogateDiagnostic =
679             zget_DefaultDiagFormat(
680                 odr, YAZ_BIB1_DATABASE_UNAVAILABLE, database.c_str());
681         package.response() = apdu;
682         
683         return;
684     }
685     package.response() = search_package.response();
686     
687     m_sets[resultSetId] =
688         Virt_db_set(id, backend_resultSetId, vhost,
689                     support_named_result_sets);
690 }
691
692 void yf::Virt_db::Rep::init(Package &package, Z_APDU *apdu, bool &move_later)
693 {
694     release_session(package);
695     boost::mutex::scoped_lock lock(m_sessions_mutex);
696
697     Z_InitRequest *req = apdu->u.initRequest;
698     
699     const char *vhost =
700         yaz_oi_get_string_oidval(&req->otherInfo, VAL_PROXY, 1, 0);
701     if (!vhost)
702     {
703         yp2::odr odr;
704         Z_APDU *apdu = zget_APDU(odr, Z_APDU_initResponse);
705         Z_InitResponse *resp = apdu->u.initResponse;
706         
707         int i;
708         static const int masks[] = {
709             Z_Options_search, Z_Options_present, Z_Options_namedResultSets, -1 
710         };
711         for (i = 0; masks[i] != -1; i++)
712             if (ODR_MASK_GET(req->options, masks[i]))
713                 ODR_MASK_SET(resp->options, masks[i]);
714         
715         static const int versions[] = {
716             Z_ProtocolVersion_1,
717             Z_ProtocolVersion_2,
718             Z_ProtocolVersion_3,
719             -1
720         };
721         for (i = 0; versions[i] != -1; i++)
722             if (ODR_MASK_GET(req->protocolVersion, versions[i]))
723                 ODR_MASK_SET(resp->protocolVersion, versions[i]);
724             else
725                 break;
726
727         package.response() = apdu;
728         
729         m_sessions[package.session()] = Virt_db_session(package.session(), false);
730     }
731     else
732     {
733         m_sessions[package.session()] = Virt_db_session(package.session(), true);
734         package.move();
735     }
736 }
737
738 void yf::Virt_db::add_map_db2vhost(std::string db, std::string vhost)
739 {
740     m_p->m_maps[db] = Virt_db_map(vhost);
741 }
742
743 #if 0
744 void yf::Virt_db::process(Package &package) const
745 {
746     yf::Frontend *f = m_p->get_frontend(package);
747     if (f)
748     {
749         Z_GDU *gdu = package.request().get();
750         if (!gdu || gdu->which != Z_GDU_Z3950 || f->m_use_vhost)
751             package.move();
752         else
753         {
754             Z_APDU *apdu = gdu->u.z3950;
755             if (apdu->which == Z_APDU_initRequest)
756             {
757                 Z_InitRequest *req = apdu->u.initRequest;
758                 
759                 const char *vhost =
760                     yaz_oi_get_string_oidval(&req->otherInfo, VAL_PROXY, 1, 0);
761                 if (!vhost)
762                 {
763                     yp2::odr odr;
764                     Z_APDU *apdu = zget_APDU(odr, Z_APDU_initResponse);
765                     Z_InitResponse *resp = apdu->u.initResponse;
766                     
767                     int i;
768                     static const int masks[] = {
769                         Z_Options_search, Z_Options_present, Z_Options_namedResultSets, -1 
770                     };
771                     for (i = 0; masks[i] != -1; i++)
772                         if (ODR_MASK_GET(req->options, masks[i]))
773                             ODR_MASK_SET(resp->options, masks[i]);
774                     
775                     static const int versions[] = {
776                         Z_ProtocolVersion_1,
777                         Z_ProtocolVersion_2,
778                         Z_ProtocolVersion_3,
779                         -1
780                     };
781                     for (i = 0; versions[i] != -1; i++)
782                         if (ODR_MASK_GET(req->protocolVersion, versions[i]))
783                             ODR_MASK_SET(resp->protocolVersion, versions[i]);
784                         else
785                             break;
786                     
787                     package.response() = apdu;
788                 }
789                 else
790                 {
791                     f->m_use_vhost = true;
792                     package.move();
793                 }
794             }
795             else if (apdu->which == Z_APDU_searchRequest)
796             {
797                 f->search(package, apdu, m_p->m_maps);
798             }
799             else if (apdu->which == Z_APDU_presentRequest)
800             {
801                 f->present(package, apdu);
802             }
803             else
804             {
805                 yp2::odr odr;
806                 
807                 package.response() = odr.create_close(
808                     Z_Close_protocolError,
809                     "unsupported APDU in filter_virt_db");
810                 
811                 package.session().close();
812             }
813         }
814     }
815     m_p->release_frontend(package);
816 }
817
818 #else
819 void yf::Virt_db::process(Package &package) const
820 {
821     Z_GDU *gdu = package.request().get();
822     
823     if (package.session().is_closed())
824         m_p->release_session(package);
825     else if (!gdu || gdu->which != Z_GDU_Z3950)
826         package.move();
827     else
828     {
829         bool move_later = false;
830         Z_APDU *apdu = gdu->u.z3950;
831         if (apdu->which == Z_APDU_initRequest)
832         {
833             m_p->init(package, apdu, move_later);
834         }
835         else if (apdu->which == Z_APDU_searchRequest)
836         {
837             m_p->search(package, apdu, move_later);
838         }
839         else if (apdu->which == Z_APDU_presentRequest)
840         {
841             m_p->present(package, apdu, move_later);
842         }
843         else if (apdu->which == Z_APDU_close)
844         {
845             package.session().close();
846             m_p->release_session(package);
847         }
848         else
849         {
850             yp2::odr odr;
851             
852             package.response() = odr.create_close(
853                 Z_Close_protocolError,
854                 "unsupported APDU in filter_virt_db");
855                                                  
856             package.session().close();
857             m_p->release_session(package);
858         }
859         if (move_later)
860             package.move();
861     }
862 }
863 #endif
864
865 void yp2::filter::Virt_db::configure(const xmlNode * ptr)
866 {
867     for (ptr = ptr->children; ptr; ptr = ptr->next)
868     {
869         if (ptr->type != XML_ELEMENT_NODE)
870             continue;
871         if (!strcmp((const char *) ptr->name, "virtual"))
872         {
873             std::string database;
874             std::string target;
875             xmlNode *v_node = ptr->children;
876             for (; v_node; v_node = v_node->next)
877             {
878                 if (v_node->type != XML_ELEMENT_NODE)
879                     continue;
880                 
881                 if (yp2::xml::is_element_yp2(v_node, "database"))
882                     database = yp2::xml::get_text(v_node);
883                 else if (yp2::xml::is_element_yp2(v_node, "target"))
884                     target = yp2::xml::get_text(v_node);
885                 else
886                     throw yp2::filter::FilterException
887                         ("Bad element " 
888                          + std::string((const char *) v_node->name)
889                          + " in virtual section"
890                             );
891             }
892             add_map_db2vhost(database, target);
893             std::cout << "Add " << database << "->" << target << "\n";
894         }
895         else
896         {
897             throw yp2::filter::FilterException
898                 ("Bad element " 
899                  + std::string((const char *) ptr->name)
900                  + " in virt_db filter");
901         }
902     }
903 }
904
905 static yp2::filter::Base* filter_creator()
906 {
907     return new yp2::filter::Virt_db;
908 }
909
910 extern "C" {
911     struct yp2_filter_struct yp2_filter_virt_db = {
912         0,
913         "virt_db",
914         filter_creator
915     };
916 }
917
918
919 /*
920  * Local variables:
921  * c-basic-offset: 4
922  * indent-tabs-mode: nil
923  * c-file-style: "stroustrup"
924  * End:
925  * vim: shiftwidth=4 tabstop=8 expandtab
926  */