source: trunk/gsdl3/src/java/org/greenstone/gsdl3/service/ServiceRack.java@ 9289

Last change on this file since 9289 was 9279, checked in by kjdon, 19 years ago

changed again how you get text strings. have gone back to using the class name if no dictionary name is specified, but will now look up the super class list until a string is found. can still specify a dictionary in the getTextString call.

  • Property svn:keywords set to Author Date Id Revision
File size: 12.9 KB
Line 
1/*
2 * ServiceRack.java
3 * Copyright (C) 2002 New Zealand Digital Library, http://www.nzdl.org
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19package org.greenstone.gsdl3.service;
20
21// greenstone classes
22import org.greenstone.gsdl3.util.*;
23import org.greenstone.gsdl3.core.*;
24
25// xml classes
26import org.w3c.dom.Node;
27import org.w3c.dom.NodeList;
28import org.w3c.dom.Element;
29import org.w3c.dom.Document;
30import org.xml.sax.InputSource;
31import javax.xml.parsers.*;
32import org.apache.xpath.XPathAPI;
33
34// general java classes
35import java.io.Reader;
36import java.io.StringReader;
37import java.io.File;
38import java.util.HashMap;
39import java.util.ResourceBundle;
40import java.util.Locale;
41import java.lang.reflect.Method;
42
43/**
44 * ServiceRack - abstract base class for services
45 *
46 * A ServiceRack provides one or more Services.
47 * This base class implements the process method.
48 *Each service is invoked
49 * by a method called process<service name> which takes one parameter - the xml request Element, and returns an XML response Element.
50 * for example, the TextQuery service would be invoked by
51 * processTextQuery(Element request)
52 *
53 * @author <a href="mailto:[email protected]">Katherine Don</a>
54 * @version $Revision: 9279 $
55 */
56public abstract class ServiceRack
57 implements ModuleInterface
58{
59
60 /** the absolute address of the site home */
61 protected String site_home =null;
62 /** the http address of the site home */
63 protected String site_http_address =null;
64
65 /** the name of the cluster (or collection) that this service
66 belongs to - if any */
67 protected String cluster_name = null;
68
69 /** some services can talk back to the message router */
70 protected ModuleInterface router = null;
71
72 /** a converter class to create Documents etc */
73 protected XMLConverter converter = null;
74
75 /** the original config info - if need to store it */
76 protected Element config_info = null;
77
78 /** XML element for describe requests - the container doc */
79 protected Document doc = null;
80
81 /** XML element for describe requests - list of supported services
82 - this is static */
83 protected Element short_service_info = null;
84
85 /** XML element for stylesheet requests - map of service name to format
86 elem */
87 protected HashMap format_info_map = null;
88
89 /** sets the cluster name */
90 public void setClusterName(String cluster_name) {
91 this.cluster_name = cluster_name;
92 }
93 /** sets the collect name */
94 public void setCollectionName(String coll_name) {
95 setClusterName(coll_name);
96 }
97
98 /** sets the site home */
99 public void setSiteHome(String site_home) {
100 this.site_home = site_home;
101 }
102 /** sets the site http address */
103 public void setSiteAddress(String site_address) {
104 this.site_http_address = site_address;
105 }
106
107 /** sets the message router */
108 public void setMessageRouter(ModuleInterface m) {
109 this.router = m;
110 }
111
112 /** the no-args constructor */
113 public ServiceRack() {
114 this.converter = new XMLConverter();
115 this.doc = this.converter.newDOM();
116 this.short_service_info = this.doc.createElement(GSXML.SERVICE_ELEM+GSXML.LIST_MODIFIER);
117 this.format_info_map = new HashMap();
118 }
119
120
121 /** configure the service module
122 *
123 * @param info the XML node <serviceRack name="XXX"/> with name equal
124 * to the class name (of the subclass)
125 *
126 * must configure short_service_info_ and service_info_map_
127 * @return true if configured ok
128 * must be implemented in subclasses
129 */
130 public boolean configure(Element info) {
131 return configure(info, null);
132 }
133
134 abstract public boolean configure(Element info, Element extra_info);
135
136 /**
137 * Process an XML document - convenience method that uses Strings rather than Elements. just calls process(Element).
138 *
139 * @param xml_in the Document to process - a string
140 * @return the resultant document as a string - contains any error messages
141 * @see String
142 */
143 public String process(String xml_in) {
144
145 Document doc = this.converter.getDOM(xml_in);
146
147 Element res = process(doc.getDocumentElement());
148 return this.converter.getString(res);
149
150 }
151
152 /** process an XML request in DOM form
153 *
154 * @param xml_in the Element node containing the request
155 * should be <message>
156 * @return an Element with the result XML
157 * @see Element
158 */
159 public Element process(Element message) {
160
161 NodeList requests = message.getElementsByTagName(GSXML.REQUEST_ELEM);
162 Document mess_doc = message.getOwnerDocument();
163 Element mainResult = this.doc.createElement(GSXML.MESSAGE_ELEM);
164 if (requests.getLength()==0) {
165 // no requests
166 return mainResult; // empty message for now
167 }
168
169 for (int i=0; i<requests.getLength(); i++) {
170 Element request = (Element)requests.item(i);
171
172 String type = request.getAttribute(GSXML.TYPE_ATT);
173 if (type.equals(GSXML.REQUEST_TYPE_DESCRIBE)) {
174 Element response = processDescribe(request);
175 if (response !=null) {
176 mainResult.appendChild(this.doc.importNode(response, true));
177 }
178
179 } else if (type.equals(GSXML.REQUEST_TYPE_FORMAT)) {
180 Element response = processFormat(request);
181 mainResult.appendChild(this.doc.importNode(response, true));
182
183
184 } else {
185 // other type of request, must be processed by the subclass -
186 // send to the service method
187 StringBuffer error_string = new StringBuffer();
188 String to = GSPath.getFirstLink(request.getAttribute(GSXML.TO_ATT));
189 Element response = null;
190 try {
191 Class c = this.getClass();
192 Class []params = {Class.forName("org.w3c.dom.Element")};
193
194 String method_name = "process"+to;
195 Method m = null;
196 while (c != null) {
197
198 try {
199 m = c.getDeclaredMethod(method_name, params);
200 // if this has worked, break
201 break;
202 } catch (NoSuchMethodException e) {
203 c = c.getSuperclass();
204 } catch (SecurityException e) {
205 System.err.println("ServiceRack.process: security exception for finding method "+method_name);
206 error_string.append("ServiceRack.process: security exception for finding method "+method_name);
207 }
208 } // while
209 if (m != null) {
210 Object []args = {request};
211 try {
212 response = (Element)m.invoke(this, args);
213
214 } catch (Exception e) {
215 System.err.println("ServiceRack.process: Trying to call a processService type method (process"+to+") on a subclass("+this.getClass().getName()+"), but an exception happened:"+e.toString());
216 error_string.append("ServiceRack.process: Trying to call a processService type method (process"+to+") on a subclass("+this.getClass().getName()+"), but an exception happened:"+e.toString());
217 }
218 } else {
219 System.err.println("ServiceRack.process: method "+method_name+" not found for class "+this.getClass().getName());
220 error_string.append("ServiceRack.process: method "+method_name+" not found for class "+this.getClass().getName());
221 }
222
223 } catch (ClassNotFoundException e) {
224 System.err.println("ServiceRack error: Element class not found");
225 error_string.append("ServiceRack error: Element class not found");
226 }
227 if (response !=null) {
228 mainResult.appendChild(this.doc.importNode(response, true));
229 } else {
230 // add in a dummy response
231 System.err.println("adding in an error element\n");
232 response = this.doc.createElement(GSXML.RESPONSE_ELEM);
233 GSXML.addError(this.doc, response, error_string.toString());
234 mainResult.appendChild(response);
235
236 }
237
238 } // else process request
239 } // for each request
240
241 return mainResult;
242
243 }
244
245
246
247 /** process method for describe requests
248 */
249 protected Element processDescribe(Element request) {
250
251 Element response = this.doc.createElement(GSXML.RESPONSE_ELEM);
252 response.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_DESCRIBE);
253
254 String lang = request.getAttribute(GSXML.LANG_ATT);
255 String to = GSPath.getFirstLink(request.getAttribute(GSXML.TO_ATT));
256 if (to.equals("")) { // return the service list
257 response.appendChild(getServiceList(lang));
258 return response;
259 }
260 response.setAttribute(GSXML.FROM_ATT, to);
261 Element param_list = (Element)GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
262 Element description = null;
263 if (param_list == null) {
264 description = getServiceDescription(to, lang, null);
265 } else {
266 NodeList params = param_list.getElementsByTagName(GSXML.PARAM_ELEM);
267 for (int i=0; i<params.getLength(); i++) {
268
269 Element param = (Element)params.item(i);
270 // Identify the structure information desired
271 if (param.getAttribute(GSXML.NAME_ATT).equals(GSXML.SUBSET_PARAM )) {
272 String info = param.getAttribute(GSXML.VALUE_ATT);
273 if (description == null) {
274 description = getServiceDescription(to, lang, info);
275 } else {
276 Element temp = getServiceDescription(to, lang, info);
277 GSXML.mergeElements(description, temp);
278 }
279 }
280 }
281 }
282 if (description != null) { // may be null if non-existant service
283 response.appendChild(description);
284 }
285 return response;
286
287 }
288
289 /** process method for stylesheet requests
290 */
291 protected Element processFormat(Element request) {
292 Element response = this.doc.createElement(GSXML.RESPONSE_ELEM);
293 response.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_FORMAT);
294
295 String to = GSPath.getFirstLink(request.getAttribute(GSXML.TO_ATT));
296
297 if (to.equals("")) { // serviceRack query - is this appropriate??
298 return response;
299 }
300
301
302 // describe a particular service
303 if (this.format_info_map.containsKey(to)) {
304 response.appendChild(getServiceFormat(to));
305 response.setAttribute(GSXML.FROM_ATT, to);
306 return response;
307 }
308 // else no format info
309 System.err.println("ServiceRack describe request: no format info for "+to+".");
310 return response;
311 }
312
313 /** returns the service list for the subclass */
314 protected Element getServiceList(String lang) {
315 // for now, it is static and has no language stuff
316 return (Element) this.short_service_info.cloneNode(true);
317 }
318
319 /** returns a specific service description */
320 abstract protected Element getServiceDescription(String service, String lang, String subset);
321
322 protected Element getServiceFormat(String service) {
323 Element format = (Element)((Element)this.format_info_map.get(service)).cloneNode(true);
324 return format;
325 }
326
327 /** overloaded version for no args case */
328 protected String getTextString(String key, String lang) {
329 return getTextString(key, lang, null, null);
330 }
331
332 protected String getTextString(String key, String lang, String dictionary) {
333 return getTextString(key, lang, dictionary, null);
334 }
335 protected String getTextString(String key, String lang, String [] args) {
336 return getTextString(key, lang, null, args);
337 }
338
339 /** getTextString - retrieves a language specific text string for the given
340key and locale, from the specified resource_bundle
341 */
342 protected String getTextString(String key, String lang, String dictionary, String[] args) {
343
344 //String class_name = this.getClass().getName();
345 //class_name = class_name.substring(class_name.lastIndexOf('.')+1);
346 if (dictionary != null) {
347 // just try the one specified dictionary
348 Dictionary dict = new Dictionary(dictionary, lang);
349 String result = dict.get(key, args);
350 if (result == null) { // not found
351 return "_"+key+"_";
352 }
353 return result;
354 }
355
356 // else we try class names for dictionary names
357 String class_name = this.getClass().getName();
358 class_name = class_name.substring(class_name.lastIndexOf('.')+1);
359 Dictionary dict = new Dictionary(class_name, lang);
360 String result = dict.get(key, args);
361 if (result != null) {
362 return result;
363 }
364
365 // we have to try super classes
366 Class c = this.getClass().getSuperclass();
367 while (result == null && c != null) {
368 class_name = c.getName();
369 class_name = class_name.substring(class_name.lastIndexOf('.')+1);
370 if (class_name.equals("ServiceRack")) {
371 // this is as far as we go
372 break;
373 }
374 dict = new Dictionary(class_name, lang);
375 result = dict.get(key, args);
376 c = c.getSuperclass();
377 }
378 if (result == null) {
379 return "_"+key+"_";
380 }
381 return result;
382
383 }
384
385 protected String getMetadataNameText(String key, String lang) {
386
387 String properties_name = "metadata_names";
388 Dictionary dict = new Dictionary(properties_name, lang);
389
390 String result = dict.get(key);
391 if (result == null) { // not found
392 return null;
393 }
394 return result;
395 }
396}
397
Note: See TracBrowser for help on using the repository browser.