source: gsdl/trunk/runtime-src/src/colservr/collectset.cpp@ 19365

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

Dr Bainbridge fixed the bug that crashed server.exe when there's no MG built collection: mgsearch (and mgppsearch and lucenesearch) pointers weren't initialised to NULL in the constructors, yet they were tested against being NULL and then used.

  • Property svn:keywords set to Author Date Id Revision
File size: 14.7 KB
Line 
1/**********************************************************************
2 *
3 * collectset.cpp --
4 * Copyright (C) 1999 The New Zealand Digital Library Project
5 *
6 * A component of the Greenstone digital library software
7 * from the New Zealand Digital Library Project at the
8 * University of Waikato, New Zealand.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 *********************************************************************/
25
26
27#include "collectset.h"
28#include "collectserver.h"
29#include "colservrconfig.h"
30#include "gsdlsitecfg.h"
31#include "gdbmclass.h"
32#include "gsdltools.h"
33#include "fileutil.h"
34#include "filter.h"
35#include "browsefilter.h"
36#include "sqlbrowsefilter.h"
37#include "queryfilter.h"
38#include "mgqueryfilter.h"
39#include "mgppqueryfilter.h"
40#include "mgsource.h"
41#include "lucenequeryfilter.h"
42#include "lucenesource.h"
43
44#include <assert.h>
45
46#ifdef USE_SQLITE
47#include "sqlitedbclass.h"
48#endif
49
50#ifdef USE_MSSQL
51#include "mssqldbclass.h"
52#endif
53
54
55collectset::collectset (text_t& gsdlhome, text_t& collecthome)
56{
57 // gsdlhome and collecthome will be set as a result of calling this function
58 // collecthome will default to "<gsdlhome>/collect" if not explicitly
59 // specified in config file
60
61 text_tarray collections;
62
63 mgsearch = NULL;
64 mgppsearch = NULL;
65 lucenesearch = NULL;
66
67 // get gsdlhome (if we fail the error will be picked up later -- in
68 // cgiwrapper)
69
70 if (site_cfg_read (gsdlhome, collecthome, httpdomain, httpprefix)) {
71 if (!gsdlhome.empty() && directory_exists(gsdlhome)) {
72 if (read_dir (collecthome, collections)) {
73
74 text_tarray::const_iterator thiscol = collections.begin();
75 text_tarray::const_iterator endcol = collections.end();
76
77 while (thiscol != endcol) {
78 // ignore the modelcol
79 if (*thiscol == "modelcol") {
80 ++thiscol;
81 continue;
82 }
83
84 this->add_collection (*thiscol, gsdlhome, collecthome);
85
86 ++thiscol;
87 }
88
89 this->add_all_collection_groups(gsdlhome, collecthome);
90 }
91 }
92 }
93
94 set_gsdl_env_vars(gsdlhome);
95}
96
97
98collectset::collectset (text_t& httpprefix_arg)
99{
100 httpprefix = httpprefix_arg;
101
102 mgsearch = NULL;
103 mgppsearch = NULL;
104 lucenesearch = NULL;
105
106}
107
108collectset::collectset ()
109{
110 mgsearch = NULL;
111 mgppsearch = NULL;
112 lucenesearch = NULL;
113}
114
115collectset::~collectset () {
116 collectservermapclass::iterator here = cservers.begin();
117 collectservermapclass::iterator end = cservers.end();
118
119 while (here != end) {
120 if ((*here).second.c != NULL) {
121 delete (*here).second.c;
122 }
123 ++here;
124 }
125 cservers.clear();
126}
127
128bool collectset::init (ostream &logout) {
129 collectservermapclass::iterator here = cservers.begin();
130 collectservermapclass::iterator end = cservers.end();
131
132 while (here != end) {
133 assert ((*here).second.c != NULL);
134 if ((*here).second.c != NULL) {
135 const colservrconf &configinfo = (*here).second.c->get_configinfo ();
136
137 // configure this collection server
138
139 // note that we read build.cfg before collect.cfg so that the indexmaps
140 // are available to decode defaultindex, defaultsubcollection, and
141 // defaultlanguage
142
143 bool failed_build_cfg = false;
144 if (!build_cfg_read (*((*here).second.c), configinfo.gsdlhome,
145 configinfo.collecthome, configinfo.collection)) {
146 failed_build_cfg = true;
147
148 outconvertclass text_t2ascii;
149 logout << text_t2ascii
150 << "Warning: couldn't read build.cfg file for collection \""
151 << configinfo.collection << "\""
152 << " gsdlhome=\"" << configinfo.gsdlhome << "\"\n"
153 << " collecthome=\"" << configinfo.collecthome << "\"\n";
154 }
155
156 bool failed_collect_cfg = false;
157 if (!collect_cfg_read (*((*here).second.c), configinfo.gsdlhome,
158 configinfo.collecthome, configinfo.collection)) {
159 failed_collect_cfg = true;
160 outconvertclass text_t2ascii;
161 logout << text_t2ascii
162 << "Warning: couldn't read collect.cfg file for collection \""
163 << configinfo.collection << "\""
164 << " gsdlhome=\"" << configinfo.gsdlhome << "\"\n"
165 << " collecthome=\"" << configinfo.collecthome << "\"\n";
166 }
167
168
169 bool is_colgroup = (*here).second.c->is_collection_group();
170
171 if (failed_collect_cfg) {
172 ++here;
173 continue;
174 }
175
176 if (failed_build_cfg && (!is_colgroup)) {
177 ++here;
178 continue;
179 }
180 // let a failed build.cfg through if its 'collect.cfg' marks it as 'collectgroup true'
181
182 if (!(*here).second.c->init (logout)) return false;
183
184 (*here).second.c->configure("httpdomain",httpdomain);
185 (*here).second.c->configure("httpprefix",httpprefix);
186 }
187 ++here;
188 }
189
190 return true;
191}
192
193collectservermapclass collectset::servers()
194{ return cservers;
195}
196
197
198void collectset::add_all_collections(const text_t &gsdlhome,
199 const text_t& collecthome)
200{
201 text_tarray collections;
202
203 if (read_dir(collecthome, collections)) {
204
205 text_tarray::const_iterator thiscol = collections.begin();
206 text_tarray::const_iterator endcol = collections.end();
207
208 while (thiscol != endcol) {
209
210 // ignore the modelcol
211 if (*thiscol == "modelcol") {
212 ++thiscol;
213 continue;
214 }
215
216 // create collection server for this collection
217 this->add_collection (*thiscol, gsdlhome, collecthome);
218
219 ++thiscol;
220 }
221
222 this->add_all_collection_groups(gsdlhome,collecthome);
223 }
224}
225
226// add_collection sets up the collectionserver and calls
227// add_collectserver
228void collectset::add_collection (const text_t& collection,
229 const text_t& gsdlhome,
230 const text_t& collecthome)
231{
232
233 this->remove_collection(collection);
234
235 // read config file to see if built with mg, mgpp, or lucene
236 text_t buildtype = "mg"; // mg is default
237 text_t infodbtype = "gdbm"; // gdbm is default
238
239 text_tarray cfgline;
240 text_t key;
241
242 text_t build_cfg = filename_cat(collecthome, collection, "index", "build.cfg");
243 char *build_cfgc = build_cfg.getcstr();
244 ifstream confin(build_cfgc);
245
246 if (confin) {
247 while (read_cfg_line(confin, cfgline) >= 0) {
248 if (cfgline.size() == 2) {
249 key = cfgline[0];
250 cfgline.erase(cfgline.begin());
251 if (key == "buildtype") {
252 buildtype = cfgline[0];
253 }
254 if (key == "infodbtype") {
255 infodbtype = cfgline[0];
256 }
257 }
258 }
259 confin.close();
260 }
261 delete []build_cfgc;
262
263 collectserver *cserver = new collectserver();
264
265 // Create a dbclass of the correct type
266 dbclass *db_ptr = NULL;
267
268#ifdef USE_SQLITE
269 if (infodbtype == "sqlite")
270 {
271 sqlitedbclass *sql_db_ptr = new sqlitedbclass();
272 db_ptr = sql_db_ptr;
273
274 // add a sql browse filter
275 sqlbrowsefilterclass *sqlbrowsefilter = new sqlbrowsefilterclass();
276 sqlbrowsefilter->set_sql_db_ptr(sql_db_ptr);
277 cserver->add_filter (sqlbrowsefilter);
278 }
279#endif
280
281#ifdef USE_MSSQL
282 if (infodbtype == "mssql")
283 {
284 mssqldbclass *mssql_db_ptr = new mssqldbclass();
285 db_ptr = mssql_db_ptr;
286
287 // add a sql browse filter
288 sqlbrowsefilterclass *sqlbrowsefilter = new sqlbrowsefilterclass();
289 sqlbrowsefilter->set_sql_db_ptr(mssql_db_ptr);
290 cserver->add_filter (sqlbrowsefilter);
291 }
292#endif
293
294 // Use GDBM if the infodb type is empty or not one of the values above
295 if (db_ptr == NULL)
296 {
297 db_ptr = new gdbmclass();
298 }
299
300 // add a null filter
301 filterclass *filter = new filterclass ();
302 cserver->add_filter (filter);
303
304 // add a browse filter
305 browsefilterclass *browsefilter = new browsefilterclass();
306 browsefilter->set_db_ptr(db_ptr);
307 cserver->add_filter (browsefilter);
308
309 if (buildtype == "mg") {
310 mgsearch = new mgsearchclass();
311
312 // add a query filter
313 mgqueryfilterclass *queryfilter = new mgqueryfilterclass();
314 queryfilter->set_db_ptr(db_ptr);
315 queryfilter->set_textsearchptr (mgsearch);
316 cserver->add_filter (queryfilter);
317
318 // add a mg source
319 mgsourceclass *mgsource = new mgsourceclass ();
320 mgsource->set_db_ptr(db_ptr);
321 mgsource->set_textsearchptr (mgsearch);
322 cserver->add_source (mgsource);
323 }
324 else if (buildtype == "mgpp") {
325 mgppsearch = new mgppsearchclass();
326
327 // add a query filter
328 mgppqueryfilterclass *queryfilter = new mgppqueryfilterclass();
329 queryfilter->set_db_ptr(db_ptr);
330 queryfilter->set_textsearchptr (mgppsearch);
331 cserver->add_filter (queryfilter);
332
333 // add a mg source
334 mgsourceclass *mgsource = new mgsourceclass ();
335 mgsource->set_db_ptr(db_ptr);
336 mgsource->set_textsearchptr (mgppsearch);
337 cserver->add_source (mgsource);
338 }
339 else if (buildtype == "lucene") {
340 lucenesearch = new lucenesearchclass();
341 lucenesearch->set_gsdlhome(gsdlhome);
342
343 // add a query filter
344 lucenequeryfilterclass *queryfilter = new lucenequeryfilterclass();
345 queryfilter->set_db_ptr(db_ptr);
346 queryfilter->set_textsearchptr (lucenesearch);
347 cserver->add_filter (queryfilter);
348
349 // add a lucene source
350 lucenesourceclass *lucenesource = new lucenesourceclass ();
351 lucenesource->set_db_ptr(db_ptr);
352 lucenesource->set_textsearchptr (lucenesearch);
353 cserver->add_source (lucenesource);
354 }
355
356 // inform collection server and everything it contains about its
357 // collection name
358 cserver->configure ("collection", collection);
359 cserver->configure ("gsdlhome", gsdlhome);
360 cserver->configure ("collecthome", collecthome);
361 cservers.addcollectserver (cserver);
362}
363
364void collectset::remove_all_collections () {
365
366 // first unload any cached mg databases
367 if (mgsearch != NULL) {
368 mgsearch->unload_database();
369 }
370
371 // now delete the collection server objects
372 collectservermapclass::iterator here = cservers.begin();
373 collectservermapclass::iterator end = cservers.end();
374
375 while (here != end) {
376 if ((*here).second.c != NULL) {
377 delete (*here).second.c;
378 }
379 ++here;
380 }
381 cservers.clear();
382}
383
384void collectset::add_collection_group(const text_t& collection,
385 const text_t& gsdlhome,
386 const text_t& collecthome)
387{
388 text_tarray group;
389
390 text_t collect_group_dir = filename_cat (collecthome, collection);
391
392 // need to read collect.cfg for 'collectgroup' as class hasn't been initialised through 'init' yet
393 text_t is_collect_group;
394 text_tarray cfgline;
395 text_t key;
396 text_t collect_cfg = filename_cat(collect_group_dir, "etc", "collect.cfg");
397 char *collect_cfgc = collect_cfg.getcstr();
398 ifstream confin(collect_cfgc);
399
400 if (confin) {
401 while (read_cfg_line(confin, cfgline) >= 0) {
402 if (cfgline.size() == 2) {
403 key = cfgline[0];
404 cfgline.erase(cfgline.begin());
405 if (key == "collectgroup") {
406 is_collect_group = cfgline[0];
407 break;
408 }
409 }
410 }
411 confin.close();
412 }
413 delete []collect_cfgc;
414
415 if (is_collect_group == "true") {
416 if (read_dir (collect_group_dir, group)) {
417
418 text_tarray::const_iterator thiscol = group.begin();
419 text_tarray::const_iterator endcol = group.end();
420
421 while (thiscol != endcol) {
422 // ignore the etc directory
423 if (*thiscol == "etc") {
424 ++thiscol;
425 continue;
426 }
427
428 //text_t group_col = filename_cat(collection,*thiscol);
429 // later we check for / in the name. When this is used in a path (via fileanme_cat) the / will be converted to \ on windows
430 text_t group_col = collection + "/" + *thiscol;
431 this->add_collection (group_col, gsdlhome, collecthome);
432
433 ++thiscol;
434 }
435 }
436 }
437}
438
439void collectset::add_all_collection_groups (const text_t& gsdlhome,
440 const text_t& collecthome)
441
442{
443 collectservermapclass::iterator here = cservers.begin();
444 collectservermapclass::iterator end = cservers.end();
445
446 while (here != end) {
447 text_t collection = (*here).second.c->get_collection_name();
448 this->add_collection_group(collection,gsdlhome,collecthome);
449
450 ++here;
451 }
452}
453
454
455// remove_collection deletes the collection server of collection.
456// This only needs to be called if a collectionserver is to be
457// removed while the library is running. The destructor function
458// cleans up all collectservers when the program exits.
459void collectset::remove_collection (const text_t &collection) {
460
461 // do nothing if no collection server exists for this collection
462 if (cservers.getcollectserver(collection) == NULL) return;
463
464 // first unload any cached mg databases - we may need to do something
465 // similar to this for mgpp and lucene too
466 if (mgsearch != NULL) {
467 mgsearch->unload_database();
468 }
469
470 // now delete the collection server object
471 collectservermapclass::iterator here = cservers.begin();
472 collectservermapclass::iterator end = cservers.end();
473
474 while (here != end) {
475 if ((*here).second.c != NULL && (*here).first == collection) {
476 delete (*here).second.c;
477 cservers.erase (here);
478 return;
479 }
480 ++here;
481 }
482}
483
484
485// remove_collection deletes the collection server of collection.
486// This only needs to be called if a collectionserver is to be
487// removed while the library is running. The destructor function
488// cleans up all collectservers when the program exits.
489void collectset::remove_collection (const text_t &collection, ostream &logout) {
490
491 remove_collection(collection);
492
493 outconvertclass text_t2ascii;
494 logout << text_t2ascii << "collectset::remove_collection: failed to remove collectserver for "
495 << collection << "\n";
496}
497
498void collectset::configure(const text_t &key, const text_tarray &cfgline)
499{
500 if ((key == "collection") || (key == "collectdir")) return;
501
502 collectservermapclass::iterator here = cservers.begin();
503 collectservermapclass::iterator end = cservers.end();
504
505 while (here != end) {
506 assert ((*here).second.c != NULL);
507 if ((*here).second.c != NULL) {
508 if (key == "collectinfo") {
509 if ((*here).first == cfgline[0]) {
510 if (cfgline.size()==3) {
511 (*here).second.c->configure ("gsdlhome", cfgline[1]);
512 (*here).second.c->configure ("gdbmhome", cfgline[2]);
513 }
514 else {
515 (*here).second.c->configure ("gsdlhome", cfgline[1]);
516 (*here).second.c->configure ("collecthome", cfgline[2]);
517 (*here).second.c->configure ("gdbmhome", cfgline[3]);
518 }
519 }
520 } else {
521 (*here).second.c->configure (key, cfgline);
522 }
523 }
524
525 ++here;
526 }
527}
528
529void collectset::getCollectionList (text_tarray &collist)
530{
531 collist.erase(collist.begin(),collist.end());
532
533 collectservermapclass::iterator here = cservers.begin();
534 collectservermapclass::iterator end = cservers.end();
535 while (here != end) {
536 assert ((*here).second.c != NULL);
537 if ((*here).second.c != NULL) {
538 collist.push_back ((*here).second.c->get_collection_name());
539 }
540 ++here;
541 }
542}
543
Note: See TracBrowser for help on using the repository browser.