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

Last change on this file since 15027 was 15027, checked in by kjdon, 16 years ago

tidied up this file, working on configure and reconfigure stuff. Hopefully when reconfiguring, all the old Module objects will now be cleaned up properly (releasing file handles) before the new ones are created.

  • Property svn:keywords set to Author Date Id Revision
File size: 40.6 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.io.Reader;
37import java.io.StringReader;
38import java.net.Authenticator;
39import java.net.PasswordAuthentication;
40import java.util.HashMap;
41import java.util.Iterator;
42import java.util.Properties;
43
44import org.apache.log4j.*;
45
46/**
47 * The hub of a Greenstone system.
48 *
49 * Accepts XML requests (via process method of ModuleInterface) and routes them to the appropriate collection or
50 * service or external entity.
51 *
52 * contains a map of module objects - may be services, collections, comms
53 * objects talking to other MessageRouters etc.
54 *
55 *
56 * @author <a href="mailto:[email protected]">Katherine Don</a>
57 * @version $Revision: 15027 $
58 * @see ModuleInterface
59 * @see Collection
60 * @see ServiceRack
61 * @see Communicator
62 *
63 * Since some service classes are moved into a separate directory in order for them to be checked out from a different repository,
64 * we modify the configureServices method to search some of the classes in other place if they are not found in the service directory.
65 */
66public class MessageRouter implements ModuleInterface {
67
68 static Logger logger = Logger.getLogger(org.greenstone.gsdl3.core.MessageRouter.class.getName());
69
70 /** the (directory) name of the site */
71 protected String site_name = null;
72 /** site home - the home directory for the site */
73 protected String site_home=null;
74 /** the http address for this site */
75 protected String site_http_address=null;
76
77
78 protected String library_name = null;
79
80 /** map of names to Module objects */
81 protected HashMap module_map=null;
82
83 /** container Document to create XML Nodes */
84 protected Document doc=null;
85 /** the full description of this site */
86
87 // should these things be separated into local and remote??
88
89 /** the original xml config element */
90 public Element config_info = null;
91
92 /** list of collections that can be reached */
93 protected Element collection_list = null;
94 /** list of collections that are loaded but are private */
95 protected Element private_collection_list = null;
96
97
98 /** list of collections that are public and OAI-supportive */
99 protected Element oai_collection_list = null;
100
101 /** list of service clusters that can be reached */
102 protected Element cluster_list = null;
103 /** list of single services that can be reached */
104 protected Element service_list = null;
105 /** list of sites that can be reached */
106 protected Element site_list = null;
107
108
109 /** a converter class to parse XML and create Docs */
110 protected XMLConverter converter=null;
111
112 //***************************************************************
113 // public methods
114 //***************************************************************
115
116 /** constructor */
117 public MessageRouter() {
118 this.converter = new XMLConverter();
119 this.doc = this.converter.newDOM();
120 }
121
122 public void cleanUp() {
123 cleanUpModuleMapEntire();
124 }
125
126 /** site_name must be set before configure is called */
127 public void setSiteName(String site_name) {
128 this.site_name = site_name;
129 }
130 public String getSiteName() {
131 return this.site_name;
132 }
133
134 /** library_name must be set before configure is called */
135 public void setLibraryName(String library_name) {
136 this.library_name = library_name;
137 }
138 public String getLibraryName() {
139 return this.library_name;
140 }
141
142 /**
143 * configures the system
144 *
145 * looks in site_home/collect for collections, reads config file
146 * site_home/siteConfig.xml
147 *
148 */
149 public boolean configure() {
150
151 logger.info("configuring the Message Router");
152
153 if (this.site_name==null) {
154 logger.error(" You must set site_name before calling configure");
155 return false;
156 }
157 this.site_home = GSFile.siteHome(GlobalProperties.getGSDL3Home(), this.site_name);
158 this.site_http_address = GlobalProperties.getGSDL3WebAddress()+"/sites/"+this.site_name;
159
160 // are we behind a firewall?? - is there a better place to set up the proxy?
161 String host = GlobalProperties.getProperty("proxy.host");
162 String port = GlobalProperties.getProperty("proxy.port");
163 final String user = GlobalProperties.getProperty("proxy.user");
164 final String passwd = GlobalProperties.getProperty("proxy.password");
165
166 if (host != null && !host.equals("") && port !=null && !port.equals("")) {
167 System.setProperty("http.proxyType", "4");
168 System.setProperty("http.proxyHost", host);
169 System.setProperty("http.proxyPort", port);
170 System.setProperty("http.proxySet", "true");
171 // have we got a user/password?
172 if (user != null && !user.equals("") && passwd != null && !passwd.equals("")) {
173 try {
174 // set up the authenticator
175 Authenticator.setDefault(new Authenticator(){
176 protected PasswordAuthentication getPasswordAuthentication(){
177 return new PasswordAuthentication(user, new String(passwd).toCharArray());
178 }
179 });
180
181 } catch (Exception e) {
182 logger.error("MessageRouter Error: couldn't set up an authenticator the proxy");
183
184 }
185 }
186 }
187
188 this.module_map = new HashMap();
189
190 // This stuff may be done at a reconfigure also
191 return configureLocalSite();
192
193 }
194
195
196 /**
197 * Process an XML request - as a String
198 *
199 * @param xml_in the request to process
200 * @return the response - contains any error messages
201 * @see String
202 */
203 public String process(String xml_in) {
204
205 Document doc = this.converter.getDOM(xml_in);
206
207 Element result = process(doc.getDocumentElement());
208 return this.converter.getString(result);
209 }
210
211 /**
212 * Process an XML request - as a DOM Element
213 *
214 * @param xml_in the message to process - should be <message>
215 * @return the response - contains any error messages
216 * @see Element
217 */
218 public Element process(Element message) {
219
220 // check that its a correct message tag
221 if (!message.getTagName().equals(GSXML.MESSAGE_ELEM)) {
222 logger.error(" Invalid message. GSDL message should start with <"+GSXML.MESSAGE_ELEM+">, instead it starts with:"+message.getTagName()+".");
223 return null;
224 }
225
226 NodeList requests = message.getElementsByTagName(GSXML.REQUEST_ELEM);
227
228 Element mainResult = this.doc.createElement(GSXML.MESSAGE_ELEM);
229
230 // empty request
231 if (requests.getLength()==0) {
232 logger.error("empty request");
233 return mainResult;
234 }
235
236 Document message_doc = message.getOwnerDocument();
237
238 // for now, just process each request one by one, and append the results to mainResult
239 // Note: if you add an element to another node in the same document, it
240 // 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
241 int num_requests = requests.getLength();
242 for (int i=0; i< num_requests; i++) {
243 Node result=null;
244 Element req = (Element)requests.item(i);
245 if (req == null) {
246 logger.error("request "+i+" is null");
247 continue;
248 }
249 String path = req.getAttribute(GSXML.TO_ATT); // returns "" if no att of this name
250 if (path.equals("")) {
251 // its a message for the message router
252 String type_att = req.getAttribute(GSXML.TYPE_ATT);
253 if (type_att.equals(GSXML.REQUEST_TYPE_MESSAGING)) {
254 // its a messaging request - modifies the requests/responses
255 result = modifyMessages(req, message, mainResult);
256 } else {
257 // standard request
258 result = processMessage(req);
259 }
260
261 mainResult.appendChild(this.doc.importNode(result, true));
262 } else {
263 // The message needs to go to another module. The same message can
264 // be passed to multiple modules - they will be in a comma
265 // separated list in the 'to' attribute
266 String [] modules = path.split(",");
267
268 for (int j=0; j<modules.length; j++) {
269 // why can't we do this outside the loop??
270 Element mess = this.doc.createElement(GSXML.MESSAGE_ELEM);
271 Element copied_request = (Element)this.doc.importNode(req, true);
272 mess.appendChild(copied_request);
273
274 String this_mod = modules[j];
275 // find the module to pass it on to
276 // need to put the request into a message element
277 String obj = GSPath.getFirstLink(this_mod);
278
279 if (this.module_map.containsKey(obj)) {
280 copied_request.setAttribute(GSXML.TO_ATT, this_mod);
281 result = ((ModuleInterface)this.module_map.get(obj)).process(mess);
282 if (result !=null ) {
283 // append the contents of the message to the mainResult - there will only be one response at this stage
284 Node res = GSXML.getChildByTagName(result, GSXML.RESPONSE_ELEM);
285 if (res != null){
286 mainResult.appendChild(this.doc.importNode(res, true));
287
288 }
289 } else {
290 // add in a place holder response
291 Element response = this.doc.createElement(GSXML.RESPONSE_ELEM);
292 response.setAttribute(GSXML.FROM_ATT, this_mod);
293 mainResult.appendChild(response);
294 logger.error("MessageRouter Error: request had null result!");
295 }
296
297 } else {
298 logger.error("MessageRouter Error: request has illegal module name in:\n"+this.converter.getString(req));
299 }
300 }
301 }
302
303 } // for each request
304
305 logger.debug("MR returned response");
306 logger.debug(this.converter.getString(mainResult));
307
308 return mainResult;
309 }
310
311 // ********************************************************************
312 // auxiliary configure and cleanup methods
313 // *******************************************************************
314
315 /** Calls clean up on all modules referenced in the module_map and
316 removes them . */
317 protected void cleanUpModuleMapEntire() {
318 if (this.module_map != null) {
319 Iterator i = this.module_map.values().iterator();
320 while (i.hasNext()) {
321 ((ModuleInterface)i.next()).cleanUp();
322 i.remove();
323 }
324 }
325 }
326
327 /**
328 Goes through the children of list, and for each local/site-specific
329 name attribute, calls cleanUp on the module and removes it from the
330 module_map and removes it from the list
331 */
332 protected void cleanUpModuleMapSubset(Element list, String remote_site) {
333 logger.error(this.converter.getString(list));
334 NodeList elements = list.getChildNodes(); // we are assuming no extraneous nodes
335 for(int i=elements.getLength()-1; i>=0; i--) {
336 Element item = (Element)elements.item(i);
337 String name = item.getAttribute(GSXML.NAME_ATT);
338 String potential_site_name = GSPath.getFirstLink(name);
339 if (remote_site != null) {
340 if (remote_site.equals(potential_site_name)) {
341 list.removeChild(item);
342 }
343 } else {
344 if (name.equals(potential_site_name)) {// there was no site
345 list.removeChild(item);
346 ModuleInterface m = (ModuleInterface)this.module_map.remove(name);
347 m.cleanUp(); // clean up any open files/connections etc
348 m=null;
349 }
350 }
351 }
352
353 logger.error(this.converter.getString(list));
354
355 }
356
357 /** removes all site modules from module_map, and any stored info about this sites collections and services */
358 protected void cleanUpAllExternalSiteInfo() {
359
360 NodeList site_nodes = this.site_list.getChildNodes();
361 for(int i=site_nodes.getLength()-1; i>=0; i--) {
362 Element item = (Element)site_nodes.item(i);
363 String name = item.getAttribute(GSXML.NAME_ATT);
364 // will remove the node from site_list
365 deactivateModule(GSXML.SITE_ELEM, name);
366 }
367
368 }
369 /** read thru own site config file - create services and connect to sites
370 */
371 protected boolean configureLocalSite() {
372
373 // this may be a reconfigure, so clean up the old moduleMap
374 cleanUpModuleMapEntire();
375
376 File configFile = new File(GSFile.siteConfigFile(this.site_home));
377
378 if (!configFile.exists() ) {
379 logger.error(" site config file: "+configFile.getPath()+" not found!");
380 return false;
381 }
382
383 Document config_doc = this.converter.getDOM(configFile);
384 if (config_doc == null) {
385 logger.error(" couldn't parse site config file: "+configFile.getPath());
386 return false;
387 }
388
389 this.config_info = config_doc.getDocumentElement();
390
391 // load up the services: serviceRackList
392 this.service_list = this.doc.createElement(GSXML.SERVICE_ELEM+GSXML.LIST_MODIFIER);
393 Element service_rack_list_elem = (Element)GSXML.getChildByTagName(config_info, GSXML.SERVICE_CLASS_ELEM+GSXML.LIST_MODIFIER);
394 configureServices(service_rack_list_elem);
395
396 // load up the service clusters
397 this.cluster_list = this.doc.createElement(GSXML.CLUSTER_ELEM+GSXML.LIST_MODIFIER);
398 Element cluster_list_elem = (Element)GSXML.getChildByTagName(config_info, GSXML.CLUSTER_ELEM+GSXML.LIST_MODIFIER);
399 configureClusters(cluster_list_elem);
400
401 // load up the collections
402 this.collection_list = this.doc.createElement(GSXML.COLLECTION_ELEM+GSXML.LIST_MODIFIER);
403 this.private_collection_list = this.doc.createElement(GSXML.COLLECTION_ELEM+GSXML.LIST_MODIFIER);
404 this.oai_collection_list = this.doc.createElement(GSXML.COLLECTION_ELEM+GSXML.LIST_MODIFIER);
405 configureCollections();
406
407 // load up the external sites - this also adds their services/clusters/collections to the other lists - so must be done last
408 this.site_list = this.doc.createElement(GSXML.SITE_ELEM+GSXML.LIST_MODIFIER);
409 Element site_list_elem = (Element)GSXML.getChildByTagName(config_info, GSXML.SITE_ELEM+GSXML.LIST_MODIFIER);
410 configureExternalSites(site_list_elem);
411
412 return true;
413
414 }
415
416 protected boolean configureServices(Element service_rack_list) {
417
418
419 // load up the individual services
420 logger.info("loading service modules...");
421
422 if (service_rack_list == null) {
423 logger.info("... none to be loaded");
424 return true;
425 }
426
427 NodeList service_racks = service_rack_list.getElementsByTagName(GSXML.SERVICE_CLASS_ELEM);
428 if (service_racks.getLength()==0) {
429 logger.info("... none to be loaded");
430 return true;
431 }
432
433 Element service_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
434 Element service_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_DESCRIBE, "", "", "");
435 service_message.appendChild(service_request);
436
437 for(int i=0; i<service_racks.getLength(); i++) {
438 Element n = (Element)service_racks.item(i);
439 String service_name = n.getAttribute(GSXML.NAME_ATT);
440 logger.info("..."+service_name);
441
442 Class service_class = null;
443 try {
444 service_class = Class.forName("org.greenstone.gsdl3.service."+service_name);
445 } catch(ClassNotFoundException e) {
446
447 try {
448 //try the service_name alone in case the package name is already specified
449 service_class = Class.forName(service_name);
450
451 }catch(ClassNotFoundException ae) {
452 logger.info(ae.getMessage());
453 }
454 }
455 try {
456
457 ServiceRack s = (ServiceRack)service_class.newInstance();
458 s.setSiteHome(this.site_home);
459 s.setSiteAddress(this.site_http_address);
460 s.setLibraryName(this.library_name);
461 s.setMessageRouter(this);
462 // pass the XML node to the service for service configuration
463 if (!s.configure(n, null)) {
464 logger.error ("couldn't configure ServiceRack "+service_name);
465 continue;
466 }
467
468 // find out the supported services for this service module
469 Element service_response = (Element) s.process(service_message);
470 NodeList services = service_response.getElementsByTagName(GSXML.SERVICE_ELEM);
471 if (services.getLength()==0) {
472 logger.error("MessageRouter configure error: serviceRack "+service_name+" has no services!");
473 } else {
474 for (int j=0; j<services.getLength();j++) {
475 String service = ((Element)services.item(j)).getAttribute(GSXML.NAME_ATT);
476 this.module_map.put(service, s);
477
478 // add short info to service_list_ XML
479 this.service_list.appendChild(this.doc.importNode(services.item(j), true));
480 }
481 }
482 } catch (Exception e ) {
483 logger.error("MessageRouter configure exception: in ServiceRack class specification: "+ e.getMessage());
484 e.printStackTrace();
485 }
486 } // for each service module
487 return true;
488 }
489
490 protected boolean configureClusters(Element config_cluster_list) {
491
492 // load up the service clusters
493 logger.info("loading service clusters ...");
494 if (config_cluster_list == null) {
495 logger.info("... none to be loaded");
496 return true;
497 }
498 NodeList service_clusters = config_cluster_list.getElementsByTagName(GSXML.CLUSTER_ELEM);
499 if (service_clusters.getLength()==0) {
500 logger.info("... none to be loaded");
501 return true;
502 }
503
504 for (int i=0; i<service_clusters.getLength(); i++) {
505 Element cluster = (Element)service_clusters.item(i);
506 String name = cluster.getAttribute(GSXML.NAME_ATT);
507 logger.info("..."+name);
508 ServiceCluster sc = new ServiceCluster();
509 sc.setSiteHome(this.site_home);
510 sc.setSiteAddress(this.site_http_address);
511 sc.setClusterName(name);
512 sc.setMessageRouter(this);
513 if (!sc.configure(cluster)) {
514 logger.error ("couldn't configure ServiceCluster "+name);
515 continue;
516 }
517
518 this.module_map.put(name, sc); // this replaces the old one if there was one already present
519 //add short info to cluster list
520 Element e = this.doc.createElement(GSXML.CLUSTER_ELEM);
521 e.setAttribute(GSXML.NAME_ATT, name);
522 this.cluster_list.appendChild(e);
523
524 }
525 return true;
526 }
527
528 /** looks through the collect directory and activates any collections it finds. If this is a reconfigure, clean up must be done first before calling this */
529 protected boolean configureCollections() {
530
531 // read thru the collect directory and activate all the valid collections
532 File collectDir = new File(GSFile.collectDir(this.site_home));
533 if (collectDir.exists()) {
534 logger.info("Reading thru directory "+collectDir.getPath()+" to find collections.");
535 File[] contents = collectDir.listFiles();
536 for (int i=0; i<contents.length;i++) {
537 if(contents[i].isDirectory()) {
538
539 String colName = contents[i].getName();
540 if (!colName.startsWith("CVS") && !colName.startsWith(".svn")) {
541 activateCollectionByName(colName);
542 }
543 }
544 }
545 } // collectDir
546 return true;
547 }
548
549 /** creates and configures a new collection
550 if this is done for a reconfigure, the collection should be deactivated first.
551 *
552 *@param col_name the name of the collection
553 *@return true if collection created ok
554 */
555 protected boolean activateCollectionByName(String col_name) {
556
557 logger.info("Activating collection: "+col_name+".");
558
559 // Look for the etc/collectionInit.xml file, and see what sort of Collection to load
560 Collection c = null;
561 File init_file = new File(GSFile.collectionInitFile(this.site_home, col_name));
562
563 if (init_file.exists()) {
564 Document init_doc = this.converter.getDOM(init_file);
565 if (init_doc != null) {
566 Element init_elem = init_doc.getDocumentElement();
567 if (init_elem != null) {
568 String coll_class_name = init_elem.getAttribute("class");
569 if (!coll_class_name.equals("")) {
570 try {
571 c = (Collection)Class.forName("org.greenstone.gsdl3.collection."+coll_class_name).newInstance();
572 } catch (Exception e) {
573 logger.info(" couldn't create a new collection, type "+coll_class_name+", defaulting to class Collection");
574 }
575 }
576 }
577 }
578 }
579 if (c==null) { // we haven't found another classname to use
580 c = new Collection();
581 }
582
583 c.setCollectionName(col_name);
584 c.setSiteHome(this.site_home);
585 c.setSiteAddress(this.site_http_address);
586 c.setMessageRouter(this);
587 if (c.configure()) {
588 logger.info("have just configured collection " + col_name);
589 // add to list of collections
590 this.module_map.put(col_name, c);
591 Element e = this.doc.createElement(GSXML.COLLECTION_ELEM);
592 e.setAttribute(GSXML.NAME_ATT, col_name);
593
594 if(c.isPublic()) {
595 // only public collections will appear on the home page
596 // add short description_ to collection_list_
597 this.collection_list.appendChild(e);
598
599 if (c.hasOAI()) {
600 Element ane = this.doc.createElement(GSXML.COLLECTION_ELEM);
601 //The collection name is returned as site_name:coll_name, which is in fact the set specification
602 ane.setAttribute(GSXML.NAME_ATT, site_name + ":" + col_name);
603 ane.setAttribute(OAIXML.LASTMODIFIED, "" + c.getLastmodified());
604
605 this.oai_collection_list.appendChild(ane);
606 //logger.info(GSXML.xmlNodeToString(oai_collection_list));
607 }
608
609 } else {
610 this.private_collection_list.appendChild(e);
611 }
612 return true;
613 } else {
614 logger.error("Couldn't configure collection: "+
615 col_name+".");
616 return false;
617 }
618 }
619
620
621 /** Goes through the siteList and activates each site found. If this is done for a reconfigure, a clean up must be done first ****HOW??? */
622 protected boolean configureExternalSites(Element config_site_list) {
623
624 // load up the sites
625 logger.info("loading external sites...");
626 if (config_site_list ==null ) {
627 logger.info("...none found");
628 return true;
629 }
630
631 NodeList sites = config_site_list.getElementsByTagName(GSXML.SITE_ELEM);
632 if (sites.getLength()==0) {
633 logger.info("...none found");
634 return true;
635 }
636
637 // this is a name to identify the current site in the Communicator
638 String local_site_name = config_site_list.getAttribute(GSXML.LOCAL_SITE_NAME_ATT);
639 if (local_site_name.equals("")) {
640 local_site_name = site_name;
641 }
642
643 for (int i=0; i<sites.getLength(); i++) {
644 Element s = (Element)sites.item(i);
645 activateSite(s, local_site_name);
646 }
647 return true;
648 }
649
650 protected boolean activateSiteByName(String site_name) {
651 logger.info("Activating site: "+site_name+".");
652
653 File configFile = new File(GSFile.siteConfigFile(this.site_home));
654
655 if (!configFile.exists() ) {
656 logger.error(" site config file: "+configFile.getPath()+" not found!");
657 return false;
658 }
659 Document config_doc = this.converter.getDOM(configFile);
660 if (config_doc == null) {
661 logger.error(" couldn't parse site config file: "+configFile.getPath());
662 return false;
663 }
664 Element config_elem = config_doc.getDocumentElement();
665
666 Element config_site_list = (Element)GSXML.getChildByTagName(config_elem, GSXML.SITE_ELEM+GSXML.LIST_MODIFIER);
667 if (config_site_list ==null ) {
668 logger.error("activateSite, no sites found");
669 return false;
670 }
671 // this is a name to identify the current site in the Communicator
672 String local_site_name = config_site_list.getAttribute("localSiteName");
673 if (local_site_name.equals("")) {
674 local_site_name = site_name;
675 }
676
677 Element this_site_elem = GSXML.getNamedElement(config_site_list, GSXML.SITE_ELEM, GSXML.NAME_ATT, site_name);
678 if (this_site_elem == null) {
679 logger.error("activateSite, site "+site_name+" not found");
680 return false;
681 }
682
683 return activateSite(this_site_elem, local_site_name);
684 }
685
686 protected boolean activateSite(Element site_elem, String local_site_name) {
687
688 Communicator comm=null;
689 String type = site_elem.getAttribute(GSXML.TYPE_ATT);
690 String name = site_elem.getAttribute(GSXML.NAME_ATT);
691 if (type.equals(GSXML.COMM_TYPE_SOAP_JAVA)) {
692 logger.info("activating SOAP site "+name);
693 comm = new SOAPCommunicator();
694 if (comm.configure(site_elem)) {
695 comm.setLocalSiteName(local_site_name);
696
697 // add to map of modules
698 this.module_map.put(name, comm);
699 this.site_list.appendChild(this.doc.importNode(site_elem, true));
700 // need to get collection list and service
701 // list from here- if the site isn't up yet, the site will
702 // have to be added later
703 if (!getRemoteSiteInfo(comm, name)) {
704 logger.error(" couldn't get info from site");
705 }
706 } else {
707 logger.error(" couldn't configure site");
708 return false;
709 }
710
711 } else {
712 System.err.print(" cant talk to server of type:"+type + ", so not making a connection to "+name);
713 return false;
714 }
715 return true;
716 }
717
718 /** get site info from external site
719 *
720 * @param comm - the communicator object for the external site
721 * @param site_name - the name of the external site
722 * @return true if successful
723 */
724 protected boolean getRemoteSiteInfo(Communicator comm, String site_name) {
725
726 logger.info(" getting info from site:"+site_name);
727
728 Element info_request = this.doc.createElement(GSXML.MESSAGE_ELEM);
729 Element req = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_DESCRIBE, "", "", "");
730 info_request.appendChild(req);
731
732 // process the message
733 Element info_response = comm.process(info_request);
734 if (info_response == null) {
735 return false;
736 }
737 // collection info
738 NodeList colls = info_response.getElementsByTagName(GSXML.COLLECTION_ELEM);
739 if (colls.getLength()>0) {
740 for (int i=0; i<colls.getLength(); i++) {
741 Element e = (Element)colls.item(i);
742 String col_name = e.getAttribute(GSXML.NAME_ATT);
743 // add the info to own coll list - may want to keep
744 // this separate in future - so can distinguish own and
745 // other collections ??
746 e.setAttribute(GSXML.NAME_ATT, GSPath.prependLink(col_name, site_name));
747 this.collection_list.appendChild(this.doc.importNode(e, true));
748 }
749 }
750
751 // service info
752 NodeList services = info_response.getElementsByTagName(GSXML.SERVICE_ELEM);
753 if (services.getLength()>0) {
754 for (int i=0; i<services.getLength(); i++) {
755 Element e = (Element)services.item(i);
756 String serv_name = e.getAttribute(GSXML.NAME_ATT);
757 e.setAttribute(GSXML.NAME_ATT, GSPath.prependLink(serv_name, site_name));
758 this.service_list.appendChild(this.doc.importNode(e, true));
759 }
760 }
761
762 // serviceCluster info
763 NodeList clusters = info_response.getElementsByTagName(GSXML.CLUSTER_ELEM);
764 if (clusters.getLength()>0) {
765 for (int i=0; i<clusters.getLength(); i++) {
766 Element e = (Element)clusters.item(i);
767 String clus_name = e.getAttribute(GSXML.NAME_ATT);
768 e.setAttribute(GSXML.NAME_ATT, GSPath.prependLink(clus_name, site_name));
769 this.cluster_list.appendChild(this.doc.importNode(e, true));
770 }
771 }
772 return true;
773 }
774
775
776
777 protected boolean activateServiceClusterByName(String cluster_name) {
778 return false;
779
780 }
781
782 protected boolean activateServiceRackByName(String module_name) {
783 return false;
784 }
785
786 protected boolean deactivateModule(String type, String name) {
787
788 logger.info("deactivating "+ type+" module: "+name);
789 if (this.module_map.containsKey(name)) {
790
791 logger.info("found the module");
792 ModuleInterface m = (ModuleInterface)this.module_map.remove(name);
793 // also remove the xml bit from description list
794 if (type.equals(GSXML.COLLECTION_ELEM)) {
795 if (((Collection)m).isPublic()) {
796 Element this_col = GSXML.getNamedElement(this.collection_list, GSXML.COLLECTION_ELEM, GSXML.NAME_ATT, name);
797 if (this_col != null) {
798 this.collection_list.removeChild(this_col);
799 }
800 if (((Collection)m).hasOAI()) {
801 this_col = GSXML.getNamedElement(this.oai_collection_list, GSXML.COLLECTION_ELEM, GSXML.NAME_ATT, name);
802 if (this_col != null) {
803 this.oai_collection_list.removeChild(this_col);
804 }
805 }
806 } else {
807 // a private collection
808 Element this_col = GSXML.getNamedElement(this.private_collection_list, GSXML.COLLECTION_ELEM, GSXML.NAME_ATT, name);
809 if (this_col != null) {
810 this.private_collection_list.removeChild(this_col);
811 }
812 }
813 } else if (type.equals(GSXML.SERVICE_ELEM)) {
814 Element this_service = GSXML.getNamedElement(this.service_list, GSXML.SERVICE_ELEM, GSXML.NAME_ATT, name);
815 if (this_service != null) {
816 this.service_list.removeChild(this_service);
817 }
818 } else if (type.equals(GSXML.CLUSTER_ELEM)) {
819 Element this_cluster = GSXML.getNamedElement(this.cluster_list, GSXML.CLUSTER_ELEM, GSXML.NAME_ATT, name);
820 if (this_cluster != null) {
821 this.cluster_list.removeChild(this_cluster);
822 }
823 } else if (type.equals(GSXML.SITE_ELEM)) {
824 Element this_site = GSXML.getNamedElement(this.site_list, GSXML.SITE_ELEM, GSXML.NAME_ATT, name);
825 if (this_site != null) {
826 this.site_list.removeChild(this_site);
827
828 // also remove this sites colls, services, clusters etc
829 cleanUpModuleMapSubset(this.collection_list, name);
830 cleanUpModuleMapSubset(this.cluster_list, name);
831 cleanUpModuleMapSubset(this.service_list, name);
832
833 // can remote collections be in the oai_coll list, or private coll list ??
834 }
835 } else {
836 logger.error("invalid module type: "+type+", can't remove info about this module");
837 }
838
839 m.cleanUp(); // clean up any open files/connections etc - can cause trouble on windows
840 m=null;
841 return true;
842 }
843 // else not deactivated
844 logger.error(name+" module not found");
845 return false;
846
847 }
848
849 //*****************************************************************
850 // auxiliary process methods
851 //*****************************************************************
852
853 /** handles requests made to the MessageRouter itself
854 *
855 * @param req - the request Element- <request>
856 * @return the result Element - should be <response>
857 */
858 protected Element processMessage(Element req) {
859
860 // message for self, should be type=describe/configure at this stage
861 String type = req.getAttribute(GSXML.TYPE_ATT);
862 Element response = this.doc.createElement(GSXML.RESPONSE_ELEM);
863 response.setAttribute(GSXML.FROM_ATT, "");
864 if (type.equals(GSXML.REQUEST_TYPE_DESCRIBE)) {
865 response.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_DESCRIBE);
866 // check the param list
867 Element param_list = (Element) GSXML.getChildByTagName(req, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
868 if (param_list == null) {
869 response.appendChild(this.collection_list);
870 response.appendChild(this.cluster_list);
871 response.appendChild(this.site_list);
872 response.appendChild(this.service_list);
873 return response;
874 }
875 NodeList params = param_list.getElementsByTagName(GSXML.PARAM_ELEM);
876
877 // go through the param list and see what components are wanted
878 for (int i=0; i<params.getLength(); i++) {
879
880 Element param = (Element)params.item(i);
881 // Identify the structure information desired
882 if (param.getAttribute(GSXML.NAME_ATT).equals(GSXML.SUBSET_PARAM)) {
883 String info = param.getAttribute(GSXML.VALUE_ATT);
884 if (info.equals(GSXML.COLLECTION_ELEM+GSXML.LIST_MODIFIER)) {
885 response.appendChild(this.collection_list);
886
887 } else if (info.equals(GSXML.CLUSTER_ELEM+GSXML.LIST_MODIFIER)) {
888 response.appendChild(this.cluster_list);
889
890 } else if (info.equals(GSXML.SERVICE_ELEM+GSXML.LIST_MODIFIER)) {
891 response.appendChild(this.service_list);
892 } else if (info.equals(GSXML.SITE_ELEM+GSXML.LIST_MODIFIER)) {
893 response.appendChild(this.site_list);
894 }
895 }
896 }
897 return response;
898
899 }
900
901 if (type.equals(OAIXML.OAI_SET_LIST)) {
902 logger.info("oaiSetList request received");
903 //this is the oai receptionist asking for a list of oai-support collections
904 response.setAttribute(GSXML.TYPE_ATT, OAIXML.OAI_SET_LIST );
905 response.appendChild(this.oai_collection_list);
906 return response;
907 }
908
909
910 if (type.equals(GSXML.REQUEST_TYPE_SYSTEM)) {
911
912 // a list of system requests - should put any error messages
913 // or success messages into response
914 NodeList commands = req.getElementsByTagName(GSXML.SYSTEM_ELEM);
915 Element site_config_elem = null;
916 boolean success = false;
917
918 for (int i=0; i<commands.getLength(); i++) {
919 // all the commands should be Elements
920 Element elem = (Element)commands.item(i);
921 String action = elem.getAttribute(GSXML.TYPE_ATT);
922 if (action.equals(GSXML.SYSTEM_TYPE_CONFIGURE)) {
923 String subset = elem.getAttribute(GSXML.SYSTEM_SUBSET_ATT);
924 if (subset.equals("")) {
925 // need to reconfigure the MR
926 this.configureLocalSite();
927 Element s = GSXML.createTextElement(this.doc, GSXML.STATUS_ELEM, "MessageRouter reconfigured successfully");
928 response.appendChild(s);
929
930 } else {
931 // else it a specific request
932 if (subset.equals(GSXML.COLLECTION_ELEM+GSXML.LIST_MODIFIER)) {
933 // get rid of all the old collection stuff (not counting remote ones) before activating all the new ones
934 cleanUpModuleMapSubset(this.collection_list, null);
935 cleanUpModuleMapSubset(this.private_collection_list, null);
936 success = configureCollections();
937 } else {
938
939 // need the site config file
940 if (site_config_elem==null) {
941
942 File configFile = new File(GSFile.siteConfigFile(this.site_home));
943 if (!configFile.exists() ) {
944 logger.error(" site config file: "+configFile.getPath()+" not found!");
945 continue;
946 }
947 Document site_config_doc = this.converter.getDOM(configFile);
948 if (site_config_doc == null) {
949 logger.error(" couldn't parse site config file: "+configFile.getPath());
950 continue;
951 }
952 site_config_elem = site_config_doc.getDocumentElement();
953 }
954 if (subset.equals(GSXML.SERVICE_ELEM+GSXML.LIST_MODIFIER)) {
955 Element service_rack_list = (Element)GSXML.getChildByTagName(site_config_elem, GSXML.SERVICE_CLASS_ELEM+GSXML.LIST_MODIFIER);
956 cleanUpModuleMapSubset(this.service_list, null);
957 success = configureServices(service_rack_list);
958 } else if (subset.equals(GSXML.CLUSTER_ELEM+GSXML.LIST_MODIFIER)) {
959 Element cluster_list = (Element)GSXML.getChildByTagName(site_config_elem, GSXML.CLUSTER_ELEM+GSXML.LIST_MODIFIER);
960 cleanUpModuleMapSubset(this.cluster_list, null);
961 success = configureClusters(cluster_list);
962 } else if (subset.equals(GSXML.SITE_ELEM+GSXML.LIST_MODIFIER)) {
963 Element site_list = (Element)GSXML.getChildByTagName(site_config_elem, GSXML.SITE_ELEM+GSXML.LIST_MODIFIER);
964 cleanUpAllExternalSiteInfo();
965 success = configureExternalSites(site_list);
966 }
967 }
968 String message=null;
969 if (success) {
970 message = subset + "reconfigured successfully";
971 } else {
972 message = "Error in reconfiguring "+subset;
973 }
974 Element s = GSXML.createTextElement(this.doc, GSXML.STATUS_ELEM, message);
975 response.appendChild(s);
976 }
977
978
979 } else {
980 String module_name = elem.getAttribute(GSXML.SYSTEM_MODULE_NAME_ATT);
981 String module_type = elem.getAttribute(GSXML.SYSTEM_MODULE_TYPE_ATT);
982
983 if (action.equals(GSXML.SYSTEM_TYPE_DEACTIVATE)) {
984 success = deactivateModule(module_type, module_name);
985 if (success) {
986 Element s = GSXML.createTextElement(this.doc, GSXML.STATUS_ELEM, module_type+": "+module_name+" deactivated");
987 response.appendChild(s);
988 } else {
989 Element s = GSXML.createTextElement(this.doc, GSXML.STATUS_ELEM, module_type+": "+module_name+" could not be deactivated");
990 response.appendChild(s);
991 }
992
993 } else if (action.equals(GSXML.SYSTEM_TYPE_ACTIVATE)) {
994 // we need to deactivate the module first, in case this is a
995 // reconfigure
996 deactivateModule(module_type, module_name);
997 if (module_type.equals(GSXML.COLLECTION_ELEM)) {
998 success = activateCollectionByName(module_name);
999 } else if (module_type.equals(GSXML.SITE_ELEM)) {
1000 success = activateSiteByName(module_name);
1001 } else if (module_type.equals(GSXML.CLUSTER_ELEM)) {
1002 success = activateServiceClusterByName(module_name);
1003 }
1004 if (success) {
1005 Element s = GSXML.createTextElement(this.doc, GSXML.STATUS_ELEM, module_type+": "+module_name+" activated");
1006 response.appendChild(s);
1007 } else {
1008 Element s = GSXML.createTextElement(this.doc, GSXML.STATUS_ELEM, module_type+": "+module_name+" could not be activated");
1009 response.appendChild(s);
1010 }
1011 }
1012 } // else not a configure action
1013 } // for all commands
1014 return response;
1015
1016
1017 } // system type request
1018
1019 // if get here something has gone wrong
1020 logger.error(" cant process request:");
1021 logger.error(this.converter.getString(req));
1022 return null;
1023
1024 }
1025
1026 //* Used to copy nodes from one message to another. E.g. copy a response node to the next request. Not sure if this is actually used anywhere yet... */
1027
1028 protected Element modifyMessages(Element request, Element message, Element result) {
1029 Element response = this.doc.createElement(GSXML.RESPONSE_ELEM);
1030 response.setAttribute(GSXML.FROM_ATT, "");
1031 response.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_MESSAGING);
1032
1033 NodeList commands = request.getElementsByTagName("command");
1034 if (commands == null) {
1035 logger.error("no commands, "+converter.getPrettyString(request));
1036 return response;
1037 }
1038 for (int i=0; i<commands.getLength(); i++) {
1039 Element action = (Element)commands.item(i);
1040 String type = action.getAttribute(GSXML.TYPE_ATT);
1041 if (type.equals("copyNode")) {
1042 // copies the from node as a child of to node
1043 String from_path = action.getAttribute("from");
1044 String to_path = action.getAttribute("to");
1045 Element from_node = null;
1046 String from_node_root = GSPath.getFirstLink(from_path);
1047 if (from_node_root.startsWith(GSXML.REQUEST_ELEM)) {
1048 from_node = message;
1049 } else if (from_node_root.startsWith(GSXML.RESPONSE_ELEM)) {
1050 from_node = result;
1051 }
1052 if (from_node == null) {
1053 continue;
1054 }
1055 Element to_node = null;
1056 String to_node_root = GSPath.getFirstLink(to_path);
1057 if (to_node_root.startsWith(GSXML.REQUEST_ELEM)) {
1058 to_node = message;
1059 } else if (to_node_root.startsWith(GSXML.RESPONSE_ELEM)) {
1060 to_node = result;
1061 }
1062 if (to_node == null) {
1063 continue;
1064 }
1065 // now we know what node to copy where
1066 Node orig_node = GSXML.getNodeByPathIndexed(from_node, from_path);
1067 if (orig_node == null) {
1068 continue;
1069 }
1070 Node new_parent = GSXML.getNodeByPathIndexed(to_node, to_path);
1071 if (new_parent == null) {
1072 continue;
1073
1074 }
1075 new_parent.appendChild(to_node.getOwnerDocument().importNode(orig_node, true));
1076 }
1077
1078 else if (type.equals("copyChildren")) {
1079
1080 }
1081 } // for each command
1082 return response;
1083 }
1084
1085 // ****************************************************
1086 // other methods
1087 // ****************************************************
1088
1089
1090
1091}
1092
1093
Note: See TracBrowser for help on using the repository browser.