source: trunk/gsdl/src/colservr/collectserver.cpp@ 10021

Last change on this file since 10021 was 9934, checked in by kjdon, 19 years ago

added level map to the list of mapping cfg lines to process

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