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

Last change on this file since 17476 was 17476, checked in by mdewsnip, 16 years ago

Support for using MSSQL for infodb databases, many thanks to Jeffrey Ke from DL Consulting Ltd. (http://www.dlconsulting.com). Please note that MSSQL only runs on Windows, and requires some setup before use. Documentation will be added to the Greenstone Wiki explaining this.

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