1 /* $Id: filter_virt_db.cpp,v 1.19 2006-01-09 21:20:15 adam Exp $
2 Copyright (c) 2005, Index Data.
11 #include "package.hpp"
13 #include <boost/thread/mutex.hpp>
14 #include <boost/thread/condition.hpp>
17 #include "filter_virt_db.hpp"
20 #include <yaz/otherinfo.h>
21 #include <yaz/diagbib1.h>
26 namespace yf = yp2::filter;
31 Virt_db_set(yp2::Session &id, std::string setname,
32 std::string vhost, bool named_result_sets);
36 yp2::Session m_backend_session;
37 std::string m_backend_setname;
39 bool m_named_result_sets;
41 struct Virt_db_session {
42 Virt_db_session(yp2::Session &id, bool use_vhost);
44 yp2::Session m_session;
46 std::map<std::string,Virt_db_set> m_sets;
49 Virt_db_map(std::string vhost);
56 yp2::Session m_session;
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;
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);
74 Frontend *get_frontend(Package &package);
75 void release_frontend(Package &package);
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;
81 typedef std::map<yp2::Session,Virt_db_session>::iterator Ses_it;
82 typedef std::map<std::string,Virt_db_set>::iterator Sets_it;
85 boost::condition m_cond_session_ready;
86 std::map<yp2::Session,Frontend *> m_clients;
93 yf::Frontend::Frontend()
98 void yf::Frontend::close(Package &package)
100 Sets_it sit = m_sets.begin();
101 for (; sit != m_sets.end(); sit++)
103 sit->second.m_backend_session.close();
104 Package close_package(sit->second.m_backend_session, package.origin());
105 close_package.copy_filter(package);
107 close_package.move();
111 yf::Frontend::~Frontend()
115 yf::Frontend *yf::Virt_db::Rep::get_frontend(Package &package)
117 boost::mutex::scoped_lock lock(m_mutex);
119 std::map<yp2::Session,yf::Frontend *>::iterator it;
123 it = m_clients.find(package.session());
124 if (it == m_clients.end())
127 if (!it->second->m_in_use)
129 it->second->m_in_use = true;
132 m_cond_session_ready.wait(lock);
134 Frontend *f = new Frontend;
135 m_clients[package.session()] = f;
141 void yf::Virt_db::Rep::release_frontend(Package &package)
143 boost::mutex::scoped_lock lock(m_mutex);
144 std::map<yp2::Session,yf::Frontend *>::iterator it;
146 it = m_clients.find(package.session());
147 if (it != m_clients.end())
149 if (package.session().is_closed())
151 std::cout << "Closing IT\n";
152 it->second->close(package);
158 it->second->m_in_use = false;
160 m_cond_session_ready.notify_all();
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)
172 yf::Virt_db_set::Virt_db_set()
177 yf::Virt_db_set::~Virt_db_set()
181 yf::Virt_db_map::Virt_db_map(std::string vhost)
186 yf::Virt_db_map::Virt_db_map()
190 yf::Virt_db_session::Virt_db_session()
196 yf::Virt_db_session::Virt_db_session(yp2::Session &id,
198 m_session(id) , m_use_vhost(use_vhost)
203 yf::Virt_db::Virt_db() : m_p(new Virt_db::Rep)
207 yf::Virt_db::~Virt_db() {
210 void yf::Virt_db::Rep::release_session(Package &package)
212 boost::mutex::scoped_lock lock(m_sessions_mutex);
214 Ses_it it = m_sessions.find(package.session());
216 if (it != m_sessions.end())
218 Sets_it sit = it->second.m_sets.begin();
219 for (; sit != it->second.m_sets.end(); sit++)
221 sit->second.m_backend_session.close();
222 Package close_package(sit->second.m_backend_session, package.origin());
223 close_package.copy_filter(package);
225 close_package.move();
228 m_sessions.erase(package.session());
231 void yf::Virt_db::Rep::present(Package &package, Z_APDU *apdu, bool &move_later){
233 Z_PresentRequest *req = apdu->u.presentRequest;
234 std::string resultSetId = req->resultSetId;
237 boost::mutex::scoped_lock lock(m_sessions_mutex);
239 Ses_it it = m_sessions.find(package.session());
240 if (it == m_sessions.end())
242 package.response() = odr.create_close(
243 Z_Close_protocolError,
244 "no session for present request");
245 package.session().close();
248 if (it->second.m_use_vhost)
253 Sets_it sets_it = it->second.m_sets.find(resultSetId);
254 if (sets_it == it->second.m_sets.end())
256 Z_APDU *apdu = zget_APDU(odr, Z_APDU_presentResponse);
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(
264 YAZ_BIB1_SPECIFIED_RESULT_SET_DOES_NOT_EXIST,
265 resultSetId.c_str());
266 package.response() = apdu;
270 id = new yp2::Session(sets_it->second.m_backend_session);
273 // sending present to backend
274 Package present_package(*id, package.origin());
275 present_package.copy_filter(package);
277 req->resultSetId = odr_strdup(odr, "default");
278 present_package.request() = yazpp_1::GDU(apdu);
280 present_package.move();
282 if (present_package.session().is_closed())
284 Z_APDU *apdu = zget_APDU(odr, Z_APDU_presentResponse);
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(
292 YAZ_BIB1_RESULT_SET_NO_LONGER_EXISTS_UNILATERALLY_DELETED_BY_,
293 resultSetId.c_str());
294 package.response() = apdu;
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);
303 package.response() = present_package.response();
308 void yf::Frontend::present(Package &package, Z_APDU *apdu)
311 Z_PresentRequest *req = apdu->u.presentRequest;
312 std::string resultSetId = req->resultSetId;
315 Sets_it sets_it = m_sets.find(resultSetId);
316 if (sets_it == m_sets.end())
318 Z_APDU *apdu = zget_APDU(odr, Z_APDU_presentResponse);
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(
326 YAZ_BIB1_SPECIFIED_RESULT_SET_DOES_NOT_EXIST,
327 resultSetId.c_str());
328 package.response() = apdu;
332 id = new yp2::Session(sets_it->second.m_backend_session);
334 // sending present to backend
335 Package present_package(*id, package.origin());
336 present_package.copy_filter(package);
338 req->resultSetId = odr_strdup(odr, "default");
339 present_package.request() = yazpp_1::GDU(apdu);
341 present_package.move();
343 if (present_package.session().is_closed())
345 Z_APDU *apdu = zget_APDU(odr, Z_APDU_presentResponse);
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(
353 YAZ_BIB1_RESULT_SET_NO_LONGER_EXISTS_UNILATERALLY_DELETED_BY_,
354 resultSetId.c_str());
355 package.response() = apdu;
357 m_sets.erase(resultSetId);
361 package.response() = present_package.response();
366 void yf::Virt_db::Rep::search(Package &package, Z_APDU *apdu, bool &move_later)
368 Z_SearchRequest *req = apdu->u.searchRequest;
370 std::string database;
371 std::string resultSetId = req->resultSetName;
372 bool support_named_result_sets = false; // whether backend supports it
375 boost::mutex::scoped_lock lock(m_sessions_mutex);
377 Ses_it it = m_sessions.find(package.session());
378 if (it == m_sessions.end())
380 package.response() = odr.create_close(
381 Z_Close_protocolError,
382 "no session for search request");
383 package.session().close();
387 if (it->second.m_use_vhost)
392 if (req->num_databaseNames != 1)
393 { // exactly one database must be specified
394 Z_APDU *apdu = zget_APDU(odr, Z_APDU_searchResponse);
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;
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);
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;
423 if (*req->replaceIndicator == 0)
425 Sets_it sets_it = it->second.m_sets.find(req->resultSetName);
426 if (sets_it != it->second.m_sets.end())
428 Z_APDU *apdu = zget_APDU(odr, Z_APDU_searchResponse);
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(
436 YAZ_BIB1_RESULT_SET_EXISTS_AND_REPLACE_INDICATOR_OFF,
438 package.response() = apdu;
443 it->second.m_sets.erase(req->resultSetName);
444 vhost = map_it->second.m_vhost;
446 // we might look for an existing session with same vhost
448 const char *vhost_cstr = vhost.c_str();
450 { // sending init to backend
451 Package init_package(id, package.origin());
452 init_package.copy_filter(package);
454 Z_APDU *init_apdu = zget_APDU(odr, Z_APDU_initRequest);
456 yaz_oi_set_string_oidval(&init_apdu->u.initRequest->otherInfo, odr,
457 VAL_PROXY, 1, vhost_cstr);
459 init_package.request() = init_apdu;
461 init_package.move(); // sending init
463 if (init_package.session().is_closed())
465 Z_APDU *apdu = zget_APDU(odr, Z_APDU_searchResponse);
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;
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 ==
480 if (ODR_MASK_GET(gdu->u.z3950->u.initResponse->options,
481 Z_Options_namedResultSets))
482 support_named_result_sets = true;
486 Z_APDU *apdu = zget_APDU(odr, Z_APDU_searchResponse);
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;
499 // sending search to backend
500 Package search_package(id, package.origin());
502 search_package.copy_filter(package);
503 const char *sep = strchr(vhost_cstr, '/');
505 req->databaseNames[0] = odr_strdup(odr, sep+1);
507 *req->replaceIndicator = 1;
509 std::string backend_resultSetId = "default";
510 req->resultSetName = odr_strdup(odr, backend_resultSetId.c_str());
511 search_package.request() = yazpp_1::GDU(apdu);
513 search_package.move();
515 if (search_package.session().is_closed())
517 Z_APDU *apdu = zget_APDU(odr, Z_APDU_searchResponse);
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;
529 package.response() = search_package.response();
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);
539 void yf::Frontend::search(Package &package, Z_APDU *apdu,
540 const std::map<std::string, Virt_db_map> &maps)
542 Z_SearchRequest *req = apdu->u.searchRequest;
544 std::string database;
545 std::string resultSetId = req->resultSetName;
546 bool support_named_result_sets = false; // whether backend supports it
549 if (req->num_databaseNames != 1)
550 { // exactly one database must be specified
551 Z_APDU *apdu = zget_APDU(odr, Z_APDU_searchResponse);
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;
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);
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;
580 if (*req->replaceIndicator == 0)
582 Sets_it sets_it = m_sets.find(req->resultSetName);
583 if (sets_it != m_sets.end())
585 Z_APDU *apdu = zget_APDU(odr, Z_APDU_searchResponse);
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(
593 YAZ_BIB1_RESULT_SET_EXISTS_AND_REPLACE_INDICATOR_OFF,
595 package.response() = apdu;
600 m_sets.erase(req->resultSetName);
601 vhost = map_it->second.m_vhost;
602 // we might look for an existing session with same vhost
604 const char *vhost_cstr = vhost.c_str();
606 { // sending init to backend
607 Package init_package(id, package.origin());
608 init_package.copy_filter(package);
610 Z_APDU *init_apdu = zget_APDU(odr, Z_APDU_initRequest);
612 yaz_oi_set_string_oidval(&init_apdu->u.initRequest->otherInfo, odr,
613 VAL_PROXY, 1, vhost_cstr);
615 init_package.request() = init_apdu;
617 init_package.move(); // sending init
619 if (init_package.session().is_closed())
621 Z_APDU *apdu = zget_APDU(odr, Z_APDU_searchResponse);
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;
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 ==
636 if (ODR_MASK_GET(gdu->u.z3950->u.initResponse->options,
637 Z_Options_namedResultSets))
638 support_named_result_sets = true;
642 Z_APDU *apdu = zget_APDU(odr, Z_APDU_searchResponse);
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;
655 // sending search to backend
656 Package search_package(id, package.origin());
658 search_package.copy_filter(package);
659 const char *sep = strchr(vhost_cstr, '/');
661 req->databaseNames[0] = odr_strdup(odr, sep+1);
663 *req->replaceIndicator = 1;
665 std::string backend_resultSetId = "default";
666 req->resultSetName = odr_strdup(odr, backend_resultSetId.c_str());
667 search_package.request() = yazpp_1::GDU(apdu);
669 search_package.move();
671 if (search_package.session().is_closed())
673 Z_APDU *apdu = zget_APDU(odr, Z_APDU_searchResponse);
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;
685 package.response() = search_package.response();
687 m_sets[resultSetId] =
688 Virt_db_set(id, backend_resultSetId, vhost,
689 support_named_result_sets);
692 void yf::Virt_db::Rep::init(Package &package, Z_APDU *apdu, bool &move_later)
694 release_session(package);
695 boost::mutex::scoped_lock lock(m_sessions_mutex);
697 Z_InitRequest *req = apdu->u.initRequest;
700 yaz_oi_get_string_oidval(&req->otherInfo, VAL_PROXY, 1, 0);
704 Z_APDU *apdu = zget_APDU(odr, Z_APDU_initResponse);
705 Z_InitResponse *resp = apdu->u.initResponse;
708 static const int masks[] = {
709 Z_Options_search, Z_Options_present, Z_Options_namedResultSets, -1
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]);
715 static const int versions[] = {
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]);
727 package.response() = apdu;
729 m_sessions[package.session()] = Virt_db_session(package.session(), false);
733 m_sessions[package.session()] = Virt_db_session(package.session(), true);
738 void yf::Virt_db::add_map_db2vhost(std::string db, std::string vhost)
740 m_p->m_maps[db] = Virt_db_map(vhost);
744 void yf::Virt_db::process(Package &package) const
746 yf::Frontend *f = m_p->get_frontend(package);
749 Z_GDU *gdu = package.request().get();
750 if (!gdu || gdu->which != Z_GDU_Z3950 || f->m_use_vhost)
754 Z_APDU *apdu = gdu->u.z3950;
755 if (apdu->which == Z_APDU_initRequest)
757 Z_InitRequest *req = apdu->u.initRequest;
760 yaz_oi_get_string_oidval(&req->otherInfo, VAL_PROXY, 1, 0);
764 Z_APDU *apdu = zget_APDU(odr, Z_APDU_initResponse);
765 Z_InitResponse *resp = apdu->u.initResponse;
768 static const int masks[] = {
769 Z_Options_search, Z_Options_present, Z_Options_namedResultSets, -1
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]);
775 static const int versions[] = {
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]);
787 package.response() = apdu;
791 f->m_use_vhost = true;
795 else if (apdu->which == Z_APDU_searchRequest)
797 f->search(package, apdu, m_p->m_maps);
799 else if (apdu->which == Z_APDU_presentRequest)
801 f->present(package, apdu);
807 package.response() = odr.create_close(
808 Z_Close_protocolError,
809 "unsupported APDU in filter_virt_db");
811 package.session().close();
815 m_p->release_frontend(package);
819 void yf::Virt_db::process(Package &package) const
821 Z_GDU *gdu = package.request().get();
823 if (package.session().is_closed())
824 m_p->release_session(package);
825 else if (!gdu || gdu->which != Z_GDU_Z3950)
829 bool move_later = false;
830 Z_APDU *apdu = gdu->u.z3950;
831 if (apdu->which == Z_APDU_initRequest)
833 m_p->init(package, apdu, move_later);
835 else if (apdu->which == Z_APDU_searchRequest)
837 m_p->search(package, apdu, move_later);
839 else if (apdu->which == Z_APDU_presentRequest)
841 m_p->present(package, apdu, move_later);
843 else if (apdu->which == Z_APDU_close)
845 package.session().close();
846 m_p->release_session(package);
852 package.response() = odr.create_close(
853 Z_Close_protocolError,
854 "unsupported APDU in filter_virt_db");
856 package.session().close();
857 m_p->release_session(package);
865 void yp2::filter::Virt_db::configure(const xmlNode * ptr)
867 for (ptr = ptr->children; ptr; ptr = ptr->next)
869 if (ptr->type != XML_ELEMENT_NODE)
871 if (!strcmp((const char *) ptr->name, "virtual"))
873 std::string database;
875 xmlNode *v_node = ptr->children;
876 for (; v_node; v_node = v_node->next)
878 if (v_node->type != XML_ELEMENT_NODE)
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);
886 throw yp2::filter::FilterException
888 + std::string((const char *) v_node->name)
889 + " in virtual section"
892 add_map_db2vhost(database, target);
893 std::cout << "Add " << database << "->" << target << "\n";
897 throw yp2::filter::FilterException
899 + std::string((const char *) ptr->name)
900 + " in virt_db filter");
905 static yp2::filter::Base* filter_creator()
907 return new yp2::filter::Virt_db;
911 struct yp2_filter_struct yp2_filter_virt_db = {
922 * indent-tabs-mode: nil
923 * c-file-style: "stroustrup"
925 * vim: shiftwidth=4 tabstop=8 expandtab