source: main/trunk/greenstone3/resources/java/QBRSOAPServer.java.in@ 22295

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