source: other-projects/trunk/gs3-webservices-democlient/docs/HowToFiles/6WritingAWebServiceClient.html@ 15338

Last change on this file since 15338 was 15338, checked in by ak19, 13 years ago

Documentation on how to run the demo-client, how to write and deploy web services and how to write web service clients

File size: 20.0 KB
Line 
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2
3<html>
4<head>
5<title>How to write a simple client for Greenstone 3 web services</title>
6</head>
7<body>
8<a href="index.html">Back to index page</a>
9
10<h1>How to write a simple client for Greenstone 3 web services</h1>
11We'll be going through an example of how to write a simple client for Greenstone 3's Query, Browse and Retrieval web services provided by QBRSOAPServer.
12
13<p>In this document,
14<ul>
15<li>$GSDLHOME is the full path to your greenstone 3 directory.</li>
16</ul>
17</p>
18
19<h2>Sections</h2>
20<ul>
21<li><a href="#A">A General information on writing a client for Greenstone 3 web services</a></li>
22<li><a href="#B">B An actual code example</a></li>
23</ul>
24
25<h2><a name="A">A General information on writing a client for Greenstone 3 web services</a></h2>
26<ol>
27<li>First we need Greenstone 3 to deploy the web services in order for our client to have access to its operations.<br />
28Go to $GSDLHOME and type in an X-term:
29<pre>ant soap-deploy-site</pre>
30
31It will ask you for the
32<ul>
33<li>The greenstone Site you wish to deploy the services for.</li>
34<li>The name of the web services you wish to deploy. There are two available for Greenstone 3 so far (the default fundamental SOAPServer and the QBRSOAPServer that provides basic query, browse and retrieve functions for GS3). Choose from one of these.</li>
35<li>Give the web service a name.</li>
36</ul>
37
38If you go to the page
39<pre>http://HOST:PORT/greenstone3/services</pre>
40you will see links to various wsdl files. The one for the QBRSOAPServer we just deployed for "localsite" is the one our example program will be using to communicate with Greenstone 3's QBRSOAPServer functionality. The localsite web service has several operation query, browse and retrieve operations as well as describe operations which will describe the details of these Greenstone 3 services.
41</li>
42<li>Now you can invoke the localsite process method by writing a client.
43The basics of invoking a web service operation in Java when using Apache Axis, is to
44<ol style="list-style-type:lower-alpha">
45<li>import Axis' Call and Service objects:
46<pre>import org.apache.axis.client.Call;
47import org.apache.axis.client.Service;
48import javax.xml.namespace.QName;
49import javax.xml.rpc.ServiceException;
50</pre>
51</li>
52<li>Then write a constructor that will create the Service object using the url for the web service's wsdl file and the (namespace-qualified) name of the web service.
53<pre>try {
54 service = new Service(wsdlURLName, new QName(namespace, serviceName));
55 } catch(ServiceException e) {
56 System.err.println("Unable to connect to web services.\nExiting...");
57 throw(e);
58 }
59</pre>
60</li>
61<li>In order to invoke a web service operation, use that Service object to create a Call object for the operation. You need the (namespace-qualified) portName of the web service, which can be found in the wsdl file. Similarly, you need the name of the operation, also found in the wsdl file:
62<pre>Call call = (Call)this.service.createCall(
63 new QName(namespace, portName),
64 new QName(namespace, OPERATION_NAME)
65 );
66<pre>
67</li>
68<li>Finally, invoke the operation using that call object by
69<ul>
70<li>putting the operation's parameters in the right order into an array of Objects and passing that to Call's invoke() method.</li>
71<li>by casting the return value to the expected return type.
72<pre>MyReturnType response = (MyReturnType) call.invoke(new Object[]{
73 paramObj1, paramObj2, ..., paramObjN});
74</pre>
75</li>
76</ul>
77</li>
78</ol>
79
80
81<li>To get a Greenstone client (or web service) to compile or run, you may need to include some jar files in the compile/execution classpath. Look in
82<ul>
83<li>$GSDLHOME/web/WEB-INF/lib/</li>
84<li>$GSDLHOME/lib/</li>
85</ul>
86You may also need $GSDLHOME/web/applet/xml-apis.jar<br />
87If you ever need to use servlets, add in $GSDLHOME/packages/tomcat/common/lib/servlet-api.jar
88</li>
89</ol>
90
91<h2><a name="B">B An actual code example</a></h2>
92We're going to write a simple client for the QBRSOAPServer.
93
94<ol>
95<li>Deploy the QBRSOAPServer in order to have our client access it.
96Go to $GSDLHOME and type in an X-term:
97<pre>ant soap-deploy-site</pre>
98For our example:
99<ul>
100<li>type "localsite", to deploy the services locally.</li>
101<li>type "QBRSOAPServer", to deploy the Query, Browse and Retrieve services.</li>
102<li>press Enter to accept the default web service name of "QBRSOAPServerlocalsite".</li>
103</ul>
104</li>
105<li>The following GreenstoneConnection class is a simple client for QBRSOAPServer web service that merely uses its query and describeCollectionService web service operations in order to execute a FieldQuery on the gs2mgppdemo collection:
106<pre>
107import org.apache.axis.client.Call;
108import org.apache.axis.client.Service;
109import javax.xml.namespace.QName;
110import javax.xml.rpc.ServiceException;
111
112import java.util.Map;
113import java.util.HashMap;
114
115/** The class that connects to Greenstone 3's QBRSoapServerLocalsite web service
116 * For this to work, you need to have the QBRSOAPServer web services deployed for
117 * localsite. Once deployed, the wsdl file of QBRSOAPServer describing its web
118 * services can be found off the page http://HOST:PORT/greenstone3/services/
119*/
120public class GreenstoneConnection {
121 static final String HOST = "localhost";
122 static final String PORT = "9090";
123
124 // Name of web service methods we are going to invoke.
125 // We can get these from wsdl file.
126 static final String QUERY_METHOD = "query";
127 static final String DESCRIBE_COLLECTION_SERVICE_METHOD
128 = "describeCollectionService";
129
130
131 /** Axis Service object for connecting to invoking Greenstone 3's WebServices
132 * using its WSDL file */
133 protected Service service;
134
135 // Inspect the wsdl file to find at the very bottom, the service name, port name and soap address
136 //endpoint locations:
137 // &lt;wsdl:service name="QBRSOAPServerlocalsiteService"&gt;
138 // &lt;wsdl:port binding="impl:QBRSOAPServerlocalsiteSoapBinding" name="QBRSOAPServerlocalsite"&gt;
139 // &lt;wsdlsoap:address location="http://HOST:PORT/greenstone3/services/QBRSOAPServerlocalsite"/&gt;
140 // &lt;/wsdl:port&gt;
141 // &lt;/wsdl:service&gt;
142 // Using the above, we can create the axis Service and Call
143 // objects. At present, I am hard coding the values here as
144 // an example but you would usually discover the names of the
145 // xml tags programmatically, by either letting the Service
146 // object parse the wsdl for you or by parsing it yourself.
147 // Read-only instance variables
148 final String wsdlURLName;
149 final String namespace = "http://"+HOST+":"+PORT+"/greenstone3/services/QBRSOAPServerlocalsite";
150 final String serviceName = "QBRSOAPServerlocalsiteService";
151 final String portName = "QBRSOAPServerlocalsite";
152
153
154 // Constructor, takes a String representing the URL of the web service's
155 // wsdl file. This can be found of the Greenstone 3 services page
156 // http://HOST:PORT/greenstone3/services/
157 public GreenstoneConnection(String wsdlURLName)
158 throws Exception
159 {
160 this.wsdlURLName = wsdlURLName;
161 // create the service object needed to invoke the web service later on
162 try {
163 service = new Service(wsdlURLName, new QName(namespace, serviceName));
164 } catch(ServiceException e) {
165 System.err.println("Unable to connect to web services.\nExiting...");
166 throw(e);
167 }
168 }
169
170 /** See http://ws.apache.org/axis/java/apiDocs/org/apache/axis/client/Service.html#createCall(javax.xml.namespace.QName,%20javax.xml.namespace.QName)
171 * public Call createCall(QName portName,QName operationName)throws ServiceException
172 * "Creates a new Call object - will prefill as much info from the
173 * WSDL as it can. Right now it's target URL, SOAPAction, Parameter types,
174 * and return type of the Web Service."
175 * This query method invokes the query web service operation.
176 * One way you can find the parameters required by the query method
177 * is by inspecting the wsdl file.
178 * &lt;wsdl:message name="queryRequest"&gt;
179 * &lt;wsdl:part name="collection" type="xsd:string"/&gt;
180 * &lt;wsdl:part name="service" type="xsd:string"/&gt;
181 * &lt;wsdl:part name="lang" type="xsd:string"/&gt;
182 * &lt;wsdl:part name="nameToValsMap" type="apachesoap:Map"/&gt;
183 * &lt;/wsdl:message&gt;
184 *
185 * From the wsdl file, we also know that the return type is String:
186 * &lt;wsdl:message name="queryResponse"&gt;
187 * &lt;wsdl:part name="queryReturn" type="xsd:string"/&gt;
188 * &lt;/wsdl:message&gt;
189 */
190 public String query(String collection, String service, String lang,
191 Map nameToValsMap)
192 {
193 try {
194 // try invoking the process() method
195 Call call = (Call)this.service.createCall(
196 new QName(namespace, portName),
197 new QName(namespace, QUERY_METHOD)
198 );
199
200 // Now call the web service and pass it all the parameters as part
201 // of an array of Objects.
202 // Knowing that the return type is String, we cast the Object
203 // returned into String prior to returning it.
204 String response = (String) call.invoke(new Object[]{
205 collection, service, lang, nameToValsMap});
206
207 // later cast the return type to the correct format and return it:
208 return response;
209
210 // Note that for more complicated return types (like certain collection
211 // types or complex types), you may have to find out what the class
212 // of the return value is. For instance, when a group of elements are
213 // returned, the return type may be Array or ArrayList or something similar.
214 // In such cases, you need to find the type of each element in the array.
215 // This is necessary in order to cast the return value into the correct type.
216 // System.err.println("Return type is: " + response.getClass().getName());
217 // later cast the return type to the correct format and return it:
218 // return (Element[])response;
219 } catch(Exception e) {
220 System.err.println("ERROR trying to invoke web service" + e);
221 }
222 return "";
223 }
224
225 /** Sending a describe request to the FieldQuery service in order to
226 * find out what parameters a Greenstone 3 FieldQuery operation requires.
227 * This method invokes the web service operation describeCollectionService()
228 * for the FieldQuery service of gs2mgppdemo. */
229 public String describeFieldQueryService(String collection, String lang) {
230 // One of the query services available for collections gs2mgppdemo
231 // and gs2mgdemo
232 final String FIELD_QUERY_SERVICE = "FieldQuery";
233 try {
234 // try invoking the process() method
235 Call call = (Call)this.service.createCall(
236 new QName(namespace, portName),
237 new QName(namespace, DESCRIBE_COLLECTION_SERVICE_METHOD)
238 );
239
240 // We know that the describeService returns a String, so we
241 // cast the return value appropriately.
242 // From the wsdl, the describeCollectionService web service
243 // operation takes 4 String parameters: collection, service,
244 // language and subsetOption.
245 // We'll pass "" for that last one, since we don't want to
246 // retrieve a subset of the describeCollService XML response,
247 // but all of the response.
248 String response = (String) call.invoke(new Object[]{
249 collection, FIELD_QUERY_SERVICE, lang, ""});
250
251 // later cast the return type to the correct format and return it:
252 return response;
253
254 // Note that for more complicated return types (like certain collection
255 // types or complex types), you may have to find out what the class
256 // of the return value is. For instance, when a group of elements are
257 // returned, the return type may be Array or ArrayList or something similar.
258 // In such cases, you need to find the type of each element in the array.
259 // This is necessary in order to cast the return value into the correct type.
260 // System.err.println("Return type is: " + response.getClass().getName());
261 // later cast the return type to the correct format and return it:
262 // return (Element[])response;
263 } catch(Exception e) {
264 System.err.println("ERROR trying to invoke web service" + e);
265 }
266 return "";
267 }
268
269
270 public static void main(String[] args) {
271 try {
272 // Constructor requires wsdl url of the localsite's web services.
273 // Once the QBRSOAPServer web services have been deployed, we can
274 // find this url off greenstone's services page
275 // http://HOST:PORT/greenstone3/services/
276 GreenstoneConnection gCon = new GreenstoneConnection(
277 "http://"+HOST+":"+PORT+"/greenstone3/services/QBRSOAPServerlocalsite?wsdl");
278
279 final String language = "en"; // for English
280 String fieldQueryDescription = gCon.describeFieldQueryService(
281 "gs2mgppdemo", language);
282
283 // Inspect the output in order to move on to the next step.
284 System.out.println("THE DESCRIPTION RETURNED FOR THE FieldQuery"
285 + " SERVICE IS: " + fieldQueryDescription);
286
287 // Now that we sent a describe message to the FieldQuery Service to
288 // tell us the parameters required by the FieldQuery web service
289 // operation, the XML response told us all the parameters required.
290 // Let's use the gs2mgppdemo collection's FieldQuery service to
291 // query for "snails". The query web service operation takes a
292 // Map of (name, value) pairs where name is the name of the query
293 // parameter (e.g. which indexed field to search in,
294 // the search terms themselves or whether casefolding is on or off)
295 HashMap map = new HashMap();
296 map.put("maxDocs", "100");
297 map.put("level", "Sec");
298 map.put("accent", "1");
299 map.put("matchMode", "some");
300 map.put("fqf", "ZZ,ZZ,ZZ,ZZ");
301 map.put("case", "1");
302 map.put("sortBy", "1");
303 map.put("fqv", "snail,water,,");
304
305 String queryResult = gCon.query("gs2mgppdemo", "FieldQuery", language, map);
306
307 // print out the response to the query request
308 System.out.println("RESULT OF EXECUTING THE QUERY: " + queryResult);
309
310 }catch (Exception e) {
311 System.err.println("In main. Exception: " + e);
312 }
313 }
314}
315<pre>
316</li>
317<li>In order to compile the above client code, the required jar files are
318<ul>
319<li>$GSDLHOME/web/WEB-INF/lib/axis.jar</li>
320<li>$GSDLHOME/web/WEB-INF/lib/jaxrpc.jar</li>
321</ul>
322</li>
323<li>To get above client code to run you need to have the necessary jar files in the run path as well. (If you try to run the application, it will throw errors telling you which jars are missing.)
324For running the above example code, you need to add the following jar files to the execution classpath:
325<ul>
326<li>commons-logging-**.jar</li>
327<li>commons-discovery-**.jar</li>
328<li>saaj.jar</li>
329<li>wsdl4j-**.jar</li>
330<li>activation.jar</li>
331</ul>
332All of these can be found in the $GSDLHOME/web/WEB-INF/lib folder.
333</li>
334<li>Try executing the code in 2 above. My output is:
335<pre>
336THE DESCRIPTION RETURNED FOR THE FieldQuery SERVICE IS:
337&lt;message&gt;
338 &lt;response from="gs2mgppdemo/FieldQuery" type="describe"&gt;
339 &lt;service name="FieldQuery" type="query"&gt;
340 &lt;displayItem name="name"&gt;Form Search&lt;/displayItem&gt;
341
342 &lt;displayItem name="submit"&gt;Search&lt;/displayItem&gt;
343
344 &lt;displayItem name="description"&gt;Simple fielded search&lt;/displayItem&gt;
345
346 &lt;paramList&gt;
347 &lt;param default="Sec" name="level" type="enum_single"&gt;
348 &lt;displayItem name="name"&gt;Granularity to search at&lt;/displayItem&gt;
349
350 &lt;option name="Sec"&gt;
351 &lt;displayItem name="name"&gt;Section&lt;/displayItem&gt;
352 &lt;/option&gt;
353
354 &lt;option name="Doc"&gt;
355 &lt;displayItem name="name"&gt;Document&lt;/displayItem&gt;
356 &lt;/option&gt;
357 &lt;/param&gt;
358
359 &lt;param default="1" name="case" type="boolean"&gt;
360 &lt;displayItem name="name"&gt;Turn casefolding &lt;/displayItem&gt;
361
362 &lt;option name="0"&gt;
363 &lt;displayItem name="name"&gt;off&lt;/displayItem&gt;
364 &lt;/option&gt;
365
366 &lt;option name="1"&gt;
367 &lt;displayItem name="name"&gt;on&lt;/displayItem&gt;
368 &lt;/option&gt;
369 &lt;/param&gt;
370
371 &lt;param default="1" name="stem" type="boolean"&gt;
372 &lt;displayItem name="name"&gt;Turn stemming &lt;/displayItem&gt;
373
374 &lt;option name="0"&gt;
375 &lt;displayItem name="name"&gt;off&lt;/displayItem&gt;
376 &lt;/option&gt;
377
378 &lt;option name="1"&gt;
379 &lt;displayItem name="name"&gt;on&lt;/displayItem&gt;
380 &lt;/option&gt;
381 &lt;/param&gt;
382
383 &lt;param default="1" name="accent" type="boolean"&gt;
384 &lt;displayItem name="name"&gt;Turn accentfolding &lt;/displayItem&gt;
385
386 &lt;option name="0"&gt;
387 &lt;displayItem name="name"&gt;off&lt;/displayItem&gt;
388 &lt;/option&gt;
389
390 &lt;option name="1"&gt;
391 &lt;displayItem name="name"&gt;on&lt;/displayItem&gt;
392 &lt;/option&gt;
393 &lt;/param&gt;
394
395 &lt;param default="some" name="matchMode" type="enum_single"&gt;
396 &lt;displayItem name="name"&gt;Match&lt;/displayItem&gt;
397
398 &lt;option name="some"&gt;
399 &lt;displayItem name="name"&gt;some&lt;/displayItem&gt;
400 &lt;/option&gt;
401
402 &lt;option name="all"&gt;
403 &lt;displayItem name="name"&gt;all&lt;/displayItem&gt;
404 &lt;/option&gt;
405 &lt;/param&gt;
406
407 &lt;param default="1" name="sortBy" type="enum_single"&gt;
408 &lt;displayItem name="name"&gt;Document display order&lt;/displayItem&gt;
409
410 &lt;option name="1"&gt;
411 &lt;displayItem name="name"&gt;ranked&lt;/displayItem&gt;
412 &lt;/option&gt;
413
414 &lt;option name="0"&gt;
415 &lt;displayItem name="name"&gt;natural&lt;/displayItem&gt;
416 &lt;/option&gt;
417 &lt;/param&gt;
418
419 &lt;param default="100" name="maxDocs" type="integer"&gt;
420 &lt;displayItem name="name"&gt;Maximum hits to return&lt;/displayItem&gt;
421 &lt;/param&gt;
422
423 &lt;param name="simpleField" occurs="4" type="multi"&gt;
424 &lt;displayItem name="name"&gt;&lt;/displayItem&gt;
425
426 &lt;param name="fqv" type="string"&gt;
427 &lt;displayItem name="name"&gt;Word or phrase &lt;/displayItem&gt;
428 &lt;/param&gt;
429
430 &lt;param default="ZZ" name="fqf" type="enum_single"&gt;
431 &lt;displayItem name="name"&gt;in field&lt;/displayItem&gt;
432
433 &lt;option name="ZZ"&gt;
434 &lt;displayItem name="name"&gt;all fields&lt;/displayItem&gt;
435 &lt;/option&gt;
436
437 &lt;option name="TX"&gt;
438 &lt;displayItem name="name"&gt;text&lt;/displayItem&gt;
439 &lt;/option&gt;
440
441 &lt;option name="DL"&gt;
442 &lt;displayItem name="name"&gt; titles&lt;/displayItem&gt;
443 &lt;/option&gt;
444
445 &lt;option name="DS"&gt;
446 &lt;displayItem name="name"&gt;subjects&lt;/displayItem&gt;
447 &lt;/option&gt;
448
449 &lt;option name="DO"&gt;
450 &lt;displayItem name="name"&gt;organisations&lt;/displayItem&gt;
451 &lt;/option&gt;
452 &lt;/param&gt;
453 &lt;/param&gt;
454 &lt;/paramList&gt;
455 &lt;/service&gt;
456 &lt;/response&gt;
457&lt;/message&gt;
458
459RESULT OF EXECUTING THE QUERY:
460&lt;message&gt;
461 &lt;response from="gs2mgppdemo/FieldQuery" type="process"&gt;
462 &lt;metadataList&gt;
463 &lt;metadata name="numDocsMatched"&gt;140&lt;/metadata&gt;
464
465 &lt;metadata name="numDocsReturned"&gt;100&lt;/metadata&gt;
466
467 &lt;metadata name="query"&gt; snail water&lt;/metadata&gt;
468 &lt;/metadataList&gt;
469
470 &lt;documentNodeList&gt;
471 &lt;documentNode docType="hierarchy" nodeID="HASH011291f4f0794f8fcd324a43.13" nodeType="leaf" rank="74.75892" /&gt;
472 &lt;documentNode docType="hierarchy" nodeID="HASH0119e312094355aebcb59a77.7.1" nodeType="leaf" rank="40.254803" /&gt;
473 ...
474 &lt;documentNode docType="hierarchy" nodeID="HASH01e7ccf5c76312e6b4caaaab.7.5" nodeType="leaf" rank="0.01744299" /&gt;&lt;/documentNodeList&gt;
475
476 &lt;termList&gt;
477 &lt;term field="" freq="58" name="snail" numDocsMatch="21" stem="5"&gt;
478 &lt;equivTermList&gt;
479 &lt;term freq="" name="Snail" numDocsMatch="" /&gt;
480 &lt;term freq="" name="snail" numDocsMatch="" /&gt;&lt;/equivTermList&gt;
481 &lt;/term&gt;
482
483 &lt;term field="" freq="585" name="water" numDocsMatch="120" stem="5"&gt;
484 &lt;equivTermList&gt;
485 &lt;term freq="" name="Water" numDocsMatch="" /&gt;
486 &lt;term freq="" name="water" numDocsMatch="" /&gt;&lt;/equivTermList&gt;
487 &lt;/term&gt;
488 &lt;/termList&gt;
489 &lt;/response&gt;
490&lt;/message&gt;
491</pre>
492</li>
493</ol>
494
495</body>
496</html>
Note: See TracBrowser for help on using the repository browser.