root/main/trunk/greenstone2/runtime-src/src/oaiservr/oaiconfig.cpp @ 27673

Revision 27673, 16.2 KB (checked in by kjdon, 6 years ago)

need to return the set name\!

  • Property svn:keywords set to Author Date Id Revision
Line 
1/**********************************************************************
2 *
3 * oaiconfig.cpp --
4 *
5 * Copyright (C) 2004-2010  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 "oaiconfig.h"
28#include <iostream>
29#include <stdlib.h>
30#include "fileutil.h"
31
32/**
33 *  The mapping works as follows in the oai.cfg or collect.cfg file.
34 *
35 *  A line is in the format oaimapping <collection field> <oai field>
36 *
37 *  The map here is used to look up the "Greenstone" name which is mapped from
38 *  a given OAI field name, the reverse direction to that given in the
39 *  Greenstone collect.cfg file.  The oairecordaction class instance which
40 *  produces output for an OAI record information request thus uses the map
41 *  to work from the field in the collection it has on hand which OAI
42 *  record name it should use instead.
43 *
44 *  An extension is to be used for this in which the OAI field name in the
45 *  collect.cfg file can be made specific for a particular record format.
46 *  This is done using the OAI field name in the format of
47 *    <OAI format>.<OAI field name>
48 *  Thus, an rfc1807 Title field would be referred to as rfc1807.Title
49 *
50 *  A collection-level mapping can be provided in oai.cfg by prepending
51 *  collname to collection field:
52 *  <collname:field> <oai field>
53
54 *  In the absence of a particular format name, the mapping is taken to be
55 *  universal.
56 */
57
58oaiconfig::oaiconfig() : configurable () {
59  this->resumptionSize = -1; // Default = do not use resumption tokens
60}
61
62oaiconfig::oaiconfig(text_t &gsdlhome, text_t &gsdlcollect)
63{
64  // read main configuration file (oai.cfg) to get oai collections
65  text_t mainconfig = filename_cat(gsdlhome, "etc", "oai.cfg");
66  this->collection = "";
67  this->resumptionSize = -1;
68  this->read_configfile(mainconfig);
69
70  // then if we've not got a specified collection in the gsdlcollect
71  // parameter, read in all the collection's individual configurations
72  if (gsdlcollect == "") {
73    text_tarray::iterator start = this->collectList.begin();
74    text_tarray::iterator here  = this->collectList.end()-1;
75    while (here != start) {     
76      if (!this->configureCollection(gsdlhome, *here)) {
77    this->collectList.erase(here);
78      }
79      --here;
80    }
81    // and do the first one
82    if (!this->configureCollection(gsdlhome, *here)) {
83      this->collectList.erase(here);
84    }   
85  }
86  else {
87    // what do we do if this fails?
88    this->configureCollection(gsdlhome, gsdlcollect);
89  }
90}
91
92oaiconfig::~oaiconfig()
93{
94  oaicollectmap::iterator here = this->collectMap.begin();
95  oaicollectmap::iterator end  = this->collectMap.end();
96  while (here != end) {
97    delete here->second;
98    ++here;
99  }
100}
101
102int oaiconfig::resumeAfter()
103{ return this->resumptionSize;
104}
105
106int oaiconfig::getOAIVersion()
107{
108  if (this->oaiVersion == "1.1") {
109    return 110;
110  }
111  return 200;
112}
113
114bool oaiconfig::isValidCollection(const text_t &collection)
115{
116  for (int c = 0; c < this->collectList.size(); c++)
117    if (this->collectList[c] == collection) {
118      return true;
119    }
120  return false;
121}
122
123bool oaiconfig::configureCollection(const text_t &gsdlhome, const text_t &gsdlcollect)
124{
125  text_t cnfgfile = filename_cat(gsdlhome, "collect", gsdlcollect, "etc", "collect.cfg");
126  if (!file_exists(cnfgfile)) {
127    return false;
128  } 
129 
130  this->collection = gsdlcollect;
131  this->read_configfile(cnfgfile);
132 
133  // to work out the earliestDatestamp for the repository, need to
134  // to read in the build.cfg file of each OAI collection, in order to
135  // find the oldest earliestDatestamp field of all the OAI collections
136  text_t buildcnfgfile = filename_cat(gsdlhome, "collect", gsdlcollect, "index", "build.cfg");
137  if (file_exists(buildcnfgfile)) {
138    this->read_configfile(buildcnfgfile);
139  }
140 
141  return true;
142}
143void oaiconfig::configure (const text_t &key, const text_tarray &cfgline)
144{
145  // we've got an oai mapping item, and at least two fields
146  if (key == "oaimapping" && cfgline.size() > 1) {
147    text_t::const_iterator colonAt;
148    text_t index, name, configCollection;
149
150    // Take a default collection as being whatever the collection being configured is...
151    configCollection = this->collection;
152   
153    // get the name of the (collection) field to map; this may actually
154    // be in a colon separated format of the type
155    // <collection name>:<field name>
156    index = cfgline[0];
157    if ((colonAt = findchar(index.begin(), index.end(), ':')) != index.end()) {
158      configCollection = substr(index.begin(), colonAt);
159
160      if (this->collection != "" && configCollection != this->collection) {
161    cerr << "Attempt to configure OAI mappings for " << configCollection << " in " << this->collection << endl;
162      }
163
164      colonAt += 1;
165      index = substr(colonAt, index.end());
166    }
167   
168    // the second parameter is the metadata field to map the collection
169    // field onto.  It may be provided with a metadata protocol (which
170    // will be given first and separated by a period or full stop).  In
171    // the case of format.field name, the splitting is done here.
172    if ((colonAt = findchar(cfgline[1].begin(), cfgline[1].end(), '.')) != cfgline[1].end()) {
173      text_t stub = substr(cfgline[1].begin(), colonAt);
174      colonAt += 1;
175      name = substr(colonAt, cfgline[1].end());
176      index.append(":");
177      index.append(stub);
178    }
179    else {
180      name = cfgline[1];
181    }
182   
183    // now 'index' is in the form <collectionfield>:(formatname)
184    //     'name' is simply the fieldname within the format
185    //     'configCollection' is the collection to be configured
186   
187    // now simply map the field name (index) onto the collection name (name)
188    if (this->collectMap[configCollection] == NULL) {
189      this->collectMap[configCollection] = new oaicollectconfig(configCollection);
190    }
191    this->collectMap[configCollection]->fieldMap[index] = name;
192   
193    //    cerr << "Mapping " << index << " to " << name << " in " << configCollection << endl;
194   
195    // TODO: check that the mapped field is actually in use
196  }
197  else if (key == "oaicollection" && cfgline.size() >= 1) {
198    // Configure a collection to be used as part of the OAI archive.
199    // This line should read:
200    //
201    // oaicollection <collectionname>
202    //
203    // Where <collectionname> is the name of the directory inside the
204    // gsdl/collect folder which contains the collection.
205    //
206    // To configure several collections, merely repeat this line,
207    // or alternatively use additional collection names after the
208    // first one.
209    //
210    // This configuration should only appear in oai.cfg
211    //
212    if (this->collection != "") {
213      cerr << "Attempt to configure an oai collection outside of oai.cfg" << endl;
214      cerr << "Configuration attempted in " << this->collection << " collection." << endl;
215      exit(1);
216    }
217    for (int c = 0; c < cfgline.size(); ++c) {
218      this->collectList.push_back(cfgline[c]);
219      addToAllCollectionsList(cfgline[c]);
220    }
221  }
222  else if (key == "oaisupercollection" && cfgline.size() > 1) {
223
224    // Configure a super collection set
225    // The line should read
226    //
227    // oaisupercollection <setName> [collections part of this set]
228    //
229    // Records in specified collections will be advertised as being part
230    // of the SetName set as well as their collectionName set
231    //
232    // This configuration should only appear in oai.cfg
233    //
234    if (this->collection != "") {
235      cerr << "Attempt to configure an oai super collection outside of oai.cfg" << endl;
236      cerr << "Configuration attempted in " << this->collection << " collection." << endl;
237      exit(1);
238    }
239   
240    text_t super_set = cfgline[0];
241    this->superCollectList.push_back(super_set);
242    this->superCollectMap[super_set] = new oaisupercollectconfig(super_set);
243    for (int c = 1; c < cfgline.size(); ++c) {
244      text_t sub_coll = cfgline[c];
245      // Add the collection into the list for this supercoll
246      this->superCollectMap[super_set]->collectionList.push_back(sub_coll);
247      // Add the super coll into the list for the collection
248      if (this->collectMap[sub_coll]== NULL) {
249    this->collectMap[sub_coll] = new oaicollectconfig(sub_coll);
250      }
251      this->collectMap[sub_coll]->superCollectList.push_back(super_set);
252      addToAllCollectionsList(sub_coll);
253    }
254  }
255  else if (key == "oaimetadata" && cfgline.size() >= 1) {
256    // List of metadata prefixes to suuport
257    // This line should read:
258    //
259    // oaicollection <metadataname> <metadataname>...
260    //
261    //
262    // This configuration should only appear in oai.cfg
263    //
264    if (this->collection != "") {
265      cerr << "Attempt to configure oai metadata outside of oai.cfg" << endl;
266      cerr << "Configuration attempted in " << this->collection << " collection." << endl;
267      exit(1);
268    }
269    for (int c = 0; c < cfgline.size(); ++c) {
270      // todo: check that the set name is valid
271      this->metadataSet.insert(cfgline[c]);
272    }
273  }
274  else if (key == "oaiinfo" && cfgline.size() >= 1) {
275    // Get a piece of information for the oai repository information
276    // request.  The line should read:
277    //
278    // oaiinfo <information field name> <value>
279    //
280    // This configuration should only be attempted in oai.cfg
281    //
282    if (this->collection != "") {
283      cerr << "Attempt to set oai information outside of oai.cfg" << endl;
284      cerr << "Configuration attempted in " << this->collection << " collection." << endl;
285      exit(1);
286    }
287   
288    // if no second parameter is given, then the first parameter
289    if (cfgline.size() == 1) {
290      this->infoMap[cfgline[0]] = cfgline[0];
291    }
292    else {
293      this->infoMap[cfgline[0]] = cfgline[1];
294    }
295  }
296  else if ( key == "oaisetname" || key == "oaisetdescription") {
297    text_t coll_name;
298    text_t value = "";
299    if (this->collection != "") {
300      // we are in collect.cfg
301      coll_name = this->collection;
302      if (cfgline.size() == 1) {
303    // just the collection value
304    value = cfgline[0];
305      }
306      else if (cfgline.size() == 2) {
307    // we have a subset name (eg for classifier)
308    coll_name.append(":");
309    coll_name.append(cfgline[0]);
310    value = cfgline[1];
311      }
312    } else if (cfgline.size() == 2) {
313      // oai.cfg, line should be collname, setName
314      coll_name = cfgline[0];
315      value = cfgline[1];
316    }
317    if (value != "") {
318      // check first for super collection
319      if (this->superCollectMap[coll_name] != NULL) {
320    if (key == "oaisetname") {
321      this->superCollectMap[coll_name]->setName = value;
322    } else if (key == "oaisetdescription") {
323      this->superCollectMap[coll_name]->setDescription = value;
324    }
325      } else {
326    if (this->collectMap[coll_name] == NULL) {
327      this->collectMap[coll_name] = new oaicollectconfig(coll_name);
328    }
329    if (key == "oaisetname") {
330      this->collectMap[coll_name]->setName = value;
331    } else if (key == "oaisetdescription") {
332      this->collectMap[coll_name]->setDescription = value;
333    }
334      }
335    }
336  }
337
338  else if (key == "resumeafter" && cfgline.size() >= 1) {
339    this->resumptionSize = cfgline[0].getint();
340  }
341
342  else if (key == "maintainer") {
343    this->maintainer = cfgline[0];
344  }
345  else if (key == "repositoryName") {
346    this->repositoryName = cfgline[0];
347  }
348  else if (key == "repositoryId") {
349    this->repositoryId = cfgline[0];
350  }
351  else if (key == "repositoryIdVersion") {
352    this->repositoryIdVersion = cfgline[0];
353  }
354  else if (key == "baseServerURL") {
355    this->baseServerURL = cfgline[0];
356  }
357  else if (key == "oaiserverPath") {
358    this->oaiserverPath = cfgline[0];
359  }
360  else if (key == "libraryPath") {
361    this->libraryPath = cfgline[0];
362  }
363  else if (key == "docRootPath") {
364    this->docRootPath = cfgline[0];
365  }
366
367  else if (key == "oaiversion") {
368    this->oaiVersion = cfgline[0];
369  }
370}
371 
372void oaiconfig::addToAllCollectionsList(const text_t coll_name) {
373
374  for (int c=0; c<this->allCollectList.size(); c++) {
375    if (allCollectList[c] == coll_name) return;
376  }
377  this->allCollectList.push_back(coll_name);
378 
379}
380
381text_t oaiconfig::generateBaseServerURL() {
382  char *server_name = getenv("SERVER_NAME");
383  char *server_port = getenv("SERVER_PORT");
384  text_t url = "http://";
385  url.append(server_name);
386  url.append(":");
387  url.append(server_port);
388  return url;
389}
390
391text_t oaiconfig::getMapping(const text_t &collection, const text_t &collectfield)
392{
393  if (this->collectMap[collection] == NULL) {
394    return "";
395  }
396  return this->collectMap[collection]->fieldMap[collectfield];
397}
398
399/**
400 *  Get the mapping for a field in a given collection; if no mapping
401 *  exists, the result will be a blank string.
402 */
403text_t oaiconfig::getMapping(const text_t &collection, const text_t &collectfield, const text_t &formatname)
404{
405  text_t fullName = collectfield;
406  fullName.append(":");
407  fullName.append(formatname);
408
409  // try the collection-specific options first
410  if (this->collectMap[collection] != NULL) {
411    // first try the most specific item - this collection, and given that protocol
412    if (this->collectMap[collection]->fieldMap.count(fullName) >= 1) {
413      return this->collectMap[collection]->fieldMap[fullName];
414    }
415    // otherwise, fall back to this collection, and all protocols
416    else if (this->collectMap[collection]->fieldMap.count(collectfield) >= 1) {
417      return this->collectMap[collection]->fieldMap[collectfield];
418    }
419  }
420
421  // if no mappings exist, return an empty item
422  if (this->collectMap[""] == NULL) {
423    return "";
424  }
425
426  // then try generic rules
427  if (this->collectMap[""]->fieldMap.count(fullName) >= 1) {
428    return this->collectMap[""]->fieldMap[fullName];
429  }
430  else {
431    return this->collectMap[""]->fieldMap[collectfield];
432  }
433}
434
435text_t oaiconfig::getBaseURL()
436{
437  if (this->baseServerURL.empty()) {
438    this->baseServerURL = generateBaseServerURL();
439  }
440  return this->baseServerURL + this->oaiserverPath;
441}
442text_t oaiconfig::getBaseLibraryURL()
443{
444  if (this->baseServerURL.empty()) {
445    this->baseServerURL = generateBaseServerURL();
446  }
447  return this->baseServerURL + this->libraryPath;
448}
449text_t oaiconfig::getBaseDocRoot()
450{
451  if (this->baseServerURL.empty()) {
452    this->baseServerURL = generateBaseServerURL();
453  }
454  return this->baseServerURL + this->docRootPath;
455}
456
457text_t oaiconfig::getRelativeBaseDocRoot()
458{
459  return this->docRootPath;
460}
461text_t oaiconfig::getRepositoryName()
462{
463  return this->repositoryName;
464}
465text_t oaiconfig::getRepositoryId()
466{
467  return this->repositoryId;
468}
469text_t oaiconfig::getRepositoryIdVersion()
470{
471  return this->repositoryIdVersion;
472}
473text_t oaiconfig::getMaintainer()
474{
475  return this->maintainer;
476}
477text_t oaiconfig::getSetName(const text_t &setSpec)
478{
479  if (this->collectMap[setSpec] != NULL) {
480    return this->collectMap[setSpec]->setName;
481  }
482  if (this->superCollectMap[setSpec] != NULL) {
483    return this->superCollectMap[setSpec]->setName;
484  }
485  return "" ;
486 
487}
488
489text_t oaiconfig::getSetDescription(const text_t &setSpec)
490{
491  if (this->collectMap[setSpec] != NULL) {
492  return this->collectMap[setSpec]->setDescription;
493  }
494  if (this->superCollectMap[setSpec] != NULL) {
495    return this->superCollectMap[setSpec]->setDescription;
496  }
497 
498  return "" ;
499 
500}
501
502
503text_tarray oaiconfig::getSuperCollectionsForThisCollection(const text_t &collection)
504{
505
506  text_tarray super_colls;
507  if (this->superCollectList.size() == 0) {
508    return super_colls;
509  }
510
511  for (int s = 0; s < this->superCollectList.size(); s++) {
512    text_tarray colls = this->superCollectMap[this->superCollectList[s]]->collectionList;
513    for (int c = 0; c < colls.size(); c++)
514    {
515      if (colls[c] == collection)
516      {
517    super_colls.push_back(this->superCollectList[s]);
518    break;
519      }
520    }
521  }
522   
523  return super_colls;
524}
Note: See TracBrowser for help on using the browser.