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

Last change on this file since 32357 was 32357, checked in by ak19, 6 years ago

GS3 Java code has moved away from using tomcat.port to using tomcat.port.<protocol>.

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