e113a21c0699ed65eb264f8dc868a1d0876d4572
[yazproxy-moved-to-github.git] / src / p2_msg.cpp
1 /* $Id: p2_msg.cpp,v 1.1 2005-10-05 12:07:14 adam Exp $
2    Copyright (c) 1998-2005, Index Data.
3
4 This file is part of the yaz-proxy.
5
6 YAZ proxy is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 2, or (at your option) any later
9 version.
10
11 YAZ proxy is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with YAZ proxy; see the file LICENSE.  If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
19 02111-1307, USA.
20  */
21
22 #include <yaz/log.h>
23 #include <yaz/diagbib1.h>
24 #include "p2_backend.h"
25 #include "p2_frontend.h"
26 #include "p2_config.h"
27 #include "p2_modules.h"
28
29 using namespace yazpp_1;
30 using namespace std;
31
32 IP2_BackendSet::~IP2_BackendSet()
33 {
34 }
35
36 IP2_Backend::~IP2_Backend()
37 {
38
39 }
40
41 P2_Backend::P2_Backend(P2_ConfigTarget *cfg, IP2_Backend *backend_int)
42 {
43     m_configTarget = new P2_ConfigTarget;
44     *m_configTarget = *cfg;
45     m_busy = false;
46     m_int = backend_int;
47 }
48
49 P2_Backend::~P2_Backend()
50 {
51     delete m_configTarget;
52 }
53
54 P2_BackendResultSet::P2_BackendResultSet()
55 {
56     m_int = 0;
57 }
58
59 P2_BackendResultSet::~P2_BackendResultSet()
60 {
61     delete m_int;
62 }
63
64 P2_Backend *P2_Msg::select_backend(string db,
65                                    Yaz_Z_Query *query,
66                                    P2_BackendResultSet **bset)
67 {
68     P2_Config *cfg = m_server->lockConfig();
69
70     // see if some target has done this query before
71
72     *bset = 0;
73     P2_Backend *backend = 0;
74
75     list<P2_Backend *>::const_iterator it;
76     for (it = m_server->m_backend_list.begin(); 
77          it != m_server->m_backend_list.end(); it++)
78     {
79         if ((*it)->m_busy)
80             continue;
81
82         if (db != (*it)->m_configTarget->m_virt_database)
83             continue;
84         backend = *it;
85
86         if (query)
87         {
88             list<P2_BackendResultSet *>::const_iterator is;
89             for (is  = (*it)->m_resultSets.begin(); 
90                  is != (*it)->m_resultSets.end(); is++)
91             {
92                 if (query->match(&(*is)->m_query))
93                 {
94                     *bset = *is;
95                     break;
96                 }
97             }
98         }
99         if (bset)
100             break;
101     }
102     if (!backend)
103     {
104         P2_ConfigTarget *target_cfg = cfg->find_target(db);
105
106         if (!target_cfg)
107         {
108             yaz_log(YLOG_WARN, "No backend for database %s",
109                     db.c_str());
110         }
111         else
112         {
113             P2_ModuleInterface0 *int0 =
114             reinterpret_cast<P2_ModuleInterface0 *>
115                 (m_server->m_modules->get_interface(target_cfg->m_type.c_str(),
116                                                     0));
117             IP2_Backend *bint = 0;
118
119             if (int0)
120                 bint = int0->create(target_cfg->m_target_address.c_str());
121
122             if (bint)
123                 backend = new P2_Backend(target_cfg, bint);
124
125             if (backend)
126                 m_server->m_backend_list.push_back(backend);
127         }
128     }
129     if (backend)
130         backend->m_busy = true;
131     m_server->unlockConfig();
132     return backend;
133 }
134
135 void P2_FrontResultSet::setQuery(Z_Query *z_query)
136 {
137     m_query.set_Z_Query(z_query);
138 }
139
140 void P2_FrontResultSet::setDatabases(char **db, int num)
141 {
142     m_db_list.clear();
143
144     int i;
145     for (i = 0; i<num; i++)
146         m_db_list.push_back(db[i]);
147 }
148
149 P2_FrontResultSet::P2_FrontResultSet(const char *id)
150 {
151     m_resultSetId = id;
152 }
153
154
155 P2_FrontResultSet::~P2_FrontResultSet()
156 {
157 }
158
159 P2_Msg::P2_Msg(GDU *gdu, P2_Frontend *front, P2_Server *server)
160 {
161     m_front = front;
162     m_server = server;
163     m_output = 0;
164     m_gdu = gdu;
165     m_close_flag = 0;
166 }
167
168 P2_Msg::~P2_Msg()
169 {
170     delete m_output;
171     delete m_gdu;
172 }
173
174 Z_APDU *P2_Msg::frontend_search_resultset(Z_APDU *z_gdu, ODR odr,
175                                           P2_FrontResultSet **rset)
176 {
177     Z_SearchRequest *req = z_gdu->u.searchRequest;
178     list<P2_FrontResultSet *>::iterator it;
179     P2_FrontResultSet *s = 0;
180
181     string id = req->resultSetName;
182     for (it = m_front->m_resultSets.begin(); it != m_front->m_resultSets.end(); it++)
183     {
184         if ((*it)->m_resultSetId == id)
185         {
186             s = *it;
187             break;
188         }
189     }
190     if (s)
191     {
192         // result set already exists
193         *rset = s;
194         if (req->replaceIndicator && *req->replaceIndicator)
195         {  // replace indicator true
196             s->setQuery(req->query);
197             s->setDatabases(req->databaseNames, req->num_databaseNames);
198             return 0;
199         }
200         Z_APDU *apdu = zget_APDU(odr, Z_APDU_searchResponse);
201         Z_Records *rec = (Z_Records *) odr_malloc(odr, sizeof(Z_Records));
202         apdu->u.searchResponse->records = rec;
203         rec->which = Z_Records_NSD;
204         rec->u.nonSurrogateDiagnostic =
205             zget_DefaultDiagFormat(
206                 odr, YAZ_BIB1_RESULT_SET_EXISTS_AND_REPLACE_INDICATOR_OFF,
207                 req->resultSetName);
208         
209         return apdu;
210     }
211     // does not exist 
212     s = new P2_FrontResultSet(req->resultSetName);
213     s->setQuery(req->query);
214     s->setDatabases(req->databaseNames, req->num_databaseNames);
215     m_front->m_resultSets.push_back(s);
216     *rset = s;
217     return 0;
218 }
219
220 Z_APDU *P2_Msg::frontend_search_apdu(Z_APDU *request_apdu, ODR odr)
221 {
222     P2_FrontResultSet *rset;
223     Z_APDU *response_apdu = frontend_search_resultset(request_apdu, odr,
224                                                       &rset);
225     if (response_apdu)
226         return response_apdu;
227
228     // no immediate error (yet) 
229     size_t i;
230     for (i = 0; i<rset->m_db_list.size(); i++)
231     {
232         string db = rset->m_db_list[i];
233         P2_BackendResultSet *bset;
234         P2_Backend *b = select_backend(db, &rset->m_query, &bset);
235         if (!b)
236         {
237             Z_APDU *apdu = zget_APDU(odr, Z_APDU_searchResponse);
238             Z_Records *rec = (Z_Records *) odr_malloc(odr, sizeof(Z_Records));
239             apdu->u.searchResponse->records = rec;
240             rec->which = Z_Records_NSD;
241             rec->u.nonSurrogateDiagnostic =
242                 zget_DefaultDiagFormat(
243                     odr, YAZ_BIB1_DATABASE_UNAVAILABLE, db.c_str());
244             return apdu;
245         }
246         if (!bset)
247         {   // new set 
248             bset = new P2_BackendResultSet();
249
250             bset->m_query.set_Z_Query(request_apdu->u.searchRequest->query);
251             bset->m_db_list.push_back(db);
252
253             b->m_int->search(&bset->m_query, &bset->m_int, &bset->m_hit_count);
254             b->m_resultSets.push_back(bset);
255         }
256         else
257         {
258             bset->m_int->get(1, 1);
259         }
260         response_apdu = zget_APDU(odr, Z_APDU_searchResponse);
261         *response_apdu->u.searchResponse->resultCount = bset->m_hit_count;
262         b->m_busy = false;
263     }
264     if (!response_apdu)
265     {
266         Z_APDU *apdu = zget_APDU(odr, Z_APDU_searchResponse);
267         Z_Records *rec = (Z_Records *) odr_malloc(odr, sizeof(Z_Records));
268         apdu->u.searchResponse->records = rec;
269             rec->which = Z_Records_NSD;
270             rec->u.nonSurrogateDiagnostic =
271                 zget_DefaultDiagFormat(odr, YAZ_BIB1_UNSUPP_SEARCH, 0);
272             return apdu;
273     }
274     return response_apdu;
275 }
276
277 Z_APDU *P2_Msg::frontend_present_resultset(Z_APDU *z_gdu, ODR odr,
278                                            P2_FrontResultSet **rset)
279 {
280     Z_PresentRequest *req = z_gdu->u.presentRequest;
281     list<P2_FrontResultSet *>::iterator it;
282     P2_FrontResultSet *s = 0;
283
284     string id = req->resultSetId;
285     for (it = m_front->m_resultSets.begin(); it != m_front->m_resultSets.end(); it++)
286     {
287         if ((*it)->m_resultSetId == id)
288         {
289             s = *it;
290             break;
291         }
292     }
293     *rset = s;
294     if (s)
295         return 0;  // fine result set exists 
296
297     Z_APDU *apdu = zget_APDU(odr, Z_APDU_presentResponse);
298     
299     Z_Records *rec = (Z_Records *) odr_malloc(odr, sizeof(Z_Records));
300     apdu->u.presentResponse->records = rec;
301     rec->which = Z_Records_NSD;
302     rec->u.nonSurrogateDiagnostic =
303         zget_DefaultDiagFormat(
304             odr,
305             YAZ_BIB1_SPECIFIED_RESULT_SET_DOES_NOT_EXIST,
306             req->resultSetId);
307     return apdu;
308 }
309
310 Z_APDU *P2_Msg::frontend_present_apdu(Z_APDU *request_apdu, ODR odr)
311 {
312     P2_FrontResultSet *rset;
313     Z_APDU *response_apdu = frontend_present_resultset(request_apdu, odr,
314                                                        &rset);
315     if (response_apdu)
316         return response_apdu;
317     return zget_APDU(odr, Z_APDU_presentResponse);
318 }
319     
320 IMsg_Thread *P2_Msg::handle()
321 {
322     ODR odr = odr_createmem(ODR_ENCODE);
323     yaz_log(YLOG_LOG, "P2_Msg:handle begin");
324     Z_GDU *request_gdu = m_gdu->get();
325
326     if (request_gdu->which == Z_GDU_Z3950)
327     {
328         Z_APDU *request_apdu = request_gdu->u.z3950;
329         Z_APDU *response_apdu = 0;
330         switch(request_apdu->which)
331         {
332         case Z_APDU_initRequest:
333             response_apdu = zget_APDU(odr, Z_APDU_initResponse);
334             ODR_MASK_SET(response_apdu->u.initResponse->options, Z_Options_triggerResourceCtrl);
335             ODR_MASK_SET(response_apdu->u.initResponse->options, Z_Options_search);
336             ODR_MASK_SET(response_apdu->u.initResponse->options, Z_Options_present);
337             ODR_MASK_SET(response_apdu->u.initResponse->options, Z_Options_namedResultSets);
338             break;
339         case Z_APDU_searchRequest:
340             response_apdu = frontend_search_apdu(request_apdu, odr);
341             break;
342         case Z_APDU_presentRequest:
343             response_apdu = frontend_present_apdu(request_apdu, odr);
344             break;
345         case Z_APDU_triggerResourceControlRequest:
346             break;
347         default:
348             response_apdu = zget_APDU(odr, Z_APDU_close);
349             m_close_flag = 1;
350             break;
351         }
352         if (response_apdu)
353             m_output = new GDU(response_apdu);
354     }
355     yaz_log(YLOG_LOG, "P2_Msg:handle end");
356     odr_destroy(odr);
357     return this;
358 }
359
360 void P2_Msg::result()
361 {
362     m_front->m_no_requests--;
363     if (!m_front->m_delete_flag)
364     {
365         if (m_output)
366         {
367             int len;
368             m_front->send_GDU(m_output->get(), &len);
369         }
370         if (m_close_flag)
371         {
372             m_front->close();
373             m_front->m_delete_flag = 1;
374         }
375     }
376     if (m_front->m_delete_flag && m_front->m_no_requests == 0)
377         delete m_front;
378     delete this;
379 }
380
381 /*
382  * Local variables:
383  * c-basic-offset: 4
384  * indent-tabs-mode: nil
385  * End:
386  * vim: shiftwidth=4 tabstop=8 expandtab
387  */