metaproxy 1.22.1
filter_cql_rpn.cpp
Go to the documentation of this file.
1/* This file is part of Metaproxy.
2 Copyright (C) Index Data
3
4Metaproxy is free software; you can redistribute it and/or modify it under
5the terms of the GNU General Public License as published by the Free
6Software Foundation; either version 2, or (at your option) any later
7version.
8
9Metaproxy is distributed in the hope that it will be useful, but WITHOUT ANY
10WARRANTY; without even the implied warranty of MERCHANTABILITY or
11FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program; if not, write to the Free Software
16Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17*/
18
19#include "config.hpp"
20#include <metaproxy/util.hpp>
21
22#include <metaproxy/filter.hpp>
23#include <metaproxy/package.hpp>
24
25#include "filter_cql_rpn.hpp"
26
27#include <yazpp/z-query.h>
28#include <yaz/cql.h>
29#include <yazpp/cql2rpn.h>
30#include <yaz/zgdu.h>
31#include <yaz/diagbib1.h>
32#include <yaz/srw.h>
33#include <yaz/tpath.h>
34#include <yaz/oid_std.h>
35
36namespace mp = metaproxy_1;
37namespace yf = metaproxy_1::filter;
38
39namespace metaproxy_1 {
40 namespace filter {
42 public:
43 Impl();
44 ~Impl();
45 void process(metaproxy_1::Package & package);
46 void configure(const xmlNode *ptr, const char *path);
47 private:
48 yazpp_1::Yaz_cql2rpn m_cql2rpn;
49 bool reverse;
50 };
51 }
52}
53
54
55// define Pimpl wrapper forwarding to Impl
56
57yf::CQLtoRPN::CQLtoRPN() : m_p(new Impl)
58{
59}
60
61yf::CQLtoRPN::~CQLtoRPN()
62{ // must have a destructor because of boost::scoped_ptr
63}
64
65void yf::CQLtoRPN::configure(const xmlNode *xmlnode, bool test_only,
66 const char *path)
67{
68 m_p->configure(xmlnode, path);
69}
70
71void yf::CQLtoRPN::process(mp::Package &package) const
72{
73 m_p->process(package);
74}
75
76
77// define Implementation stuff
78
79yf::CQLtoRPN::Impl::Impl() : reverse(false)
80{
81}
82
83yf::CQLtoRPN::Impl::~Impl()
84{
85}
86
87void yf::CQLtoRPN::Impl::configure(const xmlNode *xmlnode, const char *path)
88{
89 int no_conversions = 0;
90 for (const xmlNode *node = xmlnode->children; node; node = node->next)
91 {
92 if (node->type != XML_ELEMENT_NODE)
93 continue;
94 if (strcmp((const char *) node->name, "conversion"))
95 {
96 throw mp::filter::FilterException("Bad element "
97 + std::string((const char *)
98 node->name));
99 }
100 const struct _xmlAttr *attr;
101 for (attr = node->properties; attr; attr = attr->next)
102 {
103 if (!strcmp((const char *) attr->name, "file"))
104 {
105 std::string fname = mp::xml::get_text(attr);
106 char fullpath[1024];
107 if (!yaz_filepath_resolve(fname.c_str(), path, 0, fullpath))
108 throw mp::filter::FilterException("Could not open " + fname);
109 int error = 0;
110 if (!m_cql2rpn.parse_spec_file(fullpath, &error))
111 {
112 throw mp::filter::FilterException("Bad or missing "
113 "CQL to RPN configuration "
114 + fname);
115 }
116 no_conversions++;
117 }
118 else if (!strcmp((const char *) attr->name, "key"))
119 {
120 std::string key = mp::xml::get_text(attr);
121 std::string val = mp::xml::get_text(node);
122 if (m_cql2rpn.define_pattern(key.c_str(), val.c_str()))
123 throw mp::filter::FilterException(
124 "Bad CQL to RPN pattern: " + key + "=" + val);
125 no_conversions++;
126 }
127 else if (!strcmp((const char *) attr->name, "reverse"))
128 {
129 reverse = mp::xml::get_bool(attr->children, 0);
130 }
131 else
132 throw mp::filter::FilterException(
133 "Bad attribute " + std::string((const char *)
134 attr->name));
135 }
136 }
137 if (no_conversions == 0)
138 {
139 throw mp::filter::FilterException("Missing conversion configuration "
140 "for filter cql_rpn");
141 }
142}
143
144void yf::CQLtoRPN::Impl::process(mp::Package &package)
145{
146 Z_GDU *gdu = package.request().get();
147
148 if (gdu && gdu->which == Z_GDU_Z3950 && gdu->u.z3950->which ==
149 Z_APDU_searchRequest)
150 {
151 Z_APDU *apdu_req = gdu->u.z3950;
152 Z_SearchRequest *sr = gdu->u.z3950->u.searchRequest;
153 if (reverse && sr->query && sr->query->which == Z_Query_type_1)
154 {
155 char *addinfo = 0;
156 mp::odr odr;
157 WRBUF cql = wrbuf_alloc();
158
159 int r = m_cql2rpn.rpn2cql_transform(sr->query->u.type_1, cql,
160 odr, &addinfo);
161 if (r)
162 {
163 Z_APDU *f_apdu =
164 odr.create_searchResponse(apdu_req, r, addinfo);
165 package.response() = f_apdu;
166 return;
167 }
168 else
169 {
170 Z_External *ext = (Z_External *)
171 odr_malloc(odr, sizeof(*ext));
172 ext->direct_reference = odr_oiddup(odr,
173 yaz_oid_userinfo_cql);
174 ext->indirect_reference = 0;
175 ext->descriptor = 0;
176 ext->which = Z_External_CQL;
177 ext->u.cql = odr_strdup(odr, wrbuf_cstr(cql));
178
179 sr->query->which = Z_Query_type_104;
180 sr->query->u.type_104 = ext;
181
182 package.request() = gdu;
183 }
184 wrbuf_destroy(cql);
185 }
186 if (!reverse && sr->query && sr->query->which == Z_Query_type_104 &&
187 sr->query->u.type_104->which == Z_External_CQL)
188 {
189 char *addinfo = 0;
190 Z_RPNQuery *rpnquery = 0;
191 mp::odr odr;
192
193 int r = m_cql2rpn.query_transform(sr->query->u.type_104->u.cql,
194 &rpnquery, odr,
195 &addinfo);
196 if (r == -3)
197 {
198 Z_APDU *f_apdu =
199 odr.create_searchResponse(
200 apdu_req,
201 YAZ_BIB1_PERMANENT_SYSTEM_ERROR,
202 "cql_rpn: missing CQL to RPN configuration");
203 package.response() = f_apdu;
204 return;
205 }
206 else if (r)
207 {
208 int error_code = yaz_diag_srw_to_bib1(r);
209
210 Z_APDU *f_apdu =
211 odr.create_searchResponse(apdu_req, error_code, addinfo);
212 package.response() = f_apdu;
213 return;
214 }
215 else
216 { // conversion OK
217
218 sr->query->which = Z_Query_type_1;
219 sr->query->u.type_1 = rpnquery;
220 package.request() = gdu;
221 }
222 }
223 }
224 package.move();
225}
226
227
228static mp::filter::Base* filter_creator()
229{
230 return new mp::filter::CQLtoRPN;
231}
232
233extern "C" {
234 struct metaproxy_1_filter_struct metaproxy_1_filter_cql_rpn = {
235 0,
236 "cql_rpn",
238 };
239}
240
241/*
242 * Local variables:
243 * c-basic-offset: 4
244 * c-file-style: "Stroustrup"
245 * indent-tabs-mode: nil
246 * End:
247 * vim: shiftwidth=4 tabstop=8 expandtab
248 */
249
void process(metaproxy_1::Package &package)
void configure(const xmlNode *ptr, const char *path)
static mp::filter::Base * filter_creator()
struct metaproxy_1_filter_struct metaproxy_1_filter_cql_rpn