[32707] | 1 | /*
|
---|
| 2 | * IIIFServerBridge.java
|
---|
| 3 | * Copyright (C) 2018 New Zealand Digital Library, http://www.nzdl.org
|
---|
| 4 | *
|
---|
| 5 | * This program is free software; you can redistribute it and/or modify
|
---|
| 6 | * it under the terms of the GNU General Public License as published by
|
---|
| 7 | * the Free Software Foundation; either version 2 of the License, or
|
---|
| 8 | * (at your option) any later version.
|
---|
| 9 | *
|
---|
| 10 | * This program is distributed in the hope that it will be useful,
|
---|
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
| 13 | * GNU General Public License for more details.
|
---|
| 14 | *
|
---|
| 15 | * You should have received a copy of the GNU General Public License
|
---|
| 16 | * along with this program; if not, write to the Free Software
|
---|
| 17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
---|
| 18 | */
|
---|
| 19 | package org.greenstone.gsdl3;
|
---|
| 20 |
|
---|
| 21 | import java.io.IOException;
|
---|
| 22 | import java.io.PrintWriter;
|
---|
| 23 | import java.util.HashSet;
|
---|
| 24 | import java.util.Iterator;
|
---|
| 25 | import java.util.Map;
|
---|
| 26 |
|
---|
| 27 | import javax.servlet.ServletConfig;
|
---|
| 28 | import javax.servlet.ServletException;
|
---|
| 29 | import javax.servlet.UnavailableException;
|
---|
| 30 | import javax.servlet.http.HttpServletRequest;
|
---|
| 31 | import javax.servlet.http.HttpServletResponse;
|
---|
| 32 |
|
---|
| 33 | import org.apache.log4j.Logger;
|
---|
| 34 | import org.greenstone.gsdl3.comms.Communicator;
|
---|
| 35 | import org.greenstone.gsdl3.comms.SOAPCommunicator;
|
---|
| 36 | import org.greenstone.gsdl3.core.IIIFMessageRouter;
|
---|
| 37 | import org.greenstone.gsdl3.core.IIIFReceptionist;
|
---|
| 38 | import org.greenstone.gsdl3.util.GSConstants;
|
---|
| 39 | import org.greenstone.gsdl3.util.GSParams;
|
---|
| 40 | import org.greenstone.gsdl3.util.GSXML;
|
---|
[32842] | 41 | import org.greenstone.gsdl3.util.IIIFXML;
|
---|
[32707] | 42 | import org.greenstone.gsdl3.util.XMLConverter;
|
---|
| 43 | import org.w3c.dom.Document;
|
---|
| 44 | import org.w3c.dom.Element;
|
---|
| 45 | import org.w3c.dom.Node;
|
---|
| 46 |
|
---|
| 47 | /** a class the serve as a bridge between the Cantaloupe IIIF image server and
|
---|
| 48 | * Greenstone collections. Loosely based on OAIServer
|
---|
| 49 | *
|
---|
| 50 | * the init method is called only once - the first time the bridge is established
|
---|
| 51 | * then doGet() each time a document image request is made
|
---|
| 52 | * @see Receptionist
|
---|
| 53 | */
|
---|
| 54 | /**
|
---|
[32842] | 55 | * IIIF server configuration instructions *
|
---|
[32707] | 56 | *
|
---|
| 57 | */
|
---|
| 58 | public class IIIFServerBridge
|
---|
| 59 | {
|
---|
| 60 | /** the receptionist to send messages to */
|
---|
| 61 | protected IIIFReceptionist recept = null;
|
---|
| 62 |
|
---|
| 63 | /**
|
---|
| 64 | * The name of the site with which we will finally be dealing, whether it is
|
---|
| 65 | * a local site or a remote site through a communicator.
|
---|
| 66 | */
|
---|
| 67 | protected String site = "";
|
---|
| 68 |
|
---|
| 69 | static Logger logger = Logger.getLogger(org.greenstone.gsdl3.IIIFServerBridge.class.getName());
|
---|
| 70 |
|
---|
| 71 | private void configure() throws UnavailableException
|
---|
| 72 | {
|
---|
[32842] | 73 | // Read in IIIFConfig.xml (residing web/WEB-INF/classes/) and
|
---|
[32707] | 74 | //use it to configure the receptionist.
|
---|
[32842] | 75 | Element iiif_config = IIIFXML.getIIIFConfigXML();
|
---|
| 76 | if (iiif_config == null)
|
---|
[32707] | 77 | {
|
---|
[32842] | 78 | logger.error("Fail to parse IIIF config file IIIFConfig.xml.");
|
---|
| 79 | throw new UnavailableException("IIIFServerBridge: Couldn't parse IIIFConfig.xml");
|
---|
[32707] | 80 | }
|
---|
| 81 | // pass it to the receptionist
|
---|
[32842] | 82 | if (!this.recept.configure(iiif_config)) {
|
---|
| 83 | logger.error("Couldn't configure IIIF receptionist");
|
---|
[32707] | 84 | throw new UnavailableException("IIIFServerBridge: Couldn't configure receptionist");
|
---|
| 85 | }
|
---|
| 86 | }
|
---|
| 87 |
|
---|
[32883] | 88 | /**
|
---|
| 89 | * initialise the class
|
---|
| 90 | */
|
---|
[32707] | 91 | public void init(String site_name) throws UnavailableException, Exception
|
---|
| 92 | {
|
---|
[32860] | 93 | org.greenstone.util.GlobalProperties.loadGlobalProperties("");
|
---|
[32707] | 94 | java.io.InputStream in = Class.forName("org.greenstone.util.GlobalProperties").getClassLoader().getResourceAsStream("global.properties");
|
---|
| 95 |
|
---|
| 96 | String tomcat_context = System.getProperty("tomcat.context");
|
---|
| 97 |
|
---|
| 98 | // the receptionist -the servlet will talk to this
|
---|
| 99 | this.recept = new IIIFReceptionist();
|
---|
| 100 |
|
---|
| 101 | //this site_name could consist of comma separated more than one site name.
|
---|
| 102 | IIIFMessageRouter message_router = new IIIFMessageRouter();
|
---|
| 103 |
|
---|
| 104 | message_router.setSiteName(site_name);
|
---|
| 105 | // lots of work is done in this step; see IIIFMessageRouter.java
|
---|
| 106 | if (!message_router.configure()) {
|
---|
| 107 | throw new UnavailableException("IIIFServerBridge: Couldn't configure IIIFMessageRouter");
|
---|
| 108 | }
|
---|
| 109 | this.recept.setSiteName(site_name);
|
---|
| 110 | this.recept.setMessageRouter(message_router);
|
---|
| 111 |
|
---|
| 112 | configure();
|
---|
| 113 | } // end of init()
|
---|
| 114 |
|
---|
[32883] | 115 | /*
|
---|
| 116 | Written but never used/tested
|
---|
| 117 | */
|
---|
| 118 |
|
---|
[32707] | 119 | public void remote_init(String remote_site_name, String remote_site_type, String remote_site_address) throws UnavailableException
|
---|
| 120 | {
|
---|
| 121 | if (remote_site_name == null || remote_site_type == null || remote_site_address == null)
|
---|
| 122 | {
|
---|
| 123 | logger.error("Initialisation paramters not all set!");
|
---|
| 124 | logger.error("You must have remote_site_name, remote_site_type and remote_site_address set");
|
---|
| 125 | throw new UnavailableException("IIIFServerBridge: incorrect remote connection parameters specified");
|
---|
| 126 | }
|
---|
| 127 |
|
---|
| 128 | // the receptionist -the servlet will talk to this
|
---|
| 129 | this.recept = new IIIFReceptionist();
|
---|
| 130 |
|
---|
| 131 | // talking to a remote site, create a communicator
|
---|
| 132 | Communicator communicator = null;
|
---|
| 133 | // we need to create the XML to configure the communicator
|
---|
| 134 | Document site_doc = XMLConverter.newDOM();
|
---|
| 135 | Element site_elem = site_doc.createElement(GSXML.SITE_ELEM);
|
---|
| 136 | site_elem.setAttribute(GSXML.TYPE_ATT, remote_site_type);
|
---|
| 137 | site_elem.setAttribute(GSXML.NAME_ATT, remote_site_name);
|
---|
| 138 | site_elem.setAttribute(GSXML.ADDRESS_ATT, remote_site_address);
|
---|
| 139 |
|
---|
| 140 | if (remote_site_type.equals(GSXML.COMM_TYPE_SOAP_JAVA))
|
---|
| 141 | {
|
---|
| 142 | communicator = new SOAPCommunicator();
|
---|
| 143 | }
|
---|
| 144 | else
|
---|
| 145 | {
|
---|
| 146 | logger.error("IIIFServerBridge.init Error: invalid Communicator type: " + remote_site_type);
|
---|
[32842] | 147 | throw new UnavailableException("IIIFServerBridge: invalid communicator type");
|
---|
[32707] | 148 | }
|
---|
| 149 |
|
---|
| 150 | if (!communicator.configure(site_elem))
|
---|
| 151 | {
|
---|
| 152 | logger.error("IIIFServerBridge.init Error: Couldn't configure communicator");
|
---|
[32842] | 153 | throw new UnavailableException("IIIFServerBridge: Couldn't configure communicator");
|
---|
[32707] | 154 | }
|
---|
| 155 | this.recept.setSiteName(remote_site_name);
|
---|
| 156 | this.recept.setMessageRouter(communicator);
|
---|
| 157 |
|
---|
| 158 | configure();
|
---|
| 159 | } // end of remote_init()
|
---|
| 160 |
|
---|
| 161 |
|
---|
| 162 | public String doGetDocumentMessage(String identifier)
|
---|
| 163 | {
|
---|
[32874] | 164 | String result = "";
|
---|
| 165 |
|
---|
[32720] | 166 | String[] pairs = new String[2];
|
---|
| 167 | pairs[0] = "verb=GetRecord";
|
---|
| 168 | pairs[1] = "identifier="+identifier;
|
---|
[32707] | 169 |
|
---|
| 170 | String verb = "GetRecord";
|
---|
| 171 | Document response_doc = XMLConverter.newDOM();
|
---|
[32883] | 172 | //Element xml_response = IIIFXML.createBasicResponse(response_doc, verb, pairs);
|
---|
[32891] | 173 | //Element verb_elem = null;
|
---|
[32707] | 174 |
|
---|
| 175 | // compose the request message to the receptionist
|
---|
| 176 | Document request_doc = XMLConverter.newDOM();
|
---|
| 177 | Element xml_message = request_doc.createElement(GSXML.MESSAGE_ELEM);
|
---|
| 178 | Element xml_request = request_doc.createElement(GSXML.REQUEST_ELEM);
|
---|
| 179 | xml_request.setAttribute(GSXML.TO_ATT, verb);
|
---|
| 180 | addParams(xml_request, pairs);
|
---|
| 181 |
|
---|
| 182 | xml_message.appendChild(xml_request);
|
---|
| 183 |
|
---|
| 184 | Node xml_result = this.recept.process(xml_message);
|
---|
| 185 | if (xml_result == null)
|
---|
| 186 | {
|
---|
[32891] | 187 | logger.error("xml_result is null");
|
---|
| 188 | //verb_elem = IIIFXML.createErrorElement(response_doc, "Internal error", "");
|
---|
[32883] | 189 | //xml_response.appendChild(verb_elem);
|
---|
[32707] | 190 | }
|
---|
| 191 | else
|
---|
| 192 | {
|
---|
| 193 |
|
---|
| 194 | //
|
---|
| 195 | // All response elements are in the form (with a corresponding verb
|
---|
[32883] | 196 | // name): <message> <response> <verb> ... </verb> </response> </message>
|
---|
[32707] | 197 | //
|
---|
| 198 | Node res = GSXML.getChildByTagName(xml_result, GSXML.RESPONSE_ELEM);
|
---|
| 199 | if (res == null)
|
---|
| 200 | {
|
---|
[32891] | 201 | logger.error("response element in xml_result is null");
|
---|
| 202 | //verb_elem = IIIFXML.createErrorElement(response_doc, "Internal error", "");
|
---|
[32707] | 203 | }
|
---|
[32874] | 204 | else {
|
---|
[32891] | 205 | Element verb_elem = GSXML.getFirstElementChild(res); // GetRecord
|
---|
[32874] | 206 | Node record_node = GSXML.getFirstElementChild(verb_elem); // record
|
---|
| 207 | Element metadata_list_elem = (Element)GSXML.getChildByTagName(record_node,"metadata"); // metadata
|
---|
| 208 |
|
---|
[32875] | 209 | Element assocfilepath_metadata_elem = (Element)GSXML.getChildByTagName(metadata_list_elem,"assocfilepath");
|
---|
| 210 |
|
---|
[32891] | 211 | if (assocfilepath_metadata_elem == null) {
|
---|
| 212 | logger.error("Failed to find metadata 'assocfilepath' for Document " + identifier);
|
---|
| 213 | //verb_elem = IIIFXML.createErrorElement(response_doc, "Internal error", "");
|
---|
| 214 | }
|
---|
| 215 | else {
|
---|
| 216 | String assocfilepath_metadata_val = GSXML.getNodeText(assocfilepath_metadata_elem);
|
---|
[32875] | 217 |
|
---|
[32891] | 218 | Element image_metadata_elem = (Element)GSXML.getChildByTagName(metadata_list_elem,"Image");
|
---|
| 219 | if (assocfilepath_metadata_elem == null) {
|
---|
| 220 | logger.error("Failed to find metadata 'Image' for Document " + identifier);
|
---|
| 221 | }
|
---|
| 222 | else {
|
---|
| 223 | String image_metadata_val = GSXML.getNodeText(image_metadata_elem);
|
---|
| 224 |
|
---|
| 225 | result = assocfilepath_metadata_val + "/" + image_metadata_val;
|
---|
| 226 | }
|
---|
| 227 | }
|
---|
[32707] | 228 | }
|
---|
| 229 |
|
---|
[32883] | 230 | //xml_response.appendChild(response_doc.importNode(verb_elem, true));
|
---|
[32707] | 231 | }
|
---|
[32874] | 232 | return result;
|
---|
[32707] | 233 | }
|
---|
| 234 |
|
---|
| 235 | /** append parameter elements to the request sent to the receptionist */
|
---|
| 236 | public void addParams(Element request, String[] pairs)
|
---|
| 237 | {
|
---|
| 238 | Document doc = request.getOwnerDocument();
|
---|
| 239 | // no params apart from the verb
|
---|
| 240 | if (pairs == null || pairs.length < 2)
|
---|
| 241 | return;
|
---|
| 242 |
|
---|
| 243 | /**
|
---|
| 244 | * the request xml is composed in the form: <request> <param name=.../>
|
---|
| 245 | * <param name=.../> </request> (No paramList element in between).
|
---|
| 246 | */
|
---|
| 247 | for (int i = 1; i < pairs.length; i++)
|
---|
| 248 | {
|
---|
| 249 | //the first pair in pairs is the verb=xxx
|
---|
| 250 | int index = pairs[i].indexOf("=");
|
---|
| 251 | if (index != -1)
|
---|
| 252 | { //just a double check
|
---|
[32874] | 253 | Element param = GSXML.createParameter(doc, pairs[i].substring(0, index), IIIFXML.iiifDecode(pairs[i].substring(index + 1)));
|
---|
[32707] | 254 | request.appendChild(param);
|
---|
| 255 | }
|
---|
| 256 | }
|
---|
| 257 | }
|
---|
| 258 |
|
---|
| 259 |
|
---|
| 260 | public void destroy()
|
---|
| 261 | {
|
---|
| 262 | recept.cleanUp();
|
---|
| 263 | }
|
---|
| 264 |
|
---|
| 265 | }
|
---|