source: other-projects/trunk/gs3-webservices-democlient/src/GS3DemoClient/org/greenstone/gs3services/QBRSOAPServer.java@ 16755

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

Since greenstone3 core ModuleInterface.process() now takes a Node and RETURNS a Node, need to use the XMLConverter.nodeToElement() to get back the Element version of the response.

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