source: greenstone3/trunk/resources/java/QBRSOAPServer.java.in@ 16105

Last change on this file since 16105 was 16105, checked in by ak19, 16 years ago

Changed once more to return formatted string again, and to only trim the string if the first char is whitespace (java code for trim doesn't do the check). Preserves previous change of prepending an <xml> start tag.

File size: 35.7 KB
Line 
1/**
2 *#########################################################################
3 * QBRSOAPServer.java.in: a template for a SOAPServer providing
4 * basic Query, Browse, Retrieve web services for Greenstone 3.
5 * Part of the Greenstone digital library suite from the New Zealand
6 * Digital Library Project at the University of Waikato, New Zealand.
7 * <BR><BR>
8 * Copyright (C) 2008 New Zealand Digital Library Project
9 * <BR><BR>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 * <BR><BR>
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 * <BR><BR>
20 * @author ak19
21 * based on Katherine Don's SOAPServer@sitename@ template file.
22 *########################################################################
23 */
24
25package org.greenstone.gsdl3;
26
27import java.io.File;
28import java.io.InputStream;
29
30import java.util.Properties;
31import java.util.Enumeration;
32import java.util.Map;
33import java.util.Map.Entry;
34import java.util.HashMap;
35import java.util.Set;
36import java.util.Iterator;
37
38import org.w3c.dom.Document;
39import org.w3c.dom.Element;
40import org.w3c.dom.NodeList;
41
42import org.greenstone.gsdl3.core.MessageRouter;
43import org.greenstone.gsdl3.util.GlobalProperties;
44import org.greenstone.gsdl3.util.GSFile;
45import org.greenstone.gsdl3.util.GSXML;
46import org.greenstone.gsdl3.util.XMLConverter;
47
48import org.apache.log4j.Logger; // Import log4j classes
49
50/*
51 * Add to $GSDLHOME/web/WEB-INF/server-config.wsdd:
52 * <service name="GS3WebServices" provider="java:RPC">
53 * <parameter name="allowedMethods" value="*"/>
54 * <parameter name="className" value="org.greenstone.gs3services.GS3WebServices"/>
55 * </service>
56*/
57
58/** Class that provides the basic Query, Browse and Retrieve (QBR) web service
59 * operations for Greenstone 3.
60 * It contains a MessageRouter that carries out all the tasks by calling the
61 * appropriate Greenstone functionality for each request message passed to it,
62 * and returning a response message.
63 *
64 * All response messages are returned from the MessageRouter to clients invoking
65 * the web services. All return values are strings that represent XML messages.
66 *
67 * Method help() reads from the file QBRWebServicesHelp.properties to list the web
68 * service operations available. Method helpWithMethod(String methodName)
69 * reads from the same file to display a description of the requested operation.
70 * (These method descriptions are mostly the same as those in the Javadoc
71 * comments.)
72 *
73 * NOTE: The folder containing this web service class' properties helpFile
74 * should be on the classpath. (QBRWebServicesHelp.properties)
75 * @author ak19
76*/
77public class QBRSOAPServer@sitename@ {
78 /** site_name the MessageRouter works with, here set to "localsite" */
79 protected String site_name = "@sitename@";
80
81 /** Message Router object to pass requests messages to and which
82 * will process them.*/
83 protected MessageRouter mr = null;
84
85 /** Container Document to create XML Nodes */
86 protected Document doc=null;
87 /** A converter class to parse XML and create Docs */
88 protected XMLConverter converter=null;
89
90 /** The Logger for this class */
91 private static Logger LOG = Logger.getLogger(QBRSOAPServer@[email protected]);
92
93 /** Error message loading helpFile. Remains at "" if everything is fine */
94 protected static String helpErrormessage = "";
95 /** Properties map with mappings from methodname to help
96 * description string. */
97 protected static Properties properties;
98 /** The help properties file describing the web service operations */
99 protected static String helpFile = "QBRWebServicesHelp.properties";
100
101 // static code block to initialise the help Properties from the helpFile
102 static {
103 properties = new Properties();
104 // load the properties file from a location with respect to the
105 // the Web Service .class file
106 InputStream input = null;
107 try {
108 // load the properties file from a location with respect to the
109 // the Web Service .class file
110 input
111 = QBRSOAPServer@[email protected]().getResourceAsStream(
112 helpFile);
113 if(input == null) {
114 helpErrormessage = "Cannot find file " + helpFile + " to load.";
115 LOG.warn(helpErrormessage);
116 } else {
117 properties.load(input);
118 input.close();
119 }
120 } catch(Exception e) {
121 helpErrormessage = "Exception loading properties from help file "
122 + helpFile + "\n" + e.getMessage();
123 LOG.warn("Exception loading properties from help file "
124 + helpFile + "\n" + e.getMessage());
125 }
126 }
127
128
129 /* Describe subset options for the various Greenstone3 modules */
130 protected static final String mrSubsetOptions = // messageRouter
131 "collectionList serviceClusterList serviceList siteList";
132 protected static final String csSubsetOptions = // collections and serviceClusters
133 "metadataList serviceList displayItemList";
134 protected static final String serviceSubsetOptions = // services
135 "paramList displayItemList";
136 protected static final String docStructureOptions =
137 "entire ancestors parent siblings children descendants"; // note the spelling
138 protected static final String docStructureInfo =
139 "numSiblings siblingPosition numChildren";
140 protected static final String browseStructureOptions =
141 "ancestors parent siblings children descendants"; // note the spelling
142
143
144 /** Constructor that initializes the web services' MessageRouter object
145 * Reads from GlobalProperties to get gsdl3_home and set the sitename. */
146 public QBRSOAPServer@sitename@() {
147 String gsdl3_home = GlobalProperties.getGSDL3Home();
148 if (gsdl3_home == null || gsdl3_home.equals("")) {
149 LOG.error(
150 "Couldn't access GSDL3Home from GlobalProperties.getGSDL3HOME,"
151 + "can't initialize the SOAP Server.");
152 return;
153 }
154
155 String site_home = GSFile.siteHome(gsdl3_home, this.site_name);
156
157 File site_file = new File(site_home);
158 if (!site_file.isDirectory()) {
159 LOG.error("The site directory "+site_file.getPath()
160 +" doesn't exist. Can't initialize the SOAP Server.");
161 return;
162 }
163 this.converter = new XMLConverter();
164 this.doc = this.converter.newDOM();
165
166 mr = new MessageRouter();
167 mr.setSiteName(this.site_name);
168 mr.configure();
169 }
170
171 /* (1) DESCRIBE MESSAGES, manual pages 35-41 */
172 /** Sends a describe message to the MessageRouter.
173 * @param lang is the language of the display content in the response.
174 * @param subsetOption are the requested list of items to return in the
175 * response. For the Message Router this can be collectionList,
176 * serviceClusterList, serviceList, siteList
177 * @see <a href="http://wiki.greenstone.org/wiki/index.php/Greenstone3">The Greenstone 3 Developer's Manual - pages 35-41</a>
178 */
179 public String describe(String lang, String subsetOption)
180 {
181 return describe("", lang, subsetOption, mrSubsetOptions);
182 }
183
184 /** For sending Describe messages to ServiceClusters.
185 * @param serviceCluster is the name of the Service Cluster that this describe
186 * request is sent to.
187 * @param lang is the language of the display content in the response
188 * @param subsetOption is the requested list of items to return in the response
189 * For Service Clusters this can be metadataList, serviceList, displayItemList.
190 * @see <a href="http://wiki.greenstone.org/wiki/index.php/Greenstone3">The Greenstone 3 Developer's Manual - pages 35-41</a>
191 */
192 public String describeServiceCluster(
193 String serviceCluster, String lang, String subsetOption)
194 {
195 return describe(serviceCluster, lang, subsetOption, csSubsetOptions);
196 }
197
198 /** For sending Describe messages to Collections.
199 * @param collection is the name of the Collection that this describe request
200 * is sent to.
201 * @param lang is the language of the display content in the response
202 * @param subsetOption is the requested list of items to return in the response
203 * For Collections this can be metadataList, serviceList and displayItemList.
204 * @see <a href="http://wiki.greenstone.org/wiki/index.php/Greenstone3">The Greenstone 3 Developer's Manual - pages 35-41</a>
205 */
206 public String describeCollection(
207 String collection, String lang, String subsetOption)
208 {
209 return describe(collection, lang, subsetOption, csSubsetOptions);
210 }
211
212 /**
213 * For sending a describe message to a Collection's Service.
214 * @see <a href="http://wiki.greenstone.org/wiki/index.php/Greenstone3">The Greenstone 3 Developer's Manual - pages 35-41</a>
215 * @param collection is the name of the Collection whose service
216 * this describe request is sent to.
217 * @param service is the name of the Service (of that collection) to
218 * which this describe request is sent.
219 * @param lang is the language of the display content in the response
220 * @param subsetOption is the requested list of items to return in the response
221 * For Services this can be paramList, displayItemList */
222 public String describeCollectionService(String collection, String service,
223 String lang, String subsetOption)
224 {
225 return describe(collection + "/" + service,
226 lang, subsetOption, serviceSubsetOptions);
227 }
228
229 /**
230 * For sending a describe message to a Service hosted by the Message Router
231 * (no collection).
232 * @see <a href="http://wiki.greenstone.org/wiki/index.php/Greenstone3">The Greenstone 3 Developer's Manual - pages 35-41</a>
233 * @param service is the name of the MessageRouter's Service to which this
234 * describe request is sent.
235 * @param lang is the language of the display content in the response
236 * @param subsetOption is the requested list of items to return in the response
237 * For Services this can be paramList, displayItemList
238 */
239 public String describeService(
240 String service, String lang, String subsetOption)
241 {
242 return describe(service, lang, subsetOption, serviceSubsetOptions);
243 }
244
245 /** For sending a describe message.
246 * If public, this method would give full access: a describe message that
247 * lets the user specify all the details of who the receiver is, and what
248 * details are requested.
249 * @param to - the Greenstone module (MessageRouter, Collection,
250 * ServiceCluster or (Collection-)Service to send this describe message to.
251 * (The module asked to describe itself.)
252 * @param lang - the language of the display content in the response.
253 * @param subsetOption - the set of elements of the describe response that
254 * are requested. These vary depending on the GS3 module asked to describe
255 * itself.
256 * @param validSubsetOptions - the list of subsetOptions that are allowed
257 * for the module this describe message is sent to. Parameter subsetOption
258 * has to be among the list of validSubsetOptions.
259 * @see <a href="http://wiki.greenstone.org/wiki/index.php/Greenstone3">The Greenstone 3 Developer's Manual - pages 35-41</a>
260 */
261 protected String describe(String to, String lang,
262 String subsetOption, String validSubsetOptions)
263 {
264 // Create message element: <message></message>
265 Element message = this.doc.createElement(GSXML.MESSAGE_ELEM);
266 // <message><request lang="en" to="" type="describe" uid="" /></message>
267 Element request = GSXML.createBasicRequest(
268 this.doc, GSXML.REQUEST_TYPE_DESCRIBE, to, lang, "");
269
270 // Check if only a subset of this Module Interface's data is asked
271 // to be described
272 if(!subsetOption.equals("")) {
273 // Now deal with the value for subset param:
274 // only deal with valid params for subset of to-ModuleInterface
275 if(validSubsetOptions.indexOf(subsetOption) == -1)
276 return error("Invalid List to be described. Choose one of:\n"
277 + validSubsetOptions);
278
279 // else, append <paramList>
280 // <param name="subset" value="subsetOption" /></paramList>
281 Element paramList = this.doc.createElement(
282 GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
283 // append <param name="subset" value=paramValue />
284 // createParam(Document, name, value);
285 // Name needs to be "subset", but this can be either GSXML.SUBSET_PARAM
286 // or GSXML.SYSTEM_SUBSET_ATT. It's the first one probably.
287 paramList.appendChild(GSXML.createParameter(
288 this.doc, GSXML.SUBSET_PARAM, subsetOption));
289 request.appendChild(paramList);
290 }
291 message.appendChild(request);
292
293 // Send it off to the Message Router and return the response
294 return this.processInternal(message);
295 }
296
297 /* (2) Process-type message, QUERY-TYPE SERVICES - p.45 */
298 /** For executing a (process-type message) query-type service.
299 * @see <a href="http://wiki.greenstone.org/wiki/index.php/Greenstone3">The Greenstone 3 Developer's Manual - page 45</a>
300 * @param collection is the name of the Collection whose query service this
301 * query-process request is sent to. If "", then the Message Router is assumed.
302 * @param service is the name of the Query Service (of that collection) to
303 * which this request is sent.
304 * @param lang is the language of the display content in the response
305 * @param nameToValsMap is a Map of the (fieldname, value) pairs for the
306 * parameters of the query. The field names should be those recognised by
307 * Greenstone 3. That is, the names must exist for the (Collection-)Service Query that this
308 * message is sent To (as given in 'to' argument).
309 * For names of Greenstone-accepted arguments,
310 * @see <a href="http://wiki.greenstone.org/wiki/index.php/Actions_and_Arguments">Greenstone wiki - Actions and Arguments</a>
311 */
312 public String query(String collection, String service,
313 String lang, Map nameToValsMap)
314 {
315 // <paramList></paramList>
316 Element paramList = this.doc.createElement(
317 GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
318 // <param>s: creating parameters of (name, value) pairs
319 Set entrySet = nameToValsMap.entrySet();
320 Iterator i = entrySet.iterator();
321 while(i.hasNext()) {
322 Entry entry = (Entry)i.next();
323 String name = (String)entry.getKey();
324 String value = (String)entry.getValue();
325 paramList.appendChild(GSXML.createParameter(
326 this.doc, name, value));
327 }
328
329 Element message = this.doc.createElement(GSXML.MESSAGE_ELEM);
330 Element request = GSXML.createBasicRequest(
331 this.doc, GSXML.REQUEST_TYPE_PROCESS,
332 collection+"/"+service, lang, "");
333
334 request.appendChild(paramList);
335 message.appendChild(request);
336
337 // Send it off to the Message Router and return the response
338 return this.processInternal(message);
339 }
340
341 /**
342 * This method is used to perform the most basic query:
343 * it assumes defaults for all other parameters and provides only
344 * the query string. It is built on top of a TextQuery.
345 * @param collection is the Greenstone collection to be searched
346 * @param lang is the preferred language of the display content in
347 * the response to be returned.
348 * @param query is the string to be sought in the Greenstone collection
349 * @return a Greenstone 3 XML response message for the query specifying
350 * the search results.
351 */
352 public String basicQuery(String collection, String lang, String query) {
353 // The basicQuery is built on top of the TextQuery service
354 final String queryService = "TextQuery";
355
356 // (1) describe request on the TextQuery
357 String queryDescription = describeCollectionService(
358 collection, queryService, "en", "paramList"); // just get paramList
359 //System.out.println(queryDescription);
360
361 Document doc = this.converter.getDOM(queryDescription);
362 NodeList nl = doc.getElementsByTagName(
363 GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
364
365 Element paramList = null;
366 if(nl.getLength() <= 0) { // no paramList in textQuery description means
367 // no query field either: that means we can't continue
368 return this.error("BasicQuery is not available for this collection"
369 + " as it provides no TextQuery service.");
370 } //else
371
372 paramList = (Element)nl.item(0);
373 nl = paramList.getElementsByTagName(GSXML.PARAM_ELEM);
374 if(nl.getLength() <= 0) { // no params, means no query field, so return
375 return this.error("BasicQuery is not available for this collection.");
376 }
377
378 // (2) get the defaults for each parameter and use that to set
379 // the defaults
380 Map params = new HashMap(nl.getLength()); // field name to value map
381 for(int i = 0; i < nl.getLength(); i++) {
382 Element param = (Element)nl.item(i);
383 String paramName = param.getAttribute(GSXML.NAME_ATT);
384 String def = param.getAttribute(GSXML.DEFAULT_ATT);
385 if(def.equals("")) {
386 // if there's no default, the field must want the query String
387 params.put(paramName, query);
388 } else { // there is a default, use the default for this param
389 params.put(paramName, def);
390 }
391 }
392
393 // (3) Perform the query using defaults and return the response
394 return this.query(collection, queryService, lang, params);
395 }
396
397
398 /* (3) RETRIEVE PROCESS METHODS - Manual, pp.47-49 */
399 /** DocumentContentRetrieve request sent to a collection's
400 * DocumentContentRetrieve service (see manual, p.48)
401 * @see <a href="http://wiki.greenstone.org/wiki/index.php/Greenstone3">The Greenstone 3 Developer's Manual - page 48</a>
402 * @param collection is the name of the Collection whose
403 * DocumentContentRetrieve is requested
404 * @param lang is the language of the display content in the response
405 * @param docNodeIDs is the list of documentNodeIDs for which the
406 * content ought to be retrieved. */
407 public String retrieveDocumentContent(
408 String collection, String lang, String[] docNodeIDs)
409 {
410 // creating <documentNodeList></documentNodeList>
411 Element docNodeList = this.doc.createElement(
412 GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
413
414 // creating subelements: <documentNode nodeID="..." />
415 for(int i = 0; i < docNodeIDs.length; i++) {
416 Element docNode = this.doc.createElement(GSXML.DOC_NODE_ELEM);
417 docNode.setAttribute(GSXML.NODE_ID_ATT, docNodeIDs[i]);
418 docNodeList.appendChild(docNode);
419 }
420
421 Element message = doc.createElement(GSXML.MESSAGE_ELEM);
422 Element request = GSXML.createBasicRequest(
423 doc, GSXML.REQUEST_TYPE_PROCESS,
424 collection+"/DocumentContentRetrieve", lang, "");
425
426 // create an empty <paramlist /> element (as example in manual)
427 Element paramlist = doc.createElement(
428 GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
429
430 request.appendChild(paramlist);
431 request.appendChild(docNodeList);
432 message.appendChild(request);
433
434 // Send it off to the Message Router and return the response
435 return this.processInternal(message);
436 }
437
438 /** DocumentStructureRetrieve request sent to a collection's
439 * DocumentStructureRetrieve service (manual pp.48, 49) to retrieve
440 * the entire document structure.
441 * @see <a href="http://wiki.greenstone.org/wiki/index.php/Greenstone3">The Greenstone 3 Developer's Manual - pages 48, 49</a>
442 * @param collection is the name of the Collection whose
443 * DocumentStructureRetrieve is requested
444 * @param lang is the language of the display content in the response
445 * @param docNodeIDs is the list of documentNodeIDs for which the
446 * entire structure ought to be retrieved. */
447 public String retrieveEntireDocumentStructure(String collection,
448 String lang, String[] docNodeIDs)
449 {
450 return retrieveDocumentStructure(collection, lang, docNodeIDs,
451 new String[] { "entire" }, null);
452 }
453
454 /** DocumentStructureRetrieve request sent to a collection's
455 * DocumentStructureRetrieve service (manual pp.48, 49) to retrieve
456 * the specified part of the document's structure.
457 * @see <a href="http://wiki.greenstone.org/wiki/index.php/Greenstone3">The Greenstone 3 Developer's Manual - pages 48, 49</a>
458 * @param collection is the name of the Collection whose
459 * DocumentStructureRetrieve is requested
460 * @param lang is the language of the display content in the response
461 * @param docNodeIDs is the list of documentNodeIDs for which the
462 * structure ought to be retrieved.
463 * @param structure specifies what structure information needs to
464 * be retrieved. The values can be one or more of ancestors, parent,
465 * siblings, children, descendants (<b>note spelling</b>), entire.
466 * @param info - for specifying extra information to be retrieved.
467 * Possible values for info parameters are numSiblings, siblingPosition,
468 * numChildren */
469 public String retrieveDocumentStructure(String collection, String lang,
470 String[] docNodeIDs, String[] structure, String[] info)
471 {
472 // creating subelements: <documentNode nodeID="..." />
473 Element docNodeList = this.doc.createElement(
474 GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
475 for(int i = 0; i < docNodeIDs.length; i++) {
476 Element docNode = this.doc.createElement(GSXML.DOC_NODE_ELEM);
477 docNode.setAttribute(GSXML.NODE_ID_ATT, docNodeIDs[i]);
478 docNodeList.appendChild(docNode);
479 }
480
481 Element message = doc.createElement(GSXML.MESSAGE_ELEM);
482 Element request = GSXML.createBasicRequest(
483 doc, GSXML.REQUEST_TYPE_PROCESS,
484 collection+"/DocumentStructureRetrieve", lang, "");
485
486 // Create the <paramlist></paramlist> element of param elements,
487 // if any; and only if values are legal (that is, if they occur in
488 // static Strings docStructureOptions and docStructureInfo):
489 // <param name="structure" value = "structure[i]">
490 // <param name="info" value = "info[i]">
491 Element paramList = doc.createElement(
492 GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
493
494 if(structure != null) {
495 for(int i = 0; i < structure.length; i++) {
496 if(docStructureOptions.indexOf(structure[i]) != -1) {
497 paramList.appendChild(GSXML.createParameter(
498 this.doc, "structure", structure[i]));
499 }
500 }
501 }
502 if(info != null) {
503 for(int i = 0; i < info.length; i++) {
504 if(docStructureInfo.indexOf(info[i]) != -1) {
505 paramList.appendChild(GSXML.createParameter(
506 this.doc, "info", info[i]));
507 }
508 }
509 }
510
511 // paramList is allowed to be empty and may indeed be empty:
512 request.appendChild(paramList);
513 request.appendChild(docNodeList);
514 message.appendChild(request);
515
516 // Send it off to the Message Router and return the response
517 return this.processInternal(message);
518 }
519
520 /* Retrieve for Doc Metadata: explained in the manual on page 47 */
521 /** DocumentMetadataRetrieve request sent to a collection's
522 * DocumentMetadataRetrieve service to retrieve all of a document's metadata.
523 * @see <a href="http://wiki.greenstone.org/wiki/index.php/Greenstone3">The Greenstone 3 Developer's Manual - page 47</a>
524 * @param collection is the name of the Collection whose
525 * DocumentMetadataRetrieve is requested
526 * @param lang is the language of the display content in the response
527 * @param docNodeIDs is the list of documentNodeIDs for which the
528 * structure ought to be retrieved.
529 */
530 public String retrieveAllDocumentMetadata(String collection, String lang,
531 String[] docNodeIDs)
532 {
533 // See bottom of manual p.44 for the fact that "all" is used
534 // as the metaName value when retrieving all metadata for a doc
535 return retrieveDocumentMetadata(collection, lang, docNodeIDs,
536 new String[]{ "all" });
537 }
538
539 /** DocumentMetadataRetrieve service to retrieve some specific
540 * metadata values of a document. (Manual on page 47.)
541 * @see <a href="http://wiki.greenstone.org/wiki/index.php/Greenstone3">The Greenstone 3 Developer's Manual - page 47</a>
542 * @param collection is the name of the Collection whose
543 * DocumentContentRetrieve is requested
544 * @param lang is the language of the display content in the response
545 * @param docNodeIDs is the list of documentNodeIDs for which the
546 * structure ought to be retrieved.
547 * @param metaNames is a list of metadata names which are requested
548 * to be fetched for the specified documents */
549 public String retrieveDocumentMetadata(String collection, String lang,
550 String[] docNodeIDs, String[] metaNames)
551 {
552 return metadataRetrieve(collection+"/DocumentMetadataRetrieve",
553 lang, docNodeIDs, metaNames, GSXML.DOC_NODE_ELEM);
554 }
555
556 /** Retrieve all classification Metadata for browsing (sent to the
557 * ClassifierBrowseMetadataRetrieve service).
558 * @see <a href="http://wiki.greenstone.org/wiki/index.php/Greenstone3">The Greenstone 3 Developer's Manual - pages 47, 48</a>
559 * @param collection is the name of the Collection whose
560 * ClassifierBrowseMetadataRetrieve service is called
561 * @param categoryName - name of the browsing category, usually
562 * ClassifierBrowse. (If left as "", then it defaults to ClassifierBrowse)
563 * @param lang is the language of the display content in the response
564 * @param nodeIDs is the list of document or classifier NodeIDs
565 * for which the metadata ought to be retrieved.*/
566 public String retrieveAllBrowseMetadata(String collection,
567 String categoryName, String lang, String[] nodeIDs)
568 {
569 if(categoryName.equals(""))
570 categoryName = "ClassifierBrowse";
571 // See bottom of manual p.47 for the fact that "all" is used as
572 // the metaName value when retrieving all metadata for a classifier
573 return metadataRetrieve(collection+"/"+categoryName+"MetadataRetrieve",
574 lang, nodeIDs, new String[]{ "all" }, GSXML.CLASS_NODE_ELEM);
575 }
576
577 /** ClassifierBrowseMetadataRetrieve service to retrieve some specific
578 * metadata values of a document.
579 * @see <a href="http://wiki.greenstone.org/wiki/index.php/Greenstone3">The Greenstone 3 Developer's Manual - pages 47, 48</a>
580 * @param collection is the name of the Collection whose
581 * ClassifierBrowseMetadataRetrieve service is called
582 * @param categoryName - name of the browsing category, usually
583 * ClassifierBrowse. (If left as "", then it defaults to ClassifierBrowse)
584 * @param lang is the language of the display content in the response
585 * @param nodeIDs is the list of document or classifier NodeIDs
586 * for which the metadata ought to be retrieved.
587 * @param metaNames is a list of metadata names which are requested
588 * to be fetched for the specified documents or classifiers */
589 public String retrieveBrowseMetadata(String collection, String categoryName,
590 String lang, String[] nodeIDs, String[] metaNames)
591 {
592 if(categoryName.equals(""))
593 categoryName = "ClassifierBrowse";
594 return metadataRetrieve(collection+"/"+categoryName+"MetadataRetrieve",
595 lang, nodeIDs, metaNames, GSXML.CLASS_NODE_ELEM);
596 }
597
598 /** Performs a metadata retrieve for documents and (browse) classification
599 * hierarchies. Sends a Document- or ClassifierBrowse- MetadataRetrieve message
600 * to the Document- or ClassifierBrowse- MetadataRetrieve service.
601 * @param to - the Document- or ClassifierBrowse- MetadataRetrieve service to
602 * send this metadata retrieve message to.
603 * @param lang - the language of the display content in the response
604 * @param nodeIDs - the list of (document or classifier) nodeIDs for which
605 * to retrieve the metadata for
606 * @param metaNames - a list specifiying the names of the metadata items
607 * to be retrieved for each nodeID. E.g. "Title", but a list is allowed.
608 * @param NODE_ELEM - either of GSXML's names for the &lt;documentNode&gt; or
609 * &lt;classifierNode&gt; elements.
610 */
611 protected String metadataRetrieve(String to, String lang,
612 String[] nodeIDs, String[] metaNames, final String NODE_ELEM)
613 {
614 // create the <paramlist></paramlist> element of param elements:
615 // <param name="metadata" value = "metaName[i]">
616 Element metadataParamList = this.doc.createElement(
617 GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
618 for(int i = 0; i < metaNames.length; i++) {
619 metadataParamList.appendChild(GSXML.createParameter(
620 this.doc, GSXML.METADATA_ELEM, metaNames[i]));
621 }
622
623 // creating subelements: <documentNode nodeID="..." />
624 // or <classifierNode nodeID="..." />
625 Element nodeList = this.doc.createElement(
626 NODE_ELEM+GSXML.LIST_MODIFIER);
627 for(int i = 0; i < nodeIDs.length; i++) {
628 Element docNode = this.doc.createElement(NODE_ELEM);
629 docNode.setAttribute(GSXML.NODE_ID_ATT, nodeIDs[i]);
630 nodeList.appendChild(docNode);
631 }
632
633 Element message = doc.createElement(GSXML.MESSAGE_ELEM);
634 Element request = GSXML.createBasicRequest(doc,
635 GSXML.REQUEST_TYPE_PROCESS, to, lang, "");
636
637 request.appendChild(metadataParamList);
638 request.appendChild(nodeList);
639 message.appendChild(request);
640
641 // Send it off to the Message Router and return the response
642 return this.processInternal(message);
643 }
644
645 /* (4) Classifier BROWSE PROCESS METHODS - p.46 */
646 /** To send a browse request for all the descendants of a classifier node.
647 * Useful for getting the entire structure of a top-level &lt;classificationNode&gt;
648 * @see <a href="http://wiki.greenstone.org/wiki/index.php/Greenstone3">The Greenstone 3 Developer's Manual - page 46</a>
649 * @param collection is the name of the Collection whose browse Classifier
650 * Browse Service is called
651 * @param browseService is the name of the (Classifier) Browse Service (of
652 * the given collection) to which this request message is sent.
653 * @param lang is the language of the display content in the response
654 * @param classifierNodeIDs is an array of classifierNodeIDs for which the
655 * structures ought to be retrieved.
656 */
657 public String browseDescendants(String collection, String browseService,
658 String lang, String[] classifierNodeIDs)
659 {
660 // We are at the top level, we want all the descendants:
661 // <param name="structure" value = "descendants">
662 // <classifierNodeList><classifier nodeID="CLx" /></classifierNodeList>
663 return browse(collection, browseService, lang,
664 classifierNodeIDs,
665 new String[] {"descendants"}); // note the spelling
666 }
667
668 /** To send a browse request for specific parts of a classifier node
669 * (children, ancestors, descendants). Useful for getting specific parts
670 * of the structure of a top-level &lt;classificationNode&gt;.
671 * @see <a href="http://wiki.greenstone.org/wiki/index.php/Greenstone3">The Greenstone 3 Developer's Manual - page 46</a>
672 * @param collection is the name of the Collection whose browse Classifier
673 * Browse Service is called
674 * @param browseService is the name of the (Classifier) Browse Service (of
675 * the given collection) to which this request message is sent.
676 * @param lang is the language of the display content in the response
677 * @param classifierNodeIDs is the list of classifierNodeIDs for which the
678 * structure ought to be retrieved.
679 * @param structureParams the list of parameters indicating what structure
680 * information is requested. Accepted values are ancestors, parent, siblings,
681 * children, descendants.
682 */
683 public String browse(String collection, String browseService, String lang,
684 String[] classifierNodeIDs, String[] structureParams)
685 {
686 if(browseService.equals(""))
687 browseService = "ClassifierBrowse";
688
689 // Create message element: <message></message>
690 Element message = this.doc.createElement(GSXML.MESSAGE_ELEM);
691 // <message><request lang="en" to="" type="process" uid="" /></message>
692 Element request = GSXML.createBasicRequest(this.doc,
693 GSXML.REQUEST_TYPE_PROCESS, collection+"/"+browseService, lang, "");
694
695 // <param name="structure" value = "structureParams[i]">
696 Element paramList = this.doc.createElement(
697 GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
698 for(int i = 0; i < structureParams.length; i++) {
699 // check it is a valid structure parameter
700 if(browseStructureOptions.indexOf(structureParams[i]) != -1) {
701 paramList.appendChild(GSXML.createParameter(
702 this.doc, "structure", structureParams[i]));
703 }
704 }
705
706 // <classifierNodeList><classifier nodeID="CLx" />
707 // <classifier nodeID="CLy" /></classifierNodeList>
708 // where CLx and CLy are given in the parameter classifierNodeIDs
709 Element classifierNodeList = this.doc.createElement(
710 GSXML.CLASS_NODE_ELEM+GSXML.LIST_MODIFIER);
711 for(int i = 0; i < classifierNodeIDs.length; i++) {
712 Element classifier = this.doc.createElement(GSXML.CLASS_NODE_ELEM);
713 classifier.setAttribute(GSXML.NODE_ID_ATT, classifierNodeIDs[i]);
714 classifierNodeList.appendChild(classifier);
715 }
716
717 // now finish constructing the request message:
718 request.appendChild(paramList);
719 request.appendChild(classifierNodeList);
720 message.appendChild(request);
721
722 // Send it off to the Message Router and return the response
723 return this.processInternal(message);
724 }
725
726 /** Called by most other methods in order to send the constructed message
727 * to the Greenstone's MessageRouter, intercept the response and return it.
728 * @param message is the XML message Element to send to GS3's MessageRouter.
729 * @return the XML response in String format. */
730 protected String processInternal(Element message) {
731 if(LOG.isDebugEnabled()) { // or LOG.isEnabledFor(Level.DEBUG).
732 // Testing for this improves efficiency
733 LOG.debug(this.converter.getPrettyString(message));
734 }
735
736 // Let the messagerouter process the request message and get the response
737 Element response = mr.process(message);
738 // won't be null, MR always returns some response
739
740 // Return it as a String formatted for display
741 String responseMsg = this.converter.getPrettyString(response);
742 // this.converter.getString(response);
743
744 // In order to avoid "Content is not allowed in prolog" exception on the
745 // web services' client end (problem encountered in GS mailing list), need
746 // to make sure no characters (incl spaces) preceed the XML sent back
747 // from here. It may also require the <?xml?> tag at the very start.
748 if(responseMsg.charAt(0) == ' ') {
749 responseMsg = responseMsg.trim();
750 }
751
752 return "<?xml version=\"1.0\" encoding=\"utf-8\"?>"+responseMsg;
753 }
754
755 /** Creates a String response message to represent an XML error response
756 * message using the error specified in the message parameter. A String is
757 * created because this method ensures that a response message is reliably
758 * constructed (no exceptions are thrown) that can be sent to clients.
759 * @param errorMessage - the errormessage to be conveyed
760 * @return an XML response message containing an GS3 error element. */
761 protected String error(String errorMessage) {
762 StringBuffer buf = new StringBuffer("<" + GSXML.MESSAGE_ELEM + ">");
763 buf.append("<" + GSXML.RESPONSE_ELEM + " "
764 + GSXML.FROM_ATT + "=\"" + "Greenstone 3 Web Services\"" + ">");
765 buf.append("<" + GSXML.ERROR_ELEM + " "
766 + GSXML.ERROR_TYPE_ATT + "=\""+ GSXML.ERROR_TYPE_OTHER + "\"" + ">");
767 buf.append(errorMessage+"\n");
768 buf.append("</" + GSXML.ERROR_ELEM + ">");
769 buf.append("</" + GSXML.RESPONSE_ELEM + ">");
770 buf.append("</" + GSXML.MESSAGE_ELEM + ">");
771 return buf.toString();
772 }
773
774 /*
775 Look in file QBRWebServicesHelp.properties
776 - Have a properties file that maps methodname to help string specific
777 to the method.
778 - Read it all in statically at the start of the class, into a Properties Map.
779 - When this method is called, display the usage: "help methodname"
780 and list all the available methods by going over the keys in the Map.
781 - When the helpWithMethod(String methodname) method is called, return the
782 value of the Map for the methodname key. This value would be the help
783 description for that method.
784 */
785 /** @return a help string for listing all the web service methods. */
786 public static String help() {
787 if(!helpErrormessage.equals("")) {
788 return helpErrormessage;
789 }
790
791 StringBuffer helpString = new StringBuffer(
792 "USAGE: helpWithMethod(String <method name>)\n");
793 helpString.append(
794 "\nNearly all the web service operations return a String\n");
795 helpString.append(
796 "representing a Greenstone 3 XML response message.\n");
797 helpString.append("\nA list of all the method names: \n");
798
799 Enumeration props = properties.keys();
800 while(props.hasMoreElements()){
801 String methodName = (String)props.nextElement();
802 helpString.append("\t");
803 helpString.append(methodName);
804 helpString.append("\n");
805 }
806
807 return helpString.toString();
808 }
809
810 /** @param methodname is the name of the method to be described.
811 * @return a help string for the given method, explaining what the method
812 * does, what parameters it expects and their types and what it returns.
813 */
814 public static String helpWithMethod(String methodname) {
815 if(!helpErrormessage.equals("")) {
816 return helpErrormessage;
817 }
818 // else we can get the method's description from the properties
819 // map loaded from the QBRWebServicesHelp.properties file:
820 String helpString = properties.getProperty(methodname,
821 "No description for " + methodname); // if the method does not exist
822
823 return helpString;
824 }
825} // end web service class
Note: See TracBrowser for help on using the repository browser.