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

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

Bugfix: sometimes GS3 asks for docnodes with ids like hash.dir, which aren't fedoraPIDs. They shouldn't be passed onto fedora.

File size: 32.1 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 }
269
270 // look for document display format
271 path = GSPath.appendLink(GSXML.DISPLAY_ELEM, GSXML.FORMAT_ELEM);
272 Element display_format = (Element)GSXML.getNodeByPath(extra_info, path);
273 if (display_format != null) {
274 this.format_info_map.put("DocumentContentRetrieve", this.doc.importNode(display_format, true));
275 // should we make a copy?
276 }
277
278 // the format info
279 Element cb_format_info = this.doc.createElement(GSXML.FORMAT_ELEM);
280 boolean format_found = false;
281
282 // look for classifier <browse><format>
283 path = GSPath.appendLink(GSXML.BROWSE_ELEM, GSXML.FORMAT_ELEM);
284 Element browse_format = (Element)GSXML.getNodeByPath(extra_info, path);
285 if (browse_format != null) {
286 cb_format_info.appendChild(GSXML.duplicateWithNewName(this.doc, browse_format, GSXML.DEFAULT_ELEM, true));
287 format_found = true;
288 }
289
290 // add in to the description a simplified list of classifiers
291 Element browse = (Element)GSXML.getChildByTagName(extra_info, "browse"); // the <browse>
292 NodeList classifiers = browse.getElementsByTagName(GSXML.CLASSIFIER_ELEM);
293 for(int i=0; i<classifiers.getLength(); i++) {
294 Element cl = (Element)classifiers.item(i);
295 Element new_cl = (Element)this.doc.importNode(cl, false); // just import this node, not the children
296
297 // get the format info out, and put inside a classifier element
298 Element format_cl = (Element)new_cl.cloneNode(false);
299 Element format = (Element)GSXML.getChildByTagName(cl, GSXML.FORMAT_ELEM);
300 if (format != null) {
301
302 //copy all the children
303 NodeList elems = format.getChildNodes();
304 for (int j=0; j<elems.getLength();j++) {
305 format_cl.appendChild(this.doc.importNode(elems.item(j), true));
306 }
307 cb_format_info.appendChild(format_cl);
308 format_found = true;
309 }
310
311 }
312
313 if (format_found) {
314 this.format_info_map.put("ClassifierBrowse", cb_format_info);
315 }
316
317
318 // set up the macro resolver
319 macro_resolver.setSiteDetails(this.site_http_address, this.cluster_name, this.getLibraryName());
320 Element replacement_elem = (Element)GSXML.getChildByTagName(extra_info, "replaceList");
321 if (replacement_elem != null) {
322 macro_resolver.addMacros(replacement_elem);
323 }
324 // look for any refs to global replace lists
325 NodeList replace_refs_elems = extra_info.getElementsByTagName("replaceListRef");
326 for (int i=0; i<replace_refs_elems.getLength(); i++) {
327 String id = ((Element)replace_refs_elems.item(i)).getAttribute("id");
328 if (!id.equals("")) {
329 Element replace_list = GSXML.getNamedElement(this.router.config_info, "replaceList", "id", id);
330 if (replace_list != null) {
331 macro_resolver.addMacros(replace_list);
332 }
333 }
334 }
335
336 // configured ok
337 return true;
338 }
339
340
341 /* "DocumentContentRetrieve", "DocumentMetadataRetrieve", "DocumentStructureRetrieve",
342 "TextQuery", "FieldQuery", "ClassifierBrowse", "ClassifierBrowseMetadataRetrieve" */
343
344 protected Element processDocumentContentRetrieve(Element request) {
345 String[] docIDs = parse(request, GSXML.DOC_NODE_ELEM, GSXML.NODE_ID_ATT);
346 String[] relLinks = parse(request, GSXML.DOC_NODE_ELEM, "externalURL");
347
348 //logger.error("### request:");
349 //logger.error(GSXML.elementToString(request, true));
350
351 if(docIDs == null) {
352 logger.error("DocumentContentRetrieve request specified no doc nodes.\n");
353 return this.doc.createElement(GSXML.RESPONSE_ELEM); // empty response
354 } else {
355 for(int i = 0; i < docIDs.length; i++) {
356 //logger.error("BEFORE: docIDs[" + i + "]: " + docIDs[i]);
357 if(relLinks[i] != null && docIDs[i].startsWith("http://")) { // need to do a look up
358 docIDs[i] = translateExternalId(docIDs[i]);
359 } else {
360 docIDs[i] = translateId(docIDs[i]);
361 }
362 //logger.error("AFTER: docIDs[" + i + "]: " + docIDs[i]);
363 }
364 }
365
366 String lang = request.getAttribute(GSXML.LANG_ATT);
367 if(!lang.equals(prevLanguage)) {
368 prevLanguage = lang;
369 fedoraServicesAPIA.setLanguage(lang);
370 }
371
372 // first param (the collection) is not used by Fedora
373 Element response = getResponseAsDOM(fedoraServicesAPIA.retrieveDocumentContent(this.cluster_name, docIDs));
374
375
376 // resolve any collection specific macros
377 NodeList nodeContents = response.getElementsByTagName(GSXML.NODE_CONTENT_ELEM);
378 for(int i = 0; i < nodeContents.getLength(); i++) {
379 Element nodeContent = (Element)nodeContents.item(i);
380 /*if(nodeContent != null) {
381 nodeContent = (Element)nodeContent.getFirstChild(); // textNode
382 }*/
383 //logger.error("GIRAFFE 1. content retrieve response - nodeContent: " + GSXML.nodeToFormattedString(nodeContent));
384 String docContent = nodeContent.getFirstChild().getNodeValue(); // getTextNode and get its contents.
385 //logger.error("GIRAFFE 2. content retrieve response - docContent: " + docContent);
386
387 if(docContent != null) {
388 // get document text and resolve and macros. Rel and external links have _httpextlink_ set by HTMLPlugin
389 docContent = macro_resolver.resolve(docContent, lang, MacroResolver.SCOPE_TEXT, ""); // doc_id
390 nodeContent.getFirstChild().setNodeValue(docContent);
391 //logger.error("GIRAFFE 3. content retrieve response. Updated docContent: " + docContent);
392 }
393 }
394
395 return (Element)response.getElementsByTagName(GSXML.RESPONSE_ELEM).item(0);
396 }
397
398 protected Element processDocumentStructureRetrieve(Element request) {
399 String[] docIDs = parse(request, GSXML.DOC_NODE_ELEM, GSXML.NODE_ID_ATT);
400 String[] relLinks = parse(request, GSXML.DOC_NODE_ELEM, "externalURL");
401
402 if(docIDs == null) {
403 logger.error("DocumentStructureRetrieve request specified no doc nodes.\n");
404 return this.doc.createElement(GSXML.RESPONSE_ELEM); // empty response
405 } else {
406 for(int i = 0; i < docIDs.length; i++) {
407 //logger.error("BEFORE: docIDs[" + i + "]: " + docIDs[i]);
408 if(relLinks[i] != null && docIDs[i].startsWith("http://")) { // need to do a look up
409 docIDs[i] = translateExternalId(docIDs[i]);
410 } else {
411 docIDs[i] = translateId(docIDs[i]);
412 }
413 }
414 }
415
416 NodeList params = request.getElementsByTagName(GSXML.PARAM_ELEM);
417 String structure="";
418 String info="";
419 for(int i = 0; i < params.getLength(); i++) {
420 Element param = (Element)params.item(i);
421 if(param.getAttribute("name").equals("structure")) {
422 structure = structure + param.getAttribute("value") + "|";
423 } else if(param.getAttribute("name").equals("info")) {
424 info = info + param.getAttribute("value") + "|";
425 }
426 }
427
428 String lang = request.getAttribute(GSXML.LANG_ATT);
429 if(!lang.equals(prevLanguage)) {
430 prevLanguage = lang;
431 fedoraServicesAPIA.setLanguage(lang);
432 }
433 Element response = getResponseAsDOM(fedoraServicesAPIA.retrieveDocumentStructure(
434 this.cluster_name, docIDs, new String[]{structure}, new String[]{info}));
435 return (Element)response.getElementsByTagName(GSXML.RESPONSE_ELEM).item(0);
436 }
437
438 protected Element processDocumentMetadataRetrieve(Element request) {
439 String[] docIDs = parse(request, GSXML.DOC_NODE_ELEM, GSXML.NODE_ID_ATT);
440 String[] relLinks = parse(request, GSXML.DOC_NODE_ELEM, "externalURL");
441
442 if(docIDs == null) {
443 logger.error("DocumentMetadataRetrieve request specified no doc nodes.\n");
444 return this.doc.createElement(GSXML.RESPONSE_ELEM); // empty response
445 } else {
446 for(int i = 0; i < docIDs.length; i++) {
447 //logger.error("**** relLinks[i]: " + relLinks[i]);
448 //logger.error("**** docIDs[i]: " + docIDs[i]);
449 if(relLinks[i] != null && docIDs[i].startsWith("http://")) { // need to do a look up
450 docIDs[i] = translateExternalId(docIDs[i]);
451 } else {
452 docIDs[i] = translateId(docIDs[i]);
453 }
454 //logger.error("AFTER: docIDs[" + i + "]: " + docIDs[i]);
455 }
456 }
457
458 NodeList params = request.getElementsByTagName(GSXML.PARAM_ELEM);
459 String[] metafields = {};
460 if(params.getLength() > 0) {
461 metafields = new String[params.getLength()];
462 for(int i = 0; i < metafields.length; i++) {
463 Element param = (Element)params.item(i);
464 //if(param.hasAttribute(GSXML.NAME_ATT) && param.getAttribute(GSXML.NAME_ATT).equals("metadata") && param.hasAttribute(GSXML.VALUE_ATT)) {
465 if(param.hasAttribute(GSXML.VALUE_ATT)){
466 metafields[i] = param.getAttribute(GSXML.VALUE_ATT);
467 } else {
468 metafields[i] = "";
469 }
470 }
471 }
472
473 String lang = request.getAttribute(GSXML.LANG_ATT);
474 if(!lang.equals(prevLanguage)) {
475 prevLanguage = lang;
476 fedoraServicesAPIA.setLanguage(lang);
477 }
478 Element response = getResponseAsDOM(fedoraServicesAPIA.retrieveDocumentMetadata(
479 this.cluster_name, docIDs, metafields));
480 return (Element)response.getElementsByTagName(GSXML.RESPONSE_ELEM).item(0);
481 }
482
483 protected Element processClassifierBrowseMetadataRetrieve(Element request) {
484 String[] classIDs = parse(request, GSXML.CLASS_NODE_ELEM, GSXML.NODE_ID_ATT);
485 //String[] relLinks = parse(request, GSXML.CLASS_NODE_ELEM, "externalURL");
486
487 if(classIDs == null) {
488 logger.error("ClassifierBrowseMetadataRetrieve request specified no classifier nodes.\n");
489 return this.doc.createElement(GSXML.RESPONSE_ELEM); // empty response
490 } else {
491 for(int i = 0; i < classIDs.length; i++) {
492 classIDs[i] = translateId(classIDs[i]);
493 }
494 }
495
496 NodeList params = request.getElementsByTagName(GSXML.PARAM_ELEM);
497 String[] metafields = {};
498 if(params.getLength() > 0) {
499 metafields = new String[params.getLength()];
500 for(int i = 0; i < metafields.length; i++) {
501 Element param = (Element)params.item(i);
502 if(param.hasAttribute(GSXML.VALUE_ATT)){
503 metafields[i] = param.getAttribute(GSXML.VALUE_ATT);
504 } else {
505 metafields[i] = "";
506 }
507 }
508 }
509
510 String lang = request.getAttribute(GSXML.LANG_ATT);
511 if(!lang.equals(prevLanguage)) {
512 prevLanguage = lang;
513 fedoraServicesAPIA.setLanguage(lang);
514 }
515 Element response = getResponseAsDOM(fedoraServicesAPIA.retrieveBrowseMetadata(
516 this.cluster_name, "ClassifierBrowseMetadataRetrieve", classIDs, metafields));
517 //logger.error("**** Response from retrieveBrowseMeta: " + GSXML.elementToString(response, true));
518 return (Element)response.getElementsByTagName(GSXML.RESPONSE_ELEM).item(0);
519 }
520
521 protected Element processClassifierBrowse(Element request) {
522 String collection = this.cluster_name;
523 String lang = request.getAttribute(GSXML.LANG_ATT);
524 if(!lang.equals(prevLanguage)) {
525 prevLanguage = lang;
526 fedoraServicesAPIA.setLanguage(lang);
527 }
528
529 NodeList classNodes = request.getElementsByTagName(GSXML.CLASS_NODE_ELEM);
530 if(classNodes == null || classNodes.getLength() <= 0) {
531 logger.error("ClassifierBrowse request specified no classifier IDs.\n");
532 return this.doc.createElement(GSXML.RESPONSE_ELEM); // empty response
533 }
534 String classifierIDs[] = new String[classNodes.getLength()];
535 for(int i = 0; i < classifierIDs.length; i++) {
536 Element e = (Element)classNodes.item(i);
537 classifierIDs[i] = e.getAttribute(GSXML.NODE_ID_ATT);
538 classifierIDs[i] = translateId(classifierIDs[i]);
539 }
540
541 NodeList params = request.getElementsByTagName(GSXML.PARAM_ELEM);
542 String structure="";
543 String info="";
544 for(int i = 0; i < params.getLength(); i++) {
545 Element param = (Element)params.item(i);
546 if(param.getAttribute("name").equals("structure")) {
547 structure = structure + param.getAttribute("value") + "|";
548 } else if(param.getAttribute("name").equals("info")) {
549 info = info + param.getAttribute("value") + "|";
550 }
551 }
552 ///structure = structure + "siblings"; //test for getting with classifier browse structure: siblings
553
554 Element response
555 = getResponseAsDOM(fedoraServicesAPIA.retrieveBrowseStructure(collection, "ClassifierBrowse", classifierIDs,
556 new String[] {structure}, new String[] {info}));
557 //logger.error("**** FedoraServiceProxy - Response from retrieveBrowseStructure: " + GSXML.elementToString(response, true));
558
559 return (Element)response.getElementsByTagName(GSXML.RESPONSE_ELEM).item(0);
560 }
561
562 protected Element processTextQuery(Element request) {
563 return processQuery(request, "TextQuery");
564 }
565
566 protected Element processFieldQuery(Element request) {
567 return processQuery(request, "FieldQuery");
568 }
569
570 protected Element processQuery(Element request, String querytype) {
571 String collection = this.cluster_name;
572
573 String lang = request.getAttribute(GSXML.LANG_ATT);
574 if(!lang.equals(prevLanguage)) {
575 prevLanguage = lang;
576 fedoraServicesAPIA.setLanguage(lang);
577 }
578
579 NodeList paramNodes = request.getElementsByTagName(GSXML.PARAM_ELEM);
580 if(paramNodes.getLength() > 0) {
581 HashMap<String, String> params = new HashMap<String, String>(paramNodes.getLength());
582 for(int i = 0; i < paramNodes.getLength(); i++) {
583 Element param = (Element)paramNodes.item(i);
584 params.put(param.getAttribute(GSXML.NAME_ATT), param.getAttribute(GSXML.VALUE_ATT));
585 }
586
587 Element response = getResponseAsDOM(fedoraServicesAPIA.query(collection, querytype, params));
588 return (Element)response.getElementsByTagName(GSXML.RESPONSE_ELEM).item(0);
589 } else {
590 logger.error("TextQuery request specified no parameters.\n");
591 return this.doc.createElement(GSXML.RESPONSE_ELEM); // empty response
592 }
593 }
594
595 // get the requested nodeIDs out of a request message
596 protected String[] parse(Element request, String nodeType, String attribute) {
597 String[] nodevalues = null;
598 int count = 0;
599
600 Element docList = (Element) GSXML.getChildByTagName(request, nodeType+GSXML.LIST_MODIFIER);
601 if (docList != null) {
602 NodeList docNodes = docList.getElementsByTagName(nodeType);
603 if(docNodes.getLength() > 0) {
604 nodevalues = new String[docNodes.getLength()];
605 for(int i = 0; i < nodevalues.length; i++) {
606 Element e = (Element)docNodes.item(i);
607 String id = e.getAttribute(attribute);
608 // Not sure why there are at times requests for hashXXX.dir, which is not a fedora PID
609 // To skip these: if not requesting an externalURL and if requesting a docNode,
610 // then the ID has to contain the : character special to fedora PIDs
611 if(attribute == "externalURL" || (nodeType != GSXML.DOC_NODE_ELEM || id.contains(":"))) {
612 nodevalues[count++] = id;
613 }
614 }
615 }
616 }
617
618 if(count == 0) {
619 return null;
620 }
621
622 String[] tmp = new String[count];
623 for(int i = 0; i < count; i++) {
624 tmp[i] = nodevalues[i];
625 }
626 nodevalues = null;
627 nodevalues = tmp;
628
629 return nodevalues;
630 }
631
632
633 /** if id ends in .fc, .pc etc, then translate it to the correct id
634 * For now (for testing things work) the default implementation is to just remove the suffix */
635 protected String translateId(String id) {
636 if (OID.needsTranslating(id)) {
637 return OID.translateOID(this, id); //return translateOID(id);
638 }
639 return id;
640 }
641
642 /** if an id is not a greenstone id (an external id) then translate
643 * it to a greenstone one
644 * default implementation: return the id. Custom implementation:
645 * the id is a url that maps to a fedorapid whose dc.title contains the required HASHID */
646 protected String translateExternalId(String id) {
647 //logger.error("*** to translate an external ID: " + id); /////return id;
648 return this.externalId2OID(id);
649 }
650
651 /** converts an external id to greenstone OID. External ID is a URL link
652 * that, if relative, maps to a fedorapid that has an entry in fedora.
653 * The dc:title meta for that fedorapid will contain the required OID. */
654 public String externalId2OID(String extid) {
655 if(extid.endsWith(".rt") && (extid.indexOf('.') != extid.lastIndexOf('.'))) {
656 // .rt is not file extension, but Greenstone request for root of document
657 // not relevant for external ID
658 extid = extid.substring(0, extid.length()-3);
659 }
660
661 // the following method is unique to FedoraServicesAPIA
662 String response = ((FedoraServicesAPIA)fedoraServicesAPIA).getDocIDforURL(extid, this.cluster_name);
663 if(response.indexOf(GSXML.ERROR_ELEM) != -1) {
664 logger.error("**** The following error occurred when trying to find externalID for ID " + extid);
665 logger.error(response);
666 return extid;
667 }
668 if(response.equals("")) {
669 return extid;
670 } else {
671 return response;
672 }
673 }
674
675
676 /** translates relative oids into proper oids:
677 * .pr (parent), .rt (root) .fc (first child), .lc (last child),
678 * .ns (next sibling), .ps (previous sibling)
679 * .np (next page), .pp (previous page) : links sections in the order that you'd read the document
680 * a suffix is expected to be present so test before using
681 */
682 public String processOID(String doc_id, String top, String suff, int sibling_num) {
683
684 // send off request to get sibling etc. information from Fedora
685 Element response = null;
686 String[] children = null;
687 if(doc_id.startsWith("CL")) { // classifiernode
688 response = getResponseAsDOM(fedoraServicesAPIA.retrieveBrowseStructure(this.cluster_name, "ClassifierBrowse", new String[]{doc_id},
689 new String[]{"children"}, new String[]{"siblingPosition"}));
690 NodeList nl = response.getElementsByTagName(GSXML.NODE_STRUCTURE_ELEM);
691 if(nl.getLength() > 0) {
692 Element nodeStructure = (Element)nl.item(0);
693
694 if(nodeStructure != null) {
695 Element root = (Element) GSXML.getChildByTagName(nodeStructure, GSXML.CLASS_NODE_ELEM);
696 if(root != null) { // get children
697 NodeList classNodes = root.getElementsByTagName(GSXML.CLASS_NODE_ELEM);
698 if(classNodes != null) {
699 children = new String[classNodes.getLength()];
700 for(int i = 0; i < children.length; i++) {
701 Element child = (Element)classNodes.item(i);
702 children[i] = child.getAttribute(GSXML.NODE_ID_ATT);
703 }
704 }
705 }
706 }
707 }
708 } else { // documentnode
709 response = getResponseAsDOM(fedoraServicesAPIA.retrieveDocumentStructure(this.cluster_name, new String[]{doc_id},
710 new String[]{"children"}, new String[]{"siblingPosition"}));
711 String path = GSPath.createPath(new String[]{GSXML.RESPONSE_ELEM, GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER,
712 GSXML.DOC_NODE_ELEM, GSXML.NODE_STRUCTURE_ELEM, GSXML.DOC_NODE_ELEM});
713 Element parentDocNode = (Element) GSXML.getNodeByPath(response, path);
714
715 if (parentDocNode == null) {
716 return top;
717 } // else
718 NodeList docNodes = parentDocNode.getElementsByTagName(GSXML.DOC_NODE_ELEM); // only children should remain, since that's what we requested
719 if(docNodes.getLength() > 0) {
720 children = new String[docNodes.getLength()];
721
722 for(int i = 0; i < children.length; i++) {
723 Element e = (Element)docNodes.item(i);
724 children[i] = e.getAttribute(GSXML.NODE_ID_ATT);
725 }
726 } else { // return root node
727 children = new String[]{doc_id};
728 }
729 }
730
731 if (suff.equals("fc")) {
732 return children[0];
733 } else if (suff.equals("lc")) {
734 return children[children.length-1];
735 } else {
736 if (suff.equals("ss")) {
737 return children[sibling_num-1];
738 }
739 // find the position that we are at.
740 int i=0;
741 while(i<children.length) {
742 if (children[i].equals(top)) {
743 break;
744 }
745 i++;
746 }
747
748 if (suff.equals("ns")) {
749 if (i==children.length-1) {
750 return children[i];
751 }
752 return children[i+1];
753 } else if (suff.equals("ps")) {
754 if (i==0) {
755 return children[i];
756 }
757 return children[i-1];
758 }
759 }
760
761 return top;
762 }
763
764
765 protected Element getResponseAsDOM(String response) {
766 if(response == null) { // will not be the case, because an empty
767 return null; // response message will be sent instead
768 }
769
770 Element message = null;
771 try{
772 // turn the String xml response into a DOM tree:
773 DocumentBuilder builder
774 = DocumentBuilderFactory.newInstance().newDocumentBuilder();
775 Document doc
776 = builder.parse(new InputSource(new StringReader(response)));
777 message = doc.getDocumentElement();
778 } catch(Exception e){
779 if(response == null) {
780 response = "";
781 }
782 logger.error("An error occurred while trying to parse the response: ");
783 logger.error(response);
784 logger.error(e.getMessage());
785 }
786
787 // Error elements in message will be processed outside of here, just return the message
788 return message;
789 }
790
791 /* //process method for stylesheet requests
792 protected Element processFormat(Element request) {} */
793
794 /* returns the service list for the subclass */
795 /* protected Element getServiceList(String lang) {
796 // for now, it is static and has no language stuff
797 return (Element) this.short_service_info.cloneNode(true);
798 }*/
799
800 /** returns a specific service description */
801 protected Element getServiceDescription(String service, String lang, String subset) {
802 if(!lang.equals(prevLanguage)) {
803 prevLanguage = lang;
804 fedoraServicesAPIA.setLanguage(lang);
805 }
806 String serviceResponse = fedoraServicesAPIA.describeService(service);
807 Element response = getResponseAsDOM(serviceResponse);
808
809 // should be no chance of an npe, since FedoraGS3 lists the services, so will have descriptions for each
810 Element e = (Element)response.getElementsByTagName(GSXML.SERVICE_ELEM).item(0);
811 e = (Element)this.doc.importNode(e, true);
812 return e;
813 }
814
815 /** overloaded version for no args case */
816 protected String getTextString(String key, String lang) {
817 return getTextString(key, lang, null, null);
818 }
819
820 protected String getTextString(String key, String lang, String dictionary) {
821 return getTextString(key, lang, dictionary, null);
822 }
823 protected String getTextString(String key, String lang, String [] args) {
824 return getTextString(key, lang, null, args);
825 }
826
827 /** getTextString - retrieves a language specific text string for the given
828key and locale, from the specified resource_bundle (dictionary)
829 */
830 protected String getTextString(String key, String lang, String dictionary, String[] args) {
831
832 // we want to use the collection class loader in case there are coll specific files
833 if (dictionary != null) {
834 // just try the one specified dictionary
835 Dictionary dict = new Dictionary(dictionary, lang, this.class_loader);
836 String result = dict.get(key, args);
837 if (result == null) { // not found
838 return "_"+key+"_";
839 }
840 return result;
841 }
842
843 // now we try class names for dictionary names
844 String class_name = this.getClass().getName();
845 class_name = class_name.substring(class_name.lastIndexOf('.')+1);
846 Dictionary dict = new Dictionary(class_name, lang, this.class_loader);
847 String result = dict.get(key, args);
848 if (result != null) {
849 return result;
850 }
851
852 // we have to try super classes
853 Class c = this.getClass().getSuperclass();
854 while (result == null && c != null) {
855 class_name = c.getName();
856 class_name = class_name.substring(class_name.lastIndexOf('.')+1);
857 if (class_name.equals("ServiceRack")) {
858 // this is as far as we go
859 break;
860 }
861 dict = new Dictionary(class_name, lang, this.class_loader);
862 result = dict.get(key, args);
863 c = c.getSuperclass();
864 }
865 if (result == null) {
866 return "_"+key+"_";
867 }
868 return result;
869
870 }
871
872 protected String getMetadataNameText(String key, String lang) {
873
874 String properties_name = "metadata_names";
875 Dictionary dict = new Dictionary(properties_name, lang);
876
877 String result = dict.get(key);
878 if (result == null) { // not found
879 return null;
880 }
881 return result;
882 }
883}
884
Note: See TracBrowser for help on using the repository browser.