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

Last change on this file since 28966 was 28966, checked in by kjdon, 10 years ago

Lots of changes. Mainly to do with removing this.doc from everywhere. Document is not thread safe. Now we tend to create a new Document everytime we are starting a new page/message etc. in service this.desc_doc is available as teh document to create service info stuff. But it should only be used for this and not for other messages. newDOM is now static for XMLConverter. method param changes for some GSXML methods.

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