*** empty log message ***
[metaproxy-moved-to-github.git] / src / filter_query_rewrite.cpp
1 /* $Id: filter_query_rewrite.cpp,v 1.4 2006-03-15 14:55:17 adam Exp $
2    Copyright (c) 2005, Index Data.
3
4 %LICENSE%
5  */
6
7
8 #include "config.hpp"
9 #include "filter.hpp"
10 #include "package.hpp"
11
12 //#include <boost/thread/mutex.hpp>
13 #include <boost/regex.hpp>
14
15 #include "util.hpp"
16 #include "filter_query_rewrite.hpp"
17
18 #include <yaz/zgdu.h>
19 #include <yaz/xmlquery.h>
20 #include <yaz/diagbib1.h>
21
22 #include <libxslt/xsltutils.h>
23 #include <libxslt/transform.h>
24
25 namespace yf = yp2::filter;
26
27 namespace yp2 {
28     namespace filter {
29         class QueryRewrite::Rep {
30         public:
31             Rep();
32             ~Rep();
33             void process(yp2::Package &package) const;
34             void configure(const xmlNode * ptr);
35         private:
36             xsltStylesheetPtr m_stylesheet;
37         };
38     }
39 }
40
41 yf::QueryRewrite::Rep::Rep()
42 {
43     m_stylesheet = 0;
44 }
45
46 yf::QueryRewrite::Rep::~Rep()
47 {
48     if (m_stylesheet)
49         xsltFreeStylesheet(m_stylesheet);
50 }
51
52 yf::QueryRewrite::QueryRewrite() : m_p(new Rep)
53 {
54 }
55
56 yf::QueryRewrite::~QueryRewrite()
57 {  // must have a destructor because of boost::scoped_ptr
58 }
59
60 void yf::QueryRewrite::process(yp2::Package &package) const
61 {
62     m_p->process(package);
63 }
64
65 void yp2::filter::QueryRewrite::configure(const xmlNode *ptr)
66 {
67     m_p->configure(ptr);
68 }
69
70 void yf::QueryRewrite::Rep::process(yp2::Package &package) const
71 {
72     Z_GDU *gdu = package.request().get();
73     
74     if (gdu && gdu->which == Z_GDU_Z3950)
75     {
76         Z_APDU *apdu_req = gdu->u.z3950;
77         if (apdu_req->which == Z_APDU_searchRequest)
78         {
79             int error_code = 0;
80             const char *addinfo = 0;
81             yp2::odr odr;
82             Z_SearchRequest *req = apdu_req->u.searchRequest;
83             
84             xmlDocPtr doc_input = 0;
85             yaz_query2xml(req->query, &doc_input);
86             
87             if (!doc_input)
88             {
89                 error_code = YAZ_BIB1_MALFORMED_QUERY;
90                 addinfo = "converion from Query to XML failed";
91             }
92             else
93             {
94                 if (m_stylesheet)
95                 {
96                     xmlDocPtr doc_res = xsltApplyStylesheet(m_stylesheet,
97                                                             doc_input, 0);
98                     if (!doc_res)
99                     {
100                         error_code = YAZ_BIB1_MALFORMED_QUERY;
101                         addinfo = "XSLT transform failed for query";
102                     }
103                     else
104                     {
105                         const xmlNode *root_element = xmlDocGetRootElement(doc_res);
106                         yaz_xml2query(root_element, &req->query, odr,
107                                       &error_code, &addinfo);
108                         xmlFreeDoc(doc_res);
109                     }
110                 }
111                 xmlFreeDoc(doc_input);
112             }
113             package.request() = gdu;
114             if (error_code)
115             {
116                 Z_APDU *f_apdu = 
117                     odr.create_searchResponse(apdu_req, error_code, addinfo);
118                 package.response() = f_apdu;
119                 return;
120             }
121         } 
122     }
123     package.move();
124 }
125
126 void yp2::filter::QueryRewrite::Rep::configure(const xmlNode *ptr)
127 {
128     for (ptr = ptr->children; ptr; ptr = ptr->next)
129     {
130         if (ptr->type != XML_ELEMENT_NODE)
131             continue;
132         if (!strcmp((const char *) ptr->name, "xslt"))
133         {
134             if (m_stylesheet)
135             {
136                 throw yp2::filter::FilterException
137                     ("Only one xslt element allowed in query_rewrite filter");
138             }
139
140             std::string fname = yp2::xml::get_text(ptr);
141             m_stylesheet = xsltParseStylesheetFile(BAD_CAST fname.c_str());
142             if (!m_stylesheet)
143             {
144                 throw yp2::filter::FilterException
145                     ("Failed to read stylesheet " 
146                      + fname
147                      + " in query_rewrite filter");
148             }
149         }
150         else
151         {
152             throw yp2::filter::FilterException
153                 ("Bad element " 
154                  + std::string((const char *) ptr->name)
155                  + " in query_rewrite filter");
156         }
157     }
158 }
159
160 static yp2::filter::Base* filter_creator()
161 {
162     return new yp2::filter::QueryRewrite;
163 }
164
165 extern "C" {
166     struct yp2_filter_struct yp2_filter_query_rewrite = {
167         0,
168         "query-rewrite",
169         filter_creator
170     };
171 }
172
173 /*
174  * Local variables:
175  * c-basic-offset: 4
176  * indent-tabs-mode: nil
177  * c-file-style: "stroustrup"
178  * End:
179  * vim: shiftwidth=4 tabstop=8 expandtab
180  */