Index: main/trunk/greenstone3/src/java/org/greenstone/gsdl3/collection/Collection.java
===================================================================
--- main/trunk/greenstone3/src/java/org/greenstone/gsdl3/collection/Collection.java	(revision 26445)
+++ main/trunk/greenstone3/src/java/org/greenstone/gsdl3/collection/Collection.java	(revision 26446)
@@ -36,4 +36,5 @@
 import org.greenstone.gsdl3.util.GSXML;
 import org.greenstone.gsdl3.util.OAIXML;
+import org.greenstone.gsdl3.util.SimpleMacroResolver;
 import org.greenstone.gsdl3.util.UserContext;
 import org.greenstone.gsdl3.util.XMLTransformer;
@@ -55,11 +56,16 @@
 	static Logger logger = Logger.getLogger(org.greenstone.gsdl3.collection.Collection.class.getName());
 
-	/** is this collection being tidied */
+	/** is this collection being tidied and therefore can support realistic book view?*/
 	protected boolean useBook = false;
-	/** is this collection public or private */
+	/** is this collection public or private  - public collections will 
+	    appear on the home page, whereas private collections won't*/
 	protected boolean is_public = true;
+	/** collection type : mg, mgpp or lucene */
+	protected String col_type = "";
+	/** database type : gdbm, jdbm or sqlite */
+	protected String db_type = "";
 
 	/** does this collection provide the OAI service */
-	protected boolean has_oai = true;
+	protected boolean has_oai = false;
 	/** time when this collection was built */
 	protected long lastmodified = 0;
@@ -75,10 +81,5 @@
 	protected ArrayList<HashMap<String, ArrayList<String>>> _securityExceptions = new ArrayList<HashMap<String, ArrayList<String>>>();
 
-	/**
-	 * An element containing the serviceRackList element of buildConfig.xml,
-	 * used to determine whether it contains the OAIPMH serviceRack
-	 */
-	//protected Element service_rack_list = null;
-
+  
 	protected XMLTransformer transformer = null;
 
@@ -112,4 +113,6 @@
 			return false;
 		}
+		
+		macro_resolver.addMacro("_httpcollection_", this.site_http_address + "/collect/" + this.cluster_name);
 
 		Element coll_config_xml = loadCollConfigFile();
@@ -138,7 +141,12 @@
 		}
 
+		this.description.setAttribute(GSXML.TYPE_ATT, col_type);
+		this.description.setAttribute(GSXML.DB_TYPE_ATT, db_type);
+		
 		_globalFormat = (Element) GSXML.getChildByTagName(coll_config_xml, GSXML.FORMAT_ELEM);
-
-		// process the metadata and display items
+		// process the metadata and display items and default library params
+		super.configureLocalData(coll_config_xml);
+		super.configureLocalData(build_config_xml);
+		// get extra collection specific stuff
 		findAndLoadInfo(coll_config_xml, build_config_xml);
 
@@ -197,5 +205,5 @@
 			return null;
 		}
-		// get the xml for both files
+		// get the xml
 		Document coll_config_doc = this.converter.getDOM(coll_config_file, CONFIG_ENCODING);
 		Element coll_config_elem = null;
@@ -237,20 +245,17 @@
 	protected boolean findAndLoadInfo(Element coll_config_xml, Element build_config_xml)
 	{
-		Element meta_list = (Element) GSXML.getChildByTagName(coll_config_xml, GSXML.METADATA_ELEM + GSXML.LIST_MODIFIER);
-		addMetadata(meta_list);
-		meta_list = (Element) GSXML.getChildByTagName(build_config_xml, GSXML.METADATA_ELEM + GSXML.LIST_MODIFIER);
-		addMetadata(meta_list);
-
-		meta_list = this.doc.createElement(GSXML.METADATA_ELEM + GSXML.LIST_MODIFIER);
-		GSXML.addMetadata(this.doc, meta_list, "httpPath", this.site_http_address + "/collect/" + this.cluster_name);
-		addMetadata(meta_list);
+		// Element meta_list = (Element) GSXML.getChildByTagName(coll_config_xml, GSXML.METADATA_ELEM + GSXML.LIST_MODIFIER);
+		// addMetadata(meta_list);
+		// meta_list = (Element) GSXML.getChildByTagName(build_config_xml, GSXML.METADATA_ELEM + GSXML.LIST_MODIFIER);
+		// addMetadata(meta_list);
+		addMetadata("httpPath", this.site_http_address + "/collect/" + this.cluster_name);
 
 		// display stuff
-		Element display_list = (Element) GSXML.getChildByTagName(coll_config_xml, GSXML.DISPLAY_TEXT_ELEM + GSXML.LIST_MODIFIER);
-		if (display_list != null)
-		{
-			resolveMacros(display_list);
-			addDisplayItems(display_list);
-		}
+		// Element display_list = (Element) GSXML.getChildByTagName(coll_config_xml, GSXML.DISPLAY_TEXT_ELEM + GSXML.LIST_MODIFIER);
+		// if (display_list != null)
+		// {
+		// 	resolveMacros(display_list);
+		// 	addDisplayItems(display_list);
+		// }
 
 		//check whether the html are tidy or not
@@ -259,5 +264,5 @@
 		{
 			Element plugin_list = (Element) GSXML.getChildByTagName(import_list, GSXML.PLUGIN_ELEM + GSXML.LIST_MODIFIER);
-			addPlugins(plugin_list);
+			//addPlugins(plugin_list);
 			if (plugin_list != null)
 			{
@@ -274,10 +279,6 @@
 			}
 		}
-		meta_list = this.doc.createElement(GSXML.METADATA_ELEM + GSXML.LIST_MODIFIER);
-		if (useBook == true)
-			GSXML.addMetadata(this.doc, meta_list, "tidyoption", "tidy");
-		else
-			GSXML.addMetadata(this.doc, meta_list, "tidyoption", "untidy");
-		addMetadata(meta_list);
+		String tidy = (useBook == true ? "tidy" : "untidy");
+		addMetadata("tidyoption", tidy);
 
 		// check whether we are public or not
@@ -389,79 +390,53 @@
 		clearServices();
 		Element service_list = (Element) GSXML.getChildByTagName(build_config_xml, GSXML.SERVICE_CLASS_ELEM + GSXML.LIST_MODIFIER);
-		configureServiceRackList(service_list, coll_config_xml);
-
+		Element oai_service_rack = null;
+		if (service_list != null) {
+		  configureServiceRackList(service_list, coll_config_xml);
+		  oai_service_rack = GSXML.getNamedElement(service_list, GSXML.SERVICE_CLASS_ELEM, OAIXML.NAME, OAIXML.OAIPMH);
+		}
 		// collection Config may also contain manually added service racks
 		service_list = (Element) GSXML.getChildByTagName(coll_config_xml, GSXML.SERVICE_CLASS_ELEM + GSXML.LIST_MODIFIER);
 		if (service_list != null)
 		{
-			configureServiceRackList(service_list, build_config_xml);
-
-			// Check for oai
-			Element oai_service_rack = GSXML.getNamedElement(service_list, GSXML.SERVICE_CLASS_ELEM, OAIXML.NAME, OAIXML.OAIPMH);
-			if (oai_service_rack == null)
-			{
-				has_oai = false;
-				logger.info("No oai for collection: " + this.cluster_name);
-
-			}
-			else
-			{
-				has_oai = true;
-
-				// extract earliestDatestamp from the buildconfig.xml for OAI
-				Element metadata_list = (Element) GSXML.getChildByTagName(build_config_xml, GSXML.METADATA_ELEM + GSXML.LIST_MODIFIER);
-
-				if (metadata_list != null)
-				{
-					NodeList children = metadata_list.getElementsByTagName(GSXML.METADATA_ELEM);
-					// can't do getChildNodes(), because whitespace, such as newlines, creates Text nodes
-					for (int i = 0; i < children.getLength(); i++)
-					{
-						Element metadata = (Element) children.item(i);
-						if (metadata.getAttribute(GSXML.NAME_ATT).equals(OAIXML.EARLIEST_DATESTAMP))
-						{
-							String earliestDatestampStr = GSXML.getValue(metadata);
-							if (!earliestDatestampStr.equals(""))
-							{
-								earliestDatestamp = Long.parseLong(earliestDatestampStr);
-							}
-							break; // found a metadata element with name=earliestDatestamp in buildconfig
-						}
-					}
-				}
-
-				// If at the end of this, there is no value for earliestDatestamp, print out a warning
-				logger.warn("No earliestDatestamp in buildConfig.xml for collection: " + this.cluster_name + ". Defaulting to 0.");
-
-			}
-		}
-		else
-		{ // no list of services (no ServiceRackList), so no oai_service_rack either
-			// explicitly set has_oai to false here, since it's initialised to true by default
-			has_oai = false;
-		}
+		  configureServiceRackList(service_list, build_config_xml);
+		  // this oai used in preference to one in buildConfig.xml
+		  oai_service_rack = GSXML.getNamedElement(service_list, GSXML.SERVICE_CLASS_ELEM, OAIXML.NAME, OAIXML.OAIPMH);
+		}
+		// Check for oai
+
+		if (oai_service_rack != null)
+		  {
+		    has_oai = true;
+		    logger.info(this.cluster_name +" has OAI services");
+		    // extract earliestDatestamp from the buildconfig.xml for OAI
+		    Element metadata_list = (Element) GSXML.getChildByTagName(build_config_xml, GSXML.METADATA_ELEM + GSXML.LIST_MODIFIER);
+		    
+		    if (metadata_list != null)
+		      {
+			NodeList children = metadata_list.getElementsByTagName(GSXML.METADATA_ELEM);
+			// can't do getChildNodes(), because whitespace, such as newlines, creates Text nodes
+			for (int i = 0; i < children.getLength(); i++)
+			  {
+			    Element metadata = (Element) children.item(i);
+			    if (metadata.getAttribute(GSXML.NAME_ATT).equals(OAIXML.EARLIEST_DATESTAMP))
+			      {
+				String earliestDatestampStr = GSXML.getValue(metadata);
+				if (!earliestDatestampStr.equals(""))
+				  {
+				    earliestDatestamp = Long.parseLong(earliestDatestampStr);
+				  }
+				break; // found a metadata element with name=earliestDatestamp in buildconfig
+			      }
+			  }
+		      }
+		    
+		    // If at the end of this, there is no value for earliestDatestamp, print out a warning
+		    logger.warn("No earliestDatestamp in buildConfig.xml for collection: " + this.cluster_name + ". Defaulting to 0.");
+		    
+		  } // if oai_service_rack != null
+	
 		return true;
 	}
 
-	protected boolean resolveMacros(Element display_list)
-	{
-		if (display_list == null)
-			return false;
-		NodeList displaynodes = display_list.getElementsByTagName(GSXML.DISPLAY_TEXT_ELEM);
-		if (displaynodes.getLength() > 0)
-		{
-			String http_site = this.site_http_address;
-			String http_collection = this.site_http_address + "/collect/" + this.cluster_name;
-			for (int k = 0; k < displaynodes.getLength(); k++)
-			{
-				Element d = (Element) displaynodes.item(k);
-				String text = GSXML.getNodeText(d);
-				text = StringUtils.replace(text, "_httpsite_", http_site);
-				text = StringUtils.replace(text, "_httpcollection_", http_collection);
-				GSXML.setNodeText(d, text);
-			}
-		}
-		return true;
-	}
 
 	/**
@@ -485,6 +460,8 @@
 		}
 
-		if (subset.equals(GSXML.METADATA_ELEM + GSXML.LIST_MODIFIER) || subset.equals(GSXML.DISPLAY_TEXT_ELEM + GSXML.LIST_MODIFIER) || subset.equals(GSXML.PLUGIN_ELEM + GSXML.LIST_MODIFIER))
-		{
+		if (subset.equals(GSXML.METADATA_ELEM + GSXML.LIST_MODIFIER) || subset.equals(GSXML.DISPLAY_TEXT_ELEM + GSXML.LIST_MODIFIER) || subset.equals("libraryParamList"))
+		{
+		  configureLocalData(coll_config_elem);
+		  configureLocalData(build_config_elem);
 			return findAndLoadInfo(coll_config_elem, build_config_elem);
 
@@ -504,283 +481,53 @@
 	protected Element processMessage(Element request)
 	{
-
+	  String type = request.getAttribute(GSXML.TYPE_ATT);
+		if (type.equals(GSXML.REQUEST_TYPE_FORMAT_STRING))
+		{
+		  return processFormatStringRequest(request);
+		}
+		else if (type.equals(GSXML.REQUEST_TYPE_SECURITY))
+		{
+		  return processSecurityRequest(request);
+		}
+		else if (type.equals(GSXML.REQUEST_TYPE_FORMAT))
+		{
 		Element response = this.doc.createElement(GSXML.RESPONSE_ELEM);
 		response.setAttribute(GSXML.FROM_ATT, this.cluster_name);
-		String type = request.getAttribute(GSXML.TYPE_ATT);
-		String lang = request.getAttribute(GSXML.LANG_ATT);
-		response.setAttribute(GSXML.TYPE_ATT, type);
-
-		if (type.equals(GSXML.REQUEST_TYPE_FORMAT_STRING))
-		{
-			String subaction = request.getAttribute("subaction");
-			String service = request.getAttribute("service");
-
-			String classifier = null;
-			if (service.equals("ClassifierBrowse"))
-			{
-				classifier = request.getAttribute("classifier");
-			}
-
-			// check for version file
-			String directory = new File(GSFile.collectionConfigFile(this.site_home, this.cluster_name)).getParent() + File.separator;
-
-			String version_filename = "";
-			if (service.equals("ClassifierBrowse"))
-				version_filename = directory + "browse_" + classifier + "_format_statement_version.txt";
-			else
-				version_filename = directory + "query_format_statement_version.txt";
-
-			File version_file = new File(version_filename);
-
-			if (subaction.equals("update"))
-			{
-				Element format_element = (Element) GSXML.getChildByTagName(request, GSXML.FORMAT_STRING_ELEM);
-				//String format_string = GSXML.getNodeText(format_element);
-				Element format_statement = (Element) format_element.getFirstChild();
-
-				String version_number = "1";
-				BufferedWriter writer;
-
-				try
-				{
-
-					if (version_file.exists())
-					{
-						// Read version
-						BufferedReader reader = new BufferedReader(new FileReader(version_filename));
-						version_number = reader.readLine();
-						int aInt = Integer.parseInt(version_number) + 1;
-						version_number = Integer.toString(aInt);
-						reader.close();
-					}
-					else
-					{
-						// Create
-						version_file.createNewFile();
-						writer = new BufferedWriter(new FileWriter(version_filename));
-						writer.write(version_number);
-						writer.close();
-					}
-
-					// Write version file
-					String format_statement_filename = "";
-
-					if (service.equals("ClassifierBrowse"))
-						format_statement_filename = directory + "browse_" + classifier + "_format_statement_v" + version_number + ".txt";
-					else
-						format_statement_filename = directory + "query_format_statement_v" + version_number + ".txt";
-
-					// Write format statement
-					String format_string = this.converter.getString(format_statement); //GSXML.xmlNodeToString(format_statement);
-					writer = new BufferedWriter(new FileWriter(format_statement_filename));
-					writer.write(format_string);
-					writer.close();
-
-					// Update version number
-					writer = new BufferedWriter(new FileWriter(version_filename));
-					writer.write(version_number);
-					writer.close();
-
-				}
-				catch (IOException e)
-				{
-					logger.error("IO Exception " + e);
-				}
-			}
-
-			if (subaction.equals("saveDocument"))
-			{
-				Element format_element = (Element) GSXML.getChildByTagName(request, GSXML.FORMAT_STRING_ELEM);
-				//String format_string = GSXML.getNodeText(format_element);
-				// Get display tag
-				Element display_format = (Element) format_element.getFirstChild();
-
-				String collection_config = directory + "collectionConfig.xml";
-				Document config = this.converter.getDOM(new File(collection_config), "UTF-8");
-
-				Node current_node = GSXML.getChildByTagName(config, "CollectionConfig");
-
-				// Get display child
-				if (GSXML.getChildByTagName(current_node, "display") == null)
-				{
-					// well then create a format tag
-					Element display_tag = config.createElement("display");
-					current_node = (Node) current_node.appendChild(display_tag);
-				}
-				else
-				{
-					current_node = GSXML.getChildByTagName(current_node, "display");
-				}
-
-				if (GSXML.getChildByTagName(current_node, "format") == null)
-				{
-					// well then create a format tag
-					Element format_tag = config.createElement("format");
-					current_node.appendChild(format_tag);
-				}
-
-				current_node.replaceChild(config.importNode(display_format, true), GSXML.getChildByTagName(current_node, "format"));
-
-				String new_config = this.converter.getString(config);
-
-				new_config = StringUtils.replace(new_config, "&lt;", "<");
-				new_config = StringUtils.replace(new_config, "&gt;", ">");
-				new_config = StringUtils.replace(new_config, "&quot;", "\"");
-
-				try
-				{
-					// Write to file (not original! for now)
-					BufferedWriter writer = new BufferedWriter(new FileWriter(collection_config + ".new"));
-					writer.write(new_config);
-					writer.close();
-				}
-				catch (IOException e)
-				{
-					logger.error("IO Exception " + e);
-				}
-			}
-
-			if (subaction.equals("save"))
-			{
-				Element format_element = (Element) GSXML.getChildByTagName(request, GSXML.FORMAT_STRING_ELEM);
-				Element format_statement = (Element) format_element.getFirstChild();
-
-				try
-				{
-					// open collectionConfig.xml and read in to w3 Document
-					String collection_config = directory + "collectionConfig.xml";
-					Document config = this.converter.getDOM(new File(collection_config), "UTF-8");
-
-					//String tag_name = "";
-					int k;
-					int index;
-					Element elem;
-					// Try importing entire tree to this.doc so we can add and remove children at ease
-					//Node current_node = this.doc.importNode(GSXML.getChildByTagName(config, "CollectionConfig"),true);
-					Node current_node = GSXML.getChildByTagName(config, "CollectionConfig");
-					NodeList current_node_list;
-
-					if (service.equals("ClassifierBrowse"))
-					{
-						//tag_name = "browse";
-						// if CLX then need to look in <classifier> X then <format>
-						// default is <browse><format>
-
-						current_node = GSXML.getChildByTagName(current_node, "browse");
-
-						// find CLX
-						if (classifier != null)
-						{
-							current_node_list = GSXML.getChildrenByTagName(current_node, "classifier");
-							index = Integer.parseInt(classifier.substring(2)) - 1;
-
-							// index should be given by X-1
-							current_node = current_node_list.item(index);
-							// what if classifier does not have a format tag?
-							if (GSXML.getChildByTagName(current_node, "format") == null)
-							{
-								// well then create a format tag
-								Element format_tag = config.createElement("format");
-								current_node.appendChild(format_tag);
-							}
-						}
-						else
-						{
-							// To support all classifiers, set classifier to null?  There is the chance here that the format tag does not exist
-							if (GSXML.getChildByTagName(current_node, "format") == null)
-							{
-								// well then create a format tag
-								Element format_tag = config.createElement("format");
-								current_node.appendChild(format_tag);
-							}
-						}
-					}
-					else if (service.equals("AllClassifierBrowse"))
-					{
-						current_node = GSXML.getChildByTagName(current_node, "browse");
-						if (GSXML.getChildByTagName(current_node, "format") == null)
-						{
-							// well then create a format tag
-							Element format_tag = config.createElement("format");
-							current_node.appendChild(format_tag);
-						}
-					}
-					else
-					{
-						// look in <format> with no attributes
-						current_node_list = GSXML.getChildrenByTagName(current_node, "search");
-						for (k = 0; k < current_node_list.getLength(); k++)
-						{
-							current_node = current_node_list.item(k);
-							// if current_node has no attributes then break
-							elem = (Element) current_node;
-							if (elem.hasAttribute("name") == false)
-								break;
-						}
-					}
-
-					current_node.replaceChild(config.importNode(format_statement, true), GSXML.getChildByTagName(current_node, "format"));
-
-					// Now convert config document to string for writing to file
-					String new_config = this.converter.getString(config);
-
-					new_config = StringUtils.replace(new_config, "&lt;", "<");
-					new_config = StringUtils.replace(new_config, "&gt;", ">");
-					new_config = StringUtils.replace(new_config, "&quot;", "\"");
-
-					// Write to file (not original! for now)
-					BufferedWriter writer = new BufferedWriter(new FileWriter(collection_config + ".new"));
-					writer.write(new_config);
-					writer.close();
-
-				}
-				catch (Exception ex)
-				{
-					logger.error("There was an exception " + ex);
-
-					StringWriter sw = new StringWriter();
-					PrintWriter pw = new PrintWriter(sw, true);
-					ex.printStackTrace(pw);
-					pw.flush();
-					sw.flush();
-					logger.error(sw.toString());
-				}
-
-			}
-		}
-		else if (type.equals(GSXML.REQUEST_TYPE_SECURITY))
-		{
-			String oid = request.getAttribute("oid");
-			if (oid.contains("."))
-			{
-				oid = oid.substring(0, oid.indexOf("."));
-			}
-
-			ArrayList<String> groups = getPermittedGroups(oid);
-
-			Element groupList = this.doc.createElement(GSXML.GROUP_ELEM + GSXML.LIST_MODIFIER);
-			response.appendChild(groupList);
-
-			for (String groupName : groups)
-			{
-				Element group = this.doc.createElement(GSXML.GROUP_ELEM);
-				groupList.appendChild(group);
-				group.setAttribute(GSXML.NAME_ATT, groupName);
-			}
-		}
-		else if (type.equals(GSXML.REQUEST_TYPE_FORMAT))
-		{
+		response.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_FORMAT);
 			if(_globalFormat != null)
 			{
-				response.appendChild(response.getOwnerDocument().importNode(_globalFormat, true));
-			}
-		}
-		else
-		{ // unknown type
-			return super.processMessage(request);
-
-		}
-		return response;
-	}
+				response.appendChild(this.doc.importNode(_globalFormat, true));
+			}
+			return response;
+		}
+		// unknown type
+		return super.processMessage(request);
+
+	}
+
+  protected Element processSecurityRequest(Element request) {
+    Element response = this.doc.createElement(GSXML.RESPONSE_ELEM);
+    response.setAttribute(GSXML.FROM_ATT, this.cluster_name);
+    response.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_SECURITY);
+    
+    String oid = request.getAttribute("oid");
+    if (oid.contains("."))
+      {
+	oid = oid.substring(0, oid.indexOf("."));
+      }
+    
+    ArrayList<String> groups = getPermittedGroups(oid);
+    
+    Element groupList = this.doc.createElement(GSXML.GROUP_ELEM + GSXML.LIST_MODIFIER);
+    response.appendChild(groupList);
+    
+    for (String groupName : groups)
+      {
+	Element group = this.doc.createElement(GSXML.GROUP_ELEM);
+	groupList.appendChild(group);
+	group.setAttribute(GSXML.NAME_ATT, groupName);
+      }
+    return response;
+  }
 
 	protected ArrayList<String> getPermittedGroups(String oid)
@@ -933,3 +680,247 @@
 		return null;
 	}
+
+  protected Element processFormatStringRequest(Element request) {
+    Element response = this.doc.createElement(GSXML.RESPONSE_ELEM);
+    response.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_FORMAT_STRING);
+    response.setAttribute(GSXML.FROM_ATT, this.cluster_name);
+
+    String subaction = request.getAttribute("subaction");
+    String service = request.getAttribute("service");
+    
+    String classifier = null;
+    if (service.equals("ClassifierBrowse"))
+      {
+	classifier = request.getAttribute("classifier");
+      }
+
+    // check for version file
+    String directory = new File(GSFile.collectionConfigFile(this.site_home, this.cluster_name)).getParent() + File.separator;
+
+    String version_filename = "";
+    if (service.equals("ClassifierBrowse"))
+      version_filename = directory + "browse_" + classifier + "_format_statement_version.txt";
+    else
+      version_filename = directory + "query_format_statement_version.txt";
+
+    File version_file = new File(version_filename);
+
+    if (subaction.equals("update"))
+      {
+	Element format_element = (Element) GSXML.getChildByTagName(request, GSXML.FORMAT_STRING_ELEM);
+	//String format_string = GSXML.getNodeText(format_element);
+	Element format_statement = (Element) format_element.getFirstChild();
+
+	String version_number = "1";
+	BufferedWriter writer;
+
+	try
+	  {
+
+	    if (version_file.exists())
+	      {
+		// Read version
+		BufferedReader reader = new BufferedReader(new FileReader(version_filename));
+		version_number = reader.readLine();
+		int aInt = Integer.parseInt(version_number) + 1;
+		version_number = Integer.toString(aInt);
+		reader.close();
+	      }
+	    else
+	      {
+		// Create
+		version_file.createNewFile();
+		writer = new BufferedWriter(new FileWriter(version_filename));
+		writer.write(version_number);
+		writer.close();
+	      }
+
+	    // Write version file
+	    String format_statement_filename = "";
+
+	    if (service.equals("ClassifierBrowse"))
+	      format_statement_filename = directory + "browse_" + classifier + "_format_statement_v" + version_number + ".txt";
+	    else
+	      format_statement_filename = directory + "query_format_statement_v" + version_number + ".txt";
+
+	    // Write format statement
+	    String format_string = this.converter.getString(format_statement); //GSXML.xmlNodeToString(format_statement);
+	    writer = new BufferedWriter(new FileWriter(format_statement_filename));
+	    writer.write(format_string);
+	    writer.close();
+
+	    // Update version number
+	    writer = new BufferedWriter(new FileWriter(version_filename));
+	    writer.write(version_number);
+	    writer.close();
+
+	  }
+	catch (IOException e)
+	  {
+	    logger.error("IO Exception " + e);
+	  }
+      }
+
+    if (subaction.equals("saveDocument"))
+      {
+	Element format_element = (Element) GSXML.getChildByTagName(request, GSXML.FORMAT_STRING_ELEM);
+	//String format_string = GSXML.getNodeText(format_element);
+	// Get display tag
+	Element display_format = (Element) format_element.getFirstChild();
+
+	String collection_config = directory + "collectionConfig.xml";
+	Document config = this.converter.getDOM(new File(collection_config), "UTF-8");
+
+	Node current_node = GSXML.getChildByTagName(config, "CollectionConfig");
+
+	// Get display child
+	if (GSXML.getChildByTagName(current_node, "display") == null)
+	  {
+	    // well then create a format tag
+	    Element display_tag = config.createElement("display");
+	    current_node = (Node) current_node.appendChild(display_tag);
+	  }
+	else
+	  {
+	    current_node = GSXML.getChildByTagName(current_node, "display");
+	  }
+
+	if (GSXML.getChildByTagName(current_node, "format") == null)
+	  {
+	    // well then create a format tag
+	    Element format_tag = config.createElement("format");
+	    current_node.appendChild(format_tag);
+	  }
+
+	current_node.replaceChild(config.importNode(display_format, true), GSXML.getChildByTagName(current_node, "format"));
+
+	String new_config = this.converter.getString(config);
+
+	new_config = StringUtils.replace(new_config, "&lt;", "<");
+	new_config = StringUtils.replace(new_config, "&gt;", ">");
+	new_config = StringUtils.replace(new_config, "&quot;", "\"");
+
+	try
+	  {
+	    // Write to file (not original! for now)
+	    BufferedWriter writer = new BufferedWriter(new FileWriter(collection_config + ".new"));
+	    writer.write(new_config);
+	    writer.close();
+	  }
+	catch (IOException e)
+	  {
+	    logger.error("IO Exception " + e);
+	  }
+      }
+
+    if (subaction.equals("save"))
+      {
+	Element format_element = (Element) GSXML.getChildByTagName(request, GSXML.FORMAT_STRING_ELEM);
+	Element format_statement = (Element) format_element.getFirstChild();
+
+	try
+	  {
+	    // open collectionConfig.xml and read in to w3 Document
+	    String collection_config = directory + "collectionConfig.xml";
+	    Document config = this.converter.getDOM(new File(collection_config), "UTF-8");
+
+	    //String tag_name = "";
+	    int k;
+	    int index;
+	    Element elem;
+	    // Try importing entire tree to this.doc so we can add and remove children at ease
+	    //Node current_node = this.doc.importNode(GSXML.getChildByTagName(config, "CollectionConfig"),true);
+	    Node current_node = GSXML.getChildByTagName(config, "CollectionConfig");
+	    NodeList current_node_list;
+
+	    if (service.equals("ClassifierBrowse"))
+	      {
+		//tag_name = "browse";
+		// if CLX then need to look in <classifier> X then <format>
+		// default is <browse><format>
+
+		current_node = GSXML.getChildByTagName(current_node, "browse");
+
+		// find CLX
+		if (classifier != null)
+		  {
+		    current_node_list = GSXML.getChildrenByTagName(current_node, "classifier");
+		    index = Integer.parseInt(classifier.substring(2)) - 1;
+
+		    // index should be given by X-1
+		    current_node = current_node_list.item(index);
+		    // what if classifier does not have a format tag?
+		    if (GSXML.getChildByTagName(current_node, "format") == null)
+		      {
+			// well then create a format tag
+			Element format_tag = config.createElement("format");
+			current_node.appendChild(format_tag);
+		      }
+		  }
+		else
+		  {
+		    // To support all classifiers, set classifier to null?  There is the chance here that the format tag does not exist
+		    if (GSXML.getChildByTagName(current_node, "format") == null)
+		      {
+			// well then create a format tag
+			Element format_tag = config.createElement("format");
+			current_node.appendChild(format_tag);
+		      }
+		  }
+	      }
+	    else if (service.equals("AllClassifierBrowse"))
+	      {
+		current_node = GSXML.getChildByTagName(current_node, "browse");
+		if (GSXML.getChildByTagName(current_node, "format") == null)
+		  {
+		    // well then create a format tag
+		    Element format_tag = config.createElement("format");
+		    current_node.appendChild(format_tag);
+		  }
+	      }
+	    else
+	      {
+		// look in <format> with no attributes
+		current_node_list = GSXML.getChildrenByTagName(current_node, "search");
+		for (k = 0; k < current_node_list.getLength(); k++)
+		  {
+		    current_node = current_node_list.item(k);
+		    // if current_node has no attributes then break
+		    elem = (Element) current_node;
+		    if (elem.hasAttribute("name") == false)
+		      break;
+		  }
+	      }
+
+	    current_node.replaceChild(config.importNode(format_statement, true), GSXML.getChildByTagName(current_node, "format"));
+
+	    // Now convert config document to string for writing to file
+	    String new_config = this.converter.getString(config);
+
+	    new_config = StringUtils.replace(new_config, "&lt;", "<");
+	    new_config = StringUtils.replace(new_config, "&gt;", ">");
+	    new_config = StringUtils.replace(new_config, "&quot;", "\"");
+
+	    // Write to file (not original! for now)
+	    BufferedWriter writer = new BufferedWriter(new FileWriter(collection_config + ".new"));
+	    writer.write(new_config);
+	    writer.close();
+
+	  }
+	catch (Exception ex)
+	  {
+	    logger.error("There was an exception " + ex);
+
+	    StringWriter sw = new StringWriter();
+	    PrintWriter pw = new PrintWriter(sw, true);
+	    ex.printStackTrace(pw);
+	    pw.flush();
+	    sw.flush();
+	    logger.error(sw.toString());
+	  }
+
+      }
+
+    return response;
+  }
 }
Index: main/trunk/greenstone3/src/java/org/greenstone/gsdl3/collection/ServiceCluster.java
===================================================================
--- main/trunk/greenstone3/src/java/org/greenstone/gsdl3/collection/ServiceCluster.java	(revision 26445)
+++ main/trunk/greenstone3/src/java/org/greenstone/gsdl3/collection/ServiceCluster.java	(revision 26446)
@@ -32,4 +32,5 @@
 import org.greenstone.gsdl3.util.GSPath;
 import org.greenstone.gsdl3.util.GSXML;
+import org.greenstone.gsdl3.util.SimpleMacroResolver;
 import org.greenstone.gsdl3.util.UserContext;
 import org.greenstone.gsdl3.util.XMLConverter;
@@ -42,6 +43,4 @@
  * Implements ModuleInterface. Contains a list of services provided by the cluster, along with metadata about the cluster itself.
  * a collection is a special type of cluster
- *  @author <a href="mailto:kjdon@cs.waikato.ac.nz">Katherine Don</a>
- *  @version $Revision$
  *  @see ModuleInterface
  */
@@ -61,9 +60,5 @@
 	/** The name of the cluster - for a collection, this is the collection name */
 	protected String cluster_name = null;
-	/** collection type : mg, mgpp or lucene */
-	protected String col_type = "";
-	/** database type : gdbm, jdbm or sqlite */
-	protected String db_type = "";
-
+ 
 	/** a reference to the message router */
 	protected MessageRouter router = null;
@@ -85,4 +80,6 @@
 	/** XML converter for String to DOM and vice versa */
 	protected XMLConverter converter = null;
+  /** a MacroResolver for resolving macros in displayItems */
+  protected SimpleMacroResolver macro_resolver = null;
 
 	/** container doc for description elements */
@@ -92,12 +89,14 @@
 	/** list of metadata - all metadata, regardless of language goes in here */
 	protected Element metadata_list = null;
-	/** language specific stuff */
-	//protected Element lang_specific_metadata_list = null;
+  /** language specific display items */
+
 	protected Element display_item_list = null;
+  /** default values for servlet params */
+  protected Element library_param_list = null;
 	/** the element that will have any descriptions passed back in */
 	protected Element description = null;
 
 	/** list of plugin */
-	protected Element plugin_item_list = null;
+	//protected Element plugin_item_list = null;
 
 	protected Element _globalFormat = null;
@@ -139,9 +138,12 @@
 		this.service_name_map = new HashMap<String, String>();
 		this.converter = new XMLConverter();
+		this.macro_resolver = new SimpleMacroResolver();
 		this.doc = this.converter.newDOM();
 		this.description = this.doc.createElement(GSXML.CLUSTER_ELEM);
 		this.display_item_list = this.doc.createElement(GSXML.DISPLAY_TEXT_ELEM + GSXML.LIST_MODIFIER);
 		this.metadata_list = this.doc.createElement(GSXML.METADATA_ELEM + GSXML.LIST_MODIFIER);
-		this.plugin_item_list = this.doc.createElement(GSXML.PLUGIN_ELEM + GSXML.LIST_MODIFIER);
+		this.library_param_list = this.doc.createElement("libraryParamList");
+		this.service_list = this.doc.createElement(GSXML.SERVICE_ELEM + GSXML.LIST_MODIFIER);
+		//this.plugin_item_list = this.doc.createElement(GSXML.PLUGIN_ELEM + GSXML.LIST_MODIFIER);
 	}
 
@@ -156,4 +158,5 @@
 	 * parsed. This method will work with any subclass.
 	 * 
+	 * This is called by ServiceCluster itself when asked to do a reconfigure
 	 * @return true if configure successful, false otherwise.
 	 */
@@ -167,4 +170,5 @@
 		}
 		logger.info("configuring service cluster");
+		macro_resolver.addMacro("_httpsite_", this.site_http_address);
 		// read the site configuration file
 		File config_file = new File(GSFile.siteConfigFile(this.site_home));
@@ -187,10 +191,55 @@
 		Element sc = GSXML.getNamedElement(cluster_list, GSXML.CLUSTER_ELEM, GSXML.NAME_ATT, this.cluster_name);
 
+		// this is probably a reconfigure, so clear all previous info
+		clearServices();
+		clearLocalData();
 		return this.configure(sc);
 	}
 
+  /** this is called by configure(), but also by MR when it is loading up all the service clusters */
 	public boolean configure(Element service_cluster_info)
 	{
-
+	  configureLocalData(service_cluster_info);
+		// //get the plugin info
+		// Element import_list = (Element) GSXML.getChildByTagName(service_cluster_info, GSXML.IMPORT_ELEM);
+		// if (import_list != null)
+		// {
+		// 	Element plugin_list = (Element) GSXML.getChildByTagName(service_cluster_info, GSXML.PLUGIN_ELEM + GSXML.LIST_MODIFIER);
+		// 	if (plugin_list != null)
+		// 	{
+		// 		if (!addPlugins(plugin_list))
+		// 		{
+
+		// 			logger.error("couldn't configure the plugins");
+		// 		}
+		// 	}
+		// }
+
+		// do the service racks
+		// empty the service map in case this is a reconfigure
+		//clearServices();
+		Element service_rack_list = (Element) GSXML.getChildByTagName(service_cluster_info, GSXML.SERVICE_CLASS_ELEM + GSXML.LIST_MODIFIER);
+		logger.error("cluster service rack list =");
+		logger.error(GSXML.xmlNodeToString(service_rack_list));
+		if (service_rack_list == null)
+		{
+			// is this an error? could you ever have a service cluster
+			// without service racks???
+			logger.error(cluster_name+" has no service racks!!");
+		}
+		else
+		{
+
+			if (!configureServiceRackList(service_rack_list, null))
+			{
+				logger.error("couldn't configure "+cluster_name+" service racks!!");
+				return false;
+			}
+		}
+
+		return true;
+	}
+
+    protected void configureLocalData(Element service_cluster_info) {
 		// get the metadata - for now just add it to the list
 		Element meta_list = (Element) GSXML.getChildByTagName(service_cluster_info, GSXML.METADATA_ELEM + GSXML.LIST_MODIFIER);
@@ -208,4 +257,5 @@
 		if (display_list != null)
 		{
+		  resolveMacros(display_list);
 			if (!addDisplayItems(display_list))
 			{
@@ -215,42 +265,13 @@
 		}
 
-		//get the plugin info
-		Element import_list = (Element) GSXML.getChildByTagName(service_cluster_info, GSXML.IMPORT_ELEM);
-		if (import_list != null)
-		{
-			Element plugin_list = (Element) GSXML.getChildByTagName(service_cluster_info, GSXML.PLUGIN_ELEM + GSXML.LIST_MODIFIER);
-			if (plugin_list != null)
-			{
-				if (!addPlugins(plugin_list))
-				{
-
-					logger.error("couldn't configure the plugins");
-				}
-			}
-		}
-
-		// do the service racks
-		// empty the service map in case this is a reconfigure
-		clearServices();
-		Element service_rack_list = (Element) GSXML.getChildByTagName(service_cluster_info, GSXML.SERVICE_CLASS_ELEM + GSXML.LIST_MODIFIER);
-		if (service_rack_list == null)
-		{
-			// is this an error? could you ever have a service cluster
-			// without service racks???
-			logger.error("cluster has no service racks!!");
-		}
-		else
-		{
-
-			if (!configureServiceRackList(service_rack_list, null))
-			{
-				logger.error("couldn't configure the  service racks!!");
-				return false;
-			}
-		}
-
-		return true;
-	}
-
+		// get the servlet params
+		Element param_list = (Element) GSXML.getChildByTagName(service_cluster_info, "libraryParamList");
+		if (param_list != null) {
+		  if (!addLibraryParams(param_list)) {
+		    logger.error("couldn't configure the library param list");
+		  }
+		}
+
+  }
 	/**
 	 * adds metadata from a metadataList into the metadata_list xml
@@ -271,5 +292,15 @@
 		return true;
 	}
-
+  /** adds an individual metadata element into the list */
+  protected boolean addMetadata(String name, String value) {
+    return GSXML.addMetadata(this.doc, this.metadata_list, name, value);
+  }
+  
+  /** in displayItemList, end up with the following for each named displayItem
+      <displayItem name="">
+        <displayItem name="" lang="">value</displayItem>
+        <displayItem name="" lang="">value</displayItem>
+      </displayItem>
+  */
 	protected boolean addDisplayItems(Element display_list)
 	{
@@ -305,26 +336,74 @@
 	}
 
-	protected boolean addPlugins(Element plugin_list)
-	{
-		if (plugin_list == null)
-			return false;
-		NodeList pluginNodes = plugin_list.getElementsByTagName(GSXML.PLUGIN_ELEM);
-		if (pluginNodes.getLength() > 0)
-		{
-			for (int k = 0; k < pluginNodes.getLength(); k++)
-			{
-				this.plugin_item_list.appendChild(this.doc.importNode(pluginNodes.item(k), true));
-			}
-		}
-
+	// protected boolean addPlugins(Element plugin_list)
+	// {
+	// 	if (plugin_list == null)
+	// 		return false;
+	// 	NodeList pluginNodes = plugin_list.getElementsByTagName(GSXML.PLUGIN_ELEM);
+	// 	if (pluginNodes.getLength() > 0)
+	// 	{
+	// 		for (int k = 0; k < pluginNodes.getLength(); k++)
+	// 		{
+	// 			this.plugin_item_list.appendChild(this.doc.importNode(pluginNodes.item(k), true));
+	// 		}
+	// 	}
+
+	// 	return true;
+	// }
+	protected boolean resolveMacros(Element display_list)
+	{
+		if (display_list == null)
+			return false;
+		NodeList displaynodes = display_list.getElementsByTagName(GSXML.DISPLAY_TEXT_ELEM);
+		if (displaynodes.getLength() > 0)
+		{
+		  //String http_site = this.site_http_address;
+		  //String http_collection = this.site_http_address + "/collect/" + this.cluster_name;
+			for (int k = 0; k < displaynodes.getLength(); k++)
+			{
+				Element d = (Element) displaynodes.item(k);
+				String text = GSXML.getNodeText(d);
+				text= macro_resolver.resolve(text);
+				//text = StringUtils.replace(text, "_httpsite_", http_site);
+				//text = StringUtils.replace(text, "_httpcollection_", http_collection);
+				GSXML.setNodeText(d, text);
+			}
+		}
 		return true;
 	}
 
+  	/**
+	 * adds library params from libraryParamList into library_param_list xml
+	 */
+	protected boolean addLibraryParams(Element param_list)
+	{
+		if (param_list == null)
+			return false;
+		NodeList paramnodes = param_list.getElementsByTagName(GSXML.PARAM_ELEM);
+		if (paramnodes.getLength() > 0)
+		{
+			for (int k = 0; k < paramnodes.getLength(); k++)
+			{
+				this.library_param_list.appendChild(this.doc.importNode(paramnodes.item(k), true));
+			}
+		}
+
+		return true;
+	}
 	protected void clearServices()
 	{
+	  cleanUp();
 		service_map.clear();
+		service_name_map.clear();
 		this.service_list = this.doc.createElement(GSXML.SERVICE_ELEM + GSXML.LIST_MODIFIER);
 	}
 
+  protected void clearLocalData() {
+    this.description = this.doc.createElement(GSXML.CLUSTER_ELEM);
+    this.display_item_list = this.doc.createElement(GSXML.DISPLAY_TEXT_ELEM + GSXML.LIST_MODIFIER);
+    this.metadata_list = this.doc.createElement(GSXML.METADATA_ELEM + GSXML.LIST_MODIFIER);
+    this.library_param_list = this.doc.createElement("libraryParamList");
+ 
+  }
 	/**
 	 * creates and configures all the services - extra_info is some more xml
@@ -555,6 +634,6 @@
 			Element description = (Element) this.description.cloneNode(false);
 			// set collection type : mg, mgpp, lucene or solr
-			description.setAttribute(GSXML.TYPE_ATT, col_type);
-			description.setAttribute(GSXML.DB_TYPE_ATT, db_type);
+			//description.setAttribute(GSXML.TYPE_ATT, col_type);
+			//description.setAttribute(GSXML.DB_TYPE_ATT, db_type);
 
 			response.appendChild(description);
@@ -566,5 +645,6 @@
 				description.appendChild(this.service_list);
 				description.appendChild(this.metadata_list);
-				description.appendChild(this.plugin_item_list);
+				description.appendChild(this.library_param_list);
+				//description.appendChild(this.plugin_item_list);
 				return response;
 			}
@@ -586,5 +666,5 @@
 					else if (info.equals(GSXML.METADATA_ELEM + GSXML.LIST_MODIFIER))
 					{
-						description.appendChild(metadata_list);
+						description.appendChild(this.metadata_list);
 					}
 					else if (info.equals(GSXML.DISPLAY_TEXT_ELEM + GSXML.LIST_MODIFIER))
@@ -592,7 +672,7 @@
 						addAllDisplayInfo(description, lang);
 					}
-					else if (info.equals(GSXML.PLUGIN_ELEM + GSXML.LIST_MODIFIER))
+					else if (info.equals("libraryParamlist"))
 					{
-						description.appendChild(plugin_item_list);
+					  description.appendChild(this.library_param_list);
 					}
 				}
@@ -820,16 +900,16 @@
 			return addMetadata(metadata_list);
 		}
-		else if (subset.equals(GSXML.PLUGIN_ELEM + GSXML.LIST_MODIFIER))
-		{
-			this.plugin_item_list = this.doc.createElement(GSXML.PLUGIN_ELEM + GSXML.LIST_MODIFIER);
-			Element import_list = (Element) GSXML.getChildByTagName(cluster_config_elem, GSXML.IMPORT_ELEM);
-			if (import_list != null)
-			{
-				Element plugin_item_list = (Element) GSXML.getChildByTagName(cluster_config_elem, GSXML.PLUGIN_ELEM + GSXML.LIST_MODIFIER);
-				return addPlugins(plugin_item_list);
-			}
-			else
-				return false;
-		}
+		// else if (subset.equals(GSXML.PLUGIN_ELEM + GSXML.LIST_MODIFIER))
+		// {
+		// 	this.plugin_item_list = this.doc.createElement(GSXML.PLUGIN_ELEM + GSXML.LIST_MODIFIER);
+		// 	Element import_list = (Element) GSXML.getChildByTagName(cluster_config_elem, GSXML.IMPORT_ELEM);
+		// 	if (import_list != null)
+		// 	{
+		// 		Element plugin_item_list = (Element) GSXML.getChildByTagName(cluster_config_elem, GSXML.PLUGIN_ELEM + GSXML.LIST_MODIFIER);
+		// 		return addPlugins(plugin_item_list);
+		// 	}
+		// 	else
+		// 		return false;
+		// }
 		else
 		{
@@ -847,5 +927,5 @@
 		{ // for each key
 			Element m = (Element) items.item(i);
-			// find the child with the correct language
+			// findthe child with the correct language
 			Element new_m = GSXML.getNamedElement(m, GSXML.DISPLAY_TEXT_ELEM, GSXML.LANG_ATT, lang);
 			if (new_m == null && lang != DEFAULT_LANG)
Index: main/trunk/greenstone3/src/java/org/greenstone/gsdl3/collection/XMLCollection.java
===================================================================
--- main/trunk/greenstone3/src/java/org/greenstone/gsdl3/collection/XMLCollection.java	(revision 26445)
+++ main/trunk/greenstone3/src/java/org/greenstone/gsdl3/collection/XMLCollection.java	(revision 26446)
@@ -48,10 +48,10 @@
 
 	//plugin stuff
-	Element import_list = (Element)GSXML.getChildByTagName(coll_config_xml, GSXML.IMPORT_ELEM);
-	if (import_list != null)
-	{
-		Element plugin_list = (Element)GSXML.getChildByTagName(import_list, GSXML.PLUGIN_ELEM+GSXML.LIST_MODIFIER);
-		addPlugins(plugin_list);
-	}
+	// Element import_list = (Element)GSXML.getChildByTagName(coll_config_xml, GSXML.IMPORT_ELEM);
+	// if (import_list != null)
+	// {
+	// 	Element plugin_list = (Element)GSXML.getChildByTagName(import_list, GSXML.PLUGIN_ELEM+GSXML.LIST_MODIFIER);
+	// 	addPlugins(plugin_list);
+	// }
 	
 	// are we a private collection??
@@ -100,5 +100,5 @@
 		description.appendChild(this.service_list);
 		description.appendChild(this.metadata_list);
-		description.appendChild(this.plugin_item_list);
+		description.appendChild(this.library_param_list);
 		description.appendChild(this.document_list);
 		return response;
@@ -122,8 +122,12 @@
 		    } else if (info.equals(GSXML.DOCUMENT_ELEM+GSXML.LIST_MODIFIER)) {
 			description.appendChild(this.document_list);
-		    } else if (info.equals(GSXML.PLUGIN_ELEM+GSXML.LIST_MODIFIER)) {
-		    	description.appendChild(this.plugin_item_list);
+		    // } else if (info.equals(GSXML.PLUGIN_ELEM+GSXML.LIST_MODIFIER)) {
+		    // 	description.appendChild(this.plugin_item_list);
+		    // }
+		    } else if (info.equals("libraryParamlist")) {
+		      
+		      description.appendChild(this.library_param_list);
 		    }
-		    
+		
 		}
 	    }
