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