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

Last change on this file since 26123 was 26123, checked in by ak19, 8 years ago

Diego discovered that the QBRSOAPServer no longer got deployed. 1. The resources/java/QBRSOAPServer.java.in class failed to compile on attempting to deploy the web service owing to the GSXML.createBasicRequest() method's signature having been changed to take a UserContext parameter in place of lang and uid. 2. Updated UserContext class with an additional constructor that now takes both lang and uid. This gets called by resources/java/QBRSOAPServer.java.in whenever it needs to pass in a UserContext object to GSXML.createBasicRequest().

File size: 36.3 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;
41import org.w3c.dom.Node;
42
43import org.greenstone.util.GlobalProperties;
44import org.greenstone.gsdl3.core.MessageRouter;
45import org.greenstone.gsdl3.util.GSFile;
46import org.greenstone.gsdl3.util.GSXML;
47import org.greenstone.gsdl3.util.UserContext;
48import org.greenstone.gsdl3.util.XMLConverter;
49
50import org.apache.log4j.Logger; // Import log4j classes
51
52/*
53 * Add to $GSDLHOME/web/WEB-INF/server-config.wsdd:
54 * <service name="GS3WebServices" provider="java:RPC">
55 * <parameter name="allowedMethods" value="*"/>
56 * <parameter name="className" value="org.greenstone.gs3services.GS3WebServices"/>
57 * </service>
58*/
59
60/** Class that provides the basic Query, Browse and Retrieve (QBR) web service
61 * operations for Greenstone 3.
62 * It contains a MessageRouter that carries out all the tasks by calling the
63 * appropriate Greenstone functionality for each request message passed to it,
64 * and returning a response message.
65 *
66 * All response messages are returned from the MessageRouter to clients invoking
67 * the web services. All return values are strings that represent XML messages.
68 *
69 * Method help() reads from the file QBRWebServicesHelp.properties to list the web
70 * service operations available. Method helpWithMethod(String methodName)
71 * reads from the same file to display a description of the requested operation.
72 * (These method descriptions are mostly the same as those in the Javadoc
73 * comments.)
74 *
75 * NOTE: The folder containing this web service class' properties helpFile
76 * should be on the classpath. (QBRWebServicesHelp.properties)
77 * @author ak19
78*/
79public class QBRSOAPServer@sitename@ {
80 /** site_name the MessageRouter works with, here set to "localsite" */
81 protected String site_name = "@sitename@";
82
83 /** Message Router object to pass requests messages to and which
84 * will process them.*/
85 protected MessageRouter mr = null;
86
87 /** Container Document to create XML Nodes */
88 protected Document doc=null;
89 /** A converter class to parse XML and create Docs */
90 protected XMLConverter converter=null;
91
92 /** The Logger for this class */
93 private static Logger LOG = Logger.getLogger(QBRSOAPServer@sitename@.class);
94
95 /** Error message loading helpFile. Remains at "" if everything is fine */
96 protected static String helpErrormessage = "";
97 /** Properties map with mappings from methodname to help
98 * description string. */
99 protected static Properties properties;
100 /** The help properties file describing the web service operations */
101 protected static String helpFile = "QBRWebServicesHelp.properties";
102
103 // static code block to initialise the help Properties from the helpFile
104 static {
105 properties = new Properties();
106 // load the properties file from a location with respect to the
107 // the Web Service .class file
108 InputStream input = null;
109 try {
110 // load the properties file from a location with respect to the
111 // the Web Service .class file
112 input
113 = QBRSOAPServer@sitename@.class.getClassLoader().getResourceAsStream(
114 helpFile);
115 if(input == null) {
116 helpErrormessage = "Cannot find file " + helpFile + " to load.";
117 LOG.warn(helpErrormessage);
118 } else {
119 properties.load(input);
120 input.close();
121 }
122 } catch(Exception e) {
123 helpErrormessage = "Exception loading properties from help file "
124 + helpFile + "\n" + e.getMessage();
125 LOG.warn("Exception loading properties from help file "
126 + helpFile + "\n" + e.getMessage());
127 }
128 }
129
130
131 /* Describe subset options for the various Greenstone3 modules */
132 protected static final String mrSubsetOptions = // messageRouter
133 "collectionList serviceClusterList serviceList siteList";
134 protected static final String csSubsetOptions = // collections and serviceClusters
135 "metadataList serviceList displayItemList";
136 protected static final String serviceSubsetOptions = // services
137 "paramList displayItemList";
138 protected static final String structureOptions =
139 "entire ancestors parent siblings children descendants"; // note the spelling
140 protected static final String structureInfoOptions =
141 "numSiblings siblingPosition numChildren";
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, new UserContext(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, new UserContext(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", new UserContext(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", new UserContext(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 structureOptions and structureInfoOptions):
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(structureOptions.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(structureInfoOptions.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, new UserContext(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"}, new String[] {""}); // 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 * @param infoParams - structural info is requested. Can be numSiblings,
683 * siblingPosition, numChildren
684 */
685 public String browse(String collection, String browseService, String lang,
686 String[] classifierNodeIDs, String[] structureParams, String[] infoParams)
687 {
688 if(browseService.equals(""))
689 browseService = "ClassifierBrowse";
690
691 // Create message element: <message></message>
692 Element message = this.doc.createElement(GSXML.MESSAGE_ELEM);
693 // <message><request lang="en" to="" type="process" uid="" /></message>
694 Element request = GSXML.createBasicRequest(this.doc,
695 GSXML.REQUEST_TYPE_PROCESS, collection+"/"+browseService, new UserContext(lang, ""));
696
697 // <param name="structure" value = "structureParams[i]">
698 Element paramList = this.doc.createElement(
699 GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
700 for(int i = 0; i < structureParams.length; i++) {
701 // check it is a valid structure parameter
702 if(structureOptions.indexOf(structureParams[i]) != -1) {
703 paramList.appendChild(GSXML.createParameter(
704 this.doc, "structure", structureParams[i]));
705 }
706 }
707
708 if(infoParams != null && !infoParams[0].equals("")) {
709 for(int i = 0; i < infoParams.length; i++) {
710 if(structureInfoOptions.indexOf(infoParams[i]) != -1) {
711 paramList.appendChild(GSXML.createParameter(
712 this.doc, "info", infoParams[i]));
713 }
714 }
715 }
716
717 // <classifierNodeList><classifier nodeID="CLx" />
718 // <classifier nodeID="CLy" /></classifierNodeList>
719 // where CLx and CLy are given in the parameter classifierNodeIDs
720 Element classifierNodeList = this.doc.createElement(
721 GSXML.CLASS_NODE_ELEM+GSXML.LIST_MODIFIER);
722 for(int i = 0; i < classifierNodeIDs.length; i++) {
723 Element classifier = this.doc.createElement(GSXML.CLASS_NODE_ELEM);
724 classifier.setAttribute(GSXML.NODE_ID_ATT, classifierNodeIDs[i]);
725 classifierNodeList.appendChild(classifier);
726 }
727
728 // now finish constructing the request message:
729 request.appendChild(paramList);
730 request.appendChild(classifierNodeList);
731 message.appendChild(request);
732
733 // Send it off to the Message Router and return the response
734 return this.processInternal(message);
735 }
736
737 /** Called by most other methods in order to send the constructed message
738 * to the Greenstone's MessageRouter, intercept the response and return it.
739 * @param message is the XML message Element to send to GS3's MessageRouter.
740 * @return the XML response in String format. */
741 protected String processInternal(Element message) {
742 if(LOG.isDebugEnabled()) { // or LOG.isEnabledFor(Level.DEBUG).
743 // Testing for this improves efficiency
744 LOG.debug(this.converter.getPrettyString(message));
745 }
746
747 // Let the messagerouter process the request message and get the response
748 Element response = XMLConverter.nodeToElement(mr.process(message));
749 // won't be null except when Node returned is not an element
750 // otherwise, MR always returns some response
751
752 // Return it as a String formatted for display
753 String responseMsg = this.converter.getPrettyString(response);
754 // this.converter.getString(response);
755
756 // In order to avoid "Content is not allowed in prolog" exception on the
757 // web services' client end (problem encountered in GS mailing list), need
758 // to make sure no characters (incl spaces) preceed the XML sent back
759 // from here. It may also require the <?xml?> tag at the very start.
760 if(responseMsg.charAt(0) == ' ') {
761 responseMsg = responseMsg.trim();
762 }
763
764 return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"+responseMsg;
765 }
766
767 /** Creates a String response message to represent an XML error response
768 * message using the error specified in the message parameter. A String is
769 * created because this method ensures that a response message is reliably
770 * constructed (no exceptions are thrown) that can be sent to clients.
771 * @param errorMessage - the errormessage to be conveyed
772 * @return an XML response message containing an GS3 error element. */
773 protected String error(String errorMessage) {
774 StringBuffer buf = new StringBuffer("<" + GSXML.MESSAGE_ELEM + ">");
775 buf.append("<" + GSXML.RESPONSE_ELEM + " "
776 + GSXML.FROM_ATT + "=\"" + "Greenstone 3 Web Services\"" + ">");
777 buf.append("<" + GSXML.ERROR_ELEM + " "
778 + GSXML.ERROR_TYPE_ATT + "=\""+ GSXML.ERROR_TYPE_OTHER + "\"" + ">");
779 buf.append(errorMessage+"\n");
780 buf.append("</" + GSXML.ERROR_ELEM + ">");
781 buf.append("</" + GSXML.RESPONSE_ELEM + ">");
782 buf.append("</" + GSXML.MESSAGE_ELEM + ">");
783 return buf.toString();
784 }
785
786 /*
787 Look in file QBRWebServicesHelp.properties
788 - Have a properties file that maps methodname to help string specific
789 to the method.
790 - Read it all in statically at the start of the class, into a Properties Map.
791 - When this method is called, display the usage: "help methodname"
792 and list all the available methods by going over the keys in the Map.
793 - When the helpWithMethod(String methodname) method is called, return the
794 value of the Map for the methodname key. This value would be the help
795 description for that method.
796 */
797 /** @return a help string for listing all the web service methods. */
798 public static String help() {
799 if(!helpErrormessage.equals("")) {
800 return helpErrormessage;
801 }
802
803 StringBuffer helpString = new StringBuffer(
804 "USAGE: helpWithMethod(String <method name>)\n");
805 helpString.append(
806 "\nNearly all the web service operations return a String\n");
807 helpString.append(
808 "representing a Greenstone 3 XML response message.\n");
809 helpString.append("\nA list of all the method names: \n");
810
811 Enumeration props = properties.keys();
812 while(props.hasMoreElements()){
813 String methodName = (String)props.nextElement();
814 helpString.append("\t");
815 helpString.append(methodName);
816 helpString.append("\n");
817 }
818
819 return helpString.toString();
820 }
821
822 /** @param methodname is the name of the method to be described.
823 * @return a help string for the given method, explaining what the method
824 * does, what parameters it expects and their types and what it returns.
825 */
826 public static String helpWithMethod(String methodname) {
827 if(!helpErrormessage.equals("")) {
828 return helpErrormessage;
829 }
830 // else we can get the method's description from the properties
831 // map loaded from the QBRWebServicesHelp.properties file:
832 String helpString = properties.getProperty(methodname,
833 "No description for " + methodname); // if the method does not exist
834
835 return helpString;
836 }
837} // end web service class
Note: See TracBrowser for help on using the repository browser.