/********************************************************************** * * browsefilter.cpp -- * Copyright (C) 1999 The New Zealand Digital Library Project * * A component of the Greenstone digital library software * from the New Zealand Digital Library Project at the * University of Waikato, New Zealand. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * *********************************************************************/ #include "browsefilter.h" #include "colservertools.h" #include "fileutil.h" #include browsefilterclass::browsefilterclass () { db_ptr = NULL; oaidb_ptr = NULL; // -- onePerQuery StartResults integer FilterOption_t filtopt; filtopt.name = "StartResults"; filtopt.type = FilterOption_t::integert; filtopt.repeatable = FilterOption_t::onePerQuery; filtopt.defaultValue = "1"; filtopt.validValues.push_back("1"); filtopt.validValues.push_back("10000"); filterOptions["StartResults"] = filtopt; // -- onePerQuery EndResults integer filtopt.clear(); filtopt.name = "EndResults"; filtopt.type = FilterOption_t::integert; filtopt.repeatable = FilterOption_t::onePerQuery; filtopt.defaultValue = "-1"; filtopt.validValues.push_back("-1"); filtopt.validValues.push_back("10000"); filterOptions["EndResults"] = filtopt; // -- onePerQuery ParentNode string ("" will return the browsing available) filtopt.clear(); filtopt.name = "ParentNode"; filtopt.type = FilterOption_t::stringt; filtopt.repeatable = FilterOption_t::onePerQuery; filtopt.defaultValue = g_EmptyText; filterOptions["ParentNode"] = filtopt; } browsefilterclass::~browsefilterclass () {} void browsefilterclass::configure (const text_t &key, const text_tarray &cfgline) { filterclass::configure (key, cfgline); if (key == "indexstem") { indexstem = cfgline[0]; } } bool browsefilterclass::init (ostream &logout) { outconvertclass text_t2ascii; if (!filterclass::init(logout)) return false; if (db_ptr == NULL || oaidb_ptr == NULL) { // most likely a configuration problem logout << text_t2ascii << "configuration error: browsefilter contains a null dbclass\n\n"; return false; } if (indexstem.empty()) { indexstem = collection; } db_filename = resolve_db_filename(gsdlhome, dbhome, collecthome, collection, indexstem,db_ptr->getfileextension()); if (!file_exists(db_filename)) { logout << text_t2ascii << "warning: database \"" << db_filename << "\" does not exist\n\n"; // return false; } oaidb_filename = resolve_oaidb_filename(gsdlhome, dbhome, collecthome, collection, oaidb_ptr->getfileextension()); return true; } void browsefilterclass::filter (const FilterRequest_t &request, FilterResponse_t &response, comerror_t &err, ostream &logout) { int numDocs = 0; outconvertclass text_t2ascii; response.clear (); err = noError; // get the browse parameters int startresults = filterOptions["StartResults"].defaultValue.getint(); int endresults = filterOptions["EndResults"].defaultValue.getint(); text_t parentnode = filterOptions["ParentNode"].defaultValue; OptionValue_tarray::const_iterator options_here = request.filterOptions.begin(); OptionValue_tarray::const_iterator options_end = request.filterOptions.end(); while (options_here != options_end) { if ((*options_here).name == "StartResults") startresults = (*options_here).value.getint(); else if ((*options_here).name == "EndResults") endresults = (*options_here).value.getint(); else if ((*options_here).name == "ParentNode") parentnode = (*options_here).value; else { logout << text_t2ascii << "warning: unknown browsefilter option \"" << (*options_here).name << "\" ignored.\n\n"; } ++options_here; } // if we're only working on oai, open oai_db, no need to work with index_db in browsefilter.cpp // (but source.cpp uses both oai-inf.db and index.db to get metadata for OAI request) // If we can't open the oai-inf db, this can be because it didn't exist in older versions of GS // in that case, proceed as usual, using the index db. if((request.filterResultOptions & FROAI)) { // OAI request bool success = false; if(parentnode == "oai") { // doing an OAI listidentifiers request // open up the oai-inf db if it exists, and return all IDs *except* the special OID=OAI_EARLIESTTIMESTAMP_OID // if oai-inf db doesn't exist, proceed as usual success = get_oaiinf_db_entries(response, err, logout); //adds any stuff in oai-inf db for the current OID to resultdoc.metadata response.numDocs = response.docInfo.size(); response.isApprox = Exact; } if (success) return; // oai request successfully completed with oai-inf.db, no need to open index_db } // Since we're here, it means we're not doing anything oai (or oai-inf.db did not exist/open) // So we don't need to work with oai_db. Instead, work with index_db: if (db_ptr == NULL) { // most likely a configuration problem logout << text_t2ascii << "configuration error: browsefilter contains a null index dbclass\n\n"; err = configurationError; return; } // open the database db_ptr->setlogout(&logout); if (!db_ptr->opendatabase (db_filename, DB_READER, 100, false)) { // most likely a system problem (we have already checked that the database exists) logout << text_t2ascii << "system problem: open on database \"" << db_filename << "\" failed\n\n"; err = systemProblem; return; } infodbclass info; // translate any ".fc", ".pr" etc. stuff in the parentnode parentnode = db_ptr->translate_OID (parentnode, info); // adjust topmost browsing node if (parentnode.empty()) parentnode = "browse"; // get the node if ((request.filterResultOptions & FROID) || (request.filterResultOptions & FRmetadata)) { if (!db_ptr->getinfo(parentnode, info)) { // didn't find the node in index db logout << text_t2ascii << "warning: lookup for node \"" << parentnode << "\" failed for browsefilter.\n\n"; } else { // found the node // replace " with the parent node name and split the contains string // into the result set text_tarray resultset; text_t tmptext; text_t &contains = info["contains"]; text_t::iterator contains_here = contains.begin(); text_t::iterator contains_end = contains.end(); while (contains_here != contains_end) { if (*contains_here == '"') tmptext += parentnode; else if (*contains_here == ';') { if (!tmptext.empty()) resultset.push_back (tmptext); tmptext.clear(); } else tmptext.push_back(*contains_here); ++contains_here; } // insert the last result in the set if (!tmptext.empty()) resultset.push_back (tmptext); text_tarray offset_resultset; text_t &md_type = info["mdtype"]; if (!md_type.empty()) { text_t &md_offset = info["mdoffset"]; if (!md_offset.empty()) { text_t offsettext; text_t::iterator offset_here = md_offset.begin(); text_t::iterator offset_end = md_offset.end(); while (offset_here != offset_end) { if (*offset_here == ';') { if (offsettext.empty()) { offset_resultset.push_back ("0"); } else { offset_resultset.push_back (offsettext); } offsettext.clear(); } else { offsettext.push_back(*offset_here); } ++offset_here; } // insert the last result in the set if (offsettext.empty()) { offset_resultset.push_back ("0"); } else { offset_resultset.push_back (offsettext); } } else { // add 0 offset for each 'contains' entry text_tarray::iterator result_here = resultset.begin(); text_tarray::iterator result_end = resultset.end(); while (result_here != result_end) { offset_resultset.push_back("0"); ++result_here; } } // do an intersection with the input set if (!request.docSet.empty()) { text_tarray intersect_resultset; text_tarray intersect_offset_resultset; text_tarray::const_iterator resultset_here = resultset.begin(); text_tarray::const_iterator resultset_end = resultset.end(); text_tarray::const_iterator offset_resultset_here = offset_resultset.begin(); while (resultset_here != resultset_end) { if (in_set (request.docSet, *resultset_here)) { intersect_resultset.push_back (*resultset_here); intersect_offset_resultset.push_back (*offset_resultset_here); } ++resultset_here; ++offset_resultset_here; } resultset = intersect_resultset; offset_resultset = intersect_offset_resultset; } } else { // do an intersection with the input set if (!request.docSet.empty()) { intersect (resultset, request.docSet); } // add 0 offset for each 'contains' entry text_tarray::iterator result_here = resultset.begin(); text_tarray::iterator result_end = resultset.end(); while (result_here != result_end) { offset_resultset.push_back("0"); ++result_here; } } // create the response numDocs = resultset.size(); int resultnum = 1; ResultDocInfo_t resultdoc; text_tarray::iterator result_here = resultset.begin(); text_tarray::iterator result_end = resultset.end(); text_tarray::iterator offset_result_here = offset_resultset.begin(); while (result_here != result_end) { // if endresults is -1 get all results if ((endresults != -1) && (resultnum > endresults)) break; if (resultnum >= startresults) { resultdoc.OID = (*result_here); if (!md_type.empty()) { resultdoc.classifier_metadata_type = md_type; resultdoc.classifier_metadata_offset = offset_result_here->getint(); } response.docInfo.push_back(resultdoc); } ++resultnum; ++result_here; if (!md_type.empty()) ++offset_result_here; } } } db_ptr->closedatabase(); // Important that local library doesn't leave any files open response.numDocs = numDocs; response.isApprox = Exact; } bool browsefilterclass::get_oaiinf_db_entries(FilterResponse_t &response, comerror_t &err, ostream &logout) { outconvertclass text_t2ascii; //logout << text_t2ascii << "browsefilterclass::get_oaiinf_db_entries\n"; // ONLY if we're doing any OAI stuff (FROAI will be set then) will we be here // So next try to open the oai-inf db if it exists for this collection if (!file_exists(oaidb_filename)) { // if the oaidb file doesn't even exist, let's not bother with oaidb logout << text_t2ascii << "warning: collection's oai-inf database \"" << oaidb_filename << "\" does not exist\n\n"; return false; } else { // let's try opening the oaidb file oaidb_ptr->setlogout(&logout); if (!oaidb_ptr->opendatabase (oaidb_filename, DB_READER, 100, false)) { // most likely a system problem (we have already checked that the database exists just above) logout << text_t2ascii << "system problem: open on database \"" << oaidb_filename << "\" failed\n\n"; err = systemProblem; return false; } // now we've opened the oai-inf db file successfully } infodbclass oai_info; ResultDocInfo_t resultdoc; text_tarray keys = oaidb_ptr->getkeys(); text_tarray::iterator key_here = keys.begin(); text_tarray::iterator key_end = keys.end(); while (key_here != key_end) { resultdoc.OID = (*key_here); // OAI_EARLIESTTIMESTAMP_OID is the OID of a special record that we'll ignore // here in browsefilter.cpp, since it's not a doc. // When the *metadata* for this special OID is requested, source.cpp will handle it if(resultdoc.OID == OAI_EARLIESTTIMESTAMP_OID) { ++key_here; continue; } if(!oaidb_ptr->getinfo(resultdoc.OID, oai_info)) { logout << text_t2ascii << "warning: lookup for node \"" << resultdoc.OID << "\" in etc/oai-inf db failed for browsefilter.\n\n"; } // We don't need to get the oai metadata from oai-inf.db at this stage. That will be // handled by a separate metadata request. See collectserver::filter() and source.cpp's get_oai_metadata(). /* else { //logout << text_t2ascii << "@@@@ found node \"" << resultdoc.OID << "\" in etc/oai-inf db.\n\n"; resultdoc.metadata["oaiinf.status"].isRef = false; resultdoc.metadata["oaiinf.status"].values.push_back(oai_info["status"]); resultdoc.metadata["oaiinf.timestamp"].isRef = false; resultdoc.metadata["oaiinf.timestamp"].values.push_back(oai_info["timestamp"]); resultdoc.metadata["oaiinf.datestamp"].isRef = false; resultdoc.metadata["oaiinf.datestamp"].values.push_back(oai_info["datestamp"]); } */ response.docInfo.push_back(resultdoc); ++key_here; } // we're done with oai-inf db oaidb_ptr->closedatabase(); // don't leave files open return true; }