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

Last change on this file since 3644 was 3644, checked in by kjdon, 21 years ago

tidying up

  • Property svn:keywords set to Author Date Id Revision
File size: 20.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: 3644 $
53 * @see ModuleInterface
54 * @see Collection
55 * @see ServiceRack
56 * @see Communicator
57 *
58 */
59public class MessageRouter implements ModuleInterface {
60
61 /** site home - the home directory for the site */
62 protected String site_home_=null;
63 /** the global name for this site */
64 protected String global_site_name_=null;
65
66 /** map of names to Module objects */
67 protected HashMap module_map_=null;
68
69 /** container Document to create XML Nodes */
70 protected Document doc_=null;
71 /** the full description of this site */
72 protected Element description_ = null;
73
74 // should these things be separated into local and remote??
75
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
84 /** list of sites that can be reached */
85 protected Element site_list_ = null;
86
87 /** a converter class to parse XML and create Docs */
88 protected XMLConverter converter_=null;
89
90 //***************************************************************
91 // public methods
92 //***************************************************************
93
94 /** constructor */
95 public MessageRouter() {
96 module_map_ = new HashMap();
97 converter_ = new XMLConverter();
98 doc_ = converter_.newDOM();
99
100
101 }
102
103 /** site_home_ must be set before configure called */
104 public void setSiteHome(String home) {
105 site_home_ = home;
106 }
107
108 /**
109 * configures the system
110 *
111 * looks in site_home_/collect for collections, reads config file
112 * site_home_/sitecfg.xml
113 *
114 */
115 public boolean configure() {
116
117 if (site_home_==null) {
118 System.err.println("You must set site_home_ before calling configure");
119 return false;
120 }
121
122 // start the description_ XML tree
123 description_ = doc_.createElement(GSXML.RESPONSE_ELEM);
124 description_.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_DESCRIBE);
125 collection_list_ = doc_.createElement(GSXML.COLLECTION_ELEM+GSXML.LIST_MODIFIER);
126 cluster_list_ = doc_.createElement(GSXML.CLUSTER_ELEM+GSXML.LIST_MODIFIER);
127 service_list_ = doc_.createElement(GSXML.SERVICE_ELEM+GSXML.LIST_MODIFIER);
128 site_list_ = doc_.createElement(GSXML.SITE_ELEM+GSXML.LIST_MODIFIER);
129
130
131 // read thru own config file - create services and connect to sites
132 File configFile = new File(GSFile.siteConfigFile(site_home_));
133
134 if (configFile.exists() ) {
135 configureSystem(configFile);
136 }
137 else {
138 System.err.println("MessageRouter: site config file: "+configFile.getPath()+" not found!");
139 return false;
140
141 }
142
143 // read thru the collect directory and activate all the valid collections
144 File collectDir = new File(GSFile.collectDir(site_home_));
145 if (collectDir.exists()) {
146 System.out.println("Reading thru directory "+collectDir.getPath()+" to find collections.");
147 File[] contents = collectDir.listFiles();
148 for (int i=0; i<contents.length;i++) {
149 if(contents[i].isDirectory()) {
150
151 String colName = contents[i].getName();
152 if (!colName.startsWith("CVS")) {
153 activateCollection(colName);
154 }
155 }
156 }
157 } // collectDir
158
159 description_.appendChild(collection_list_);
160
161 return true;
162
163 }
164
165 /**
166 * Process an XML request - as a String
167 *
168 * @param xml_in the request to process
169 * @return the response - contains any error messages
170 * @see String
171 */
172 public String process(String xml_in) {
173
174 Document doc = converter_.getDOM(xml_in);
175
176 Element result = process(doc.getDocumentElement());
177 return converter_.getString(result);
178 }
179
180 /**
181 * Process an XML request - as a DOM Element
182 *
183 * @param xml_in the message to process - should be <message>
184 * @return the response - contains any error messages
185 * @see Element
186 */
187 public Element process(Element message) {
188
189 // check that its a correct message tag
190 if (!message.getTagName().equals(GSXML.MESSAGE_ELEM)) {
191 System.out.println("Invalid message. GSDL message should start with <"+GSXML.MESSAGE_ELEM+">, instead it starts with:"+message.getTagName()+".");
192 return null;
193 }
194
195 NodeList requests = message.getElementsByTagName(GSXML.REQUEST_ELEM);
196
197 Element mainResult = doc_.createElement(GSXML.MESSAGE_ELEM);
198
199 // empty request
200 if (requests.getLength()==0) {
201 return mainResult;
202 }
203
204 Document message_doc = message.getOwnerDocument();
205
206 // for now, just process each request one by one, and append the results to mainResult
207 // Note: if you add an element to another node in the same document, it
208 // gets removed from where it was. This changes the node list - you cant iterate over the node list in a normal manner if you are moving elements out of it
209 int num_requests = requests.getLength();
210 for (int i=0; i< num_requests; i++) {
211 Node result=null;
212 Element req = (Element)requests.item(0);
213 String path = req.getAttribute(GSXML.TO_ATT); // returns "" if no att of this name
214 if (path.equals("")) {
215 // its a message for the message router
216 result = processMessage(req);
217 mainResult.appendChild(doc_.importNode(result, true));
218 } else {
219 // find the module to pass it on to
220 // need to put the request into a message element
221 Element mess = message_doc.createElement(GSXML.MESSAGE_ELEM);
222 mess.appendChild(req);
223 String obj = GSPath.getFirstLink(path);
224 if (module_map_.containsKey(obj)) {
225 result = ((ModuleInterface)module_map_.get(obj)).process(mess);
226 if (result !=null ) {
227 // append the contents of the message to the mainResult - there will only be one response at this stage
228 mainResult.appendChild(doc_.importNode(GSXML.getChildByTagName(result, GSXML.RESPONSE_ELEM), true));
229 } else {
230 System.err.println("MessageRouter Error: request had null result!");
231 }
232 } else {
233 System.err.println("MessageRouter Error: request has illegal module name in:\n"+converter_.getString(req));
234 }
235 }
236
237 } // for each request
238
239 return mainResult;
240
241 }
242
243 //********************************************************************
244 // auxiliary configure methods
245 // *******************************************************************
246
247 /**
248 * configures the message router based on the site config file
249 * - siteConfig.xml
250 *
251 */
252 protected boolean configureSystem(File file) {
253
254 System.out.println("MessageRouter:configuring site");
255 Element config = converter_.getDOM(file).getDocumentElement();
256
257 Element local_site_name = (Element)GSXML.getChildByTagName(config,
258 GSXML.SITE_NAME_ELEM);
259 if (local_site_name == null) {
260 System.err.println("MessageRouter configure error:no site name in config file");
261 return false;
262 } else {
263 global_site_name_ = local_site_name.getAttribute(GSXML.VALUE_ATT);
264 }
265
266 // load up the service clusters
267 System.out.println("loading service clusters ...");
268 Node cluster_list = GSXML.getChildByTagName(config,
269 GSXML.CLUSTER_ELEM+GSXML.LIST_MODIFIER);
270 if (cluster_list == null) {
271 System.out.println("... none to be loaded");
272 } else {
273 NodeList service_clusters = cluster_list.getChildNodes();
274 if (service_clusters.getLength()==0) {
275 System.out.println("... none to be loaded");
276 } else {
277
278 for (int i=0; i<service_clusters.getLength(); i++) {
279 if (service_clusters.item(i).getNodeName().equals(GSXML.CLUSTER_ELEM)) {
280 Element cluster = (Element)service_clusters.item(i);
281 String name = cluster.getAttribute(GSXML.NAME_ATT);
282 System.out.println("..."+name);
283 ServiceCluster sc = new ServiceCluster();
284 sc.setSiteHome(site_home_);
285 sc.setClusterName(name);
286 sc.setMessageRouter(this);
287 sc.configure(cluster);
288 module_map_.put(name, sc);
289 //add short info to
290 Element e = doc_.createElement(GSXML.CLUSTER_ELEM);
291 e.setAttribute(GSXML.NAME_ATT, name);
292 cluster_list_.appendChild(e);
293
294 }
295 }
296 }
297
298 }
299
300 // load up the individual services
301 System.out.println("loading service modules...");
302
303 Node module_list = GSXML.getChildByTagName(config,
304 GSXML.SERVICE_CLASS_ELEM+GSXML.LIST_MODIFIER);
305 if (module_list == null) {
306 System.out.println("... none to be loaded");
307 } else {
308 NodeList service_impls = module_list.getChildNodes();
309 if (service_impls.getLength()==0) {
310 System.out.println("... none to be loaded");
311 } else {
312
313 Element service_request = doc_.createElement(GSXML.REQUEST_ELEM);
314 service_request.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_DESCRIBE);
315 service_request.setAttribute(GSXML.INFO_ATT, GSXML.SERVICE_ELEM+GSXML.LIST_MODIFIER);
316
317 for(int i=0; i<service_impls.getLength(); i++) {
318 if (service_impls.item(i).getNodeName().equals(GSXML.SERVICE_CLASS_ELEM)) {
319 Element n = (Element)service_impls.item(i);
320 String service_name = n.getAttribute(GSXML.NAME_ATT);
321 System.out.println("..."+service_name);
322 try {
323 ServiceRack s = (ServiceRack)Class.forName("org.greenstone.gsdl3.service."+service_name).newInstance();
324 s.setSiteHome(site_home_);
325 s.setMessageRouter(this);
326
327 // pass the XML node to the service for service configuration
328 s.configure(n);
329
330 // find out the supported services for this service module
331 Element service_response = (Element) s.process(service_request);
332 NodeList services = service_response.getElementsByTagName(GSXML.SERVICE_ELEM);
333 if (services.getLength()==0) {
334 System.err.println("MessageRouter configure error: servicesImpl "+service_name+" has no services!");
335 } else {
336 for (int j=0; j<services.getLength();j++) {
337 String service = ((Element)services.item(j)).getAttribute(GSXML.NAME_ATT);
338 module_map_.put(service, s);
339
340 // add short info to service_list_ XML
341 service_list_.appendChild(doc_.importNode(services.item(j), true));
342 }
343 }
344 } catch (Exception e ) {
345 System.err.println("MessageRouter configure exception: in ServiceRack class specification: "+ e.getMessage());
346
347 }
348 } // if
349 } // for each service module
350 }
351 }
352
353 // load up the sites
354 System.out.println("loading external sites...");
355 Node site_list = GSXML.getChildByTagName(config, GSXML.SITE_ELEM+GSXML.LIST_MODIFIER);
356 if (site_list ==null ) {
357 System.out.println("...none found");
358 } else {
359 NodeList sites = site_list.getChildNodes();
360 if (sites.getLength()==0) {
361 System.out.println("...none found");
362 } else {
363
364 for (int i=0; i<sites.getLength(); i++) {
365 if (sites.item(i).getNodeName().equals(GSXML.SITE_ELEM)) {
366 Element s = (Element)sites.item(i);
367 Communicator comm=null;
368 String type = s.getAttribute(GSXML.TYPE_ATT);
369 String name = s.getAttribute(GSXML.NAME_ATT);
370 if (type.equals(GSXML.COMM_TYPE_SOAP_JAVA)) {
371 comm = new SOAPCommunicator();
372 if (comm.configure(s)) {
373 comm.setLocalSiteName(global_site_name_);
374
375 // add to map of modules
376 module_map_.put(name, comm);
377 site_list_.appendChild(doc_.importNode(s, true));
378 // need to get collection list and service
379 // list from here- this may introduce a
380 // configure problem - leave as is for now,
381 // but fix up later - kjdon
382 if (!getRemoteSiteInfo(comm, name)) {
383 System.err.println("couldn't get info from site "+name);
384 }
385 } else {
386 System.err.println("couldn't configure soap site:"+name);
387 }
388
389 } else {
390 System.err.print("cant talk to server of type:"+type);
391 System.err.println(", so not making a connection to "+name);
392 }
393
394 }
395 }
396 }
397 }
398 // add children to description_
399 description_.appendChild(cluster_list_);
400 description_.appendChild(service_list_);
401 description_.appendChild(site_list_);
402
403 return true;
404
405 }
406
407
408 /** get site info from external site
409 *
410 * @param comm - the communicator object for the external site
411 * @param site_name - the name of the external site
412 * @return true if successful
413 */
414 protected boolean getRemoteSiteInfo(Communicator comm, String site_name) {
415
416 System.out.println("MessageRouter: getting info from site:"+site_name);
417
418 Element info_request = doc_.createElement(GSXML.MESSAGE_ELEM);
419 Element req = doc_.createElement(GSXML.REQUEST_ELEM);
420 info_request.appendChild(req);
421 req.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_DESCRIBE);
422
423 // process the message
424 Element info_response = comm.process(info_request);
425 if (info_response == null) {
426 return false;
427 }
428 // collection info
429 NodeList colls = info_response.getElementsByTagName(GSXML.COLLECTION_ELEM);
430 if (colls.getLength()>0) {
431 for (int i=0; i<colls.getLength(); i++) {
432 Element e = (Element)colls.item(i);
433 String col_name = e.getAttribute(GSXML.NAME_ATT);
434 // add the info to own coll list - may want to keep
435 // this separate in future - so can distinguish own and
436 // other collections ??
437 e.setAttribute(GSXML.NAME_ATT, GSPath.prependLink(col_name, site_name));
438 collection_list_.appendChild(doc_.importNode(e, true));
439 }
440 }
441
442 // service info
443 NodeList services = info_response.getElementsByTagName(GSXML.SERVICE_ELEM);
444 if (services.getLength()>0) {
445 for (int i=0; i<services.getLength(); i++) {
446 Element e = (Element)services.item(i);
447 String serv_name = e.getAttribute(GSXML.NAME_ATT);
448 System.out.println("found service name="+serv_name);
449 e.setAttribute(GSXML.NAME_ATT, GSPath.prependLink(serv_name, site_name));
450 service_list_.appendChild(doc_.importNode(e, true));
451 }
452 }
453
454 // serviceCluster info
455 NodeList clusters = info_response.getElementsByTagName(GSXML.CLUSTER_ELEM);
456 if (clusters.getLength()>0) {
457 for (int i=0; i<clusters.getLength(); i++) {
458 Element e = (Element)clusters.item(i);
459 String clus_name = e.getAttribute(GSXML.NAME_ATT);
460 System.out.println("found cluster name="+clus_name);
461 e.setAttribute(GSXML.NAME_ATT, GSPath.prependLink(clus_name, site_name));
462 cluster_list_.appendChild(doc_.importNode(e, true));
463 }
464 }
465 return true;
466 }
467
468
469 /** creates and configures a new collection
470 *
471 *@param col_name the name of the collection
472 *@return true if collection created ok
473 */
474 protected boolean activateCollection(String col_name) {
475
476 System.out.println("MessageRouter:Activating collection: "+col_name+".");
477
478 Collection c = new Collection();
479 c.setCollectionName(col_name);
480 c.setSiteHome(site_home_);
481 if (c.configure()) {
482 // this could be a reactivation, so delete the old version
483 deactivate(GSXML.COLLECTION_ELEM, col_name);
484 // add to list of collections
485 module_map_.put(col_name, c);
486 //add short description_ to collection_list_
487 Element e = doc_.createElement(GSXML.COLLECTION_ELEM);
488 e.setAttribute(GSXML.NAME_ATT, col_name);
489 collection_list_.appendChild(e);
490 return true;
491 } else {
492 System.out.println("MessageRouter:Couldn't configure collection: "+
493 col_name+".");
494 return false;
495 }
496
497 }
498
499 protected boolean activateServiceCluster(String cluster_name) {
500 return false;
501
502 }
503
504 protected boolean activateServiceRack(String module_name) {
505 return false;
506 }
507
508 //*****************************************************************
509 // auxiliary process methods
510 //*****************************************************************
511
512 /** handles requests made to the MessageRouter itself
513 *
514 * @param req - the request Element- <request>
515 * @return the result Element - should be <response>
516 */
517 protected Element processMessage(Element req) {
518
519 // message for self, should be type=describe/configure at this stage
520 String type = req.getAttribute(GSXML.TYPE_ATT);
521 Element response = doc_.createElement(GSXML.RESPONSE_ELEM);
522
523 if (type.equals(GSXML.REQUEST_TYPE_DESCRIBE)) {
524 String info = req.getAttribute(GSXML.INFO_ATT);
525 if (info.equals("")) {
526 // return full description
527 return description_;
528 }
529 // use the new response with the appropriate info
530 response.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_DESCRIBE);
531
532 if (info.equals(GSXML.COLLECTION_ELEM+GSXML.LIST_MODIFIER)) {
533 response.appendChild(collection_list_);
534 return response;
535 } else if (info.equals(GSXML.CLUSTER_ELEM+GSXML.LIST_MODIFIER)) {
536 response.appendChild(cluster_list_);
537 return response;
538 } else if (info.equals(GSXML.SERVICE_ELEM+GSXML.LIST_MODIFIER)) {
539 response.appendChild(service_list_);
540 return response;
541 } else if (info.equals(GSXML.SITE_ELEM+GSXML.LIST_MODIFIER)) {
542 response.appendChild(site_list_);
543 return response;
544 }
545
546 } else if (type.equals(GSXML.REQUEST_TYPE_CONFIGURE)) {
547
548 // a list of configure requests - should put any error messages
549 // or success messages into response
550 NodeList commands = req.getElementsByTagName(GSXML.CONFIGURE_ELEM);
551 for (int i=0; i<commands.getLength(); i++) {
552 // all the commands should be Elements
553 Element elem = (Element)commands.item(i);
554 String action = elem.getAttribute(GSXML.ACTION_ATT);
555 String module_name = elem.getAttribute(GSXML.NAME_ATT);
556 String module_type = elem.getAttribute(GSXML.TYPE_ATT);
557 if (action.equals(GSXML.CONFIG_ACTION_ACTIVATE)) {
558 if (module_type.equals(GSXML.COLLECTION_ELEM)) {
559 activateCollection(module_name);
560 } else if (module_type.equals(GSXML.SERVICE_CLASS_ELEM)) {
561 activateServiceRack(module_name);
562 } else if (module_type.equals(GSXML.CLUSTER_ELEM)) {
563 activateServiceCluster(module_name);
564 } else {
565 // cant process the activation
566 // send an error
567 }
568 } else if (action.equals(GSXML.CONFIG_ACTION_DEACTIVATE)) {
569 deactivate(module_type, module_name);
570
571 }
572 }
573
574 return response;
575
576 }
577 // if get here something has gone wrong
578 System.err.println("MessageRouter: cant process request:");
579 System.err.println(converter_.getString(req));
580 return null;
581
582 }
583
584 protected boolean deactivate(String type, String name) {
585
586 if (module_map_.containsKey(name)) {
587
588 System.out.println("MessageRouter: deactivating thing, name="+name);
589 module_map_.remove(name);
590
591 // also remove the xml bit from description list
592 if (type.equals(GSXML.COLLECTION_ELEM)) {
593 Element this_col = GSXML.getNamedElement(collection_list_, GSXML.COLLECTION_ELEM, GSXML.NAME_ATT, name);
594 collection_list_.removeChild(this_col);
595 return true;
596 } else if (type.equals(GSXML.SERVICE_ELEM)) {
597 Element this_service = GSXML.getNamedElement(service_list_, GSXML.SERVICE_ELEM, GSXML.NAME_ATT, name);
598 service_list_.removeChild(this_service);
599 return true;
600 } else if (type.equals(GSXML.CLUSTER_ELEM)) {
601 Element this_cluster = GSXML.getNamedElement(cluster_list_, GSXML.CLUSTER_ELEM, GSXML.NAME_ATT, name);
602 cluster_list_.removeChild(this_cluster);
603 return true;
604 } else {
605 System.out.println("couldn't deactivate coll");
606 // couldn't do it
607 return false;
608 }
609 }
610 // else not activated
611 return false;
612
613 }
614}
615
616
Note: See TracBrowser for help on using the repository browser.