Index: gsdl/trunk/src/colservr/Makefile.in
===================================================================
--- gsdl/trunk/src/colservr/Makefile.in	(revision 15590)
+++ gsdl/trunk/src/colservr/Makefile.in	(revision 15591)
@@ -67,5 +67,4 @@
 	expat_resultset.cpp \
 	filter.cpp \
-	gdbmsource.cpp \
 	lucenegdbmsource.cpp \
 	lucenequeryfilter.cpp \
@@ -95,5 +94,4 @@
 	expat_resultset.o \
 	filter.o \
-	gdbmsource.o \
 	lucenegdbmsource.o \
 	lucenequeryfilter.o \
Index: gsdl/trunk/src/colservr/gdbmsource.cpp
===================================================================
--- gsdl/trunk/src/colservr/gdbmsource.cpp	(revision 15590)
+++ 	(revision )
@@ -1,382 +1,0 @@
-/**********************************************************************
- *
- * gdbmsource.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 "gdbmsource.h"
-#include "fileutil.h"
-#include "OIDtools.h"
-#include "gsdltools.h"
-
-
-gdbmsourceclass::gdbmsourceclass () {
-  db_ptr = NULL;
-  textsearchptr = NULL;
-  classname = "gdbmsource";
-}
-
-gdbmsourceclass::~gdbmsourceclass () {
-  if (db_ptr != NULL) delete db_ptr;
-  if (textsearchptr != NULL) delete textsearchptr;
-}
-
-void gdbmsourceclass::configure (const text_t &key, const text_tarray &cfgline) {
-  if (cfgline.size() >= 1) {
-    const text_t &value = cfgline[0];
-
-    if (key == "collection") collection = value;
-    else if (key == "collectdir") collectdir = value;
-    else if (key == "gsdlhome") gsdlhome = value;
-    else if (key == "gdbmhome") dbhome = value;
-  }
-
-  if (key == "indexmap") {
-    indexmap.importmap (cfgline);
-
-  } else if (key == "defaultindex") {
-    indexmap.from2to (cfgline[0], defaultindex);
-
-  } else if (key == "subcollectionmap") {
-    subcollectionmap.importmap (cfgline);
-
-  } else if (key == "defaultsubcollection") {
-    subcollectionmap.from2to (cfgline[0], defaultsubcollection);
-
-  } else if (key == "languagemap") {
-    languagemap.importmap (cfgline);
-
-  } else if (key == "defaultlanguage") {
-    languagemap.from2to (cfgline[0], defaultlanguage);
-  } else if (key == "indexstem") {
-    indexstem = cfgline[0];
-  }
-  
-}
-
-bool gdbmsourceclass::init (ostream &logout) {
-  outconvertclass text_t2ascii;
-  
-  if (dbhome.empty()) dbhome = gsdlhome;
-
-  if (!sourceclass::init (logout)) return false;
-
-  if (defaultindex.empty()) {
-    // use first index in map as default if no default is set explicitly
-    text_tarray toarray;
-    indexmap.gettoarray(toarray);
-    if (toarray.size()) {
-      defaultindex = toarray[0];
-    }
-  }
-
-  if (defaultsubcollection.empty()) {
-    // use first subcollection in map as default if no default is set explicitly
-    text_tarray toarray;
-    subcollectionmap.gettoarray(toarray);
-    if (toarray.size()) {
-      defaultsubcollection = toarray[0];
-    }
-  }
-
-  if (defaultlanguage.empty()) {
-    // use first language in map as default if no default is set explicitly
-    text_tarray toarray;
-    languagemap.gettoarray(toarray);
-    if (toarray.size()) {
-      defaultlanguage = toarray[0];
-    }
-  }
-  
-  // get the collection directory name
-  if (collectdir.empty()) {
-    collectdir = filename_cat (gsdlhome, "collect", collection);
-  }
-  
-  // get the filename for the database and make sure it exists
-  if (indexstem.empty()) {
-    indexstem = collection;
-  }
-  db_filename = filename_cat(dbhome, "collect", collection, "index", "text", indexstem);
-  if (littleEndian()) db_filename += ".ldb";
-  else db_filename += ".bdb";
-
-  if (!file_exists(db_filename)) {
-    logout << text_t2ascii
-	   << "warning: database \"" << db_filename << "\" does not exist\n\n";
-    // return false;
-  }
-  
-  return true;
-}
-
-bool gdbmsourceclass::translate_OID (const text_t &OIDin, text_t &OIDout, 
-				       comerror_t &err, ostream &logout) {
-
-  outconvertclass text_t2ascii;
-
-  err = noError;
-  if (db_ptr == NULL) {
-    // most likely a configuration problem
-    logout << text_t2ascii 
-	   << "configuration error: " << classname << " contains a null dbclass\n\n";
-    err = configurationError;
-    return true;
-  }
-
-  // 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 true;
-  }
-
-  infodbclass info;
-  OIDout = db_ptr->translate_OID (OIDin, info);
-  db_ptr->closedatabase();  // Important that local library doesn't leave any files open
-  return true;
-}
-
-bool gdbmsourceclass::get_metadata (const text_t &/*requestParams*/, const text_t &/*refParams*/, 
-				      bool getParents, const text_tset &fields, 
-				      const text_t &OID, MetadataInfo_tmap &metadata, 
-				      comerror_t &err, ostream &logout) {
-  outconvertclass text_t2ascii;
-
-  metadata.erase(metadata.begin(), metadata.end());
-
-  err = noError;
-  if (db_ptr == NULL) {
-    // most likely a configuration problem
-    logout << text_t2ascii 
-	   << "configuration error: " << classname <<" contains a null dbclass\n\n";
-    err = configurationError;
-    return true;
-  }
-
-  // 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 true;
-  }
-
-  // get the metadata - if getParents is set we need to get 
-  // info for all parents of OID as well as OID
-  vector<infodbclass> info_array;
-  text_tarray OIDs;
-  if (getParents) get_parents_array (OID, OIDs);
-  OIDs.push_back (OID);
-
-  text_tarray::const_iterator this_OID = OIDs.begin();
-  text_tarray::const_iterator end_OID = OIDs.end();
-
-  while (this_OID != end_OID) {
-    infodbclass info;
-    if (!db_ptr->getinfo(*this_OID, info)) return false;
-
-    // adjust the metadata
-    text_t &contains = info["contains"];
-    if (contains.empty()) info["haschildren"] = 0;
-    else info["haschildren"] = 1;
-    //contains.clear();
-
-    info_array.push_back(info);
-    ++this_OID;
-  }
-
-  // if fields set is empty we want to get all available metadata
-  text_tset tfields = fields;
-  if (tfields.empty() && !info_array.empty()) {
-    infodbclass::iterator t_info = info_array[0].begin(); 
-    infodbclass::iterator e_info = info_array[0].end(); 
-    while (t_info != e_info) {
-      if ((*t_info).first != "contains")
-	tfields.insert ((*t_info).first);
-      ++t_info;
-    }
-    tfields.insert ("hasnext");
-    tfields.insert ("hasprevious");
-  }
-    
-  // collect together the metadata
-  bool donenextprevtest = false;
-  bool hasnext=false, hasprevious=false;
-  MetadataInfo_t this_metadata;
-  text_tarray *pos_metadata;
-  text_tset::const_iterator fields_here = tfields.begin();
-  text_tset::const_iterator fields_end = tfields.end();
-
-  while (fields_here != fields_end) {
-    this_metadata.clear();
-    this_metadata.isRef = false;
-
-    vector<infodbclass>::reverse_iterator this_info = info_array.rbegin(); 
-    vector<infodbclass>::reverse_iterator end_info = info_array.rend(); 
-    MetadataInfo_t *tmetaptr = &this_metadata;
-    while (this_info != end_info) {
-
-      pos_metadata = (*this_info).getmultinfo(*fields_here);
-      if ((*fields_here == "hasnext" || *fields_here == "hasprevious")) {
-	
-	// collect metadata
-	if (!donenextprevtest) {
-	  donenextprevtest = true;
-	  
-	  // cache parent contents array
-	  text_t thisparent = get_parent (OID);
-	  if (!thisparent.empty()) {
-	    if (thisparent != parentOID) {
-	      parentOID = thisparent;
-	      parentcontents.erase(parentcontents.begin(), parentcontents.end());
-	      if (db_ptr->getinfo(parentOID, parentinfo)) {
-		text_t &parentinfocontains = parentinfo["contains"];
-		if (!parentinfocontains.empty())
-		  splitchar (parentinfocontains.begin(), parentinfocontains.end(), 
-			     ';', parentcontents);
-	      }
-	    }
-	    
-	    // do tests
-	    text_tarray::const_iterator parentcontents_here = parentcontents.begin();
-	    text_tarray::const_iterator parentcontents_end = parentcontents.end();
-	    text_t shrunk_OID = OID;
-	    shrink_parent (shrunk_OID);
-	    while (parentcontents_here != parentcontents_end) {
-	      if (*parentcontents_here == shrunk_OID) {
-		if (parentcontents_here == parentcontents.begin()) hasprevious = false;
-		else hasprevious = true;
-		
-		++parentcontents_here;
-		
-		if (parentcontents_here == parentcontents.end()) hasnext = false;
-		else hasnext = true;
-		
-		break;
-	      }  
-	      
-	      ++parentcontents_here;
-	    }
-	 
-	    // fill in metadata
-	    if ((*fields_here == "hasnext" && hasnext) ||
-		(*fields_here == "hasprevious" && hasprevious))
-	      tmetaptr->values.push_back("1");
-	    else
-	      tmetaptr->values.push_back("0");
-	  } else
-	    tmetaptr->values.push_back("0");
-	}
-      }
-      //else if (pos_metadata != NULL && *fields_here != "contains") {
-      else if (pos_metadata != NULL) {
-	tmetaptr->values = *pos_metadata;
-      }
-      else
-	tmetaptr->values.push_back("");
-
-      ++this_info;
-      if (this_info != end_info) {
-	tmetaptr->parent = new MetadataInfo_t();
-	tmetaptr = tmetaptr->parent;
-      }
-    }
-    metadata[*fields_here] = this_metadata;
-    ++fields_here;
-  }
-
-  db_ptr->closedatabase();  // Important that local library doesn't leave any files open
-  return true;
-}
-
-
-bool gdbmsourceclass::get_document (const text_t &OID, text_t &doc, 
-				      comerror_t &err, ostream &logout) {
-
-  outconvertclass text_t2ascii;
-
-  err = noError;
-  if (db_ptr == NULL) {
-    // most likely a configuration problem
-    logout << text_t2ascii 
-	   << "configuration error: " << classname << " contains a null dbclass\n\n";
-    err = configurationError;
-    return true;
-  }
-
-  // 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 true;
-  }
-
-  text_t tOID = OID;
-  if (needs_translating (OID)) 
-    translate_OID (OID, tOID, err, logout);
-  infodbclass info;
-  if (!db_ptr->getinfo(tOID, info)) {
-    db_ptr->closedatabase();  // Important that local library doesn't leave any files open
-    return false;
-  }
-  
-  if (info["hastxt"].getint() == 1) {
-    int docnum = info["docnum"].getint();
-    
-    // set the collection directory
-    textsearchptr->setcollectdir (collectdir);
-    
-    // get the text
-    textsearchptr->docTargetDocument(defaultindex, defaultsubcollection,
-				   defaultlanguage, collection, docnum, doc);
-  }
-
-  db_ptr->closedatabase();  // Important that local library doesn't leave any files open
-  return true;
-}
-
-bool gdbmsourceclass::is_searchable(bool &issearchable, comerror_t &err, ostream &logout) {
-  err = noError;
-  issearchable = false;
-
-  text_tarray fromarray;
-  indexmap.getfromarray(fromarray);
-  if (fromarray.size() == 0) {
-    return true;
-  } else if (fromarray.size() == 1) {
-    if (fromarray[0] == "dummy:text") {
-      // always return true - issearchable is false here though
-      return true;
-    }
-  }
-  issearchable = true;
-  return true;
-}
Index: gsdl/trunk/src/colservr/gdbmsource.h
===================================================================
--- gsdl/trunk/src/colservr/gdbmsource.h	(revision 15590)
+++ 	(revision )
@@ -1,95 +1,0 @@
-/**********************************************************************
- *
- * gdbmsource.h -- 
- * 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.
- *
- *********************************************************************/
-
-
-#ifndef GDBMSOURCE_H
-#define GDBMSOURCE_H
-
-#include "gsdlconf.h"
-#include "text_t.h"
-#include "comtypes.h"
-#include "dbclass.h"
-#include "maptools.h"
-#include "search.h"
-#include "source.h"
-
-
-class gdbmsourceclass : public sourceclass {
-protected:
-  text_t gsdlhome;
-  text_t dbhome;
-  text_t collection;
-  text_t collectdir;
-  
-  // these maps are only needed to convert the default indexes
-  stringmap indexmap;
-  stringmap subcollectionmap;
-  stringmap languagemap;
-
-  text_t defaultindex;
-  text_t defaultsubcollection;
-  text_t defaultlanguage;
-
-  text_t indexstem;
-
-  text_t parentOID;
-  infodbclass parentinfo;
-  text_tarray parentcontents;
-
-  text_t db_filename;
-  dbclass *db_ptr;
-  
-  searchclass *textsearchptr;
-
-public:
-  gdbmsourceclass ();
-  virtual ~gdbmsourceclass ();
-
-  // the DB ptr remains the responsibility of the calling code
-  void set_db_ptr (dbclass *db_ptr_arg) { db_ptr = db_ptr_arg; }
-
-  // the textsearchptr remains the responsibility of the calling code
-  void set_textsearchptr (searchclass *thetextsearchptr) {textsearchptr=thetextsearchptr;}
-
-  void configure (const text_t &key, const text_tarray &cfgline);
-  bool init (ostream &logout);
-  bool translate_OID (const text_t &OIDin, text_t &OIDout, 
-		      comerror_t &err, ostream &logout);
-  bool get_metadata (const text_t &requestParams, const text_t &refParams, 
-		     bool getParents, const text_tset &fields, 
-		     const text_t &OID, MetadataInfo_tmap &metadata, 
-		     comerror_t &err, ostream &logout);
-  bool get_document (const text_t &OID, text_t &doc, 
-		     comerror_t &err, ostream &logout);
-  bool is_searchable(bool &issearchable, comerror_t &err, ostream &logout);
-
- protected:
-  text_t classname;
-
-};
-
-
-
-#endif
Index: gsdl/trunk/src/colservr/lucenegdbmsource.cpp
===================================================================
--- gsdl/trunk/src/colservr/lucenegdbmsource.cpp	(revision 15590)
+++ gsdl/trunk/src/colservr/lucenegdbmsource.cpp	(revision 15591)
@@ -31,5 +31,5 @@
 
 lucenegdbmsourceclass::lucenegdbmsourceclass () 
-  : gdbmsourceclass()
+  : sourceclass()
 {
   classname = "lucenegdbmsource";
Index: gsdl/trunk/src/colservr/lucenegdbmsource.h
===================================================================
--- gsdl/trunk/src/colservr/lucenegdbmsource.h	(revision 15590)
+++ gsdl/trunk/src/colservr/lucenegdbmsource.h	(revision 15591)
@@ -33,8 +33,8 @@
 #include "maptools.h"
 #include "search.h"
-#include "gdbmsource.h"
+#include "source.h"
 
 
-class lucenegdbmsourceclass : public gdbmsourceclass {
+class lucenegdbmsourceclass : public sourceclass {
 public:
   lucenegdbmsourceclass ();
Index: gsdl/trunk/src/colservr/mggdbmsource.cpp
===================================================================
--- gsdl/trunk/src/colservr/mggdbmsource.cpp	(revision 15590)
+++ gsdl/trunk/src/colservr/mggdbmsource.cpp	(revision 15591)
@@ -26,6 +26,7 @@
 #include "mggdbmsource.h"
 
+
 mggdbmsourceclass::mggdbmsourceclass () 
-  : gdbmsourceclass()
+  : sourceclass()
 {
   classname = "mggdbsource";
Index: gsdl/trunk/src/colservr/mggdbmsource.h
===================================================================
--- gsdl/trunk/src/colservr/mggdbmsource.h	(revision 15590)
+++ gsdl/trunk/src/colservr/mggdbmsource.h	(revision 15591)
@@ -28,13 +28,8 @@
 #define MGGDBMSOURCE_H
 
-#include "gsdlconf.h"
-#include "text_t.h"
-#include "comtypes.h"
-#include "maptools.h"
-#include "search.h"
-#include "gdbmsource.h"
+#include "source.h"
 
 
-class mggdbmsourceclass : public gdbmsourceclass {
+class mggdbmsourceclass : public sourceclass {
 public:
   mggdbmsourceclass ();
@@ -44,4 +39,3 @@
 
 
-
 #endif
Index: gsdl/trunk/src/colservr/source.cpp
===================================================================
--- gsdl/trunk/src/colservr/source.cpp	(revision 15590)
+++ gsdl/trunk/src/colservr/source.cpp	(revision 15591)
@@ -25,24 +25,113 @@
 
 #include "source.h"
+#include "fileutil.h"
+#include "OIDtools.h"
+#include "gsdltools.h"
 #include <assert.h>
 
 
-// default constructor does nothing
-sourceclass::sourceclass () {
-}
-
-// default destructor does nothing
-sourceclass::~sourceclass () {
+sourceclass::sourceclass ()
+{
+  db_ptr = NULL;
+  textsearchptr = NULL;
+  classname = "source";
+}
+
+sourceclass::~sourceclass ()
+{
+  if (db_ptr != NULL) delete db_ptr;
+  if (textsearchptr != NULL) delete textsearchptr;
 }
 
 // configure should be called once for each configuration line
-// default does nothing
-void sourceclass::configure (const text_t &/*key*/, const text_tarray &/*cfgline*/) {
+void sourceclass::configure (const text_t &key, const text_tarray &cfgline)
+{
+  if (cfgline.size() >= 1) {
+    const text_t &value = cfgline[0];
+
+    if (key == "collection") collection = value;
+    else if (key == "collectdir") collectdir = value;
+    else if (key == "gsdlhome") gsdlhome = value;
+    else if (key == "gdbmhome") dbhome = value;
+  }
+
+  if (key == "indexmap") {
+    indexmap.importmap (cfgline);
+
+  } else if (key == "defaultindex") {
+    indexmap.from2to (cfgline[0], defaultindex);
+
+  } else if (key == "subcollectionmap") {
+    subcollectionmap.importmap (cfgline);
+
+  } else if (key == "defaultsubcollection") {
+    subcollectionmap.from2to (cfgline[0], defaultsubcollection);
+
+  } else if (key == "languagemap") {
+    languagemap.importmap (cfgline);
+
+  } else if (key == "defaultlanguage") {
+    languagemap.from2to (cfgline[0], defaultlanguage);
+  } else if (key == "indexstem") {
+    indexstem = cfgline[0];
+  }
 }
 
 // init should be called after all the configuration is done but
 // before any other methods are called
-// default does nothing
-bool sourceclass::init (ostream &/*logout*/) {
+bool sourceclass::init (ostream &logout)
+{
+  outconvertclass text_t2ascii;
+  
+  if (dbhome.empty()) dbhome = gsdlhome;
+
+  if (!sourceclass::init (logout)) return false;
+
+  if (defaultindex.empty()) {
+    // use first index in map as default if no default is set explicitly
+    text_tarray toarray;
+    indexmap.gettoarray(toarray);
+    if (toarray.size()) {
+      defaultindex = toarray[0];
+    }
+  }
+
+  if (defaultsubcollection.empty()) {
+    // use first subcollection in map as default if no default is set explicitly
+    text_tarray toarray;
+    subcollectionmap.gettoarray(toarray);
+    if (toarray.size()) {
+      defaultsubcollection = toarray[0];
+    }
+  }
+
+  if (defaultlanguage.empty()) {
+    // use first language in map as default if no default is set explicitly
+    text_tarray toarray;
+    languagemap.gettoarray(toarray);
+    if (toarray.size()) {
+      defaultlanguage = toarray[0];
+    }
+  }
+  
+  // get the collection directory name
+  if (collectdir.empty()) {
+    collectdir = filename_cat (gsdlhome, "collect", collection);
+  }
+  
+  // get the filename for the database and make sure it exists
+  if (indexstem.empty()) {
+    indexstem = collection;
+  }
+  db_filename = filename_cat(dbhome, "collect", collection, "index", "text", indexstem);
+  if (littleEndian()) db_filename += ".ldb";
+  else db_filename += ".bdb";
+
+  if (!file_exists(db_filename)) {
+    logout << text_t2ascii
+	   << "warning: database \"" << db_filename << "\" does not exist\n\n";
+    // return false;
+  }
+  
   return true;
 }
@@ -50,9 +139,32 @@
 
 // translate_OID translates OIDs using ".pr", ."fc" etc.
-bool sourceclass::translate_OID (const text_t &/*OIDin*/, text_t &/*OIDout*/, 
-				 comerror_t &err, ostream &/*logout*/) {
+bool sourceclass::translate_OID (const text_t &OIDin, text_t &OIDout, 
+				 comerror_t &err, ostream &logout)
+{
+  outconvertclass text_t2ascii;
+
   err = noError;
-
-  return false;
+  if (db_ptr == NULL) {
+    // most likely a configuration problem
+    logout << text_t2ascii 
+	   << "configuration error: " << classname << " contains a null dbclass\n\n";
+    err = configurationError;
+    return true;
+  }
+
+  // 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 true;
+  }
+
+  infodbclass info;
+  OIDout = db_ptr->translate_OID (OIDin, info);
+  db_ptr->closedatabase();  // Important that local library doesn't leave any files open
+  return true;
 }
 
@@ -60,30 +172,227 @@
 // get_metadata fills out the metadata if possible, if it is not responsable
 // for the given OID then it will return false.
-bool sourceclass::get_metadata (const text_t &/*requestParams*/, const text_t &/*refParams*/, 
-				bool /*getParents*/, const text_tset &/*fields*/, 
-				const text_t &/*OID*/, MetadataInfo_tmap &metadata, 
-				comerror_t &err, ostream &/*logout*/) {
+bool sourceclass::get_metadata (const text_t &requestParams, const text_t &refParams, 
+				bool getParents, const text_tset &fields, 
+				const text_t &OID, MetadataInfo_tmap &metadata, 
+				comerror_t &err, ostream &logout)
+{
+  outconvertclass text_t2ascii;
+
   metadata.erase(metadata.begin(), metadata.end());
+
   err = noError;
-
-  return false;
-}
-
-bool sourceclass::get_document (const text_t &/*OID*/, text_t &/*doc*/, 
-				comerror_t &err, ostream &/*logout*/) {
+  if (db_ptr == NULL) {
+    // most likely a configuration problem
+    logout << text_t2ascii 
+	   << "configuration error: " << classname <<" contains a null dbclass\n\n";
+    err = configurationError;
+    return true;
+  }
+
+  // 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 true;
+  }
+
+  // get the metadata - if getParents is set we need to get 
+  // info for all parents of OID as well as OID
+  vector<infodbclass> info_array;
+  text_tarray OIDs;
+  if (getParents) get_parents_array (OID, OIDs);
+  OIDs.push_back (OID);
+
+  text_tarray::const_iterator this_OID = OIDs.begin();
+  text_tarray::const_iterator end_OID = OIDs.end();
+
+  while (this_OID != end_OID) {
+    infodbclass info;
+    if (!db_ptr->getinfo(*this_OID, info)) return false;
+
+    // adjust the metadata
+    text_t &contains = info["contains"];
+    if (contains.empty()) info["haschildren"] = 0;
+    else info["haschildren"] = 1;
+    //contains.clear();
+
+    info_array.push_back(info);
+    ++this_OID;
+  }
+
+  // if fields set is empty we want to get all available metadata
+  text_tset tfields = fields;
+  if (tfields.empty() && !info_array.empty()) {
+    infodbclass::iterator t_info = info_array[0].begin(); 
+    infodbclass::iterator e_info = info_array[0].end(); 
+    while (t_info != e_info) {
+      if ((*t_info).first != "contains")
+	tfields.insert ((*t_info).first);
+      ++t_info;
+    }
+    tfields.insert ("hasnext");
+    tfields.insert ("hasprevious");
+  }
+    
+  // collect together the metadata
+  bool donenextprevtest = false;
+  bool hasnext=false, hasprevious=false;
+  MetadataInfo_t this_metadata;
+  text_tarray *pos_metadata;
+  text_tset::const_iterator fields_here = tfields.begin();
+  text_tset::const_iterator fields_end = tfields.end();
+
+  while (fields_here != fields_end) {
+    this_metadata.clear();
+    this_metadata.isRef = false;
+
+    vector<infodbclass>::reverse_iterator this_info = info_array.rbegin(); 
+    vector<infodbclass>::reverse_iterator end_info = info_array.rend(); 
+    MetadataInfo_t *tmetaptr = &this_metadata;
+    while (this_info != end_info) {
+
+      pos_metadata = (*this_info).getmultinfo(*fields_here);
+      if ((*fields_here == "hasnext" || *fields_here == "hasprevious")) {
+	
+	// collect metadata
+	if (!donenextprevtest) {
+	  donenextprevtest = true;
+	  
+	  // cache parent contents array
+	  text_t thisparent = get_parent (OID);
+	  if (!thisparent.empty()) {
+	    if (thisparent != parentOID) {
+	      parentOID = thisparent;
+	      parentcontents.erase(parentcontents.begin(), parentcontents.end());
+	      if (db_ptr->getinfo(parentOID, parentinfo)) {
+		text_t &parentinfocontains = parentinfo["contains"];
+		if (!parentinfocontains.empty())
+		  splitchar (parentinfocontains.begin(), parentinfocontains.end(), 
+			     ';', parentcontents);
+	      }
+	    }
+	    
+	    // do tests
+	    text_tarray::const_iterator parentcontents_here = parentcontents.begin();
+	    text_tarray::const_iterator parentcontents_end = parentcontents.end();
+	    text_t shrunk_OID = OID;
+	    shrink_parent (shrunk_OID);
+	    while (parentcontents_here != parentcontents_end) {
+	      if (*parentcontents_here == shrunk_OID) {
+		if (parentcontents_here == parentcontents.begin()) hasprevious = false;
+		else hasprevious = true;
+		
+		++parentcontents_here;
+		
+		if (parentcontents_here == parentcontents.end()) hasnext = false;
+		else hasnext = true;
+		
+		break;
+	      }  
+	      
+	      ++parentcontents_here;
+	    }
+	 
+	    // fill in metadata
+	    if ((*fields_here == "hasnext" && hasnext) ||
+		(*fields_here == "hasprevious" && hasprevious))
+	      tmetaptr->values.push_back("1");
+	    else
+	      tmetaptr->values.push_back("0");
+	  } else
+	    tmetaptr->values.push_back("0");
+	}
+      }
+      //else if (pos_metadata != NULL && *fields_here != "contains") {
+      else if (pos_metadata != NULL) {
+	tmetaptr->values = *pos_metadata;
+      }
+      else
+	tmetaptr->values.push_back("");
+
+      ++this_info;
+      if (this_info != end_info) {
+	tmetaptr->parent = new MetadataInfo_t();
+	tmetaptr = tmetaptr->parent;
+      }
+    }
+    metadata[*fields_here] = this_metadata;
+    ++fields_here;
+  }
+
+  db_ptr->closedatabase();  // Important that local library doesn't leave any files open
+  return true;
+}
+
+bool sourceclass::get_document (const text_t &OID, text_t &doc, 
+				comerror_t &err, ostream &logout)
+{
+  outconvertclass text_t2ascii;
+
   err = noError;
-
-  return false;
-}
-
-bool sourceclass::is_searchable(bool &issearchable, comerror_t &err, ostream &logout) {
-
-  // currently defaults to claiming the collection is searchable!!
+  if (db_ptr == NULL) {
+    // most likely a configuration problem
+    logout << text_t2ascii 
+	   << "configuration error: " << classname << " contains a null dbclass\n\n";
+    err = configurationError;
+    return true;
+  }
+
+  // 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 true;
+  }
+
+  text_t tOID = OID;
+  if (needs_translating (OID)) 
+    translate_OID (OID, tOID, err, logout);
+  infodbclass info;
+  if (!db_ptr->getinfo(tOID, info)) {
+    db_ptr->closedatabase();  // Important that local library doesn't leave any files open
+    return false;
+  }
+  
+  if (info["hastxt"].getint() == 1) {
+    int docnum = info["docnum"].getint();
+    
+    // set the collection directory
+    textsearchptr->setcollectdir (collectdir);
+    
+    // get the text
+    textsearchptr->docTargetDocument(defaultindex, defaultsubcollection,
+				   defaultlanguage, collection, docnum, doc);
+  }
+
+  db_ptr->closedatabase();  // Important that local library doesn't leave any files open
+  return true;
+}
+
+bool sourceclass::is_searchable(bool &issearchable, comerror_t &err, ostream &logout)
+{
+  err = noError;
+  issearchable = false;
+
+  text_tarray fromarray;
+  indexmap.getfromarray(fromarray);
+  if (fromarray.size() == 0) {
+    return true;
+  } else if (fromarray.size() == 1) {
+    if (fromarray[0] == "dummy:text") {
+      // always return true - issearchable is false here though
+      return true;
+    }
+  }
   issearchable = true;
-
-  err = noError;
-  
-  return false;
-}
+  return true;
+}
+
 
 bool operator==(const sourceptr &x, const sourceptr &y) {
Index: gsdl/trunk/src/colservr/source.h
===================================================================
--- gsdl/trunk/src/colservr/source.h	(revision 15590)
+++ gsdl/trunk/src/colservr/source.h	(revision 15591)
@@ -30,11 +30,47 @@
 #include "gsdlconf.h"
 #include "text_t.h"
+#include "dbclass.h"
+#include "search.h"
 #include "comtypes.h"
+#include "maptools.h"
 
 
 class sourceclass {
+protected:
+  text_t classname;
+
+  text_t gsdlhome;
+  text_t dbhome;
+  text_t collection;
+  text_t collectdir;
+
+  stringmap indexmap;
+  stringmap subcollectionmap;
+  stringmap languagemap;
+
+  text_t defaultindex;
+  text_t defaultsubcollection;
+  text_t defaultlanguage;
+
+  text_t indexstem;
+
+  text_t parentOID;
+  infodbclass parentinfo;
+  text_tarray parentcontents;
+
+  text_t db_filename;
+  dbclass *db_ptr;
+
+  searchclass *textsearchptr;
+
 public:
   sourceclass ();
   virtual ~sourceclass ();
+
+  // the DB ptr remains the responsibility of the calling code
+  void set_db_ptr (dbclass *db_ptr_arg) { db_ptr = db_ptr_arg; }
+
+  // the textsearchptr remains the responsibility of the calling code
+  void set_textsearchptr (searchclass *textsearchptr_arg) { textsearchptr = textsearchptr_arg; }
 
   // configure should be called once for each configuration line
