Index: /main/trunk/greenstone3/src/java/org/greenstone/gsdl3/core/FormatReceptionist.java
===================================================================
--- /main/trunk/greenstone3/src/java/org/greenstone/gsdl3/core/FormatReceptionist.java	(revision 22457)
+++ /main/trunk/greenstone3/src/java/org/greenstone/gsdl3/core/FormatReceptionist.java	(revision 22457)
@@ -0,0 +1,181 @@
+package org.greenstone.gsdl3.core;
+
+import org.greenstone.gsdl3.util.*;
+import org.greenstone.gsdl3.action.*;
+// XML classes
+import org.w3c.dom.Node; 
+import org.w3c.dom.NodeList; 
+import org.w3c.dom.Document; 
+import org.w3c.dom.Element; 
+
+// other java classes
+import java.io.File;
+import java.util.HashMap;
+import java.util.Enumeration;
+
+import org.apache.log4j.*;
+
+/** The default greenstone receptionist - needs some extra info for each page
+ */
+public class FormatReceptionist extends TransformingReceptionist {
+
+     static Logger logger = Logger.getLogger(org.greenstone.gsdl3.core.DefaultReceptionist.class.getName());
+    
+  /** add in the collection description to the page, then for each service, add in the service description */
+    protected void addExtraInfo(Element page) {
+      super.addExtraInfo(page);
+	
+	Element page_request = (Element)GSXML.getChildByTagName(page, GSXML.PAGE_REQUEST_ELEM);
+	// if it is a system request, then we don't bother with this.
+	String action = page_request.getAttribute(GSXML.ACTION_ATT);
+	if (action.equals("s")) {
+	    logger.error("HACK: don't ask for coll info if system action");
+	    return;
+	}
+	logger.debug("add extra info, page request="+this.converter.getString(page_request));
+	// is a collection defined?
+	Element param_list = (Element)GSXML.getChildByTagName(page_request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	if (param_list==null) { // must be the original home page
+	    logger.debug(" no param list, assuming home page");
+	    return;
+	}
+	Element coll_param = GSXML.getNamedElement(param_list, GSXML.PARAM_ELEM, GSXML.NAME_ATT, GSParams.COLLECTION);
+	if (coll_param == null) {
+	    logger.debug(" coll param is null, returning");
+	    return;
+	}
+
+	// see if the collection/cluster element is already there
+	String coll_name = coll_param.getAttribute(GSXML.VALUE_ATT);
+	String lang = page_request.getAttribute(GSXML.LANG_ATT);
+	String uid = page_request.getAttribute(GSXML.USER_ID_ATT);
+	
+	boolean get_service_description = false;
+	Element page_response = (Element)GSXML.getChildByTagName(page, GSXML.PAGE_RESPONSE_ELEM);
+	if (this.language_list != null) {
+	    page_response.appendChild(this.language_list);
+	}
+	Element coll_description = (Element)GSXML.getChildByTagName(page_response, GSXML.COLLECTION_ELEM);
+	if (coll_description == null) {
+	    // try cluster
+	    coll_description = (Element)GSXML.getChildByTagName(page_response, GSXML.CLUSTER_ELEM);
+	}
+	if (coll_description == null) { 
+	    // we dont have one yet - get it
+	    Element coll_about_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	    Element coll_about_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_DESCRIBE,  coll_name, lang, uid);
+	    coll_about_message.appendChild(coll_about_request);
+	    
+	    Node coll_about_response_message = this.mr.process(coll_about_message);
+	    Element coll_about_response = (Element)GSXML.getChildByTagName(coll_about_response_message, GSXML.RESPONSE_ELEM);
+	    if (coll_about_response == null) {
+		return;
+	    }
+	    coll_description = (Element)GSXML.getChildByTagName(coll_about_response, GSXML.COLLECTION_ELEM);
+	    if (coll_description==null) { // may be a cluster
+		coll_description = (Element)GSXML.getChildByTagName(coll_about_response, GSXML.CLUSTER_ELEM);
+	    }
+	    
+	    if (coll_description == null) {
+		logger.error(" no collection description, returning");
+		return;
+	    }
+	    // have found one, append it to the page response
+	    coll_description = (Element)this.doc.importNode(coll_description, true);
+	    page_response.appendChild(coll_description);
+	    get_service_description = true;
+	}
+
+	// have got a coll description
+	
+	// now get the dispay info for the services
+	Element service_list = (Element)GSXML.getChildByTagName(coll_description, GSXML.SERVICE_ELEM+GSXML.LIST_MODIFIER);
+	if (service_list == null) {
+	    logger.error(" no service list, returning");
+	    // something weird has gone wrong
+	    return;
+	}
+
+	NodeList services = service_list.getElementsByTagName(GSXML.SERVICE_ELEM);
+	if (services.getLength()==0) {
+	    logger.error("DefaultReceoptionist: no services found for colllection/cluster "+ coll_name);
+	    return;
+	}
+	// check one service for display items
+	if (!get_service_description) {
+	    // we dont know yet if we need to get these
+	    int i=1;
+	    Element test_s = (Element)services.item(0);
+	    while (i<services.getLength() && (test_s.getAttribute(GSXML.TYPE_ATT).equals(GSXML.SERVICE_TYPE_RETRIEVE) || test_s.getAttribute(GSXML.TYPE_ATT).equals(GSXML.SERVICE_TYPE_OAI))) {
+		test_s = (Element)services.item(i); i++;
+	    }
+	    if (i==services.getLength()) {
+		// we have only found retrieve or oai services, so dont need descripitons anyway
+		return;
+	    }
+	    if (GSXML.getChildByTagName(test_s, GSXML.DISPLAY_TEXT_ELEM) !=null) {
+		// have got descriptions already, 
+		return;
+	    }
+	}
+
+	// if get here, we need to get the service descriptions
+	    
+	// we will send all the requests in a single message
+	Element info_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	for (int i=0; i<services.getLength(); i++) {
+	    Element c = (Element)services.item(i);
+	    String name = c.getAttribute(GSXML.NAME_ATT);
+	    String address = GSPath.appendLink(coll_name, name);
+	    Element info_request = GSXML.createBasicRequest(this.doc,  GSXML.REQUEST_TYPE_DESCRIBE, address, lang, uid);
+	    Element req_param_list = this.doc.createElement(GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	    req_param_list.appendChild(GSXML.createParameter(this.doc, GSXML.SUBSET_PARAM, GSXML.DISPLAY_TEXT_ELEM+GSXML.LIST_MODIFIER));
+	    info_request.appendChild(req_param_list);
+	    info_message.appendChild(info_request);
+	    
+	}
+
+	Element info_response = (Element)this.mr.process(info_message);
+
+	NodeList service_responses = info_response.getElementsByTagName(GSXML.RESPONSE_ELEM);
+	// check that have same number of responses as collections
+	if (services.getLength() != service_responses.getLength()) {
+	    logger.error(" didn't get a response for each service - somethings gone wrong!");
+	    // for now, dont use the metadata
+	} else {
+	    for (int i=0; i<services.getLength(); i++) {
+		Element c1 = (Element)services.item(i);
+		Element c2 = (Element)GSXML.getChildByTagName((Element)service_responses.item(i), GSXML.SERVICE_ELEM);
+		if (c1 !=null && c2 !=null && c1.getAttribute(GSXML.NAME_ATT).equals(c2.getAttribute(GSXML.NAME_ATT))) {
+		    //add the service data into the original response
+		    GSXML.mergeElements(c1, c2);
+		} else {
+		    logger.debug(" response does not correspond to request!");
+		} 
+		
+	    }
+	}
+
+    // Request collection metadata
+    info_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
+    String address = GSPath.appendLink(coll_name, "CoverageMetadataRetrieve");
+    Element info_request = GSXML.createBasicRequest(this.doc,  GSXML.REQUEST_TYPE_PROCESS, address, lang, uid);
+    Element req_param_list = this.doc.createElement(GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+    req_param_list.appendChild(GSXML.createParameter(this.doc, "metadata", "All")); // GSXML.SUBSET_PARAM, GSXML.DISPLAY_TEXT_ELEM+GSXML.LIST_MODIFIER));
+    info_request.appendChild(req_param_list);
+    info_message.appendChild(info_request);
+
+    logger.error("************ Coverage Metadata request created");
+    logger.error("************ add extra info, page request="+this.converter.getString(info_message));
+
+    info_response = (Element)this.mr.process(info_message);
+    logger.error("************ page response="+this.converter.getString(info_response));
+
+    Element coverage_metadata = (Element)GSXML.getNodeByPath(info_response, "response/metadataSetList");
+    logger.error("************ This should be metadata set list="+this.converter.getString(coverage_metadata));
+    coverage_metadata = (Element)this.doc.importNode(coverage_metadata, true);
+    coll_description.appendChild(coverage_metadata);
+	
+    }
+}
+
Index: /main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/CoverageMetadataRetrieve.java
===================================================================
--- /main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/CoverageMetadataRetrieve.java	(revision 22457)
+++ /main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/CoverageMetadataRetrieve.java	(revision 22457)
@@ -0,0 +1,257 @@
+/*
+ * MyNewServicesTemplate.java - a dummy class showing how to create new 
+ * services for Greenstone3
+ *
+ * This class has two dummy services: TextQuery and MyDifferentService
+ */
+
+// This file needs to be put in org/greenstone/gsdl3/service
+package org.greenstone.gsdl3.service;
+
+// Greenstone classes
+import org.greenstone.gsdl3.util.*;
+
+// XML classes
+import org.w3c.dom.Document;
+import org.w3c.dom.Element; 
+import org.w3c.dom.NodeList;
+
+import org.apache.log4j.*;
+
+import java.util.Iterator;
+import java.util.Vector;
+import java.util.Set;
+
+// change the class name (and the filename) to something more appropriate
+public class CoverageMetadataRetrieve 
+    extends ServiceRack {
+
+    // add in a logger for error messages
+    static Logger logger = Logger.getLogger("CoverageMetadataRetrieve");
+
+    protected SimpleCollectionDatabase coll_db = null;
+    protected String index_stem = null;
+
+
+    // the new service names
+    protected static final String COVERAGE_SERVICE = "CoverageMetadataRetrieve";
+
+    // initialize any custom variables
+    public CoverageMetadataRetrieve() {
+
+    }
+
+    // clean up anything that we need to 
+    public void cleanUp() {
+	super.cleanUp();
+    }
+    
+    // Configure the class based in info in buildConfig.xml and collectionConfig.xml
+    // info is the <serviceRack name="MyNewServicesTemplate"/> element from
+    // buildConfig.xml, and extra_info is the whole collectionConfig.xml file
+    // in case its needed
+    public boolean configure(Element info, Element extra_info) {
+
+	if (!super.configure(info, extra_info)) {
+	    return false;
+	}
+
+	logger.info("Configuring CoverageMetadataRetrieve...");
+
+	// set up short_service_info - this currently is a list of services, 
+	// with their names and service types
+	// we have two services, a new textquery, and a new one of a new type
+	//Element tq_service = this.doc.createElement(GSXML.SERVICE_ELEM);
+	//tq_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_QUERY);
+	//tq_service.setAttribute(GSXML.NAME_ATT, QUERY_SERVICE);
+	//this.short_service_info.appendChild(tq_service);
+
+	Element diff_service = this.doc.createElement(GSXML.SERVICE_ELEM);
+	diff_service.setAttribute(GSXML.TYPE_ATT, "retrieve");
+	diff_service.setAttribute(GSXML.NAME_ATT, COVERAGE_SERVICE);
+	this.short_service_info.appendChild(diff_service);
+
+    // the index stem is either specified in the config file or is  the collection name
+    Element index_stem_elem = (Element) GSXML.getChildByTagName(info, GSXML.INDEX_STEM_ELEM);
+    if (index_stem_elem != null) {
+        this.index_stem = index_stem_elem.getAttribute(GSXML.NAME_ATT);
+    }
+    if (this.index_stem == null || this.index_stem.equals("")) {
+        logger.error("CoverageMetadataRetrieve.configure(): indexStem element not found, stem will default to collection name");
+        this.index_stem = this.cluster_name;
+    }
+
+    // find out what kind of database we have
+    Element database_type_elem = (Element) GSXML.getChildByTagName(info, GSXML.DATABASE_TYPE_ELEM);
+    String database_type = null;
+    if (database_type_elem != null) {
+      database_type = database_type_elem.getAttribute(GSXML.NAME_ATT);
+    }
+    if (database_type == null || database_type.equals("")) {
+      database_type = "gdbm"; // the default
+    }
+    coll_db = new SimpleCollectionDatabase(database_type);
+    if (coll_db == null) {
+      logger.error("Couldn't create the collection database of type "+database_type);
+      return false;
+    }
+
+    // Open database for querying
+    String coll_db_file = GSFile.collectionDatabaseFile(this.site_home, this.cluster_name, this.index_stem, database_type);
+    if (!this.coll_db.openDatabase(coll_db_file, SimpleCollectionDatabase.READ)) {
+        logger.error("Could not open collection database!");
+        return false;
+    }
+
+
+	// Extract any relevant information from info and extra_info
+	// This can be used to set up variables.
+
+	// If there is any formatting information, add it in to format_info_map
+	
+	// Do this for all services as appropriate
+	Element format = null; // find it from info/extra_info
+	if (format != null) {
+	    this.format_info_map.put(COVERAGE_SERVICE, this.doc.importNode(format, true));
+	}
+
+	return true;
+	
+    }
+
+    // get the desription of a service. Could include parameter lists, displayText
+    protected Element getServiceDescription(String service, String lang, String subset) {
+
+	// check that we have been asked for the right service
+	if (!service.equals(COVERAGE_SERVICE)) {
+	    return null;
+	}
+
+    /*
+	if (service.equals(QUERY_SERVICE)) {
+	    Element tq_service = this.doc.createElement(GSXML.SERVICE_ELEM);
+	    tq_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_QUERY);
+	    tq_service.setAttribute(GSXML.NAME_ATT, QUERY_SERVICE);
+	    if (subset==null || subset.equals(GSXML.DISPLAY_TEXT_ELEM+GSXML.LIST_MODIFIER)) {
+		// add in any <displayText> elements
+		// name, for example - get from properties file
+		tq_service.appendChild(GSXML.createDisplayTextElement(this.doc, GSXML.DISPLAY_TEXT_NAME, getTextString(QUERY_SERVICE+".name", lang) ));
+	    }
+	
+	    if (subset==null || subset.equals(GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER)) {
+		// add in a param list if this service has parameters
+		Element param_list = this.doc.createElement(GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+		tq_service.appendChild(param_list);
+		// create any params and append to param_list
+	    }
+	    return tq_service;
+	} 
+    */
+
+	if (service.equals(COVERAGE_SERVICE)) {
+	    Element diff_service = this.doc.createElement(GSXML.SERVICE_ELEM);
+	    diff_service.setAttribute(GSXML.TYPE_ATT, "retrieve");
+	    diff_service.setAttribute(GSXML.NAME_ATT, COVERAGE_SERVICE);
+	    if (subset==null || subset.equals(GSXML.DISPLAY_TEXT_ELEM+GSXML.LIST_MODIFIER)) {
+		// add in any <displayText> elements
+		// name, for example - get from properties file
+		diff_service.appendChild(GSXML.createDisplayTextElement(this.doc, GSXML.DISPLAY_TEXT_NAME, getTextString(COVERAGE_SERVICE+".name", lang) ));
+	    }
+	
+	    if (subset==null || subset.equals(GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER)) {
+		// add in a param list if this service has parameters
+		Element param_list = this.doc.createElement(GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+		diff_service.appendChild(param_list);
+		// create any params and append to param_list
+	    }
+
+	    return diff_service;
+	} 
+	
+	// not a valid service for this class
+	return null;
+	
+
+
+    }
+
+    /** This is the method that actually handles the TextQuery Service */
+    //protected Element processTextQuery(Element request) {
+
+	//Element result = this.doc.createElement(GSXML.RESPONSE_ELEM);
+	//result.setAttribute(GSXML.FROM_ATT, QUERY_SERVICE);
+	//result.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS);
+
+	// fill in the rest
+	//return result;
+    //}
+
+    /** This is the method that actually handles the MyDifferentService service */
+    protected Element processCoverageMetadataRetrieve(Element request) {
+
+    DBInfo collection_info = this.coll_db.getInfo("collection");
+    
+    Set keys = collection_info.getKeys();
+
+    Vector valid_keys = new Vector();
+
+    // Iterate over keys and add valid ones to the valid_keys vector
+    String current_key = null;
+    Iterator iter = keys.iterator();
+
+    while (iter.hasNext()) {
+        current_key = (String) iter.next();
+        if(current_key.matches("^metadatalist-([a-zA-Z][^-])*$"))
+        {
+            logger.error("********** ADDING " + current_key + " TO VALID KEYS LIST **********\n");
+            valid_keys.add(current_key);
+        }
+    }
+   
+    // Create response
+    Element result = this.doc.createElement(GSXML.RESPONSE_ELEM);
+    result.setAttribute(GSXML.FROM_ATT, COVERAGE_SERVICE);
+    result.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS);
+
+    Element metadataSetList = this.doc.createElement("metadataSetList");
+    result.appendChild(metadataSetList);
+
+
+    // Iterate over valid keys and build up response
+    Element metadataSet = null;
+    Element metadata = null;
+    String value = null;
+    String name = null;
+    iter = valid_keys.iterator();
+
+    while (iter.hasNext()) {
+        current_key = (String) iter.next();
+
+        // Create metadataSet using the current key and add to metadataSetList
+        metadataSet = this.doc.createElement("metadataSet");
+        if(current_key.indexOf("-") != -1)
+        {
+            name = current_key.split("-")[1];
+        }
+        metadataSet.setAttribute(GSXML.NAME_ATT, name);
+        metadataSetList.appendChild(metadataSet);
+
+        // Create a metadata element for each value and add to metadataSet
+        Vector sub_info = collection_info.getMultiInfo(current_key);
+        Iterator iter2 = sub_info.iterator();
+        while (iter2.hasNext()) {
+            value = (String) iter2.next();     
+            metadata = this.doc.createElement("metadata");
+            metadata.setAttribute(GSXML.NAME_ATT, value);
+            metadataSet.appendChild(metadata);
+        }
+
+    }
+
+    return result;
+
+    }
+}
+
+
+
