source: trunk/gsdl3/src/java/org/greenstone/gsdl3/core/MessageRouter.java@ 3461

Last change on this file since 3461 was 3461, checked in by kjdon, 22 years ago

hack for SOAP stuff - need to look into message format more

  • Property svn:keywords set to Author Date Id Revision
File size: 15.4 KB
Line 
1/*
2 * MessageRouter.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.core;
20
21import org.greenstone.gsdl3.util.*;
22import org.greenstone.gsdl3.service.*;
23import org.greenstone.gsdl3.comms.*;
24import org.greenstone.gsdl3.collection.*;
25
26// XML classes
27import org.w3c.dom.Node;
28import org.w3c.dom.NodeList;
29import org.w3c.dom.Document;
30import org.w3c.dom.Element;
31import org.xml.sax.InputSource;
32import javax.xml.parsers.*;
33
34// other java classes
35import java.io.File;
36import java.util.HashMap;
37import java.util.Iterator;
38import java.io.Reader;
39import java.io.StringReader;
40
41/**
42 * The hub of a Greenstone system.
43 *
44 * Accepts XML requests (via process method of ModuleInterface) and routes them to the appropriate collection or
45 * service or external entity.
46 *
47 * contains a map of module objects - may be services, collections, comms
48 * objects talking to other MessageRouters etc.
49 *
50 *
51 * @author <a href="mailto:[email protected]">Katherine Don</a>
52 * @version $Revision: 3461 $
53 * @see ModuleInterface
54 * @see Collection
55 * @see ServiceModule
56 * @see Communicator
57 *
58 */
59public class MessageRouter implements ModuleInterface {
60
61 // should go in a separate class? do other names too?
62 static protected String GSDL_MESSAGE_NAME = "message";
63
64 /** site home */
65 protected String site_home_=null;
66 /** the global name for this site */
67 protected String site_name_=null;
68
69 /** map of name to Module object */
70 protected HashMap module_map_=null;
71
72 /** container Document to create XML Nodes */
73 protected Document doc_=null;
74 /** the full description of this site */
75 protected Element description_ = null;
76 /** list of collections that can be reached */
77 protected Element collection_list_ = null;
78 /** list of services that can be reached */
79 protected Element service_list_ = null;
80 /** list of sites that can be reached */
81 protected Element site_list_ = null;
82
83 /** a converter class to parse XML and create Docs */
84 protected XMLConverter converter_=null;
85
86 //***************************************************************
87 // public methods
88 //***************************************************************
89
90 /** constructor */
91 public MessageRouter() {
92 module_map_ = new HashMap();
93 converter_ = new XMLConverter();
94 doc_ = converter_.newDOM();
95
96
97 }
98
99 /** site_home_ must be set before configure called */
100 public void setSiteHome(String home) {
101 site_home_ = home;
102 }
103
104 /**
105 * configures the system
106 *
107 * looks in site_home_/collect for collections, reads config file
108 * site_home_/sitecfg.xml
109 *
110 */
111 public boolean configure() {
112
113 if (site_home_==null) {
114 System.err.println("You must set site_home_ before calling configure");
115 return false;
116 }
117
118 // start the description_ XML tree
119 description_ = doc_.createElement("response");
120 description_.setAttribute("type", "describe");
121 collection_list_ = doc_.createElement("collectionList");
122 service_list_ = doc_.createElement("serviceList");
123 site_list_ = doc_.createElement("siteList");
124
125
126 // read thru own config file - create services and connect to sites
127 File configFile = new File(GSFile.siteConfigFile(site_home_));
128
129 if (configFile.exists() ) {
130 configureSystem(configFile);
131 }
132 else {
133 System.err.println("MessageRouter: site config file: "+configFile.getPath()+" not found!");
134 return false;
135
136 }
137
138 // read thru the collect directory and create all the collections
139 File collectDir = new File(GSFile.collectDir(site_home_));
140 if (collectDir.exists()) {
141 System.out.println("Reading thru directory "+collectDir.getPath()+" to find collections.");
142 File[] contents = collectDir.listFiles();
143 for (int i=0; i<contents.length;i++) {
144 if(contents[i].isDirectory()) {
145
146 String colName = contents[i].getName();
147 if (!colName.startsWith("CVS")) {
148 // need to ignore CVS
149 createCollection(colName);
150 }
151 }
152 }
153 } // collectDir
154
155 description_.appendChild(collection_list_);
156
157 return true;
158
159 }
160
161 /**
162 * Process an XML request - as a String
163 *
164 * @param xml_in the request to process
165 * @return the response - contains any error messages
166 * @see String
167 */
168 public String process(String xml_in) {
169
170 Document doc = converter_.getDOM(xml_in);
171
172 Node result = process(doc);
173 return converter_.getString(result);
174 }
175
176 /**
177 * Process an XML request - as a DOM model node
178 * the Node may be an Element or a Document
179 *
180 * @param xml_in the message to process - should be <message>
181 * @return the response - contains any error messages
182 * @see Node
183 * @see Document
184 * @see Element
185 */
186 public Node process(Node xml_in) {
187
188 // check if Element or Document - we want to deal with Elements
189 Element message=null;
190 short node_type = xml_in.getNodeType();
191 if (node_type == Node.DOCUMENT_NODE) {
192 message = ((Document)xml_in).getDocumentElement();
193 } else if (node_type == Node.ELEMENT_NODE) {
194 message = (Element)xml_in;
195 } else {
196 System.err.println("MessageRouter:process: invalid Node type");
197 }
198
199 // check that its a correct message tag
200 if (!message.getTagName().equals(GSDL_MESSAGE_NAME)) {
201 System.out.println("Invalid message. GSDL message should start with <"+GSDL_MESSAGE_NAME+">, instead it starts with:"+message.getTagName()+".");
202 return null;
203 }
204
205 NodeList requests = message.getElementsByTagName("request");
206
207 Element mainResult = doc_.createElement("message");
208
209 // empty request
210 if (requests.getLength()==0) {
211 return mainResult;
212 }
213
214 // for now, just process each request one by one
215 for (int i=0; i<requests.getLength(); i++) {
216 Node result=null;
217 Element req = (Element)requests.item(i);
218 String path = req.getAttribute("to"); // returns "" if no att of this name
219 if (path.equals("")) {
220 // its a message for the message router
221 result = processMessage(req);
222 } else {
223 // find the module to pass it on to
224 String obj = GSPath.getFirstLink(path);
225 if (module_map_.containsKey(obj)) {
226 result = ((ModuleInterface)module_map_.get(obj)).process(req);
227 } else {
228 System.err.println("MessageRouter: request has illegal module name in:\n"+converter_.getString(req));
229 }
230 }
231
232 if (result !=null ) {
233 // hack for now for external comms stuff
234 if (result.getNodeName().equals("message")) {
235 // remove the message bit
236 Node child = result.getFirstChild();
237 while (child !=null) {
238 mainResult.appendChild(doc_.importNode(child, true));
239 child = child.getNextSibling();
240 }
241 } else {
242 // just append the whole node
243 mainResult.appendChild(doc_.importNode(result, true));
244 }
245 }
246 } // for each request
247 return mainResult;
248
249 }
250
251 //********************************************************************
252 // auxiliary configure methods
253 // *******************************************************************
254
255 /**
256 * configures the message router based on the site config file
257 * - sitecfg.xml
258 *
259 */
260 protected boolean configureSystem(File file) {
261
262 System.out.println("MessageRouter:configuring site");
263 Document config_doc = converter_.getDOM(file);
264
265 NodeList local_site_name = config_doc.getElementsByTagName("localSiteName");
266 if (local_site_name.getLength()==0) {
267 System.err.println("MessageRouter configure error:no site name in config file");
268 return false;
269 } else {
270 Element elem = (Element)local_site_name.item(0);
271 site_name_ = elem.getAttribute("value");
272 }
273
274 // load up the services
275 System.out.println("loading service modules...");
276
277 NodeList service_modules = config_doc.getElementsByTagName("serviceModule");
278 if (service_modules.getLength()==0) {
279 System.out.println("... none to be loaded");
280 } else {
281
282 Element service_request = doc_.createElement("request");
283 service_request.setAttribute("type", "describe");
284 service_request.setAttribute("info", "serviceList");
285
286 for(int i=0; i<service_modules.getLength(); i++) {
287 Element n = (Element)service_modules.item(i);
288 String service_name = n.getAttribute("name");
289 System.out.println("..."+service_name);
290 try {
291 ServiceModule s = (ServiceModule)Class.forName("org.greenstone.gsdl3.service."+service_name).newInstance();
292 s.setSiteHome(site_home_);
293 s.setMessageRouter(this);
294
295 // pass the XML node to the service for service configuration
296 s.configure(n);
297
298 // find out the supported services for this service module
299 Element service_response = (Element) s.process(service_request);
300 NodeList services = service_response.getElementsByTagName("service");
301 if (services.getLength()==0) {
302 System.err.println("MessageRouter configure error: serviceModule "+service_name+" has no services!");
303 } else {
304 for (int j=0; j<services.getLength();j++) {
305 String service = ((Element)services.item(j)).getAttribute("name");
306 module_map_.put(service, s);
307
308 // add short info to service_list_ XML
309 service_list_.appendChild(doc_.importNode(services.item(j), true));
310 }
311 }
312 } catch (Exception e ) {
313 System.err.println("MessageRouter configure exception: in ServiceModule class specification: "+ e.getMessage());
314
315 }
316
317 } // for each service module
318 }
319
320 // load up the sites
321 System.out.println("loading external sites...");
322 NodeList sites = config_doc.getElementsByTagName("site");
323 if (sites.getLength()==0) {
324 System.out.println("...none found");
325 } else {
326
327 for (int i=0; i<sites.getLength(); i++) {
328 Element s = (Element)sites.item(i);
329 Communicator comm=null;
330 String type = s.getAttribute("type");
331 String name = s.getAttribute("name");
332 System.out.println("..."+name+", type="+type);
333 if (type.equals("soap")) {
334 comm = new SOAPCommunicator();
335 comm.setSiteHome(site_home_);
336 comm.setConnectionName(name);
337 comm.setConnectionAddress(s.getAttribute("address"));
338 comm.setSiteName(site_name_);
339
340 // add to map of modules
341 module_map_.put(name, comm);
342 site_list_.appendChild(doc_.importNode(s, true));
343 // need to get collection list and service list from here
344 // this may introduce a configure problem - leave as
345 // is for now, but fix up later - kjdon
346 getRemoteCollectionInfo(comm, name);
347 getRemoteServiceInfo(comm, name);
348
349 } else {
350 System.err.print("cant talk to server of type:"+type);
351 System.err.println(", so not making a connection to "+name);
352 }
353
354
355 }
356 }
357 // add children to description_
358 description_.appendChild(service_list_);
359 description_.appendChild(site_list_);
360
361 return true;
362
363 }
364
365 /** get collection list from external site
366 *
367 * @param comm - the communicator object for the external site
368 * @param site_name - the name of the external site
369 * @return true if successful
370 */
371 protected boolean getRemoteCollectionInfo(Communicator comm, String site_name) {
372 System.out.println("MessageRouter: getting coll info from site:"+site_name);
373 String coll_request = "<request type='describe' info='collectionList'/>";
374
375 String coll_response = comm.process(coll_request);
376
377 Document coll_doc = converter_.getDOM(coll_response);
378 NodeList colls = coll_doc.getElementsByTagName("collection");
379 if (colls.getLength()>0) {
380 for (int i=0; i<colls.getLength(); i++) {
381 Element e = (Element)colls.item(i);
382 String col_name = e.getAttribute("name");
383 // add the info to own coll list - may want to keep
384 // this separate in future - so can distinguish own and
385 // other collections
386 e.setAttribute("name", GSPath.prependLink(col_name, site_name));
387 collection_list_.appendChild(doc_.importNode(e, true));
388 }
389 }
390 return true;
391
392 }
393 /** get service list from external site
394 *
395 * @param comm - the communicator object for the external site
396 * @param site_name - the name of the external site
397 * @return true if successful
398 */
399 protected boolean getRemoteServiceInfo(Communicator comm, String site_name) {
400 System.out.println("MessageRouter: getting service info from site:"+site_name);
401 String serv_request = "<request type='describe' info='serviceList'/>";
402 String serv_response = comm.process(serv_request);
403 Document serv_doc = converter_.getDOM(serv_response);
404 NodeList services = serv_doc.getElementsByTagName("service");
405 if (services.getLength()>0) {
406 for (int i=0; i<services.getLength(); i++) {
407 Element e = (Element)services.item(i);
408 String serv_name = e.getAttribute("name");
409 System.out.println("found service name="+serv_name);
410 e.setAttribute("name", GSPath.prependLink(serv_name, site_name));
411 service_list_.appendChild(doc_.importNode(e, true));
412 }
413 }
414 return true;
415
416 }
417
418 /** creates and configures a new collection
419 *
420 *@param col_name the name of the collection
421 *@return true if collection created ok
422 */
423 protected boolean createCollection(String col_name) {
424
425 System.out.println("MessageRouter:Creating and configuring collection: "+col_name+".");
426
427 Collection c = new Collection();
428 c.setCollectionName(col_name);
429 c.setSiteHome(site_home_);
430 if (c.configure()) {
431 // add to list of collections
432 module_map_.put(col_name, c);
433 //add short description_ to collection_list_
434 Element e = doc_.createElement("collection");
435 e.setAttribute("name", col_name);
436 collection_list_.appendChild(e);
437 return true;
438 } else {
439 System.out.println("MessageRouter:Couldn't configure collection: "+
440 col_name+".");
441 return false;
442 }
443
444 }
445
446 //*****************************************************************
447 // auxiliary process methods
448 //*****************************************************************
449
450 /** handles requests made to the MessageRouter itself
451 *
452 * @param req - the request Element- <request>
453 * @return the result Element - should be <response>
454 */
455 protected Element processMessage(Element req) {
456
457 // message for self, should be type=describe at this stage
458 String type = req.getAttribute("type");
459
460 if (type.equals("describe")) {
461 String info = req.getAttribute("info");
462 if (info.equals("")) {
463 // return full description
464 return description_;
465 }
466 // else create a new response with the appropriate info
467 Element response = doc_.createElement("response");
468 response.setAttribute("type", "describe");
469
470 if (info.equals("collectionList")) {
471 response.appendChild(collection_list_);
472 return response;
473 } else if (info.equals("serviceList")) {
474 response.appendChild(service_list_);
475 return response;
476 } else if (info.equals("sitelist")) {
477 response.appendChild(site_list_);
478 return response;
479 }
480
481 }
482 // if get here something has gone wrong
483 System.err.println("MessageRouter: cant process request:");
484 System.err.println(converter_.getString(req));
485 return null;
486
487 }
488
489}
Note: See TracBrowser for help on using the repository browser.