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

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

now looks for service clusters in its config file, and loads them up too.

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