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