3844e0d74066086442b02cd279b6228d3f0e4794
[metaproxy-moved-to-github.git] / src / filter_cql_to_rpn.cpp
1 /* $Id: filter_cql_to_rpn.cpp,v 1.5 2007-01-16 09:04:54 marc Exp $
2    Copyright (c) 2005-2006, Index Data.
3
4    See the LICENSE file for details
5  */
6
7 #include "config.hpp"
8 #include "util.hpp"
9
10 #include "filter.hpp"
11 #include "package.hpp"
12
13 #include "filter_cql_to_rpn.hpp"
14
15 #include <yazpp/z-query.h>
16 #include <yaz/cql.h>
17 #include <yazpp/cql2rpn.h>
18 #include <yaz/zgdu.h>
19 #include <yaz/diagbib1.h>
20 #include <yaz/srw.h>
21
22
23 namespace mp = metaproxy_1;
24 namespace yf = metaproxy_1::filter;
25
26 namespace metaproxy_1 {
27     namespace filter {
28         class CQLtoRPN::Impl {
29         public:
30             Impl();
31             ~Impl();
32             void process(metaproxy_1::Package & package);
33             void configure(const xmlNode * ptr);
34         private:
35             yazpp_1::Yaz_cql2rpn m_cql2rpn;
36         };
37     }
38 }
39
40
41 // define Pimpl wrapper forwarding to Impl
42  
43 yf::CQLtoRPN::CQLtoRPN() : m_p(new Impl)
44 {
45 }
46
47 yf::CQLtoRPN::~CQLtoRPN()
48 {  // must have a destructor because of boost::scoped_ptr
49 }
50
51 void yf::CQLtoRPN::configure(const xmlNode *xmlnode)
52 {
53     m_p->configure(xmlnode);
54 }
55
56 void yf::CQLtoRPN::process(mp::Package &package) const
57 {
58     m_p->process(package);
59 }
60
61
62 // define Implementation stuff
63
64 yf::CQLtoRPN::Impl::Impl()
65 {
66 }
67
68 yf::CQLtoRPN::Impl::~Impl()
69
70 }
71
72 void yf::CQLtoRPN::Impl::configure(const xmlNode *xmlnode)
73 {
74
75     /*
76       <filter type="cql_rpn">
77       <conversion file="pqf.properties"/>
78       </filter>
79     */
80     
81     std::string fname;
82     for (xmlnode = xmlnode->children; xmlnode; xmlnode = xmlnode->next)
83     {
84         if (xmlnode->type != XML_ELEMENT_NODE)
85             continue;
86         if (!strcmp((const char *) xmlnode->name, "conversion"))
87         {
88             const struct _xmlAttr *attr;
89             for (attr = xmlnode->properties; attr; attr = attr->next)
90             {
91                 if (!strcmp((const char *) attr->name, "file"))
92                     fname = mp::xml::get_text(attr);
93                 else
94                     throw mp::filter::FilterException(
95                         "Bad attribute " + std::string((const char *)
96                                                        attr->name));
97             }
98         }
99         else
100         {
101             throw mp::filter::FilterException("Bad element " 
102                                                + std::string((const char *)
103                                                              xmlnode->name));
104         }
105     }
106     if (fname.length() == 0)
107     {
108         throw mp::filter::FilterException("Missing conversion configuration "
109                                           "for filter cql_rpn");
110     }
111
112     int error = 0;
113     if (!m_cql2rpn.parse_spec_file(fname.c_str(), &error))
114     {
115         throw mp::filter::FilterException("Bad or missing "
116                                           "CQL to RPN configuration "
117                                           + fname);
118     }
119 }
120
121 void yf::CQLtoRPN::Impl::process(mp::Package &package)
122 {
123     Z_GDU *gdu = package.request().get();
124
125     if (gdu && gdu->which == Z_GDU_Z3950 && gdu->u.z3950->which ==
126         Z_APDU_searchRequest)
127     {
128         Z_APDU *apdu_req = gdu->u.z3950;
129         Z_SearchRequest *sr = gdu->u.z3950->u.searchRequest;
130         if (sr->query && sr->query->which == Z_Query_type_104 &&
131             sr->query->u.type_104->which == Z_External_CQL)
132         {
133             char *addinfo = 0;
134             Z_RPNQuery *rpnquery = 0;
135             mp::odr odr;
136             
137             int r = m_cql2rpn.query_transform(sr->query->u.type_104->u.cql,
138                                                  &rpnquery, odr,
139                                                  &addinfo);
140             if (r == -3)
141             {
142                 Z_APDU *f_apdu = 
143                     odr.create_searchResponse(
144                         apdu_req, 
145                         YAZ_BIB1_TEMPORARY_SYSTEM_ERROR,
146                         "Missing CQL to RPN configuration");
147                 package.response() = f_apdu;
148                 return;
149             }
150             else if (r)
151             {
152                 int error_code = yaz_diag_srw_to_bib1(r);
153
154                 Z_APDU *f_apdu = 
155                     odr.create_searchResponse(apdu_req, error_code, addinfo);
156                 package.response() = f_apdu;
157                 return;
158             }
159             else
160             {   // conversion OK
161                 
162                 sr->query->which = Z_Query_type_1;
163                 sr->query->u.type_1 = rpnquery;
164                 package.request() = gdu;
165             }
166         }
167     }
168     package.move();
169 }
170
171
172 static mp::filter::Base* filter_creator()
173 {
174     return new mp::filter::CQLtoRPN;
175 }
176
177 extern "C" {
178     struct metaproxy_1_filter_struct metaproxy_1_filter_cql_to_rpn = {
179         0,
180         "cql_rpn",
181         filter_creator
182     };
183 }
184
185 /*
186  * Local variables:
187  * c-basic-offset: 4
188  * indent-tabs-mode: nil
189  * c-file-style: "stroustrup"
190  * End:
191  * vim: shiftwidth=4 tabstop=8 expandtab
192  */