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