added XML config file parsing, still need to read and parse XML attributes
[metaproxy-moved-to-github.git] / src / filter_query_rewrite.cpp
1 /* $Id: filter_query_rewrite.cpp,v 1.3 2006-01-22 00:05:51 marc 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
20 namespace yf = yp2::filter;
21
22 namespace yp2 {
23     namespace filter {
24         class QueryRewrite::Rep {
25             //friend class QueryRewrite;
26         public:
27             void process(yp2::Package &package) const;
28             void configure(const xmlNode * ptr);
29         private:
30             void rewriteRegex(Z_Query *query) const;
31         };
32     }
33 }
34
35 // Class QueryRewrite frowarding to class QueryRewrite::Rep
36
37 yf::QueryRewrite::QueryRewrite() : m_p(new Rep)
38 {
39 }
40
41 yf::QueryRewrite::~QueryRewrite()
42 {  // must have a destructor because of boost::scoped_ptr
43 }
44
45 void yf::QueryRewrite::process(yp2::Package &package) const
46 {
47     m_p->process(package);
48 }
49
50 void yp2::filter::QueryRewrite::configure(const xmlNode *ptr)
51 {
52     m_p->configure(ptr);
53 }
54
55
56 // Class QueryRewrite::Rep implementation
57
58 void yf::QueryRewrite::Rep::process(yp2::Package &package) const
59 {
60     if (package.session().is_closed())
61     {
62         //std::cout << "Got Close.\n";
63     }
64     
65     Z_GDU *gdu = package.request().get();
66     
67     if (gdu && gdu->which == Z_GDU_Z3950 && gdu->u.z3950->which ==
68         Z_APDU_initRequest)
69     {
70         //std::cout << "Got Z3950 Init PDU\n";         
71         //Z_InitRequest *req = gdu->u.z3950->u.initRequest;
72         //package.request() = gdu;
73     } 
74     else if (gdu && gdu->which == Z_GDU_Z3950 && gdu->u.z3950->which ==
75              Z_APDU_searchRequest)
76     {
77         //std::cout << "Got Z3950 Search PDU\n";   
78         Z_SearchRequest *req = gdu->u.z3950->u.searchRequest;
79
80         // applying regex query rewriting
81         rewriteRegex(req->query);
82             
83         // fold new query structure into gdu package ..       
84         // yp2::util::pqf(odr, gdu->u.z3950, query_out);
85         // question: which odr structure to use in this call ??
86         // memory alignment has to be correct, this is a little tricky ...
87         // I'd rather like to alter the gdu and pack it back using:
88         package.request() = gdu;
89     } 
90     else if (gdu && gdu->which == Z_GDU_Z3950 && gdu->u.z3950->which ==
91              Z_APDU_scanRequest)
92     {
93         std::cout << "Got Z3950 Scan PDU\n";   
94         //Z_ScanRequest *req = gdu->u.z3950->u.scanRequest;
95         //package.request() = gdu;
96     } 
97     package.move();
98 }
99
100
101 void yf::QueryRewrite::Rep::rewriteRegex(Z_Query *query) const
102 {
103     std::string query_in = yp2::util::zQueryToString(query);
104     //std::cout << "QUERY IN  '" << query_in << "'\n";
105
106     std::string query_out;
107     
108     boost::regex rgx;
109     try{
110         // make regular expression replacement here 
111         std::string expression("@attr 1=4");
112         std::string format("@attr 1=4 @attr 4=3");
113         //std::string expression("the");
114         //std::string format("else");
115         //std::string expression("(<)|(>)|\\r");
116         //std::string format("(?1&lt;)(?2&gt;)");
117
118         //std::cout << "EXPRESSION  '" << expression << "'\n";
119         //std::cout << "FORMAT      '" << format << "'\n";
120
121         rgx.assign(expression.c_str());
122
123         bool match(false);
124         bool search(false);
125
126         // other flags
127         // see http://www.boost.org/libs/regex/doc/match_flag_type.html
128         //boost::match_flag_type flags = boost::match_default;
129         // boost::format_default
130         // boost::format_perl
131         // boost::format_literal
132         // boost::format_all
133         // boost::format_no_copy
134         // boost::format_first_only
135
136         boost::match_flag_type flags 
137             = boost::match_default | boost::format_all;
138
139         match = regex_match(query_in, rgx, flags);
140         search = regex_search(query_in, rgx, flags);
141         query_out = boost::regex_replace(query_in, rgx, format, flags);
142         //std::cout << "MATCH  '" << match <<  "'\n";
143         //std::cout << "SEARCH '" << search <<  "'\n";
144         //std::cout << "QUERY OUT '" << query_out << "'\n";
145
146     }
147     catch(boost::regex_error &e)
148     {
149         std::cout << "REGEX Error code=" << e.code() 
150                   << " position=" << e.position() << "\n";
151     }
152     
153     //std::cout << "QUERY OUT '" << query_out << "'\n";
154     // still need to fold this new rpn query string into Z_Query structure...
155 }
156
157
158
159 void yp2::filter::QueryRewrite::Rep::configure(const xmlNode *filter)
160 {
161
162     //std::cout << "XML node '" << filter->name << "'\n";
163     yp2::xml::check_element_yp2(filter, "filter");
164
165     const xmlNode* regex 
166         = yp2::xml::jump_to_children(filter, XML_ELEMENT_NODE);
167     
168     while (regex){
169         //std::cout << "XML node '" << regex->name << "'\n";
170         yp2::xml::check_element_yp2(regex, "regex");
171
172         // parsing action
173 //         const xmlNode* action 
174 //             = yp2::xml::jump_to_children(regex, XML_ATTRIBUTE_NODE);
175 //         if (action){
176 //             std::cout << "XML node '" << action->name << "' '";
177 //             std::cout << yp2::xml::get_text(action) << "'\n";
178 //             //yp2::xml::check_element_yp2(expression, "expression");
179 //         }
180
181         // parsing regex expression
182         std::string expr;
183         const xmlNode* expression 
184             = yp2::xml::jump_to_children(regex, XML_ELEMENT_NODE);
185         if (expression){
186             yp2::xml::check_element_yp2(expression, "expression");
187             expr = yp2::xml::get_text(expression);
188             //std::cout << "XML node '" << expression->name << "' '";
189             //std::cout << yp2::xml::get_text(expression) << "'\n";
190         }
191         
192         // parsing regex format
193         std::string form;
194         const xmlNode* format
195             =  yp2::xml::jump_to_next(expression, XML_ELEMENT_NODE);
196         if (format){
197             yp2::xml::check_element_yp2(format, "format");
198             form = yp2::xml::get_text(format);
199             //std::cout << "XML node '" << format->name << "' '";
200             //std::cout << yp2::xml::get_text(format) << "'\n";
201         }
202
203         // adding configuration
204         if (expr.size() && form.size()){
205             //std::cout << "adding regular expression\n";
206         }
207
208         // moving forward to next regex
209         regex = yp2::xml::jump_to_next(regex, XML_ELEMENT_NODE);
210     }
211     
212     // done parsing XML config
213     
214 }
215
216 static yp2::filter::Base* filter_creator()
217 {
218     return new yp2::filter::QueryRewrite;
219 }
220
221 extern "C" {
222     struct yp2_filter_struct yp2_filter_query_rewrite = {
223         0,
224         "query-rewrite",
225         filter_creator
226     };
227 }
228
229 extern "C" {
230     extern struct yp2_filter_struct yp2_filter_query_rewrite;
231 }
232
233
234 /*
235  * Local variables:
236  * c-basic-offset: 4
237  * indent-tabs-mode: nil
238  * c-file-style: "stroustrup"
239  * End:
240  * vim: shiftwidth=4 tabstop=8 expandtab
241  */