#include "oaiconfig.h" #include #include #include "fileutil.h" /** * The mapping works as follows in the collect.cfg file. * * A line is in the format oaimapping * * The map here is used to look up the "Greenstone" name which is mapped from * a given OAI field name, the reverse direction to that given in the * Greenstone collect.cfg file. The oairecordaction class instance which * produces output for an OAI record information request thus uses the map * to work from the field in the collection it has on hand which OAI * record name it should use instead. * * An extension is to be used for this in which the OAI field name in the * collect.cfg file can be made specific for a particular record format. * This is done using the OAI field name in the format of * : * Thus, an rfc1807 Title field would be referred to as rfc1807:Title * * A collection-level mapping is not needed - to configure the behaviour * of a collection, ensure that you place the appropriate configuration in * its etc/collect.cfg file - the oaimapping stuff IS NOT picked up from * the central main.cfg file at the moment. * * In the absence of a particular format name, the mapping is taken to be * universal. */ oaiconfig::oaiconfig() : configurable () { this->resumptionSize = -1; // Default = do not use resumption tokens } oaiconfig::oaiconfig(text_t &gsdlhome, text_t &gsdlcollect) { // read main configuration file to get oai collections text_t mainconfig = filename_cat(gsdlhome, "etc", "oai.cfg"); this->collection = ""; this->resumptionSize = -1; this->read_configfile(mainconfig); // then if we've not got a specified collection in the gsdlcollect // parameter, read in all the collection's individual configurations if (gsdlcollect == "") { text_tarray::iterator here = this->collectList.begin(); text_tarray::iterator end = this->collectList.end(); while (here != end) { this->configureCollection(gsdlhome, *here); ++here; } } else { this->configureCollection(gsdlhome, gsdlcollect); } } oaiconfig::~oaiconfig() { oaicollectmap::iterator here = this->collectMap.begin(); oaicollectmap::iterator end = this->collectMap.end(); while (here != end) { delete here->second; ++here; } } int oaiconfig::resumeAfter() { return this->resumptionSize; } int oaiconfig::getOAIVersion() { if (this->oaiVersion == "1.1") { return 110; } return 200; } void oaiconfig::configureCollection(const text_t &gsdlhome, const text_t &gsdlcollect) { text_t cnfgfile = filename_cat(gsdlhome, "collect", gsdlcollect, "etc", "collect.cfg"); this->collection = gsdlcollect; this->read_configfile(cnfgfile); } void oaiconfig::configure (const text_t &key, const text_tarray &cfgline) { // we've got an oai mapping item, and at least two fields if (key == "oaimapping" && cfgline.size() > 1) { text_t::const_iterator colonAt; text_t index, name, configCollection; // Take a default collection as being whatever the collection being configured is... configCollection = this->collection; // get the name of the (collection) field to map; this may actually // be in a colon separated format of the type // : index = cfgline[0]; if ((colonAt = find(index.begin(), index.end(), ':')) != index.end()) { configCollection = substr(index.begin(), colonAt); if (this->collection != "" && configCollection != this->collection) { cerr << "Attempt to configure OAI mappings for " << configCollection << " in " << this->collection << endl; } colonAt += 1; index = substr(colonAt, index.end()); } // the second parameter is the metadata field to map the collection // field onto. It may be provided with a metadata protocol (which // will be given first and separated by a period or full stop). In // the case of format.field name, the splitting is done here. if ((colonAt = find(cfgline[1].begin(), cfgline[1].end(), '.')) != cfgline[1].end()) { text_t stub = substr(cfgline[1].begin(), colonAt); colonAt += 1; name = substr(colonAt, cfgline[1].end()); index.append(":"); index.append(stub); } else { name = cfgline[1]; } // now 'index' is in the form :(formatname) // 'name' is simply the fieldname within the format // 'configCollection' is the collection to be configured // now simply map the field name (index) onto the collection name (name) if (this->collectMap[configCollection] == NULL) { this->collectMap[configCollection] = new oaicollectconfig(configCollection); } this->collectMap[configCollection]->fieldMap[index] = name; // cerr << "Mapping " << index << " to " << name << " in " << configCollection << endl; // TODO: check that the mapped field is actually in use } else if (key == "oaicollection" && cfgline.size() >= 1) { // Configure a collection to be used as part of the OAI archive. // This line should read: // // oaicollection // // Where is the name of the directory inside the // gsdl/collect folder which contains the collection. // // To configure several collections, merely repeat this line, // or alternatively use additional collection names after the // first one. // // This configuration should only appear in main.cfg // if (this->collection != "") { cerr << "Attempt to configure an oai collection outside of main.cfg" << endl; cerr << "Configuration attempted in " << this->collection << " collection." << endl; exit(1); } for (int c = 0; c < cfgline.size(); ++c) { this->collectList.push_back(cfgline[c]); } } else if (key == "oaiinfo" && cfgline.size() >= 1) { // Get a piece of information for the oai repository information // request. The line should read: // // oaiinfo // // This configuration should only be attempted in main.cfg // if (this->collection != "") { cerr << "Attempt to set oai information outside of main.cfg" << endl; cerr << "Configuration attempted in " << this->collection << " collection." << endl; exit(1); } // if no second parameter is given, then the first parameter if (cfgline.size() == 1) { this->infoMap[cfgline[0]] = cfgline[0]; } else { this->infoMap[cfgline[0]] = cfgline[1]; } } else if (key == "oaiversion" && cfgline.size() >= 1) { this->oaiVersion = cfgline[0]; } else if (key == "resumeafter" && cfgline.size() >= 1) { this->resumptionSize = cfgline[0].getint(); } // get and note a maintainer item to support the Identify Verb of OAI else if (key == "maintainer" && cfgline.size() >= 1) { int line = 0; // TODO: exhaustive checks for empty or default values of maintainer while (line < cfgline.size()) { if (cfgline[line] != "NULL" && cfgline[line] != "") { // do something break; } else { ++line; } } // Only try to set the configuration if we have a legitimate value ... if (line < cfgline.size()) { // ensure we have a map to write to if (this->collectMap[this->collection] == NULL) { this->collectMap[this->collection] = new oaicollectconfig(this->collection); } this->collectMap[this->collection]->maintainer = cfgline[line]; } } else if (key == "repositoryName" && cfgline.size() >= 1) { int line = 0; // TODO: exhaustive checks for empty or default values of repositoryName while (line < cfgline.size()) { if (cfgline[line] != "NULL" && cfgline[line] != "") { // do something break; } else { ++line; } } // Only try to set the configuration if we have a legitimate value ... if (line < cfgline.size()) { // ensure we have a map to write to if (this->collectMap[this->collection] == NULL) { this->collectMap[this->collection] = new oaicollectconfig(this->collection); } this->collectMap[this->collection]->repositoryName = cfgline[line]; } } else if (key == "baseURL" && cfgline.size() >= 1) { int line = 0; while (line < cfgline.size()) { if (cfgline[line] != "NULL" && cfgline[line] != "") { // do something break; } else { ++line; } } // Only try to set the configuration if we have a legitimate value ... if (line < cfgline.size()) { // ensure we have a map to write to if (this->collectMap[this->collection] == NULL) { this->collectMap[this->collection] = new oaicollectconfig(this->collection); } this->collectMap[this->collection]->baseURL = cfgline[line]; } } else if (key == "baseDocRoot" && cfgline.size() >= 1) { int line = 0; while (line < cfgline.size()) { if (cfgline[line] != "NULL" && cfgline[line] != "") { // do something break; } else { ++line; } } // Only try to set the configuration if we have a legitimate value ... if (line < cfgline.size()) { // ensure we have a map to write to if (this->collectMap[this->collection] == NULL) { this->collectMap[this->collection] = new oaicollectconfig(this->collection); } this->collectMap[this->collection]->baseDocRoot = cfgline[line]; } } } /** * TODO: store all field values in a map per collection */ text_t oaiconfig::getCollectionConfig(const text_t &collection, const text_t &field) { if (this->collectMap[collection] == NULL) { return ""; } if (field == "maintainer") { return this->collectMap[collection]->maintainer; } if (field == "repositoryName") { return this->collectMap[collection]->repositoryName; } if (field == "baseURL") { return this->collectMap[collection]->baseURL; } if (field == "baseDocRoot") { return this->collectMap[collection]->baseDocRoot; } return ""; } text_t oaiconfig::getMapping(const text_t &collection, const text_t &collectfield) { if (this->collectMap[collection] == NULL) { return ""; } return this->collectMap[collection]->fieldMap[collectfield]; } /** * Get the mapping for a field in a given collection; if no mapping * exists, the result will be a blank string. */ text_t oaiconfig::getMapping(const text_t &collection, const text_t &collectfield, const text_t &formatname) { text_t fullName = collectfield; fullName.append(":"); fullName.append(formatname); // try the collection-specific options first if (this->collectMap[collection] != NULL) { // first try the most specific item - this collection, and given that protocol if (this->collectMap[collection]->fieldMap.count(fullName) >= 1) { return this->collectMap[collection]->fieldMap[fullName]; } // otherwise, fall back to this collection, and all protocols else if (this->collectMap[collection]->fieldMap.count(collectfield) >= 1) { return this->collectMap[collection]->fieldMap[collectfield]; } } // if no mappings exist, return an empty item if (this->collectMap[""] == NULL) { return ""; } // then try generic rules if (this->collectMap[""]->fieldMap.count(fullName) >= 1) { return this->collectMap[""]->fieldMap[fullName]; } else { return this->collectMap[""]->fieldMap[collectfield]; } }