source: gsdl/trunk/src/colservr/source.cpp@ 15680

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

(Adding new DB support) Now uses the new dbclass::getfileextension() function to avoid having GDBM-specific filename extension code scattered around.

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