source: gsdl/trunk/runtime-src/src/colservr/collectserver.cpp@ 20799

Last change on this file since 20799 was 20799, checked in by ak19, 15 years ago

The wiki page on Authentication had a typo: authen_groups instead of the authen_group that the Greenstone server was expecting. Dr Bainbridge corrected this in the code which now 1. accepts both authen_group and authen_groups; 2. collectinfo struct is zeroed (cleared) in the constructor so it has no random values.

  • Property svn:keywords set to Author Date Id Revision
File size: 17.5 KB
Line 
1
2/**********************************************************************
3 *
4 * collectserver.cpp --
5 * Copyright (C) 1999 The New Zealand Digital Library Project
6 *
7 * A component of the Greenstone digital library software
8 * from the New Zealand Digital Library Project at the
9 * University of Waikato, New Zealand.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 *********************************************************************/
26
27#include "collectserver.h"
28#include "OIDtools.h"
29#include <assert.h>
30#include "display.h"
31
32
33collectserver::collectserver ()
34 : collectinfo()
35{
36 configinfo.collection = "null";
37}
38
39collectserver::~collectserver () {
40
41 // clean up the sources
42 sourcelistclass::iterator source_here = sources.begin();
43 sourcelistclass::iterator source_end = sources.end();
44 while (source_here != source_end) {
45 if ((*source_here).s != NULL)
46 delete (*source_here).s;
47 ++source_here;
48 }
49 sources.clear();
50
51 // clean up the filters
52 filtermapclass::iterator filter_here = filters.begin();
53 filtermapclass::iterator filter_end = filters.end();
54 while (filter_here != filter_end) {
55 if ((*filter_here).second.f != NULL)
56 delete (*filter_here).second.f;
57 ++filter_here;
58 }
59 filters.clear();
60}
61
62// configure should be called for each line in the
63// configuration files to configure the collection server and everything
64// it contains. The configuration should take place just before initialisation
65void collectserver::configure (const text_t &key, const text_tarray &cfgline) {
66 if (cfgline.size() >= 1) {
67 const text_t &value = cfgline[0];
68 if (key == "plugin")
69 {
70 //get the plugin name
71 const text_t &name = cfgline[0];
72
73 if (name == "HTMLPlugin")
74 {
75 for (int hI = 1; hI < cfgline.size(); hI++)
76 {
77 const text_t &plugOption = cfgline[hI];
78
79 if (plugOption == "-use_realistic_book")
80 {
81 collectinfo.useBook = true;
82 break;
83 }
84 }
85 }
86 }
87 else if (key == "gsdlhome") configinfo.gsdlhome = value;
88 else if (key == "gdbmhome") configinfo.dbhome = value;
89 else if (key == "collecthome") configinfo.collecthome = value;
90 else if (key == "collection") {
91 configinfo.collection = value;
92 collectinfo.shortInfo.name = value;
93 }
94 else if (key == "collectdir") configinfo.collectdir = value;
95 else if (key == "host") collectinfo.shortInfo.host = value;
96 else if (key == "port") collectinfo.shortInfo.port = value.getint();
97 else if (key == "public") {
98 if (value == "true") collectinfo.isPublic = true;
99 else collectinfo.isPublic = false;
100 } else if (key == "beta") {
101 if (value == "true") collectinfo.isBeta = true;
102 else collectinfo.isBeta = false;
103 } else if (key == "collectgroup") {
104 if (value == "true") collectinfo.isCollectGroup = true;
105 else collectinfo.isCollectGroup = false;
106 } else if ((key == "ccscols") || (key == "supercollection")) collectinfo.ccsCols = cfgline;
107 else if (key == "supercollectionoptions") {
108 text_tarray::const_iterator begin = cfgline.begin();
109 text_tarray::const_iterator end = cfgline.end();
110 while(begin != end) {
111
112 if (*begin == "uniform_search_results_formatting") {
113 collectinfo.ccsOptions |= CCSUniformSearchResultsFormatting;
114 }
115 begin++;
116 }
117 }
118 else if (key == "builddate") collectinfo.buildDate = value.getint();
119 else if (key == "languages") collectinfo.languages = cfgline;
120 else if (key == "numdocs") collectinfo.numDocs = value.getint();
121 else if (key == "numsections") collectinfo.numSections = value.getint();
122 else if (key == "numwords") collectinfo.numWords = value.getint();
123 else if (key == "numbytes") collectinfo.numBytes = value.getint();
124 else if (key == "stemindexes") collectinfo.stemIndexes = value.getint();
125 else if (key == "collectionmeta") {
126 // genuine collmeta get added as collectionmeta and collection_macros
127 // .collmeta just get added as collection_macros
128 text_t params;
129 if (cfgline.size() == 3) {
130 // get the params for later
131 text_t::const_iterator first=cfgline[1].begin()+1;
132 text_t::const_iterator last=cfgline[1].end()-1;
133 params=substr(first, last);
134 }
135
136 text_t meta_name = cfgline[0];
137 if (*(meta_name.begin())=='.') {
138 // a .xxx collectionmeta. strip off the . and
139 // look it up in the indexmap to get the actual value
140
141 text_t name = substr(cfgline[0].begin()+1,cfgline[0].end());
142 text_t new_name;
143 if (indexmap.from2to(name, new_name)) {
144 meta_name = new_name;
145 }
146 } else {
147 // add them to collectionmeta
148 text_tmap lang_map = collectinfo.collectionmeta[cfgline[0]];
149 if (cfgline.size() == 2) {
150 lang_map[g_EmptyText] = cfgline[1];
151 } else if (cfgline.size() == 3 ) {
152 // get the lang out of params
153 paramhashtype params_hash;
154 splitparams(params, params_hash);
155
156 text_t lang = params_hash["l"];
157 lang_map[lang] = cfgline[2];
158 if (lang_map[g_EmptyText].empty()) {
159 // want the first one as the default if no default specified
160 lang_map[g_EmptyText] = cfgline[2];
161 }
162 }
163 collectinfo.collectionmeta[cfgline[0]] = lang_map;
164
165 }
166
167 // add all collectionmeta to macro list
168 text_tmap params_map = collectinfo.collection_macros[meta_name];
169
170 if (cfgline.size() == 2) {// no params for this macro
171 params_map[g_EmptyText] = cfgline[1];
172 }
173 else if (cfgline.size() == 3) {// has params
174 params_map[params] = cfgline[2];
175 if (params_map[g_EmptyText].empty()) {
176 params_map[g_EmptyText] = cfgline[2];
177 }
178 }
179 collectinfo.collection_macros[meta_name] = params_map;
180 }
181 else if (key == "collectionmacro") {
182 text_t nobrackets;
183 text_tmap params_map = collectinfo.collection_macros[cfgline[0]];
184 // add all to macro list
185 if (cfgline.size() == 2) { // no params for this macro
186 params_map[g_EmptyText] = cfgline[1];
187 }
188 else if (cfgline.size() == 3) {// has params
189 // strip [ ] brackets from params
190 text_t::const_iterator first=cfgline[1].begin()+1;
191 text_t::const_iterator last=cfgline[1].end()-1;
192 nobrackets=substr(first, last);
193 params_map[nobrackets] = cfgline[2];
194 }
195 collectinfo.collection_macros[cfgline[0]] = params_map;
196
197 } else if (key == "format" && cfgline.size() == 2)
198 collectinfo.format[cfgline[0]] = cfgline[1];
199 else if (key == "building" && cfgline.size() == 2)
200 collectinfo.building[cfgline[0]] = cfgline[1];
201 else if (key == "httpdomain") collectinfo.httpdomain = value;
202 else if (key == "httpprefix") collectinfo.httpprefix = value;
203 else if (key == "receptionist") collectinfo.receptionist = value;
204 else if (key == "buildtype") collectinfo.buildType = value;
205 // backwards compatibility - searchytpes is now a format statement
206 else if (key == "searchtype") { // means buildtype is mgpp
207 if (collectinfo.buildType.empty()) {
208 collectinfo.buildType = "mgpp";
209 }
210 joinchar(cfgline, ',', collectinfo.format["SearchTypes"]);
211 //collectinfo.searchTypes = cfgline;
212 }
213 else if (key == "separate_cjk") {
214 if (value == "true") collectinfo.isSegmented = true;
215 else collectinfo.isSegmented = false;
216 }
217 // What have we set in our collect.cfg file : document or collection ?
218 else if (key == "authenticate") collectinfo.authenticate = value;
219
220 // What have we set for our group list
221 else if ((key == "auth_group") || (key == "auth_groups")) joinchar(cfgline,',',collectinfo.auth_group);
222
223 // store all the mappings for use when collection meta is read later
224 // (build.cfg read before collect.cfg)
225 else if (key == "indexmap" || key == "indexfieldmap" || key == "subcollectionmap" || key == "languagemap" || key == "levelmap") {
226 indexmap.importmap (cfgline, true);
227
228 }
229 // In the map the key-value pair contain the same
230 // data i.e key == data, if key is 2 then data is 2
231
232 // What have we set for our public_documents ACL
233 else if (key == "public_documents")
234 {
235 text_tarray::const_iterator begin = cfgline.begin();
236 text_tarray::const_iterator end = cfgline.end();
237 while(begin != end)
238 {
239 // key = data i.e if key is 2 then data is 2
240 // collectinfo.public_documents[*begin] is the key
241 // *begin is the data value
242
243 collectinfo.public_documents[*begin] = *begin;
244 ++begin;
245 }
246 }
247
248 // What have we set for our private_documents ACL
249 else if (key == "private_documents")
250 {
251 text_tarray::const_iterator begin = cfgline.begin();
252 text_tarray::const_iterator end = cfgline.end();
253 while(begin != end)
254 {
255 // key = data i.e if key is 2 then data is 2
256 // collectinfo.public_documents[*begin] is the key
257 // *begin is the data value
258
259 collectinfo.private_documents[*begin] = *begin;
260 ++begin;
261 }
262 }
263
264 // dynamic_classifier <UniqueID> "<Options>"
265 else if (key == "dynamic_classifier")
266 {
267 collectinfo.dynamic_classifiers[cfgline[0]] = cfgline[1];
268 }
269 }
270
271 // configure the filters
272 filtermapclass::iterator filter_here = filters.begin();
273 filtermapclass::iterator filter_end = filters.end();
274 while (filter_here != filter_end) {
275 assert ((*filter_here).second.f != NULL);
276 if ((*filter_here).second.f != NULL)
277 (*filter_here).second.f->configure(key, cfgline);
278
279 ++filter_here;
280 }
281
282 // configure the sources
283 sourcelistclass::iterator source_here = sources.begin();
284 sourcelistclass::iterator source_end = sources.end();
285 while (source_here != source_end) {
286 assert ((*source_here).s != NULL);
287 if ((*source_here).s != NULL)
288 (*source_here).s->configure(key, cfgline);
289
290 ++source_here;
291 }
292}
293
294
295void collectserver::configure (const text_t &key, const text_t &value) {
296 text_tarray cfgline;
297 cfgline.push_back (value);
298 configure(key, cfgline);
299}
300
301void collectserver::ping (bool &wasSuccess, comerror_t &error, ostream &logout) {
302 // if we've not been properly configured, then it is a foregone
303 // conclusion that we cannot be active
304 if (this->configinfo.collection == "null")
305 {
306 wasSuccess = false;
307 }
308 // if no build date exists, then the collection was probably not built;
309 // ditto if the number of documents is zero, then something is pretty
310 // wrong
311 else if (this->collectinfo.buildDate == 0 ||
312 this->collectinfo.numDocs == 0)
313 {
314 wasSuccess = false;
315 }
316 // it is probably okay
317 else
318 wasSuccess = true;
319}
320
321
322bool collectserver::init (ostream &logout) {
323 // delete the indexmap
324 indexmap.clear();
325
326 // init the filters
327 filtermapclass::iterator filter_here = filters.begin();
328 filtermapclass::iterator filter_end = filters.end();
329 while (filter_here != filter_end) {
330 assert ((*filter_here).second.f != NULL);
331 if (((*filter_here).second.f != NULL) &&
332 !(*filter_here).second.f->init(logout)) return false;
333
334 ++filter_here;
335 }
336
337 // init the sources
338 sourcelistclass::iterator source_here = sources.begin();
339 sourcelistclass::iterator source_end = sources.end();
340 while (source_here != source_end) {
341 assert ((*source_here).s != NULL);
342 if (((*source_here).s != NULL) &&
343 !(*source_here).s->init(logout)) return false;
344
345 ++source_here;
346 }
347
348 return true;
349}
350
351
352void collectserver::get_collectinfo (ColInfoResponse_t &reponse,
353 comerror_t &err, ostream &/*logout*/) {
354 reponse = collectinfo;
355 err = noError;
356}
357
358void collectserver::get_filterinfo (InfoFiltersResponse_t &response,
359 comerror_t &err, ostream &/*logout*/) {
360 response.clear ();
361
362 // get a list of filter names
363 filtermapclass::iterator filter_here = filters.begin();
364 filtermapclass::iterator filter_end = filters.end();
365 while (filter_here != filter_end) {
366 response.filterNames.insert ((*filter_here).first);
367 ++filter_here;
368 }
369
370 err = noError;
371}
372
373void collectserver::get_filteroptions (const InfoFilterOptionsRequest_t &request,
374 InfoFilterOptionsResponse_t &response,
375 comerror_t &err, ostream &logout) {
376 outconvertclass text_t2ascii;
377
378 filterclass *thisfilter = filters.getfilter(request.filterName);
379 if (thisfilter != NULL) {
380 thisfilter->get_filteroptions (response, err, logout);
381 } else {
382 response.clear ();
383 err = protocolError;
384 logout << text_t2ascii << "Protocol Error: filter options requested for non-existent\n"
385 << "filter \"" << request.filterName << "\".\n\n";
386 }
387}
388
389void collectserver::filter (FilterRequest_t &request,
390 FilterResponse_t &response,
391 comerror_t &err, ostream &logout) {
392 outconvertclass text_t2ascii;
393
394 // translate any ".fc", ".pr" etc. stuff in the docSet
395 text_t translatedOID;
396 text_tarray translatedOIDs;
397 text_tarray::iterator doc_here = request.docSet.begin();
398 text_tarray::iterator doc_end = request.docSet.end();
399 while (doc_here != doc_end) {
400 if (needs_translating (*doc_here)) {
401 sourcelistclass::iterator source_here = sources.begin();
402 sourcelistclass::iterator source_end = sources.end();
403 while (source_here != source_end) {
404 assert ((*source_here).s != NULL);
405 if (((*source_here).s != NULL) &&
406 ((*source_here).s->translate_OID (*doc_here, translatedOID, err, logout))) {
407 if (err != noError) return;
408 break;
409 }
410 ++source_here;
411 }
412 translatedOIDs.push_back (translatedOID);
413 } else {
414 translatedOIDs.push_back (*doc_here);
415 }
416 ++doc_here;
417 }
418 request.docSet = translatedOIDs;
419
420 response.clear();
421
422 filterclass *thisfilter = filters.getfilter(request.filterName);
423 if (thisfilter != NULL) {
424 // filter the data
425 thisfilter->filter (request, response, err, logout);
426 if (err != noError) return;
427 // fill in the metadata for each of the OIDs (if it is requested)
428 if (request.filterResultOptions & FRmetadata) {
429 bool processed = false;
430 ResultDocInfo_tarray::iterator resultdoc_here = response.docInfo.begin();
431 ResultDocInfo_tarray::iterator resultdoc_end = response.docInfo.end();
432 while (resultdoc_here != resultdoc_end) {
433 // try each of the sources in turn
434 sourcelistclass::iterator source_here = sources.begin();
435 sourcelistclass::iterator source_end = sources.end();
436 while (source_here != source_end) {
437 assert ((*source_here).s != NULL);
438 if (((*source_here).s != NULL) &&
439 ((*source_here).s->get_metadata(request.requestParams, request.refParams,
440 request.getParents, request.fields,
441 (*resultdoc_here).OID, (*resultdoc_here).metadata,
442 err, logout))) {
443 if (err != noError) return;
444 processed = true;
445 break;
446 }
447 ++source_here;
448 }
449 if (!processed) {
450
451 logout << text_t2ascii << "Protocol Error: nothing processed for "
452 << "filter \"" << request.filterName << "\".\n\n";
453
454 err = protocolError;
455 return;
456 }
457 ++resultdoc_here;
458 }
459 }
460
461 err = noError;
462 }
463 else
464 {
465 response.clear ();
466 err = protocolError;
467 logout << text_t2ascii << "Protocol Error: filter options requested for non-existent\n"
468 << "filter \"" << request.filterName << "\".\n\n";
469 }
470}
471
472void collectserver::get_document (const DocumentRequest_t &request,
473 DocumentResponse_t &response,
474 comerror_t &err, ostream &logout) {
475
476 sourcelistclass::iterator source_here = sources.begin();
477 sourcelistclass::iterator source_end = sources.end();
478 while (source_here != source_end) {
479 assert ((*source_here).s != NULL);
480 if (((*source_here).s != NULL) &&
481 ((*source_here).s->get_document (request.OID, response.doc, err, logout))) {
482 if (err != noError) return;
483 break;
484 }
485 ++source_here;
486 }
487}
488
489void collectserver::is_searchable (bool &issearchable, comerror_t &err,
490 ostream &logout) {
491
492 sourcelistclass::iterator source_here = sources.begin();
493 sourcelistclass::iterator source_end = sources.end();
494 while (source_here != source_end) {
495 assert ((*source_here).s != NULL);
496 if (((*source_here).s != NULL) &&
497 ((*source_here).s->is_searchable (issearchable, err, logout))) {
498 if (err != noError) return;
499 break;
500 }
501 ++source_here;
502 }
503}
504
505
506bool operator==(const collectserverptr &x, const collectserverptr &y) {
507 return (x.c == y.c);
508}
509
510bool operator<(const collectserverptr &x, const collectserverptr &y) {
511 return (x.c < y.c);
512}
513
514
515// thecollectserver remains the property of the calling code but
516// should not be deleted until it is removed from this list.
517void collectservermapclass::addcollectserver (collectserver *thecollectserver) {
518 // can't add a null collection server
519 assert (thecollectserver != NULL);
520 if (thecollectserver == NULL) return;
521
522 // can't add an collection server with no collection name
523 assert (!(thecollectserver->get_collection_name()).empty());
524 if ((thecollectserver->get_collection_name()).empty()) return;
525
526 collectserverptr cptr;
527 cptr.c = thecollectserver;
528 collectserverptrs[thecollectserver->get_collection_name()] = cptr;
529}
530
531// getcollectserver will return NULL if the collectserver could not be found
532collectserver *collectservermapclass::getcollectserver (const text_t &collection) {
533 // can't find a collection with no name
534 if (collection.empty()) return NULL;
535
536 iterator here = collectserverptrs.find (collection);
537 if (here == collectserverptrs.end()) return NULL;
538
539 return (*here).second.c;
540}
Note: See TracBrowser for help on using the repository browser.