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

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

Greenstone3 web services demo-clientadded to GS3's other-projects

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