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

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

Changed processInternal(), keeping it in sync with older change made to official QBRSOAPServer.java.in in Greenstone3 checkout. Now this method does not return a prettyString version of the response, but instead trims the response so there's no whitespace (illegal in XML) and prepends the official xml tag to the response

File size: 15.6 KB
Line 
1package org.greenstone.gs3services;
2
3import java.io.File;
4import java.io.InputStream;
5import java.util.Enumeration;
6import java.util.Properties;
7
8import org.apache.log4j.Logger;
9import org.greenstone.gsdl3.core.MessageRouter;
10import org.greenstone.gsdl3.util.GSFile;
11import org.greenstone.gsdl3.util.GSXML;
12import org.greenstone.gsdl3.util.GlobalProperties;
13import org.greenstone.gsdl3.util.XMLConverter;
14import org.w3c.dom.Document;
15import org.w3c.dom.Element;
16import org.w3c.dom.Node;
17
18/**
19 * A beginning to the AdminSOAPServer class which will contain management/admin
20 * related web services such as adding new documents, creating, building and
21 * importing collections and configuring Greenstone modules.
22 *
23 * NOTE: to run this class, the folder containing this web service class'
24 * properties helpFile should be on the classpath.
25*/
26public class AdminSOAPServer {
27 /** The Logger for this class */
28 private static Logger LOG = Logger.getLogger(AdminSOAPServer.class);
29
30 /** Error message loading helpFile. Remains at "" if everything is fine */
31 protected static String helpErrormessage = "";
32 /** Properties map with mappings from methodname to help
33 * description string */
34 protected static Properties properties;
35 /** The help properties file describing the web service operations */
36 protected static String helpFile = "AdminWebServicesHelp.properties";
37
38 // static code block to initialise the help Properties from the helpFile
39 static {
40 properties = new Properties();
41 // load the properties file from a location with respect to the
42 // the Web Service .class file
43 InputStream input = null;
44 try {
45 // load the properties file from a location with respect to the
46 // the Web Service .class file
47 input = AdminSOAPServer.class.getClassLoader().getResourceAsStream(
48 helpFile);
49 if(input == null) {
50 helpErrormessage = "Cannot find file " + helpFile + " to load.";
51 LOG.warn(helpErrormessage);
52 } else {
53 properties.load(input);
54 input.close();
55 }
56 } catch(Exception e) {
57 helpErrormessage = "Exception loading properties from help file "
58 + helpFile + "\n" + e.getMessage();
59 LOG.warn("Exception loading properties from help file "
60 + helpFile + "\n" + e.getMessage());
61 }
62 }
63
64 /** site_name the MessageRouter works with, here set to "localsite" */
65 protected String site_name = "localsite";
66
67 /** Message Router object to pass requests messages to and which
68 * will process them.*/
69 protected MessageRouter mr = null;
70
71 /** Container Document to create XML Nodes */
72 protected Document doc=null;
73 /** A converter class to parse XML and create Docs */
74 protected XMLConverter converter=null;
75
76 /** Constructor that initializes the web services' MessageRouter object
77 * Reads from GlobalProperties to get gsdl3_home and set the sitename. */
78 public AdminSOAPServer() {
79 String gsdl3_home = GlobalProperties.getGSDL3Home();
80 if (gsdl3_home == null || gsdl3_home.equals("")) {
81 LOG.error(
82 "Couldn't access GSDL3Home from GlobalProperties.getGSDL3HOME,"
83 + "can't initialize the SOAP Server.");
84 return;
85 }
86
87 String site_home = GSFile.siteHome(gsdl3_home, this.site_name);
88
89 File site_file = new File(site_home);
90 if (!site_file.isDirectory()) {
91 LOG.error("The site directory "+site_file.getPath()
92 +" doesn't exist. Can't initialize the SOAP Server.");
93 return;
94 }
95 this.converter = new XMLConverter();
96 this.doc = this.converter.newDOM();
97
98 mr = new MessageRouter();
99 mr.setSiteName(this.site_name);
100 mr.configure();
101 }
102
103// (5) Status-type messages, manual pages 42, 43
104 /** Sends a status-type message to poll the status of a process that was
105 * initiated but which may not yet have terminated.
106 * @see <a href="http://wiki.greenstone.org/wiki/index.php/Greenstone3">The Greenstone 3 Developer's Manual - pages 42, 43</a>
107 * @param to - the processing service to send this status message to.
108 * @param language - the preferred language of the display content in the
109 * response.
110 * @param pid - the process id of the process whose status is requested.
111 */
112 public String status(String to, String language, String pid) {
113 // Create message element: <message></message>
114 Element message = this.doc.createElement(GSXML.MESSAGE_ELEM);
115 // <message><request lang="en" to="" type="status" uid="" /></message>
116 Element request = GSXML.createBasicRequest(this.doc,
117 GSXML.REQUEST_TYPE_STATUS, to, language, "");
118
119 // create the <paramlist></paramlist> element of param elements:
120 Element paramList = this.doc.createElement(
121 GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
122 paramList.appendChild(GSXML.createParameter(this.doc, "pid", pid));
123
124 // now finish constructing the request message:
125 request.appendChild(paramList);
126 message.appendChild(request);
127
128 // Send it off to the Message Router and return the response
129 return this.processInternal(message);
130 }
131
132 // (6) System-type messages, manual pages 41, 42
133 /** Sends a configure system-type message to configure all of the Message Router.
134 * @see <a href="http://wiki.greenstone.org/wiki/index.php/Greenstone3">The Greenstone 3 Developer's Manual - pp. 13, 41, 42</a>
135 */
136 public String reconfigureMessageRouter() {
137 return this.reconfigure(""); // subset=MessageRouter="", type=configure
138 // Not applicable: systemModuleName="", systemModuleType=""
139 //return this.system("", GSXML.SYSTEM_TYPE_CONFIGURE, subset, "", "");
140 }
141
142 /** Sends a configure system-type message to configure the Message Router.
143 * @see <a href="http://wiki.greenstone.org/wiki/index.php/Greenstone3">The Greenstone 3 Developer's Manual - pp. 13, 41, 42</a>
144 * @param subset - the particular subset of the module which is to be
145 * reconfigured. For a collection/serviceRack it can be metadataList,
146 * serviceList. For the MessageRouter this can be siteList, collectionList,
147 * clusterList, serviceList
148 */
149 public String reconfigure(String subset) {
150 // type=configure
151 // Not applicable: systemModuleName="", systemModuleType=""
152 return this.system(GSXML.SYSTEM_TYPE_CONFIGURE, subset, "", "");
153 }
154
155 /** Sends a (re-)activate system-type message to activate a Greenstone module.
156 * @see <a href="http://wiki.greenstone.org/wiki/index.php/Greenstone3">The Greenstone 3 Developer's Manual - pp. 13, 41, 42</a>
157 * @param systemModuleName - name of the module to be (re-)activated.
158 * @param systemModuleType - type of the module. For instance, this may be
159 * site or collection.
160 */
161 public String activate(String systemModuleType, String systemModuleName)
162 {
163 // type=activate
164 // Not applicable: subset=""
165 return this.system(GSXML.SYSTEM_TYPE_ACTIVATE, "",
166 systemModuleType, systemModuleName);
167 }
168
169 /** Sends a deactivate system-type message to activate a Greenstone module.
170 * @see <a href="http://wiki.greenstone.org/wiki/index.php/Greenstone3">The Greenstone 3 Developer's Manual - pp. 13, 41, 42</a>
171 * @param systemModuleName - name of the module to be deactivated.
172 * @param systemModuleType - type of the module. For instance, this may be
173 * site or collection.
174 */
175 public String deactivate(String systemModuleType, String systemModuleName)
176 {
177 // type=deactivate
178 // Not applicable: subset=""
179 return this.system(GSXML.SYSTEM_TYPE_DEACTIVATE, "",
180 systemModuleType, systemModuleName);
181 }
182
183 /** For sending system-type messages.
184 * For parameter type=configure, the subset value is set (or "").
185 * For parameter type=(de)activate, the systemModuleName and systemModuleType
186 * are set.
187 * @param type - one of GSXML.SYSTEM_TYPE_CONFIGURE,
188 * GSXML.SYSTEM_TYPE_ACTIVATE, GSXML.SYSTEM_TYPE_DEACTIVATE
189 * (configure, activate or deactivate, respectively).
190 * @param subset - for system type configure, this can specify the To module's
191 * subset that needs to be reconfigured.
192 * @param systemModuleName - for system type (de)activate, this specifies the
193 * name of the module to be (de)activated.
194 * @param systemModuleType - for system type (de)activate, this specifies the
195 * type of the module to be (de)activated. For instance, this may be
196 * site or collection.
197 */
198 protected String system(String type, String subset,
199 String systemModuleType, String systemModuleName)
200 {
201 // Create message element: <message></message>
202 Element message = this.doc.createElement(GSXML.MESSAGE_ELEM);
203 // <message><request lang="" to="" type="system" uid="" /></message>
204 Element request = GSXML.createBasicRequest(this.doc,
205 GSXML.REQUEST_TYPE_SYSTEM, "", "", ""); // no to, no language
206 // (to is the MessageRouter which deals with system requests)
207
208 Element system = this.doc.createElement(GSXML.SYSTEM_ELEM);
209 system.setAttribute(GSXML.TYPE_ATT, type);
210
211 if(type.equals(GSXML.SYSTEM_TYPE_CONFIGURE)) {
212 // EITHER: <system type='configure' subset=''/>, OR:
213 // <system type='configure' subset='collectionList'/>
214 system.setAttribute(GSXML.SYSTEM_SUBSET_ATT, subset);
215 } else { // GSXML.SYSTEM_TYPE_ACTIVATE || GSXML.SYSTEM_TYPE_DEACTIVATE
216 // For example:
217 // <system type='activate' moduleType='collection' moduleName='demo'/>
218 system.setAttribute(GSXML.SYSTEM_MODULE_TYPE_ATT, systemModuleType);
219 system.setAttribute(GSXML.SYSTEM_MODULE_NAME_ATT, systemModuleName);
220 }
221 // now finish constructing the request message:
222 request.appendChild(system);
223 message.appendChild(request);
224
225 // Send it off to the Message Router and return the response
226 return this.processInternal(message);
227 }
228
229 /** Sends a format-type message to a Service containing format (Greenstone
230 * Format, GSF) XSLT statements to specify how a collection looks.
231 * @see <a href="http://wiki.greenstone.org/wiki/index.php/Greenstone3">The Greenstone 3 Developer's Manual - page 42</a>
232 * @param collection - the name of the collection this message is sent to.
233 * @param service - name of the service this format message is to be sent to.
234 * @param language - the preferred language of the display content in the
235 * response.
236 */
237 public String format(String collection, String service, String language)
238 {
239 String to = service;
240 if(!collection.equals(""))
241 to = collection+"/"+to; // prepend collection with slash to service
242
243 // Create message element: <message></message>
244 Element message = this.doc.createElement(GSXML.MESSAGE_ELEM);
245 // <message><request lang="" to="" type="system" uid="" /></message>
246 Element request = GSXML.createBasicRequest(this.doc,
247 GSXML.REQUEST_TYPE_FORMAT, to, language, ""); // no language
248 message.appendChild(request);
249
250 // Send it off to the Message Router and return the response
251 return this.processInternal(message);
252 }
253
254 /** Called by most other methods in order to send the constructed message
255 * to the Greenstone's MessageRouter, intercept the response and return it.
256 * @param message is the XML message Element to send to GS3's MessageRouter.
257 * @return the XML response in String format. */
258 protected String processInternal(Element message) {
259 // Let the messagerouter process the request message and get the response
260 LOG.debug(this.converter.getPrettyString(message));
261
262 // Let the messagerouter process the request message and get the response
263 Element response = converter.nodeToElement(mr.process(message));
264 // won't be null except when Node returned is not an element
265 // otherwise, MR always returns some response
266
267 // Return it as a String formatted for display
268 //return this.converter.getPrettyString(response);
269
270 // In order to avoid "Content is not allowed in prolog" exception on the
271 // web services' client end (problem encountered in GS mailing list), need
272 // to make sure no characters (incl spaces) preceed the XML sent back
273 // from here. It may also require the <?xml?> tag at the very start.
274 if(responseMsg.charAt(0) == ' ') {
275 responseMsg = responseMsg.trim();
276 }
277
278 return "<?xml version=\"1.0\" encoding=\"utf-8\"?>"+responseMsg;
279 }
280
281 /** Creates a String response message to represent an XML error response
282 * message using the error specified in the message parameter. A String is
283 * created because this method ensures that a response message is reliably
284 * constructed (no exceptions are thrown) that can be sent to clients.
285 * @param errorMessage - the errormessage to be conveyed
286 * @return an XML response message containing an GS3 error element. */
287 protected String error(String errorMessage) {
288 StringBuffer buf = new StringBuffer("<" + GSXML.MESSAGE_ELEM + ">");
289 buf.append("<" + GSXML.RESPONSE_ELEM + " "
290 + GSXML.FROM_ATT + "=\"" + "Greenstone 3 Web Services\"" + ">");
291 buf.append("<" + GSXML.ERROR_ELEM + " "
292 + GSXML.ERROR_TYPE_ATT + "=\""+ GSXML.ERROR_TYPE_OTHER + "\"" + ">");
293 buf.append(errorMessage+"\n");
294 buf.append("</" + GSXML.ERROR_ELEM + ">");
295 buf.append("</" + GSXML.RESPONSE_ELEM + ">");
296 buf.append("</" + GSXML.MESSAGE_ELEM + ">");
297 return buf.toString();
298 }
299
300 /*
301 Look in the helpFile
302 - Have a properties file that maps methodname to help string specific
303 to the method.
304 - Read it all in statically at the start of the class, into a Properties Map.
305 - When this method is called, display the usage: "help methodname"
306 and list all the available methods by going over the keys in the Map.
307 - When the helpWithMethod(String methodname) method is called, return the
308 value of the Map for the methodname key. This value would be the help
309 description for that method.
310 */
311 /** @return a help string for listing all the web service methods. */
312 public static String help() {
313 if(!helpErrormessage.equals("")) {
314 return helpErrormessage;
315 }
316
317 StringBuffer helpString = new StringBuffer(
318 "USAGE: helpWithMethod(String <method name>)\n");
319 helpString.append(
320 "\nNearly all the web service operations return a String\n");
321 helpString.append(
322 "representing a Greenstone 3 XML response message.\n");
323 helpString.append("\nA list of all the method names: \n");
324
325 Enumeration props = properties.keys();
326 while(props.hasMoreElements()){
327 String methodName = (String)props.nextElement();
328 helpString.append("\t");
329 helpString.append(methodName);
330 helpString.append("\n");
331 }
332
333 return helpString.toString();
334 }
335
336 /** @param methodname is the name of the method to be described.
337 * @return a help string for the given method, explaining what the method
338 * does, what parameters it expects and their types and what it returns.
339 */
340 public static String helpWithMethod(String methodname) {
341 if(!helpErrormessage.equals("")) {
342 return helpErrormessage;
343 }
344 // else we can get the method's description from the properties
345 // map loaded from the QBRWebServicesHelp.properties file:
346 String helpString = properties.getProperty(methodname,
347 "No description for " + methodname); // if the method does not exist
348
349 return helpString;
350 }
351
352
353 // Here we just try calling some of the methods
354 public static void main(String[] args) {
355 AdminSOAPServer ws = new AdminSOAPServer();
356
357 // (1) activate, deactivate and the 2 reconfigures
358 System.out.println("activate:\n" + ws.activate("collection", "gs2mgppdemo"));
359 System.out.println("deactivate:\n" + ws.deactivate("site", "site1"));
360 System.out.println("configure MR:\n" + ws.reconfigureMessageRouter());
361 System.out.println("configure:\n" + ws.reconfigure("collectionList"));
362
363 // (2) 1 format
364 System.out.println("format:\n" + ws.format("gs2mgppdemo", "FieldQuery", ""));
365
366 // (3) How to test status(), especially when processType messages above don't work?
367 // System.out.println("status:\n" + ws.status(toProcess/service, language, pid));
368 System.out.println("status:\n" + ws.status("build/NewCollection", "", "1"));
369
370 // (4) try help
371 System.out.println(ws.help());
372 System.out.println(ws.helpWithMethod("describe"));
373 System.out.println(ws.helpWithMethod("help"));
374 System.out.println(ws.helpWithMethod("helpWithMethod"));
375
376 System.out.println("Finished executing");
377 }
378
379}
Note: See TracBrowser for help on using the repository browser.