source: main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/FedoraServiceProxy.java@ 27316

Last change on this file since 27316 was 26311, checked in by ak19, 12 years ago

Second bugfix. Just one line for an elusive bug: need search results to link. Since the format wasn't been stored during the configure() stage, the gsf statements to add in the link weren't getting through.

File size: 32.2 KB
Line 
1/*
2 * ServiceRack.java
3 * Copyright (C) 2002 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 java.io.StringReader;
23import java.util.HashMap;
24import java.util.Properties;
25import java.util.regex.Matcher;
26import java.util.regex.Pattern;
27
28import javax.xml.parsers.DocumentBuilder;
29import javax.xml.parsers.DocumentBuilderFactory;
30
31import org.apache.log4j.Logger;
32import org.greenstone.gs3client.dlservices.DigitalLibraryServicesAPIA;
33import org.greenstone.gs3client.dlservices.FedoraServicesAPIA;
34import org.greenstone.gsdl3.core.MessageRouter;
35import org.greenstone.gsdl3.util.Dictionary;
36import org.greenstone.gsdl3.util.GSPath;
37import org.greenstone.gsdl3.util.GSXML;
38import org.greenstone.gsdl3.util.MacroResolver;
39import org.greenstone.gsdl3.util.OID;
40import org.greenstone.gsdl3.util.XMLConverter;
41import org.w3c.dom.Document;
42import org.w3c.dom.Element;
43import org.w3c.dom.Node;
44import org.w3c.dom.NodeList;
45import org.xml.sax.InputSource;
46
47import org.apache.commons.lang3.StringUtils;
48
49/*
50// greenstone classes
51import org.greenstone.gsdl3.util.*;
52import org.greenstone.gsdl3.core.*;
53
54// for fedora
55import org.greenstone.gs3client.dlservices.*;
56import org.greenstone.fedora.services.FedoraGS3Exception.CancelledException;
57
58// xml classes
59import org.w3c.dom.Node;
60import org.w3c.dom.NodeList;
61import org.w3c.dom.Element;
62import org.w3c.dom.Document;
63import org.xml.sax.InputSource;
64import javax.xml.parsers.*;
65import org.apache.xpath.XPathAPI;
66
67// general java classes
68import java.io.Reader;
69import java.io.StringReader;
70import java.io.File;
71import java.util.HashMap;
72import java.util.Locale;
73import java.util.Properties;
74import java.util.ResourceBundle;
75import java.util.regex.*;
76import java.lang.reflect.Method;
77*/
78
79import org.apache.log4j.*;
80
81/**
82 * FedoraServiceProxy - communicates with the FedoraGS3 interface.
83 *
84 * @author Anupama Krishnan
85 */
86public class FedoraServiceProxy
87 extends ServiceRack implements OID.OIDTranslatable
88{
89 public static class BasicTextMacroResolver extends MacroResolver {
90 private static final Pattern p_back_slash = Pattern.compile("\\\"");// create a pattern "\\\"", but it matches both " and \"
91
92 public String resolve(String text, String lang, String scope, String doc_oid)
93 {
94
95 if (text == null || text.equals("")) {
96 return text;
97 }
98 if (!scope.equals(SCOPE_TEXT) || text_macros.size()==0) {
99 return text;
100 }
101
102 java.util.ArrayList macros = text_macros;
103 for (int i=0; i<macros.size(); i++) {
104 String new_text = null;
105 Macro m = (Macro)macros.get(i);
106
107 if(m.type == TYPE_TEXT) {
108 // make sure we resolve any macros in the text
109
110 if(text.contains(m.macro)) {
111 if (m.resolve) {
112 new_text = this.resolve(m.text, lang, scope, doc_oid);
113 } else {
114 new_text = m.text;
115 }
116 text = StringUtils.replace(text, m.macro, new_text);//text = text.replaceAll(m.macro, new_text);
117 if (m.macro.endsWith("\\\\")) { // to get rid of "\" from the string like: "src="http://www.greenstone.org:80/.../mw.gif\">"
118 Matcher m_slash = p_back_slash.matcher(text);
119 String clean_str = "";
120 int s=0;
121 while (m_slash.find()) {
122 if (!text.substring(m_slash.end()-2, m_slash.end()-1).equals("\\")) {
123 clean_str = clean_str + text.substring(s,m_slash.end()-1); // it matches ", so get a substring before "
124 }else{
125 clean_str = clean_str + text.substring(s,m_slash.end()-2);// it matches \", so get a substring before \
126 }
127 s = m_slash.end();// get the index of the last match
128 clean_str = clean_str + "\"";
129 }
130 text = clean_str + text.substring(s,text.length());
131 }
132 }
133 }
134 }
135 return text;
136 }
137 }
138
139 static Logger logger = Logger.getLogger(org.greenstone.gsdl3.service.FedoraServiceProxy.class.getName());
140 protected MacroResolver macro_resolver = null;
141
142
143 /** The handle to the fedora connection */
144 private DigitalLibraryServicesAPIA fedoraServicesAPIA;
145
146 private String prevLanguage = "";
147
148 public void cleanUp() {
149 super.cleanUp();
150 }
151
152 /** sets the message router */
153 public void setMessageRouter(MessageRouter m) {
154 this.router = m;
155 setLibraryName(m.getLibraryName());
156 }
157
158 /** the no-args constructor */
159 public FedoraServiceProxy() {
160 super();
161
162 this.converter = new XMLConverter();
163 this.doc = this.converter.newDOM();
164 this.short_service_info = this.doc.createElement(GSXML.SERVICE_ELEM+GSXML.LIST_MODIFIER);
165 this.macro_resolver = new BasicTextMacroResolver();
166 }
167
168
169 /* configure the service module
170 *
171 * @param info the XML node <serviceRack name="XXX"/> with name equal
172 * to the class name (of the subclass)
173 *
174 * must configure short_service_info_ and service_info_map_
175 * @return true if configured ok
176 * must be implemented in subclasses
177 */
178 /*public boolean configure(Element info) {
179 return configure(info, null);
180 }*/
181
182 public boolean configure(Element info, Element extra_info) {
183 // set up the class loader
184
185 if (!super.configure(info, extra_info)){
186 return false;
187 }
188
189 // Try to instantiate a Fedora dl handle
190 try {
191 // Fedora connection settings defaults.
192 // Read host and port from global.properties, since by default, we expect the Greenstone server to be used
193 Properties globalProperties = new Properties();
194 globalProperties.load(Class.forName("org.greenstone.util.GlobalProperties").getClassLoader().getResourceAsStream("global.properties"));
195 String host = globalProperties.getProperty("tomcat.server", "localhost");
196 String port = globalProperties.getProperty("tomcat.port", "8383");
197 String protocol = "http";
198 String username = "fedoraIntCallUser"; //"fedoraAdmin"
199 String password = "changeme"; //"<user password>"
200
201 // See if buildConfig.xml overrides any of the defaults
202 // info is the <serviceRack> Element from buildConfig.xml (extra_info are the Elements of collectionConfig.xml)
203
204 NodeList nodes = info.getElementsByTagName("fedoraConnection");
205 if(nodes != null && nodes.getLength() > 0) {
206
207 Element fedoraElement = (Element)nodes.item(0);
208 if(fedoraElement.hasAttribute("protocol")) {
209 protocol = fedoraElement.getAttribute("protocol");
210 }
211 if(fedoraElement.hasAttribute("host")) {
212 host = fedoraElement.getAttribute("host");
213 }
214 if(fedoraElement.hasAttribute("port")) {
215 port = fedoraElement.getAttribute("port");
216 }
217 if(fedoraElement.hasAttribute("username")) {
218 username = fedoraElement.getAttribute("username");
219 }
220 if(fedoraElement.hasAttribute("password")) {
221 password = fedoraElement.getAttribute("password");
222 }
223 }
224
225 fedoraServicesAPIA = new FedoraServicesAPIA(protocol, host, Integer.parseInt(port), username, password);
226
227 } catch(org.greenstone.fedora.services.FedoraGS3Exception.CancelledException e) {
228 // The user pressed cancel in the fedora services instantiation dialog
229 return false;
230 } catch(Exception e) {
231 logger.error("Error instantiating the interface to the Fedora Repository:\n", e); // second parameter prints e's stacktrace
232 return false;
233 }
234
235
236 // Need to put the available services into short_service_info
237 // This is used by DefaultReceptionist.process() has an exception. But DefaultReceptionist.addExtraInfo()
238 // isn't helpful, and the problem actually already occurs in
239 // Receptionist.process() -> PageAction.process() -> MessageRouter.process()
240 // -> Collection/ServiceCluster.process() -> ServiceCluster.configureServiceRackList()
241 // -> ServiceRack.process() -> ServiceRack.processDescribe() -> ServiceRack.getServiceList().
242 // ServiceRack.getServiceList() requires this ServiceRack's services to be filled into the
243 // short_service_info Element which needs to be done in this FedoraServiceProxy.configure().
244
245 // get the display and format elements from the coll config file for
246 // the classifiers
247 AbstractBrowse.extractExtraClassifierInfo(info, extra_info);
248
249 // Copied from IViaProxy.java:
250 String collection = fedoraServicesAPIA.describeCollection(this.cluster_name);
251
252 Element collNode = getResponseAsDOM(collection);
253 Element serviceList = (Element)collNode.getElementsByTagName(GSXML.SERVICE_ELEM+GSXML.LIST_MODIFIER).item(0);
254
255//this.short_service_info.appendChild(short_service_info.getOwnerDocument().importNode(serviceList, true));
256 // we want the individual service Elements, not the serviceList Element which will wrap it later
257 NodeList services = collNode.getElementsByTagName(GSXML.SERVICE_ELEM);
258 for(int i = 0; i < services.getLength(); i++) {
259 Node service = services.item(i);
260 this.short_service_info.appendChild(short_service_info.getOwnerDocument().importNode(service, true));
261 }
262
263 // add some format info to service map if there is any
264 String path = GSPath.appendLink(GSXML.SEARCH_ELEM, GSXML.FORMAT_ELEM);
265 Element search_format = (Element) GSXML.getNodeByPath(extra_info, path);
266 if (search_format != null) {
267 this.format_info_map.put("TextQuery", this.doc.importNode(search_format, true));
268 this.format_info_map.put("FieldQuery", this.doc.importNode(search_format, true));
269 }
270
271 // look for document display format
272 path = GSPath.appendLink(GSXML.DISPLAY_ELEM, GSXML.FORMAT_ELEM);
273 Element display_format = (Element)GSXML.getNodeByPath(extra_info, path);
274 if (display_format != null) {
275 this.format_info_map.put("DocumentContentRetrieve", this.doc.importNode(display_format, true));
276 // should we make a copy?
277 }
278
279 // the format info
280 Element cb_format_info = this.doc.createElement(GSXML.FORMAT_ELEM);
281 boolean format_found = false;
282
283 // look for classifier <browse><format>
284 path = GSPath.appendLink(GSXML.BROWSE_ELEM, GSXML.FORMAT_ELEM);
285 Element browse_format = (Element)GSXML.getNodeByPath(extra_info, path);
286 if (browse_format != null) {
287 cb_format_info.appendChild(GSXML.duplicateWithNewName(this.doc, browse_format, GSXML.DEFAULT_ELEM, true));
288 format_found = true;
289 }
290
291 // add in to the description a simplified list of classifiers
292 Element browse = (Element)GSXML.getChildByTagName(extra_info, "browse"); // the <browse>
293 NodeList classifiers = browse.getElementsByTagName(GSXML.CLASSIFIER_ELEM);
294 for(int i=0; i<classifiers.getLength(); i++) {
295 Element cl = (Element)classifiers.item(i);
296 Element new_cl = (Element)this.doc.importNode(cl, false); // just import this node, not the children
297
298 // get the format info out, and put inside a classifier element
299 Element format_cl = (Element)new_cl.cloneNode(false);
300 Element format = (Element)GSXML.getChildByTagName(cl, GSXML.FORMAT_ELEM);
301 if (format != null) {
302
303 //copy all the children
304 NodeList elems = format.getChildNodes();
305 for (int j=0; j<elems.getLength();j++) {
306 format_cl.appendChild(this.doc.importNode(elems.item(j), true));
307 }
308 cb_format_info.appendChild(format_cl);
309 format_found = true;
310 }
311
312 }
313
314 if (format_found) {
315 this.format_info_map.put("ClassifierBrowse", cb_format_info);
316 }
317
318
319 // set up the macro resolver
320 macro_resolver.setSiteDetails(this.site_http_address, this.cluster_name, this.getLibraryName());
321 Element replacement_elem = (Element)GSXML.getChildByTagName(extra_info, "replaceList");
322 if (replacement_elem != null) {
323 macro_resolver.addMacros(replacement_elem);
324 }
325 // look for any refs to global replace lists
326 NodeList replace_refs_elems = extra_info.getElementsByTagName("replaceListRef");
327 for (int i=0; i<replace_refs_elems.getLength(); i++) {
328 String id = ((Element)replace_refs_elems.item(i)).getAttribute("id");
329 if (!id.equals("")) {
330 Element replace_list = GSXML.getNamedElement(this.router.config_info, "replaceList", "id", id);
331 if (replace_list != null) {
332 macro_resolver.addMacros(replace_list);
333 }
334 }
335 }
336
337 // configured ok
338 return true;
339 }
340
341
342 /* "DocumentContentRetrieve", "DocumentMetadataRetrieve", "DocumentStructureRetrieve",
343 "TextQuery", "FieldQuery", "ClassifierBrowse", "ClassifierBrowseMetadataRetrieve" */
344
345 protected Element processDocumentContentRetrieve(Element request) {
346 String[] docIDs = parse(request, GSXML.DOC_NODE_ELEM, GSXML.NODE_ID_ATT);
347 String[] relLinks = parse(request, GSXML.DOC_NODE_ELEM, "externalURL");
348
349 //logger.error("### request:");
350 //logger.error(GSXML.elementToString(request, true));
351
352 if(docIDs == null) {
353 logger.error("DocumentContentRetrieve request specified no doc nodes.\n");
354 return this.doc.createElement(GSXML.RESPONSE_ELEM); // empty response
355 } else {
356 for(int i = 0; i < docIDs.length; i++) {
357 //logger.error("BEFORE: docIDs[" + i + "]: " + docIDs[i]);
358 if(relLinks[i] != null && docIDs[i].startsWith("http://")) { // need to do a look up
359 docIDs[i] = translateExternalId(docIDs[i]);
360 } else {
361 docIDs[i] = translateId(docIDs[i]);
362 }
363 //logger.error("AFTER: docIDs[" + i + "]: " + docIDs[i]);
364 }
365 }
366
367 String lang = request.getAttribute(GSXML.LANG_ATT);
368 if(!lang.equals(prevLanguage)) {
369 prevLanguage = lang;
370 fedoraServicesAPIA.setLanguage(lang);
371 }
372
373 // first param (the collection) is not used by Fedora
374 Element response = getResponseAsDOM(fedoraServicesAPIA.retrieveDocumentContent(this.cluster_name, docIDs));
375
376
377 // resolve any collection specific macros
378 NodeList nodeContents = response.getElementsByTagName(GSXML.NODE_CONTENT_ELEM);
379 for(int i = 0; i < nodeContents.getLength(); i++) {
380 Element nodeContent = (Element)nodeContents.item(i);
381 /*if(nodeContent != null) {
382 nodeContent = (Element)nodeContent.getFirstChild(); // textNode
383 }*/
384 //logger.error("GIRAFFE 1. content retrieve response - nodeContent: " + GSXML.nodeToFormattedString(nodeContent));
385 String docContent = nodeContent.getFirstChild().getNodeValue(); // getTextNode and get its contents.
386 //logger.error("GIRAFFE 2. content retrieve response - docContent: " + docContent);
387
388 if(docContent != null) {
389 // get document text and resolve and macros. Rel and external links have _httpextlink_ set by HTMLPlugin
390 docContent = macro_resolver.resolve(docContent, lang, MacroResolver.SCOPE_TEXT, ""); // doc_id
391 nodeContent.getFirstChild().setNodeValue(docContent);
392 //logger.error("GIRAFFE 3. content retrieve response. Updated docContent: " + docContent);
393 }
394 }
395
396 return (Element)response.getElementsByTagName(GSXML.RESPONSE_ELEM).item(0);
397 }
398
399 protected Element processDocumentStructureRetrieve(Element request) {
400 String[] docIDs = parse(request, GSXML.DOC_NODE_ELEM, GSXML.NODE_ID_ATT);
401 String[] relLinks = parse(request, GSXML.DOC_NODE_ELEM, "externalURL");
402
403 if(docIDs == null) {
404 logger.error("DocumentStructureRetrieve request specified no doc nodes.\n");
405 return this.doc.createElement(GSXML.RESPONSE_ELEM); // empty response
406 } else {
407 for(int i = 0; i < docIDs.length; i++) {
408 //logger.error("BEFORE: docIDs[" + i + "]: " + docIDs[i]);
409 if(relLinks[i] != null && docIDs[i].startsWith("http://")) { // need to do a look up
410 docIDs[i] = translateExternalId(docIDs[i]);
411 } else {
412 docIDs[i] = translateId(docIDs[i]);
413 }
414 }
415 }
416
417 NodeList params = request.getElementsByTagName(GSXML.PARAM_ELEM);
418 String structure="";
419 String info="";
420 for(int i = 0; i < params.getLength(); i++) {
421 Element param = (Element)params.item(i);
422 if(param.getAttribute("name").equals("structure")) {
423 structure = structure + param.getAttribute("value") + "|";
424 } else if(param.getAttribute("name").equals("info")) {
425 info = info + param.getAttribute("value") + "|";
426 }
427 }
428
429 String lang = request.getAttribute(GSXML.LANG_ATT);
430 if(!lang.equals(prevLanguage)) {
431 prevLanguage = lang;
432 fedoraServicesAPIA.setLanguage(lang);
433 }
434 Element response = getResponseAsDOM(fedoraServicesAPIA.retrieveDocumentStructure(
435 this.cluster_name, docIDs, new String[]{structure}, new String[]{info}));
436 return (Element)response.getElementsByTagName(GSXML.RESPONSE_ELEM).item(0);
437 }
438
439 protected Element processDocumentMetadataRetrieve(Element request) {
440 String[] docIDs = parse(request, GSXML.DOC_NODE_ELEM, GSXML.NODE_ID_ATT);
441 String[] relLinks = parse(request, GSXML.DOC_NODE_ELEM, "externalURL");
442
443 if(docIDs == null) {
444 logger.error("DocumentMetadataRetrieve request specified no doc nodes.\n");
445 return this.doc.createElement(GSXML.RESPONSE_ELEM); // empty response
446 } else {
447 for(int i = 0; i < docIDs.length; i++) {
448 //logger.error("**** relLinks[i]: " + relLinks[i]);
449 //logger.error("**** docIDs[i]: " + docIDs[i]);
450 if(relLinks[i] != null && docIDs[i].startsWith("http://")) { // need to do a look up
451 docIDs[i] = translateExternalId(docIDs[i]);
452 } else {
453 docIDs[i] = translateId(docIDs[i]);
454 }
455 //logger.error("AFTER: docIDs[" + i + "]: " + docIDs[i]);
456 }
457 }
458
459 NodeList params = request.getElementsByTagName(GSXML.PARAM_ELEM);
460 String[] metafields = {};
461 if(params.getLength() > 0) {
462 metafields = new String[params.getLength()];
463 for(int i = 0; i < metafields.length; i++) {
464 Element param = (Element)params.item(i);
465 //if(param.hasAttribute(GSXML.NAME_ATT) && param.getAttribute(GSXML.NAME_ATT).equals("metadata") && param.hasAttribute(GSXML.VALUE_ATT)) {
466 if(param.hasAttribute(GSXML.VALUE_ATT)){
467 metafields[i] = param.getAttribute(GSXML.VALUE_ATT);
468 } else {
469 metafields[i] = "";
470 }
471 }
472 }
473
474 String lang = request.getAttribute(GSXML.LANG_ATT);
475 if(!lang.equals(prevLanguage)) {
476 prevLanguage = lang;
477 fedoraServicesAPIA.setLanguage(lang);
478 }
479 Element response = getResponseAsDOM(fedoraServicesAPIA.retrieveDocumentMetadata(
480 this.cluster_name, docIDs, metafields));
481 return (Element)response.getElementsByTagName(GSXML.RESPONSE_ELEM).item(0);
482 }
483
484 protected Element processClassifierBrowseMetadataRetrieve(Element request) {
485 String[] classIDs = parse(request, GSXML.CLASS_NODE_ELEM, GSXML.NODE_ID_ATT);
486 //String[] relLinks = parse(request, GSXML.CLASS_NODE_ELEM, "externalURL");
487
488 if(classIDs == null) {
489 logger.error("ClassifierBrowseMetadataRetrieve request specified no classifier nodes.\n");
490 return this.doc.createElement(GSXML.RESPONSE_ELEM); // empty response
491 } else {
492 for(int i = 0; i < classIDs.length; i++) {
493 classIDs[i] = translateId(classIDs[i]);
494 }
495 }
496
497 NodeList params = request.getElementsByTagName(GSXML.PARAM_ELEM);
498 String[] metafields = {};
499 if(params.getLength() > 0) {
500 metafields = new String[params.getLength()];
501 for(int i = 0; i < metafields.length; i++) {
502 Element param = (Element)params.item(i);
503 if(param.hasAttribute(GSXML.VALUE_ATT)){
504 metafields[i] = param.getAttribute(GSXML.VALUE_ATT);
505 } else {
506 metafields[i] = "";
507 }
508 }
509 }
510
511 String lang = request.getAttribute(GSXML.LANG_ATT);
512 if(!lang.equals(prevLanguage)) {
513 prevLanguage = lang;
514 fedoraServicesAPIA.setLanguage(lang);
515 }
516 Element response = getResponseAsDOM(fedoraServicesAPIA.retrieveBrowseMetadata(
517 this.cluster_name, "ClassifierBrowseMetadataRetrieve", classIDs, metafields));
518 //logger.error("**** Response from retrieveBrowseMeta: " + GSXML.elementToString(response, true));
519 return (Element)response.getElementsByTagName(GSXML.RESPONSE_ELEM).item(0);
520 }
521
522 protected Element processClassifierBrowse(Element request) {
523 String collection = this.cluster_name;
524 String lang = request.getAttribute(GSXML.LANG_ATT);
525 if(!lang.equals(prevLanguage)) {
526 prevLanguage = lang;
527 fedoraServicesAPIA.setLanguage(lang);
528 }
529
530 NodeList classNodes = request.getElementsByTagName(GSXML.CLASS_NODE_ELEM);
531 if(classNodes == null || classNodes.getLength() <= 0) {
532 logger.error("ClassifierBrowse request specified no classifier IDs.\n");
533 return this.doc.createElement(GSXML.RESPONSE_ELEM); // empty response
534 }
535 String classifierIDs[] = new String[classNodes.getLength()];
536 for(int i = 0; i < classifierIDs.length; i++) {
537 Element e = (Element)classNodes.item(i);
538 classifierIDs[i] = e.getAttribute(GSXML.NODE_ID_ATT);
539 classifierIDs[i] = translateId(classifierIDs[i]);
540 }
541
542 NodeList params = request.getElementsByTagName(GSXML.PARAM_ELEM);
543 String structure="";
544 String info="";
545 for(int i = 0; i < params.getLength(); i++) {
546 Element param = (Element)params.item(i);
547 if(param.getAttribute("name").equals("structure")) {
548 structure = structure + param.getAttribute("value") + "|";
549 } else if(param.getAttribute("name").equals("info")) {
550 info = info + param.getAttribute("value") + "|";
551 }
552 }
553 ///structure = structure + "siblings"; //test for getting with classifier browse structure: siblings
554
555 Element response
556 = getResponseAsDOM(fedoraServicesAPIA.retrieveBrowseStructure(collection, "ClassifierBrowse", classifierIDs,
557 new String[] {structure}, new String[] {info}));
558 //logger.error("**** FedoraServiceProxy - Response from retrieveBrowseStructure: " + GSXML.elementToString(response, true));
559
560 return (Element)response.getElementsByTagName(GSXML.RESPONSE_ELEM).item(0);
561 }
562
563 protected Element processTextQuery(Element request) {
564 return processQuery(request, "TextQuery");
565 }
566
567 protected Element processFieldQuery(Element request) {
568 return processQuery(request, "FieldQuery");
569 }
570
571 protected Element processQuery(Element request, String querytype) {
572 String collection = this.cluster_name;
573
574 String lang = request.getAttribute(GSXML.LANG_ATT);
575 if(!lang.equals(prevLanguage)) {
576 prevLanguage = lang;
577 fedoraServicesAPIA.setLanguage(lang);
578 }
579
580 NodeList paramNodes = request.getElementsByTagName(GSXML.PARAM_ELEM);
581 if(paramNodes.getLength() > 0) {
582 HashMap<String, String> params = new HashMap<String, String>(paramNodes.getLength());
583 for(int i = 0; i < paramNodes.getLength(); i++) {
584 Element param = (Element)paramNodes.item(i);
585 params.put(param.getAttribute(GSXML.NAME_ATT), param.getAttribute(GSXML.VALUE_ATT));
586 }
587
588 Element response = getResponseAsDOM(fedoraServicesAPIA.query(collection, querytype, params));
589 return (Element)response.getElementsByTagName(GSXML.RESPONSE_ELEM).item(0);
590 } else {
591 logger.error("TextQuery request specified no parameters.\n");
592 return this.doc.createElement(GSXML.RESPONSE_ELEM); // empty response
593 }
594 }
595
596 // get the requested nodeIDs out of a request message
597 protected String[] parse(Element request, String nodeType, String attribute) {
598 String[] nodevalues = null;
599 int count = 0;
600
601 Element docList = (Element) GSXML.getChildByTagName(request, nodeType+GSXML.LIST_MODIFIER);
602 if (docList != null) {
603 NodeList docNodes = docList.getElementsByTagName(nodeType);
604 if(docNodes.getLength() > 0) {
605 nodevalues = new String[docNodes.getLength()];
606 for(int i = 0; i < nodevalues.length; i++) {
607 Element e = (Element)docNodes.item(i);
608 String id = e.getAttribute(attribute);
609 // Not sure why there are at times requests for hashXXX.dir, which is not a fedora PID
610 // To skip these: if not requesting an externalURL and if requesting a docNode,
611 // then the ID has to contain the : character special to fedora PIDs
612 if(attribute == "externalURL" || (nodeType != GSXML.DOC_NODE_ELEM || id.contains(":"))) {
613 nodevalues[count++] = id;
614 }
615 }
616 }
617 }
618
619 if(count == 0) {
620 return null;
621 }
622
623 String[] tmp = new String[count];
624 for(int i = 0; i < count; i++) {
625 tmp[i] = nodevalues[i];
626 }
627 nodevalues = null;
628 nodevalues = tmp;
629
630 return nodevalues;
631 }
632
633
634 /** if id ends in .fc, .pc etc, then translate it to the correct id
635 * For now (for testing things work) the default implementation is to just remove the suffix */
636 protected String translateId(String id) {
637 if (OID.needsTranslating(id)) {
638 return OID.translateOID(this, id); //return translateOID(id);
639 }
640 return id;
641 }
642
643 /** if an id is not a greenstone id (an external id) then translate
644 * it to a greenstone one
645 * default implementation: return the id. Custom implementation:
646 * the id is a url that maps to a fedorapid whose dc.title contains the required HASHID */
647 protected String translateExternalId(String id) {
648 //logger.error("*** to translate an external ID: " + id); /////return id;
649 return this.externalId2OID(id);
650 }
651
652 /** converts an external id to greenstone OID. External ID is a URL link
653 * that, if relative, maps to a fedorapid that has an entry in fedora.
654 * The dc:title meta for that fedorapid will contain the required OID. */
655 public String externalId2OID(String extid) {
656 if(extid.endsWith(".rt") && (extid.indexOf('.') != extid.lastIndexOf('.'))) {
657 // .rt is not file extension, but Greenstone request for root of document
658 // not relevant for external ID
659 extid = extid.substring(0, extid.length()-3);
660 }
661
662 // the following method is unique to FedoraServicesAPIA
663 String response = ((FedoraServicesAPIA)fedoraServicesAPIA).getDocIDforURL(extid, this.cluster_name);
664 if(response.indexOf(GSXML.ERROR_ELEM) != -1) {
665 logger.error("**** The following error occurred when trying to find externalID for ID " + extid);
666 logger.error(response);
667 return extid;
668 }
669 if(response.equals("")) {
670 return extid;
671 } else {
672 return response;
673 }
674 }
675
676
677 /** translates relative oids into proper oids:
678 * .pr (parent), .rt (root) .fc (first child), .lc (last child),
679 * .ns (next sibling), .ps (previous sibling)
680 * .np (next page), .pp (previous page) : links sections in the order that you'd read the document
681 * a suffix is expected to be present so test before using
682 */
683 public String processOID(String doc_id, String top, String suff, int sibling_num) {
684
685 // send off request to get sibling etc. information from Fedora
686 Element response = null;
687 String[] children = null;
688 if(doc_id.startsWith("CL")) { // classifiernode
689 response = getResponseAsDOM(fedoraServicesAPIA.retrieveBrowseStructure(this.cluster_name, "ClassifierBrowse", new String[]{doc_id},
690 new String[]{"children"}, new String[]{"siblingPosition"}));
691 NodeList nl = response.getElementsByTagName(GSXML.NODE_STRUCTURE_ELEM);
692 if(nl.getLength() > 0) {
693 Element nodeStructure = (Element)nl.item(0);
694
695 if(nodeStructure != null) {
696 Element root = (Element) GSXML.getChildByTagName(nodeStructure, GSXML.CLASS_NODE_ELEM);
697 if(root != null) { // get children
698 NodeList classNodes = root.getElementsByTagName(GSXML.CLASS_NODE_ELEM);
699 if(classNodes != null) {
700 children = new String[classNodes.getLength()];
701 for(int i = 0; i < children.length; i++) {
702 Element child = (Element)classNodes.item(i);
703 children[i] = child.getAttribute(GSXML.NODE_ID_ATT);
704 }
705 }
706 }
707 }
708 }
709 } else { // documentnode
710 response = getResponseAsDOM(fedoraServicesAPIA.retrieveDocumentStructure(this.cluster_name, new String[]{doc_id},
711 new String[]{"children"}, new String[]{"siblingPosition"}));
712 String path = GSPath.createPath(new String[]{GSXML.RESPONSE_ELEM, GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER,
713 GSXML.DOC_NODE_ELEM, GSXML.NODE_STRUCTURE_ELEM, GSXML.DOC_NODE_ELEM});
714 Element parentDocNode = (Element) GSXML.getNodeByPath(response, path);
715
716 if (parentDocNode == null) {
717 return top;
718 } // else
719 NodeList docNodes = parentDocNode.getElementsByTagName(GSXML.DOC_NODE_ELEM); // only children should remain, since that's what we requested
720 if(docNodes.getLength() > 0) {
721 children = new String[docNodes.getLength()];
722
723 for(int i = 0; i < children.length; i++) {
724 Element e = (Element)docNodes.item(i);
725 children[i] = e.getAttribute(GSXML.NODE_ID_ATT);
726 }
727 } else { // return root node
728 children = new String[]{doc_id};
729 }
730 }
731
732 if (suff.equals("fc")) {
733 return children[0];
734 } else if (suff.equals("lc")) {
735 return children[children.length-1];
736 } else {
737 if (suff.equals("ss")) {
738 return children[sibling_num-1];
739 }
740 // find the position that we are at.
741 int i=0;
742 while(i<children.length) {
743 if (children[i].equals(top)) {
744 break;
745 }
746 i++;
747 }
748
749 if (suff.equals("ns")) {
750 if (i==children.length-1) {
751 return children[i];
752 }
753 return children[i+1];
754 } else if (suff.equals("ps")) {
755 if (i==0) {
756 return children[i];
757 }
758 return children[i-1];
759 }
760 }
761
762 return top;
763 }
764
765
766 protected Element getResponseAsDOM(String response) {
767 if(response == null) { // will not be the case, because an empty
768 return null; // response message will be sent instead
769 }
770
771 Element message = null;
772 try{
773 // turn the String xml response into a DOM tree:
774 DocumentBuilder builder
775 = DocumentBuilderFactory.newInstance().newDocumentBuilder();
776 Document doc
777 = builder.parse(new InputSource(new StringReader(response)));
778 message = doc.getDocumentElement();
779 } catch(Exception e){
780 if(response == null) {
781 response = "";
782 }
783 logger.error("An error occurred while trying to parse the response: ");
784 logger.error(response);
785 logger.error(e.getMessage());
786 }
787
788 // Error elements in message will be processed outside of here, just return the message
789 return message;
790 }
791
792 /* //process method for stylesheet requests
793 protected Element processFormat(Element request) {} */
794
795 /* returns the service list for the subclass */
796 /* protected Element getServiceList(String lang) {
797 // for now, it is static and has no language stuff
798 return (Element) this.short_service_info.cloneNode(true);
799 }*/
800
801 /** returns a specific service description */
802 protected Element getServiceDescription(String service, String lang, String subset) {
803 if(!lang.equals(prevLanguage)) {
804 prevLanguage = lang;
805 fedoraServicesAPIA.setLanguage(lang);
806 }
807 String serviceResponse = fedoraServicesAPIA.describeService(service);
808 Element response = getResponseAsDOM(serviceResponse);
809
810 // should be no chance of an npe, since FedoraGS3 lists the services, so will have descriptions for each
811 Element e = (Element)response.getElementsByTagName(GSXML.SERVICE_ELEM).item(0);
812 e = (Element)this.doc.importNode(e, true);
813 return e;
814 }
815
816 /** overloaded version for no args case */
817 protected String getTextString(String key, String lang) {
818 return getTextString(key, lang, null, null);
819 }
820
821 protected String getTextString(String key, String lang, String dictionary) {
822 return getTextString(key, lang, dictionary, null);
823 }
824 protected String getTextString(String key, String lang, String [] args) {
825 return getTextString(key, lang, null, args);
826 }
827
828 /** getTextString - retrieves a language specific text string for the given
829key and locale, from the specified resource_bundle (dictionary)
830 */
831 protected String getTextString(String key, String lang, String dictionary, String[] args) {
832
833 // we want to use the collection class loader in case there are coll specific files
834 if (dictionary != null) {
835 // just try the one specified dictionary
836 Dictionary dict = new Dictionary(dictionary, lang, this.class_loader);
837 String result = dict.get(key, args);
838 if (result == null) { // not found
839 return "_"+key+"_";
840 }
841 return result;
842 }
843
844 // now we try class names for dictionary names
845 String class_name = this.getClass().getName();
846 class_name = class_name.substring(class_name.lastIndexOf('.')+1);
847 Dictionary dict = new Dictionary(class_name, lang, this.class_loader);
848 String result = dict.get(key, args);
849 if (result != null) {
850 return result;
851 }
852
853 // we have to try super classes
854 Class c = this.getClass().getSuperclass();
855 while (result == null && c != null) {
856 class_name = c.getName();
857 class_name = class_name.substring(class_name.lastIndexOf('.')+1);
858 if (class_name.equals("ServiceRack")) {
859 // this is as far as we go
860 break;
861 }
862 dict = new Dictionary(class_name, lang, this.class_loader);
863 result = dict.get(key, args);
864 c = c.getSuperclass();
865 }
866 if (result == null) {
867 return "_"+key+"_";
868 }
869 return result;
870
871 }
872
873 protected String getMetadataNameText(String key, String lang) {
874
875 String properties_name = "metadata_names";
876 Dictionary dict = new Dictionary(properties_name, lang);
877
878 String result = dict.get(key);
879 if (result == null) { // not found
880 return null;
881 }
882 return result;
883 }
884}
885
Note: See TracBrowser for help on using the repository browser.