source: trunk/gsdl/src/colservr/gdbmsource.cpp@ 13780

Last change on this file since 13780 was 13780, checked in by mdewsnip, 17 years ago

GLI/LOCAL LIBRARY: To prevent the problems with the GLI being unable to install newly built collections because the local library is holding files open, much more care needs to be taken to close files (typically the GDBM database and the MG/MGPP index files) after use. Fixed a lot of places where files were being left open.

  • Property svn:keywords set to Author Date Id Revision
File size: 11.5 KB
Line 
1/**********************************************************************
2 *
3 * gdbmsource.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#include "gdbmsource.h"
27#include "fileutil.h"
28#include "OIDtools.h"
29#include "gsdltools.h"
30
31
32gdbmsourceclass::gdbmsourceclass () {
33 gdbmptr = NULL;
34 textsearchptr = NULL;
35 classname = "gdbmsource";
36}
37
38gdbmsourceclass::~gdbmsourceclass () {
39 if (gdbmptr != NULL) delete gdbmptr;
40 if (textsearchptr != NULL) delete textsearchptr;
41}
42
43void gdbmsourceclass::configure (const text_t &key, const text_tarray &cfgline) {
44 if (cfgline.size() >= 1) {
45 const text_t &value = cfgline[0];
46
47 if (key == "collection") collection = value;
48 else if (key == "collectdir") collectdir = value;
49 else if (key == "gsdlhome") gsdlhome = value;
50 else if (key == "gdbmhome") gdbmhome = value;
51 }
52
53 if (key == "indexmap") {
54 indexmap.importmap (cfgline);
55
56 } else if (key == "defaultindex") {
57 indexmap.from2to (cfgline[0], defaultindex);
58
59 } else if (key == "subcollectionmap") {
60 subcollectionmap.importmap (cfgline);
61
62 } else if (key == "defaultsubcollection") {
63 subcollectionmap.from2to (cfgline[0], defaultsubcollection);
64
65 } else if (key == "languagemap") {
66 languagemap.importmap (cfgline);
67
68 } else if (key == "defaultlanguage") {
69 languagemap.from2to (cfgline[0], defaultlanguage);
70 } else if (key == "indexstem") {
71 indexstem = cfgline[0];
72 }
73
74}
75
76bool gdbmsourceclass::init (ostream &logout) {
77 outconvertclass text_t2ascii;
78
79 if (gdbmhome.empty()) gdbmhome = gsdlhome;
80
81 if (!sourceclass::init (logout)) return false;
82
83 if (defaultindex.empty()) {
84 // use first index in map as default if no default is set explicitly
85 text_tarray toarray;
86 indexmap.gettoarray(toarray);
87 if (toarray.size()) {
88 defaultindex = toarray[0];
89 }
90 }
91
92 if (defaultsubcollection.empty()) {
93 // use first subcollection in map as default if no default is set explicitly
94 text_tarray toarray;
95 subcollectionmap.gettoarray(toarray);
96 if (toarray.size()) {
97 defaultsubcollection = toarray[0];
98 }
99 }
100
101 if (defaultlanguage.empty()) {
102 // use first language in map as default if no default is set explicitly
103 text_tarray toarray;
104 languagemap.gettoarray(toarray);
105 if (toarray.size()) {
106 defaultlanguage = toarray[0];
107 }
108 }
109
110 // get the collection directory name
111 if (collectdir.empty()) {
112 collectdir = filename_cat (gsdlhome, "collect", collection);
113 }
114
115 // get the filename for the database and make sure it exists
116 if (indexstem.empty()) {
117 indexstem = collection;
118 }
119 gdbm_filename = filename_cat(gdbmhome, "collect", collection, "index", "text", indexstem);
120 if (littleEndian()) gdbm_filename += ".ldb";
121 else gdbm_filename += ".bdb";
122
123 if (!file_exists(gdbm_filename)) {
124 logout << text_t2ascii
125 << "warning: gdbm database \"" //****
126 << gdbm_filename << "\" does not exist\n\n";
127 // return false; //****
128 }
129
130 return true;
131}
132
133bool gdbmsourceclass::translate_OID (const text_t &OIDin, text_t &OIDout,
134 comerror_t &err, ostream &logout) {
135
136 outconvertclass text_t2ascii;
137
138 err = noError;
139 if (gdbmptr == NULL) {
140 // most likely a configuration problem
141 logout << text_t2ascii
142 << "configuration error: " << classname << " contains a null gdbmclass\n\n";
143 err = configurationError;
144 return true;
145 }
146
147 // open the database
148 gdbmptr->setlogout(&logout);
149 if (!gdbmptr->opendatabase (gdbm_filename, GDBM_READER, 100, false)) {
150 // most likely a system problem (we have already checked that the
151 // gdbm database exists)
152 logout << text_t2ascii
153 << "system problem: open on gdbm database \""
154 << gdbm_filename << "\" failed\n\n";
155 err = systemProblem;
156 return true;
157 }
158
159 infodbclass info;
160 OIDout = gdbmptr->translate_OID (OIDin, info);
161 gdbmptr->closedatabase(); // Important that local library doesn't leave any files open
162 return true;
163}
164
165bool gdbmsourceclass::get_metadata (const text_t &/*requestParams*/, const text_t &/*refParams*/,
166 bool getParents, const text_tset &fields,
167 const text_t &OID, MetadataInfo_tmap &metadata,
168 comerror_t &err, ostream &logout) {
169 outconvertclass text_t2ascii;
170
171 metadata.erase(metadata.begin(), metadata.end());
172
173 err = noError;
174 if (gdbmptr == NULL) {
175 // most likely a configuration problem
176 logout << text_t2ascii
177 << "configuration error: " << classname <<" contains a null gdbmclass\n\n";
178 err = configurationError;
179 return true;
180 }
181
182 // open the database
183 gdbmptr->setlogout(&logout);
184 if (!gdbmptr->opendatabase (gdbm_filename, GDBM_READER, 100, false)) {
185 // most likely a system problem (we have already checked that the
186 // gdbm database exists)
187 logout << text_t2ascii
188 << "system problem: open on gdbm database \""
189 << gdbm_filename << "\" failed\n\n";
190 err = systemProblem;
191 return true;
192 }
193
194 // get the metadata - if getParents is set we need to get
195 // info for all parents of OID as well as OID
196 vector<infodbclass> info_array;
197 text_tarray OIDs;
198 if (getParents) get_parents_array (OID, OIDs);
199 OIDs.push_back (OID);
200
201 text_tarray::const_iterator this_OID = OIDs.begin();
202 text_tarray::const_iterator end_OID = OIDs.end();
203
204 while (this_OID != end_OID) {
205 infodbclass info;
206 if (!gdbmptr->getinfo(*this_OID, info)) return false;
207
208 // adjust the metadata
209 text_t &contains = info["contains"];
210 if (contains.empty()) info["haschildren"] = 0;
211 else info["haschildren"] = 1;
212 //contains.clear();
213
214 info_array.push_back(info);
215 ++this_OID;
216 }
217
218 // if fields set is empty we want to get all available metadata
219 text_tset tfields = fields;
220 if (tfields.empty() && !info_array.empty()) {
221 infodbclass::iterator t_info = info_array[0].begin();
222 infodbclass::iterator e_info = info_array[0].end();
223 while (t_info != e_info) {
224 if ((*t_info).first != "contains")
225 tfields.insert ((*t_info).first);
226 ++t_info;
227 }
228 tfields.insert ("hasnext");
229 tfields.insert ("hasprevious");
230 }
231
232 // collect together the metadata
233 bool donenextprevtest = false;
234 bool hasnext=false, hasprevious=false;
235 MetadataInfo_t this_metadata;
236 text_tarray *pos_metadata;
237 text_tset::const_iterator fields_here = tfields.begin();
238 text_tset::const_iterator fields_end = tfields.end();
239
240 while (fields_here != fields_end) {
241 this_metadata.clear();
242 this_metadata.isRef = false;
243
244 vector<infodbclass>::reverse_iterator this_info = info_array.rbegin();
245 vector<infodbclass>::reverse_iterator end_info = info_array.rend();
246 MetadataInfo_t *tmetaptr = &this_metadata;
247 while (this_info != end_info) {
248
249 pos_metadata = (*this_info).getmultinfo(*fields_here);
250 if ((*fields_here == "hasnext" || *fields_here == "hasprevious")) {
251
252 // collect metadata
253 if (!donenextprevtest) {
254 donenextprevtest = true;
255
256 // cache parent contents array
257 text_t thisparent = get_parent (OID);
258 if (!thisparent.empty()) {
259 if (thisparent != parentOID) {
260 parentOID = thisparent;
261 parentcontents.erase(parentcontents.begin(), parentcontents.end());
262 if (gdbmptr->getinfo(parentOID, parentinfo)) {
263 text_t &parentinfocontains = parentinfo["contains"];
264 if (!parentinfocontains.empty())
265 splitchar (parentinfocontains.begin(), parentinfocontains.end(),
266 ';', parentcontents);
267 }
268 }
269
270 // do tests
271 text_tarray::const_iterator parentcontents_here = parentcontents.begin();
272 text_tarray::const_iterator parentcontents_end = parentcontents.end();
273 text_t shrunk_OID = OID;
274 shrink_parent (shrunk_OID);
275 while (parentcontents_here != parentcontents_end) {
276 if (*parentcontents_here == shrunk_OID) {
277 if (parentcontents_here == parentcontents.begin()) hasprevious = false;
278 else hasprevious = true;
279
280 ++parentcontents_here;
281
282 if (parentcontents_here == parentcontents.end()) hasnext = false;
283 else hasnext = true;
284
285 break;
286 }
287
288 ++parentcontents_here;
289 }
290
291 // fill in metadata
292 if ((*fields_here == "hasnext" && hasnext) ||
293 (*fields_here == "hasprevious" && hasprevious))
294 tmetaptr->values.push_back("1");
295 else
296 tmetaptr->values.push_back("0");
297 } else
298 tmetaptr->values.push_back("0");
299 }
300 }
301 //else if (pos_metadata != NULL && *fields_here != "contains") {
302 else if (pos_metadata != NULL) {
303 tmetaptr->values = *pos_metadata;
304 }
305 else
306 tmetaptr->values.push_back("");
307
308 ++this_info;
309 if (this_info != end_info) {
310 tmetaptr->parent = new MetadataInfo_t();
311 tmetaptr = tmetaptr->parent;
312 }
313 }
314 metadata[*fields_here] = this_metadata;
315 ++fields_here;
316 }
317
318 gdbmptr->closedatabase(); // Important that local library doesn't leave any files open
319 return true;
320}
321
322
323bool gdbmsourceclass::get_document (const text_t &OID, text_t &doc,
324 comerror_t &err, ostream &logout) {
325
326 outconvertclass text_t2ascii;
327
328 err = noError;
329 if (gdbmptr == NULL) {
330 // most likely a configuration problem
331 logout << text_t2ascii
332 << "configuration error: " << classname << " contains a null gdbmclass\n\n";
333 err = configurationError;
334 return true;
335 }
336
337 // open the database
338 gdbmptr->setlogout(&logout);
339 if (!gdbmptr->opendatabase (gdbm_filename, GDBM_READER, 100, false)) {
340 // most likely a system problem (we have already checked that the
341 // gdbm database exists)
342 logout << text_t2ascii
343 << "system problem: open on gdbm database \""
344 << gdbm_filename << "\" failed\n\n";
345 err = systemProblem;
346 return true;
347 }
348
349 text_t tOID = OID;
350 if (needs_translating (OID))
351 translate_OID (OID, tOID, err, logout);
352 infodbclass info;
353 if (!gdbmptr->getinfo(tOID, info)) {
354 gdbmptr->closedatabase(); // Important that local library doesn't leave any files open
355 return false;
356 }
357
358 if (info["hastxt"].getint() == 1) {
359 int docnum = info["docnum"].getint();
360
361 // set the collection directory
362 textsearchptr->setcollectdir (collectdir);
363
364 // get the text
365 textsearchptr->docTargetDocument(defaultindex, defaultsubcollection,
366 defaultlanguage, collection, docnum, doc);
367 }
368
369 gdbmptr->closedatabase(); // Important that local library doesn't leave any files open
370 return true;
371}
372
373bool gdbmsourceclass::is_searchable(bool &issearchable, comerror_t &err, ostream &logout) {
374 err = noError;
375 issearchable = false;
376
377 text_tarray fromarray;
378 indexmap.getfromarray(fromarray);
379 if (fromarray.size() == 0) {
380 return true;
381 } else if (fromarray.size() == 1) {
382 if (fromarray[0] == "dummy:text") {
383 // always return true - issearchable is false here though
384 return true;
385 }
386 }
387 issearchable = true;
388 return true;
389}
Note: See TracBrowser for help on using the repository browser.