Index: gs3-extensions/pharos/trunk/src/java/pharosimageis/PharosImageISServiceRack.java
===================================================================
--- gs3-extensions/pharos/trunk/src/java/pharosimageis/PharosImageISServiceRack.java	(revision 21264)
+++ gs3-extensions/pharos/trunk/src/java/pharosimageis/PharosImageISServiceRack.java	(revision 21264)
@@ -0,0 +1,268 @@
+/*
+ *    PharosImageISServiceRack.java
+ *    Copyright (C) 2009 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 pharosimageis;
+
+
+// Greenstone classes
+import org.greenstone.gsdl3.service.ServiceRack;
+import org.greenstone.gsdl3.util.GSXML;
+import org.greenstone.gsdl3.util.GSPath;
+
+// XML classes
+import org.w3c.dom.Document;
+import org.w3c.dom.Element; 
+import org.w3c.dom.NodeList;
+
+// java classes
+import java.util.ArrayList;
+import java.util.HashMap;
+
+// pharos
+//import PharosImageIS;
+
+import org.apache.log4j.*;
+
+/** Pharos Image Similarity Search service
+ *
+ * @author Katherine Don
+ */
+
+public class PharosImageISServiceRack
+    extends ServiceRack 
+{
+
+   static Logger logger = Logger.getLogger(pharosimageis.PharosImageISServiceRack.class.getName());
+
+    
+    // the search service
+    protected static final String PHAROS_QUERY_SERVICE = "PharosQuery";
+
+    // compulsory params
+    protected static final String IMAGE_ID_PARAM = "id";
+  //protected static final String COLLECTION_PARAM = "collection";
+  protected PharosImageIS pharos_engine = null;
+ 
+    public PharosImageISServiceRack()
+    {
+      pharos_engine = new PharosImageIS();
+    }
+
+    /** sets up the short service info for PharosQuery. If other services 
+     * will be provided, should be added in the subclass configure
+     * also looks for search format info, and document format info
+     */
+    public boolean configure(Element info, Element extra_info)
+    {
+	if (!super.configure(info, extra_info)){
+	    return false;
+	}
+
+	logger.info("Configuring PharosImageISServiceRack...");
+	
+	this.config_info = info;
+
+	// set up short_service_info_ - for now just has id and type. the name (lang dependent) will be added in if the list is requested.
+	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, PHAROS_QUERY_SERVICE);
+	this.short_service_info.appendChild(tq_service);
+
+	// add some format info to service map if there is any - look in extra info
+	// first look in buildConfig
+	Element format = (Element)GSXML.getChildByTagName(info, GSXML.FORMAT_ELEM);
+
+	if (format==null) {
+	    String path = GSPath.appendLink(GSXML.SEARCH_ELEM, GSXML.FORMAT_ELEM);
+
+      //note by xiao: instead of retrieving the first 'format' element inside the 'search'
+      // element, we are trying to find the real format element which has at least one
+      // 'gsf:template' child element. (extra_info is collectionConfig.xml)
+      //format = (Element) GSXML.getNodeByPath(extra_info, path);
+      Element search_elem = (Element) GSXML.getChildByTagName(extra_info, GSXML.SEARCH_ELEM);
+      NodeList format_elems = null;
+      if (search_elem != null) {
+        format_elems = search_elem.getElementsByTagName(GSXML.FORMAT_ELEM);
+      }
+      for(int i=0; i<format_elems.getLength(); i++) {
+          format = (Element)format_elems.item(i);
+          if (format.getElementsByTagName("gsf:template").getLength() != 0) {
+            break;
+          }
+      }
+	}//end of if(format==null)
+	//
+	if (format != null) {
+	    this.format_info_map.put(PHAROS_QUERY_SERVICE, this.doc.importNode(format, true));
+	}
+	
+	// is the following relevant here. and what is it anyway??
+	// look for document display format - for documentType
+	/*	String path = GSPath.appendLink(GSXML.DISPLAY_ELEM, GSXML.FORMAT_ELEM);
+	Element display_format = (Element)GSXML.getNodeByPath(extra_info, path);
+	if (display_format != null) {
+	    // check for docType option.
+	    Element doc_type_opt = GSXML.getNamedElement(display_format, "gsf:option", GSXML.NAME_ATT, "documentType");
+	    if (doc_type_opt != null) {
+		String value = doc_type_opt.getAttribute(GSXML.VALUE_ATT);
+		if (!value.equals("")) {
+		    this.default_document_type = value;
+		}
+	    }
+	    }*/
+
+	return true;
+    }
+    
+    /** returns the description of the TextQuery service. If a subclass 
+     * provides other services they need to provides their own descriptions */
+    public Element getServiceDescription(String service, String lang, String subset) 
+    {
+	if (!service.equals(PHAROS_QUERY_SERVICE)) {
+	    return null;
+	}
+
+	Element pq_service = this.doc.createElement(GSXML.SERVICE_ELEM);
+	pq_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_QUERY);
+	pq_service.setAttribute(GSXML.NAME_ATT, PHAROS_QUERY_SERVICE);
+	if (subset==null || subset.equals(GSXML.DISPLAY_TEXT_ELEM+GSXML.LIST_MODIFIER)) {
+	    pq_service.appendChild(GSXML.createDisplayTextElement(this.doc, GSXML.DISPLAY_TEXT_NAME, getServiceName(PHAROS_QUERY_SERVICE, lang) ));
+	    pq_service.appendChild(GSXML.createDisplayTextElement(this.doc, GSXML.DISPLAY_TEXT_SUBMIT, getServiceSubmit(PHAROS_QUERY_SERVICE, lang) ));
+	    pq_service.appendChild(GSXML.createDisplayTextElement(this.doc, GSXML.DISPLAY_TEXT_DESCRIPTION, getServiceDescription(PHAROS_QUERY_SERVICE, lang)));
+	}
+	if (subset==null || subset.equals(GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER)) {
+	    Element param_list = this.doc.createElement(GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	    Element param = GSXML.createParameterDescription(this.doc, IMAGE_ID_PARAM, getTextString("param."+IMAGE_ID_PARAM, lang), GSXML.PARAM_TYPE_STRING, null, null, null);
+	    param_list.appendChild(param);
+
+	    pq_service.appendChild(param_list);
+	}
+	return pq_service;
+	
+    }
+
+    // perhaps these should be changed to search down the class hierarchy for 
+    // values - do can just put the info in the resource bundle to use it
+    /** returns the default name a service */
+    public String getServiceName(String service_id, String lang) {
+	return getTextString(service_id+".name", lang);
+    }
+    
+    /** returns the default description for a service */
+    public String getServiceDescription(String service_id, String lang) {
+	return getTextString(service_id+".description", lang);
+    }
+
+    /** returns the default submit button text for a service */
+    public String getServiceSubmit(String service_id, String lang) {
+	return getTextString(service_id+".submit", lang);
+
+    }
+    /** create an element to go into the search results list. A node element
+     * has the form
+     * <docNode nodeId='xxx' nodeType='root' docType='simple' rank='0.23'/>
+     */
+    public Element createDocNode(String node_id, String rank) {
+	Element node = this.doc.createElement(GSXML.DOC_NODE_ELEM);
+	node.setAttribute(GSXML.NODE_ID_ATT, node_id);
+	node.setAttribute(GSXML.NODE_RANK_ATT, rank);
+	// default values for now
+	node.setAttribute(GSXML.DOC_TYPE_ATT, "simple");
+	node.setAttribute(GSXML.NODE_TYPE_ATT, "root");
+	return node;
+    }
+
+  
+    /** do the actual query 
+     * must be implemented by subclass */
+  public Element processPharosQuery(Element request) {
+    
+    // Create a new (empty) result message ('doc' is in ServiceRack.java)
+    Element result = this.doc.createElement (GSXML.RESPONSE_ELEM);
+    result.setAttribute (GSXML.FROM_ATT, PHAROS_QUERY_SERVICE);
+    result.setAttribute (GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS);
+        
+    // Get the parameters of the request
+    Element param_list = (Element) GSXML.getChildByTagName (request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+    if (param_list == null) {
+      logger.error ("PharosQuery request had no paramList.");
+      return result;  // Return the empty result
+    }
+    
+    // Process the request parameters
+    HashMap params = GSXML.extractParams (param_list, false);
+    
+    // Make sure an id has been specified
+    String query = (String) params.get (IMAGE_ID_PARAM);
+    if (query == null || query.equals ("")) {
+      return result;  // Return the empty result
+    }
+     
+    String search_results = null;
+    try {
+      search_results = pharos_engine.query(this.cluster_name, query);
+    } catch (Exception e) {
+      logger.error(e.getMessage(), e);
+    }
+    if (search_results == null || search_results.equals("")) {
+      logger.error("Empty results string");
+      return result;
+    }
+
+    Element document_list = this.doc.createElement (GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
+    
+    try {
+      Document result_xml = this.converter.getDOM(search_results);
+      if (result_xml == null) {
+	logger.error("Couldn't parse XML");
+	return result;
+      }
+      
+      Element result_element = result_xml.getDocumentElement();
+      NodeList result_items = result_element.getElementsByTagName("ResultItem");
+      String coll_prefix = this.cluster_name+":";
+      int prefix_len = coll_prefix.length();
+      for (int i=0; i<result_items.getLength(); i++) {
+	Element item = (Element)result_items.item(i);
+	String rank = item.getAttribute("confidence");
+	Element resource = (Element)GSXML.getChildByTagName(item, "MediaResource");
+	String id = GSXML.getNodeText(resource);
+	
+	System.err.println("id = "+id+", rank = "+rank);
+	if (id.startsWith(coll_prefix)) {
+	  
+	  Element result_node = createDocNode(id.substring(prefix_len), rank);
+	  document_list.appendChild(result_node);
+	}
+      }
+      
+    } catch (Exception e) {
+      logger.error(e.getMessage(), e);
+    }
+    
+    result.appendChild (document_list);
+
+    return result;
+    
+
+    
+  }
+	
+
+}
+
