1 | package org.greenstone.gsdl3.service;
|
---|
2 |
|
---|
3 | // greenstone classes
|
---|
4 | import org.greenstone.gsdl3.util.*;
|
---|
5 | import org.greenstone.gsdl3.core.*;
|
---|
6 |
|
---|
7 | // xml classes
|
---|
8 | import org.w3c.dom.Node;
|
---|
9 | import org.w3c.dom.Element;
|
---|
10 | import org.w3c.dom.Document;
|
---|
11 | import org.xml.sax.InputSource;
|
---|
12 | import javax.xml.parsers.*;
|
---|
13 | import org.apache.xpath.XPathAPI;
|
---|
14 |
|
---|
15 | // general java classes
|
---|
16 | import java.io.Reader;
|
---|
17 | import java.io.StringReader;
|
---|
18 | import java.io.File;
|
---|
19 | import java.util.HashMap;
|
---|
20 |
|
---|
21 | /**
|
---|
22 | * ServiceModule - abstract base class
|
---|
23 | *
|
---|
24 | * A ServiceModule provides Services to a collection/system.
|
---|
25 | * It may provide more than one Service. for eg
|
---|
26 | * MGGDBMServiceModule may support "DocRetrieve", "TextQuery", "MetadataRetrieve" services
|
---|
27 | *
|
---|
28 | */
|
---|
29 | public abstract class ServiceModule
|
---|
30 | implements ModuleInterface
|
---|
31 | {
|
---|
32 | /** the absolute address of the site home */
|
---|
33 | protected String site_home_ =null;
|
---|
34 | /** the name of the collection directory that this service belongs to -
|
---|
35 | if any */
|
---|
36 | protected String collection_name_ = null;
|
---|
37 |
|
---|
38 | /** some services can talk back to the message router */
|
---|
39 | protected ModuleInterface router_ = null;
|
---|
40 |
|
---|
41 | /** a converter class to create Documents etc */
|
---|
42 | protected XMLConverter converter_ = null;
|
---|
43 |
|
---|
44 | /** XML element for describe requests - the container doc */
|
---|
45 | protected Document doc_ = null;
|
---|
46 |
|
---|
47 | /** XML element for describe requests - list of supported services */
|
---|
48 | protected Element short_service_info_ = null;
|
---|
49 |
|
---|
50 | /** XML element for describe requests - map of service name to full
|
---|
51 | description */
|
---|
52 | protected HashMap service_info_map_ = null;
|
---|
53 |
|
---|
54 | public void setCollectionName(String coll_name) {
|
---|
55 | collection_name_ = coll_name;
|
---|
56 | }
|
---|
57 |
|
---|
58 | public void setSiteHome(String site_home) {
|
---|
59 | site_home_ = site_home;
|
---|
60 | }
|
---|
61 |
|
---|
62 | public void setMessageRouter(ModuleInterface m) {
|
---|
63 | router_ = m;
|
---|
64 | }
|
---|
65 |
|
---|
66 | public ServiceModule() {
|
---|
67 | converter_ = new XMLConverter();
|
---|
68 | doc_ = converter_.newDOM();
|
---|
69 | short_service_info_ = doc_.createElement("serviceList");
|
---|
70 | service_info_map_ = new HashMap();
|
---|
71 | }
|
---|
72 |
|
---|
73 | /**
|
---|
74 | * Configure the object. - default method for service modules
|
---|
75 | *
|
---|
76 | * reads either collection (if a collection name has been set), or system
|
---|
77 | * configuration file, and configures itself
|
---|
78 | * this calls configure(Element) with the XML element node from the config
|
---|
79 | * file.
|
---|
80 | * configure(Element) should be used if the config file has already been
|
---|
81 | * parsed. This method will work with any subclass.
|
---|
82 | *
|
---|
83 | * @return true if configure successful, false otherwise.
|
---|
84 | */
|
---|
85 | public boolean configure(){
|
---|
86 |
|
---|
87 | if (site_home_==null) {
|
---|
88 | System.err.println("setSiteHome() must be called before configure()");
|
---|
89 | return false;
|
---|
90 | }
|
---|
91 |
|
---|
92 | File config_file=null;
|
---|
93 | if (collection_name_ !=null) {
|
---|
94 |
|
---|
95 | config_file = GSFile.collectionBuildConfigFile(site_home_, collection_name_);
|
---|
96 | }
|
---|
97 | else {
|
---|
98 | config_file = GSFile.siteConfigFile(site_home_);
|
---|
99 | }
|
---|
100 |
|
---|
101 | if (config_file.exists() ) {
|
---|
102 |
|
---|
103 | Document doc = converter_.getDOM(config_file);
|
---|
104 |
|
---|
105 | try {
|
---|
106 | // get the service list and look for own service
|
---|
107 | // Note: XPathAPI is slow apparently
|
---|
108 | String xpath = "//ServiceModule[@name='"+this.getClass().getName()+"']";
|
---|
109 | System.out.println("xpath="+xpath);
|
---|
110 | Node n = XPathAPI.selectSingleNode(doc, xpath);
|
---|
111 | if (n !=null) {
|
---|
112 | return this.configure((Element)n);
|
---|
113 | }
|
---|
114 | } catch (Exception e) {
|
---|
115 | System.err.println("ServiceModule configure exception: "+e.getMessage());
|
---|
116 | return false;
|
---|
117 | }
|
---|
118 | }
|
---|
119 | System.err.println("ServiceModule error: unable to configure ServiceModule " + this.getClass().getName() );
|
---|
120 | return false;
|
---|
121 |
|
---|
122 |
|
---|
123 | }
|
---|
124 |
|
---|
125 | /** The configure method that does the real work
|
---|
126 | *
|
---|
127 | * @param info the XML node <serviceModule name="XXX"/> with name equal
|
---|
128 | * to the class name (of the subclass)
|
---|
129 | *
|
---|
130 | * must initialise short_service_info_ and service_info_map_
|
---|
131 | * @return true if configured ok
|
---|
132 | * must be implemented in subclasses
|
---|
133 | */
|
---|
134 | abstract public boolean configure(Element info);
|
---|
135 |
|
---|
136 | /**
|
---|
137 | * Process an XML document - convenience method that uses Strings rather than Nodes. just calls process(Node).
|
---|
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 = converter_.getDOM(xml_in);
|
---|
146 |
|
---|
147 | Node res = process(doc);
|
---|
148 | return 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 <request> or maybe <multipleRequest>?? if more than one
|
---|
156 | * request coming at once
|
---|
157 | * @return an Element with the result XML
|
---|
158 | * @see Element
|
---|
159 | */
|
---|
160 | public Node process(Node xml_in) {
|
---|
161 |
|
---|
162 | // check if request is Element or Document - we want to work
|
---|
163 | // with an Element
|
---|
164 | Element request=null;
|
---|
165 |
|
---|
166 | short node_type = xml_in.getNodeType();
|
---|
167 | if (node_type == Node.DOCUMENT_NODE) {
|
---|
168 | request = ((Document)xml_in).getDocumentElement();
|
---|
169 | } else if (node_type == Node.ELEMENT_NODE) {
|
---|
170 | request = (Element)xml_in;
|
---|
171 | } else {
|
---|
172 | System.err.println("ServiceModule:process error: input should be an Element or Document!");
|
---|
173 | }
|
---|
174 |
|
---|
175 | String req = request.getNodeName();
|
---|
176 | if (!req.equals("request")) {
|
---|
177 | System.err.println("ServiceModule:process - should have been passed a request element, instead was given a "+req+" element!");
|
---|
178 | return null;
|
---|
179 | }
|
---|
180 |
|
---|
181 | String type = request.getAttribute("type");
|
---|
182 | String to = GSPath.getFirstLink(request.getAttribute("to"));
|
---|
183 | String info = request.getAttribute("info");
|
---|
184 | if (type.equals("describe")) { // process here, not by subclass
|
---|
185 | if (to.equals("")) { // to="", look at info
|
---|
186 | if (info.equals("serviceList")) {
|
---|
187 | return short_service_info_;
|
---|
188 | }
|
---|
189 | // else error in info field
|
---|
190 | System.err.println("ServiceModule describe request: error in 'info' field, info='"+info+"'.");
|
---|
191 | return null;
|
---|
192 | } else { // describe a particular service
|
---|
193 | if (service_info_map_.containsKey(to)) {
|
---|
194 | return (Element)service_info_map_.get(to);
|
---|
195 | }
|
---|
196 | // else error in to field
|
---|
197 | System.err.println("ServiceModule describe request: error in 'to' field, to='"+to+"'.");
|
---|
198 | return null;
|
---|
199 | }
|
---|
200 | } else { // other type of request, must be processed by the subclass -
|
---|
201 | // send to the service method
|
---|
202 | if (service_info_map_.containsKey(to)) {
|
---|
203 | return processService(to, request);
|
---|
204 | }
|
---|
205 | else {
|
---|
206 | // else error in to field
|
---|
207 | System.err.println("ServiceModule describe request: error in 'to' field, to='"+to+"'.");
|
---|
208 | return null;
|
---|
209 | }
|
---|
210 | }
|
---|
211 |
|
---|
212 | }
|
---|
213 |
|
---|
214 | /** process method for specific services - must be implemented by all
|
---|
215 | * subclasses
|
---|
216 | * should implement all services supported by the serviceModule except
|
---|
217 | * for describe, which is implemented by this base class
|
---|
218 | *
|
---|
219 | */
|
---|
220 | abstract protected Element processService(String service, Element request);
|
---|
221 |
|
---|
222 |
|
---|
223 | }
|
---|