Index: /gs3-extensions/iiif-servlet/trunk/src/gsdl-src/java/org/greenstone/gsdl3/collection/IIIFCollection.java
===================================================================
--- /gs3-extensions/iiif-servlet/trunk/src/gsdl-src/java/org/greenstone/gsdl3/collection/IIIFCollection.java	(revision 32843)
+++ /gs3-extensions/iiif-servlet/trunk/src/gsdl-src/java/org/greenstone/gsdl3/collection/IIIFCollection.java	(revision 32843)
@@ -0,0 +1,230 @@
+/*
+ *    IIIFCollection.java
+ *    Copyright (C) 2019 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    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.
+ */
+package org.greenstone.gsdl3.collection;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.log4j.Logger;
+import org.greenstone.gsdl3.core.ModuleInterface;
+import org.greenstone.gsdl3.service.ServiceRack;
+import org.greenstone.gsdl3.service.IIIFPMH;
+import org.greenstone.gsdl3.util.GSFile;
+import org.greenstone.gsdl3.util.GSXML;
+import org.greenstone.gsdl3.util.GSXSLT;
+import org.greenstone.gsdl3.util.IIIFXML;
+import org.greenstone.gsdl3.util.SimpleMacroResolver;
+import org.greenstone.gsdl3.util.UserContext;
+import org.greenstone.gsdl3.util.XMLConverter;
+import org.greenstone.gsdl3.util.XMLTransformer;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ * Represents a collection for the IIIFServerBridge. This is a cut down version of Collection, as we
+ * only want to load the IIIFPMH service rack, not any of the others
+ * 
+ */
+public class IIIFCollection extends Collection
+{
+
+	static Logger logger = Logger.getLogger(org.greenstone.gsdl3.collection.IIIFCollection.class.getName());
+
+	/** does this collection provide the IIIF service */
+	protected boolean has_iiif = false;
+
+	/** earliest datestamp of an OAI collection. Also used to work out the earliest datetimestamp of the entire OAI repository */
+    /*
+	protected long earliestOAIDatestamp = 0;
+    */
+    
+	/** a reference to the IIIFPMH service rack */
+	protected IIIFPMH iiif_service_rack = null;
+
+	/**
+	 * Configures the collection.
+	 * 
+	 * site_home and cluster_name  must be set before configure is called.
+	 * 
+	 * collection metadata is obtained, and services loaded.
+	 * 
+	 * @return true/false on success/fail
+	 */
+	public boolean configure()
+	{
+		if (this.site_home == null || this.cluster_name == null)
+		{
+			logger.error("Collection: site_home and collection_name must be set before configure called!");
+			return false;
+		}
+
+		macro_resolver.addMacro("_httpcollection_", this.site_http_address + "/collect/" + this.cluster_name);
+
+		Element coll_config_xml = loadCollConfigFile();
+		if (coll_config_xml == null) {
+		  logger.error("Collection: couldn't configure collection: " + this.cluster_name + ", " + "Couldn't load collection config file");
+
+		  return false;
+		}
+		Element build_config_xml = loadBuildConfigFile();
+		if (build_config_xml == null)
+		{
+		  logger.error("Collection: couldn't configure collection: " + this.cluster_name + ", " + "Couldn't load build config file");
+
+		  return false;
+		}
+		GSXSLT.modifyCollectionConfigForDebug(coll_config_xml);
+
+		// 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);
+
+		// load up the IIIFPMH serviceRack
+		configureServiceRacks(coll_config_xml, build_config_xml);
+
+		return true;
+
+	}
+
+	// NOTE:
+	// Calling cleanUp() on IIIFPMH object iiif_service_rack will
+	// close any open dbs handles on module deactivation by
+	// MESSAGEROUTER (no deactivate yet called by
+	// IIIFMessageRouter)
+
+	// But the IIIFPMH object's cleanUp() is already called by
+	// superclass ServiceCluster, which goes around calling
+	// cleanUp() on all services/ServiceRacks.
+
+	/**
+	 * whether this collection has IIIFPMH services
+	 */
+	public boolean hasIIIF()
+	{
+		return has_iiif;
+	}
+
+	/**
+	 * The earliesttimestamp entry in the oai-inf.db representing when the collection was created.
+	 * Used by the OAIReceptionist
+	*/
+    /*
+	public long getEarliestOAIDatestamp()
+	{
+		return earliestOAIDatestamp;
+	}
+    */
+    
+  /** add any extra info for collection from IIIFConfig.xml */
+  public boolean configureIIIF(Element iiif_config) {
+    // just pass the element to each service - should only be one
+    return this.iiif_service_rack.configureIIIF(iiif_config);
+  }
+
+  /** override this to only load up IIIFPMH serviceRack  - don't need all the rest of them for iiif*/
+	protected boolean configureServiceRackList(Element service_rack_list, Element extra_info)
+	{
+
+	  // find the IIIFPMH service
+	  Element iiif_service_xml = GSXML.getNamedElement(service_rack_list, GSXML.SERVICE_CLASS_ELEM, GSXML.NAME_ATT, "IIIFPMH");
+	  if (iiif_service_xml == null) {
+	    return false;
+	  }
+	  
+	  // the xml request to send to the serviceRack to query what services it provides
+	  Document doc = XMLConverter.newDOM();
+	  Element message = doc.createElement(GSXML.MESSAGE_ELEM);
+	  Element request = GSXML.createBasicRequest(doc, GSXML.REQUEST_TYPE_DESCRIBE, "", new UserContext());
+	  message.appendChild(request);
+
+	  if(this.iiif_service_rack == null) {
+	      logger.info("*** away to call constructor to IIIFPMH");
+		this.iiif_service_rack = new IIIFPMH();
+	  }
+	  this.iiif_service_rack.setSiteHome(this.site_home);
+	  this.iiif_service_rack.setSiteAddress(this.site_http_address);
+	  this.iiif_service_rack.setClusterName(this.cluster_name);
+	  this.iiif_service_rack.setServiceCluster(this);
+	  this.iiif_service_rack.setMessageRouter(this.router);
+
+	  // pass the xml node to the service for configuration
+	  logger.info("*** away to configure service rack IIIFPMH");
+	  
+	  if (this.iiif_service_rack.configure(iiif_service_xml, extra_info)) {
+
+	      /*
+	      // once we've configured the IIIFPMH service, we can use the OAIPMH service to
+	      // retrieve the earliest timestamp of this OAI collection from the oai-inf db
+	      long earliestTimestamp = this.oai_service_rack.getEarliestTimestamp();
+	      if(earliestTimestamp == -1) {
+		  this.earliestOAIDatestamp = -1;
+		  logger.warn("No OAI timestamp for collection " + this.cluster_name);
+	      } else {
+		  this.earliestOAIDatestamp = earliestTimestamp; // milliseconds
+	      }
+	      */
+	    
+	    // find out the supported service types for this service module
+	    Node types = this.iiif_service_rack.process(message);
+	    NodeList typenodes = ((Element) types).getElementsByTagName(GSXML.SERVICE_ELEM);
+	    
+	    for (int j = 0; j < typenodes.getLength(); j++)
+	      {
+		String service = ((Element) typenodes.item(j)).getAttribute(GSXML.NAME_ATT);
+		
+		if (service_map.get(service) != null)
+		  {
+		    char extra = '0';
+		    String new_service = service + extra;
+		    
+		    while (service_map.get(new_service) != null)
+		      {
+			extra++;
+			new_service = service + extra;
+		      }
+		    this.service_name_map.put(new_service, service);
+		    service = new_service;
+		    ((Element) typenodes.item(j)).setAttribute(GSXML.NAME_ATT, service);
+		  }
+		this.service_map.put(service, this.iiif_service_rack);
+		// also add info to the ServiceInfo XML element
+		this.service_list.appendChild(this.desc_doc.importNode(typenodes.item(j), true));
+	      }
+	    has_iiif = true;
+	    return true;
+	  }
+	  
+
+	  return false;
+	}
+
+}
