source: gs3-extensions/iiif-servlet/trunk/src/gsdl-src/java/org/greenstone/gsdl3/service/IIIFPMH.java@ 32860

Last change on this file since 32860 was 32860, checked in by davidb, 5 years ago

Mostly code tidy-up. In IIIFServerBridge.java, edit to remove hard-wired path

File size: 12.3 KB
Line 
1/*
2 * IIIFPMH.java
3 * Copyright (C) 2019 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 */
19package org.greenstone.gsdl3.service;
20
21// Greenstone classes
22import org.greenstone.gsdl3.core.GSException;
23import org.greenstone.gsdl3.util.GSXML;
24import org.greenstone.gsdl3.util.IIIFXML;
25import org.greenstone.gsdl3.util.OAIXML; // ****
26import org.greenstone.gsdl3.util.OID;
27import org.greenstone.gsdl3.util.GSFile;
28import org.greenstone.gsdl3.util.XMLConverter;
29
30import org.greenstone.gsdl3.util.SimpleCollectionDatabase;
31import org.greenstone.gsdl3.util.DBInfo;
32// XML classes
33import org.w3c.dom.Document;
34import org.w3c.dom.Element;
35import org.w3c.dom.NodeList;
36
37// General Java classes
38import java.io.File;
39import java.util.StringTokenizer;
40import java.util.Vector;
41import java.util.Set;
42import java.util.Iterator;
43import java.util.ArrayList;
44import java.util.Date;
45import java.util.HashMap;
46import java.util.HashSet;
47import java.util.Map.Entry;
48
49import org.apache.log4j.Logger;
50
51/** Implements the IIIF service for GS3 collections.
52 * Digs into each collection's database to study the metadata
53 * and from that determine what file in a document's assocdir
54 * can be used to provide a source image for the doc
55 *
56 */
57
58public class IIIFPMH extends ServiceRack {
59
60 static Logger logger = Logger.getLogger(org.greenstone.gsdl3.service.IIIFPMH.class.getName());
61
62 protected SimpleCollectionDatabase coll_db = null;
63
64 protected String site_name = "";
65 protected String coll_name = "";
66
67 // set this up during configure
68 protected Element list_sets_response = null;
69
70 protected Element meta_formats_definition = null;
71 protected HashMap<String, HashSet<String>> format_elements_map = null;
72 protected HashMap<String, Element> format_response_map = null;
73 protected HashMap<String, Element> format_meta_elem_map = null;
74
75 protected String index_stem = "";
76 protected String infodb_type = "";
77
78 /** constructor */
79 public IIIFPMH() {
80 }
81
82 public void cleanUp() {
83 super.cleanUp();//??
84
85 if(this.coll_db != null) {
86 this.coll_db.closeDatabase();
87 this.coll_db = null;
88 }
89 }
90
91 /** configure this service
92 info is the IIIFPMH service rack from collectionConfig.xml, and
93 extra_info is buildConfig.xml */
94 public boolean configure(Element info, Element extra_info) {
95 if (!super.configure(info, extra_info)){
96 logger.info("Configuring IIIFPMH(extends ServiceRack) returns false.");
97 return false;
98 }
99
100 //get the names from ServiceRack.java
101 this.site_name = this.router.getSiteName();
102 this.coll_name = this.cluster_name;
103
104 logger.info("Configuring IIIFPMH...");
105
106 this.config_info = info;
107
108 // the index stem is either specified in the buildConfig.xml file (extra_info) or uses the collection name
109 Element metadata_list = (Element) GSXML.getChildByTagName(extra_info, GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER);
110
111 // Is indexStem needed for IIIF // ****
112 if (metadata_list != null) {
113
114 Element index_stem_elem = (Element) GSXML.getNamedElement(metadata_list, GSXML.METADATA_ELEM, GSXML.NAME_ATT, "indexStem");
115
116 if (index_stem_elem != null) {
117 this.index_stem = GSXML.getNodeText(index_stem_elem);
118 }
119
120 Element infodb_type_elem = (Element) GSXML.getNamedElement(metadata_list, GSXML.METADATA_ELEM, GSXML.NAME_ATT, "infodbType");
121 if (infodb_type_elem != null) {
122 this.infodb_type = GSXML.getNodeText(infodb_type_elem);
123 }
124
125 }
126
127 if (index_stem == null || index_stem.equals("")) {
128 this.index_stem = this.cluster_name; // index_stem is the name of the db in indext/text, it is <colname>.<db>
129 }
130 if (infodb_type == null || infodb_type.equals("")) {
131 this.infodb_type = "gdbm"; // the default
132 }
133
134 Element get_record = this.desc_doc.createElement(GSXML.SERVICE_ELEM);
135 get_record.setAttribute(GSXML.NAME_ATT, IIIFXML.GET_RECORD);
136 get_record.setAttribute(GSXML.TYPE_ATT, "oai");
137 this.short_service_info.appendChild(get_record);
138
139 return true;
140 }
141
142 public boolean configureIIIF(Element iiif_config_elem) {
143
144 // Open the coll db db databases and store handles to them
145 coll_db = new SimpleCollectionDatabase(infodb_type);
146 if (!coll_db.databaseOK()) {
147 logger.error("Couldn't create the collection database of type "+infodb_type);
148 return false;
149 }
150
151 // Open databases for querying
152 String coll_db_file = GSFile.collectionDatabaseFile(this.site_home, this.cluster_name, index_stem, infodb_type);
153 if (!this.coll_db.openDatabase(coll_db_file, SimpleCollectionDatabase.READ)) {
154 logger.error("Could not open collection database!");
155 return false;
156 }
157
158 return true;
159 }
160
161 /** returns a specific service description */
162 public Element getServiceDescription(Document doc, String service_id, String lang, String subset) {
163
164 if (service_id.equals(IIIFXML.GET_RECORD)) {
165 Element get_record = doc.createElement(GSXML.SERVICE_ELEM);
166 get_record.setAttribute(GSXML.NAME_ATT, IIIFXML.GET_RECORD);
167 get_record.setAttribute(GSXML.TYPE_ATT, "oai");
168 return get_record;
169 }
170
171 return null;
172 }
173
174 /** returns the actual record element used in the OAI GetRecord response */
175 protected Element processGetRecord(Element req) {
176 /** arguments:
177 identifier: required
178 metadataPrefix: required
179 * Exceptions: badArgument; cannotDisseminateFormat; idDoesNotExist
180 */
181 NodeList params = GSXML.getChildrenByTagName(req, GSXML.PARAM_ELEM);
182 HashMap<String, String> param_map = GSXML.getParamMap(params);
183
184 String prefix = param_map.get(OAIXML.METADATA_PREFIX);
185 if (prefix == null || prefix.equals("")) {
186 //Just a double-check
187 logger.error("the value of metadataPrefix att is not present in the request.");
188 return IIIFXML.createErrorResponse(OAIXML.CANNOT_DISSEMINATE_FORMAT, "");
189 }
190
191 // check that we support this format
192 if (!format_response_map.containsKey(prefix)) {
193 logger.error("metadata prefix is not supported for collection "+this.coll_name);
194 return IIIFXML.createErrorResponse(OAIXML.CANNOT_DISSEMINATE_FORMAT, "");
195 }
196
197 Document doc = XMLConverter.newDOM();
198
199 String oid = param_map.get(IIIFXML.OID); // TODO should this be identifier???
200
201 //get a DBInfo object of the identifier; if this identifier is not present in the database,
202 // null is returned.
203 DBInfo info = this.coll_db.getInfo(oid);
204 if (info == null) {
205 //if(!OID_is_deleted) { // we don't expect to find entries for deleted docs in index db. // ****
206 logger.error("OID: " + oid + " is not present in the collection index database.");
207 return IIIFXML.createErrorResponse(IIIFXML.ID_DOES_NOT_EXIST, "");
208 //} // if doc deleted, id missing in indexdb is not an error: doc id would exist only in oai-inf db, marked as deleted 'D' // ****
209 }
210
211
212 // ****
213 Element get_record_response = doc.createElement(GSXML.RESPONSE_ELEM);
214 Element get_record = doc.createElement(IIIFXML.GET_RECORD);
215 get_record_response.appendChild(get_record);
216 Element record = doc.createElement(IIIFXML.RECORD);
217 //compose the header element
218 record.appendChild(createHeaderElement(doc, oid));
219 //compose the metadata element
220 record.appendChild(createMetadataElement(doc, prefix, info));
221 get_record.appendChild(record);
222 return get_record_response;
223 }
224
225
226 /** create the metadata element used when processing ListRecords/GetRecord requests
227 */
228
229 protected Element createMetadataElement(Document doc, String prefix, DBInfo info) {
230 // the <metadata> element
231 Element metadata = doc.createElement(OAIXML.METADATA);
232 // the <oai:dc namespace...> element
233 Element prfx_str_elem = (Element)doc.importNode(this.format_meta_elem_map.get(prefix), true);
234 metadata.appendChild(prfx_str_elem);
235
236 Element meta_format_element = GSXML.getNamedElement(this.meta_formats_definition, OAIXML.METADATA_FORMAT, GSXML.NAME_ATT, prefix);
237 NodeList elements = meta_format_element.getElementsByTagName(OAIXML.ELEMENT);
238 // for each element in the definition
239 for (int i=0; i<elements.getLength(); i++) {
240 Element e = (Element)elements.item(i);
241 Element map = (Element)GSXML.getChildByTagName(e, OAIXML.MAPPING);
242 if (map == null) {
243 // look up the element name
244 addMetadata(prfx_str_elem, e.getAttribute(GSXML.NAME_ATT), info);
245 } else {
246 // we go though the list of names in the mapping
247 addMetadata(prfx_str_elem, e.getAttribute(GSXML.NAME_ATT), map.getAttribute(OAIXML.SELECT), map.getAttribute(OAIXML.ELEMENTS), info);
248 }
249 }
250 // output any metadata that is not just a simple mapping
251 // addCustomMetadata(prfx_str_elem, prefix, info); // ****
252 return metadata;
253 }
254
255 /** a simple addMetadata where we look for meta_name metadata, and add as that name*/
256
257 protected void addMetadata(Element meta_list_elem, String meta_name, DBInfo info) {
258 Vector<String> values = info.getMultiInfo(meta_name);
259 if (values != null && values.size()!=0) {
260 for (int i=0; i<values.size(); i++) {
261 addMetadataElement(meta_list_elem, meta_name, values.get(i));
262 }
263 }
264 }
265
266 /** more complicated addMetadata - can add multiple items. */
267
268 protected void addMetadata(Element meta_list_elem, String new_meta_name, String select_type, String name_list, DBInfo info) {
269 String[] names = name_list.split(",");
270 for (int i=0; i<names.length; i++) {
271 Vector<String> values;
272 // some special words
273 if (names[i].startsWith(OAIXML.GSF_LINK_PREFIX)) {
274 values = new Vector<String>();
275 String base_url = OAIXML.getBaseURL(); // e.g. e.g. http://host:port/greenstone3/oaiserver
276 String link_url = null;
277 if (names[i].equals(OAIXML.GSF_LINK_PREFIX+OAIXML.LINK_TYPE_DOCUMENT)) {
278 link_url = base_url.replace("oaiserver", "library") + "/collection/" + this.coll_name + "/document/" + info.getInfo("Identifier");
279 } else if (names[i].equals(OAIXML.GSF_LINK_PREFIX+OAIXML.LINK_TYPE_SOURCE)) {
280 String srcfile = info.getInfo("srclinkFile");
281 if (!srcfile.equals("")) {
282 link_url = base_url.replace("oaiserver", "") + "sites/"
283 + this.site_name
284 + "/collect/" + this.coll_name + "/index/assoc/"
285 + info.getInfo("assocfilepath") + "/" + srcfile;
286 }
287 }
288 if (link_url !=null) {
289 values.add(link_url);
290 }
291 } else {
292 values = info.getMultiInfo(names[i]);
293 }
294 if (values == null || values.size()==0) {
295 continue;
296 }
297 for (int j=0; j<values.size(); j++) {
298 addMetadataElement(meta_list_elem, new_meta_name, values.get(j));
299 if (select_type.equals(OAIXML.SELECT_SINGLE_VALUE)) {
300 return; // only want to add one value
301 }
302 }
303 if (select_type.equals(OAIXML.SELECT_FIRST_VALID_META)) {
304 return; // we have added all values of this meta elem
305 }
306 // otherwise, we will keep going through the list and add them all.
307 }
308 }
309
310 // specific metadata formats might need to do some custom metadata that is not
311 //just a standard mapping.
312 protected void addCustomMetadata(Element meta_list_elem, String prefix, DBInfo info) {
313
314
315 }
316
317 /** create the actual metadata element for the list */
318
319 protected void addMetadataElement(Element meta_list_elem, String name, String value) {
320
321 Element meta = GSXML.createTextElement(meta_list_elem.getOwnerDocument(), name, value);
322 meta_list_elem.appendChild(meta);
323 }
324
325
326 /** create a header element used when processing requests like GetRecord
327 */
328 protected Element createHeaderElement(Document doc, String oid) {
329
330 Element header = doc.createElement(OAIXML.HEADER);
331
332 Element identifier = doc.createElement(IIIFXML.IDENTIFIER);
333 GSXML.setNodeText(identifier, coll_name + ":" + oid);
334 header.appendChild(identifier);
335
336 return header;
337 }
338
339}
340
341
Note: See TracBrowser for help on using the repository browser.