/* * IIIFServerBridge.java * Copyright (C) 2018 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; import java.io.IOException; import java.io.PrintWriter; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.UnavailableException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.log4j.Logger; import org.greenstone.gsdl3.comms.Communicator; import org.greenstone.gsdl3.comms.SOAPCommunicator; import org.greenstone.gsdl3.core.IIIFMessageRouter; import org.greenstone.gsdl3.core.IIIFReceptionist; import org.greenstone.gsdl3.util.GSConstants; import org.greenstone.gsdl3.util.GSParams; import org.greenstone.gsdl3.util.GSXML; import org.greenstone.gsdl3.util.IIIFXML; import org.greenstone.gsdl3.util.XMLConverter; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; /** a class the serve as a bridge between the Cantaloupe IIIF image server and * Greenstone collections. Loosely based on OAIServer * * the init method is called only once - the first time the bridge is established * then doGet() each time a document image request is made * @see Receptionist */ /** * IIIF server configuration instructions * * */ public class IIIFServerBridge { /** the receptionist to send messages to */ protected IIIFReceptionist recept = null; /** * The name of the site with which we will finally be dealing, whether it is * a local site or a remote site through a communicator. */ protected String site = ""; static Logger logger = Logger.getLogger(org.greenstone.gsdl3.IIIFServerBridge.class.getName()); private void configure() throws UnavailableException { // Read in IIIFConfig.xml (residing web/WEB-INF/classes/) and //use it to configure the receptionist. Element iiif_config = IIIFXML.getIIIFConfigXML(); if (iiif_config == null) { logger.error("Fail to parse IIIF config file IIIFConfig.xml."); throw new UnavailableException("IIIFServerBridge: Couldn't parse IIIFConfig.xml"); } // pass it to the receptionist if (!this.recept.configure(iiif_config)) { logger.error("Couldn't configure IIIF receptionist"); throw new UnavailableException("IIIFServerBridge: Couldn't configure receptionist"); } } /** * initialise the class */ public void init(String site_name) throws UnavailableException, Exception { org.greenstone.util.GlobalProperties.loadGlobalProperties(""); java.io.InputStream in = Class.forName("org.greenstone.util.GlobalProperties").getClassLoader().getResourceAsStream("global.properties"); String tomcat_context = System.getProperty("tomcat.context"); // the receptionist -the servlet will talk to this this.recept = new IIIFReceptionist(); //this site_name could consist of comma separated more than one site name. IIIFMessageRouter message_router = new IIIFMessageRouter(); message_router.setSiteName(site_name); // lots of work is done in this step; see IIIFMessageRouter.java if (!message_router.configure()) { throw new UnavailableException("IIIFServerBridge: Couldn't configure IIIFMessageRouter"); } this.recept.setSiteName(site_name); this.recept.setMessageRouter(message_router); configure(); } // end of init() /* Written but never used/tested */ public void remote_init(String remote_site_name, String remote_site_type, String remote_site_address) throws UnavailableException { if (remote_site_name == null || remote_site_type == null || remote_site_address == null) { logger.error("Initialisation paramters not all set!"); logger.error("You must have remote_site_name, remote_site_type and remote_site_address set"); throw new UnavailableException("IIIFServerBridge: incorrect remote connection parameters specified"); } // the receptionist -the servlet will talk to this this.recept = new IIIFReceptionist(); // talking to a remote site, create a communicator Communicator communicator = null; // we need to create the XML to configure the communicator Document site_doc = XMLConverter.newDOM(); Element site_elem = site_doc.createElement(GSXML.SITE_ELEM); site_elem.setAttribute(GSXML.TYPE_ATT, remote_site_type); site_elem.setAttribute(GSXML.NAME_ATT, remote_site_name); site_elem.setAttribute(GSXML.ADDRESS_ATT, remote_site_address); if (remote_site_type.equals(GSXML.COMM_TYPE_SOAP_JAVA)) { communicator = new SOAPCommunicator(); } else { logger.error("IIIFServerBridge.init Error: invalid Communicator type: " + remote_site_type); throw new UnavailableException("IIIFServerBridge: invalid communicator type"); } if (!communicator.configure(site_elem)) { logger.error("IIIFServerBridge.init Error: Couldn't configure communicator"); throw new UnavailableException("IIIFServerBridge: Couldn't configure communicator"); } this.recept.setSiteName(remote_site_name); this.recept.setMessageRouter(communicator); configure(); } // end of remote_init() public String doGetDocumentMessage(String identifier) { String result = ""; String[] pairs = new String[2]; pairs[0] = "verb=GetRecord"; pairs[1] = "identifier="+identifier; String verb = "GetRecord"; Document response_doc = XMLConverter.newDOM(); //Element xml_response = IIIFXML.createBasicResponse(response_doc, verb, pairs); //Element verb_elem = null; // compose the request message to the receptionist Document request_doc = XMLConverter.newDOM(); Element xml_message = request_doc.createElement(GSXML.MESSAGE_ELEM); Element xml_request = request_doc.createElement(GSXML.REQUEST_ELEM); xml_request.setAttribute(GSXML.TO_ATT, verb); addParams(xml_request, pairs); xml_message.appendChild(xml_request); Node xml_result = this.recept.process(xml_message); if (xml_result == null) { logger.error("xml_result is null"); //verb_elem = IIIFXML.createErrorElement(response_doc, "Internal error", ""); //xml_response.appendChild(verb_elem); } else { // // All response elements are in the form (with a corresponding verb // name): ... // Node res = GSXML.getChildByTagName(xml_result, GSXML.RESPONSE_ELEM); if (res == null) { logger.error("response element in xml_result is null"); //verb_elem = IIIFXML.createErrorElement(response_doc, "Internal error", ""); } else { Element verb_elem = GSXML.getFirstElementChild(res); // GetRecord Node record_node = GSXML.getFirstElementChild(verb_elem); // record Element metadata_list_elem = (Element)GSXML.getChildByTagName(record_node,"metadata"); // metadata Element assocfilepath_metadata_elem = (Element)GSXML.getChildByTagName(metadata_list_elem,"assocfilepath"); if (assocfilepath_metadata_elem == null) { logger.error("Failed to find metadata 'assocfilepath' for Document " + identifier); //verb_elem = IIIFXML.createErrorElement(response_doc, "Internal error", ""); } else { String assocfilepath_metadata_val = GSXML.getNodeText(assocfilepath_metadata_elem); Element image_metadata_elem = (Element)GSXML.getChildByTagName(metadata_list_elem,"Image"); if (assocfilepath_metadata_elem == null) { logger.error("Failed to find metadata 'Image' for Document " + identifier); } else { String image_metadata_val = GSXML.getNodeText(image_metadata_elem); result = assocfilepath_metadata_val + "/" + image_metadata_val; } } } //xml_response.appendChild(response_doc.importNode(verb_elem, true)); } return result; } /** append parameter elements to the request sent to the receptionist */ public void addParams(Element request, String[] pairs) { Document doc = request.getOwnerDocument(); // no params apart from the verb if (pairs == null || pairs.length < 2) return; /** * the request xml is composed in the form: * (No paramList element in between). */ for (int i = 1; i < pairs.length; i++) { //the first pair in pairs is the verb=xxx int index = pairs[i].indexOf("="); if (index != -1) { //just a double check Element param = GSXML.createParameter(doc, pairs[i].substring(0, index), IIIFXML.iiifDecode(pairs[i].substring(index + 1))); request.appendChild(param); } } } public void destroy() { recept.cleanUp(); } }