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

Last change on this file since 15944 was 15944, checked in by xiao, 16 years ago

add method getModuleMap used by Flax webservice

  • Property svn:keywords set to Author Date Id Revision
File size: 40.8 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: 15944 $
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 public Element getCollectionList() {
311 return collection_list;
312 }
313 public HashMap getModuleMap() {
314 return module_map;
315 }
316 // ********************************************************************
317 // auxiliary configure and cleanup methods
318 // *******************************************************************
319
320 /** Calls clean up on all modules referenced in the module_map and
321 removes them . */
322 protected void cleanUpModuleMapEntire() {
323 if (this.module_map != null) {
324 Iterator i = this.module_map.values().iterator();
325 while (i.hasNext()) {
326 ((ModuleInterface)i.next()).cleanUp();
327 i.remove();
328 }
329 }
330 }
331
332 /**
333 Goes through the children of list, and for each local/site-specific
334 name attribute, calls cleanUp on the module and removes it from the
335 module_map and removes it from the list
336 */
337 protected void cleanUpModuleMapSubset(Element list, String remote_site) {
338 logger.error(this.converter.getString(list));
339 NodeList elements = list.getChildNodes(); // we are assuming no extraneous nodes
340 for(int i=elements.getLength()-1; i>=0; i--) {
341 Element item = (Element)elements.item(i);
342 String name = item.getAttribute(GSXML.NAME_ATT);
343 String potential_site_name = GSPath.getFirstLink(name);
344 if (remote_site != null) {
345 if (remote_site.equals(potential_site_name)) {
346 list.removeChild(item);
347 }
348 } else {
349 if (name.equals(potential_site_name)) {// there was no site
350 list.removeChild(item);
351 ModuleInterface m = (ModuleInterface)this.module_map.remove(name);
352 m.cleanUp(); // clean up any open files/connections etc
353 m=null;
354 }
355 }
356 }
357
358 logger.error(this.converter.getString(list));
359
360 }
361
362 /** removes all site modules from module_map, and any stored info about this sites collections and services */
363 protected void cleanUpAllExternalSiteInfo() {
364
365 NodeList site_nodes = this.site_list.getChildNodes();
366 for(int i=site_nodes.getLength()-1; i>=0; i--) {
367 Element item = (Element)site_nodes.item(i);
368 String name = item.getAttribute(GSXML.NAME_ATT);
369 // will remove the node from site_list
370 deactivateModule(GSXML.SITE_ELEM, name);
371 }
372
373 }
374 /** read thru own site config file - create services and connect to sites
375 */
376 protected boolean configureLocalSite() {
377
378 // this may be a reconfigure, so clean up the old moduleMap
379 cleanUpModuleMapEntire();
380
381 File configFile = new File(GSFile.siteConfigFile(this.site_home));
382
383 if (!configFile.exists() ) {
384 logger.error(" site config file: "+configFile.getPath()+" not found!");
385 return false;
386 }
387
388 Document config_doc = this.converter.getDOM(configFile);
389 if (config_doc == null) {
390 logger.error(" couldn't parse site config file: "+configFile.getPath());
391 return false;
392 }
393
394 this.config_info = config_doc.getDocumentElement();
395
396 // load up the services: serviceRackList
397 this.service_list = this.doc.createElement(GSXML.SERVICE_ELEM+GSXML.LIST_MODIFIER);
398 Element service_rack_list_elem = (Element)GSXML.getChildByTagName(config_info, GSXML.SERVICE_CLASS_ELEM+GSXML.LIST_MODIFIER);
399 configureServices(service_rack_list_elem);
400
401 // load up the service clusters
402 this.cluster_list = this.doc.createElement(GSXML.CLUSTER_ELEM+GSXML.LIST_MODIFIER);
403 Element cluster_list_elem = (Element)GSXML.getChildByTagName(config_info, GSXML.CLUSTER_ELEM+GSXML.LIST_MODIFIER);
404 configureClusters(cluster_list_elem);
405
406 // load up the collections
407 this.collection_list = this.doc.createElement(GSXML.COLLECTION_ELEM+GSXML.LIST_MODIFIER);
408 this.private_collection_list = this.doc.createElement(GSXML.COLLECTION_ELEM+GSXML.LIST_MODIFIER);
409 this.oai_collection_list = this.doc.createElement(GSXML.COLLECTION_ELEM+GSXML.LIST_MODIFIER);
410 configureCollections();
411
412 // load up the external sites - this also adds their services/clusters/collections to the other lists - so must be done last
413 this.site_list = this.doc.createElement(GSXML.SITE_ELEM+GSXML.LIST_MODIFIER);
414 Element site_list_elem = (Element)GSXML.getChildByTagName(config_info, GSXML.SITE_ELEM+GSXML.LIST_MODIFIER);
415 configureExternalSites(site_list_elem);
416
417 return true;
418
419 }
420
421 protected boolean configureServices(Element service_rack_list) {
422
423
424 // load up the individual services
425 logger.info("loading service modules...");
426
427 if (service_rack_list == null) {
428 logger.info("... none to be loaded");
429 return true;
430 }
431
432 NodeList service_racks = service_rack_list.getElementsByTagName(GSXML.SERVICE_CLASS_ELEM);
433 if (service_racks.getLength()==0) {
434 logger.info("... none to be loaded");
435 return true;
436 }
437
438 Element service_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
439 Element service_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_DESCRIBE, "", "", "");
440 service_message.appendChild(service_request);
441
442 for(int i=0; i<service_racks.getLength(); i++) {
443 Element n = (Element)service_racks.item(i);
444 String service_name = n.getAttribute(GSXML.NAME_ATT);
445 logger.info("..."+service_name);
446
447 Class service_class = null;
448 try {
449 service_class = Class.forName("org.greenstone.gsdl3.service."+service_name);
450 } catch(ClassNotFoundException e) {
451
452 try {
453 //try the service_name alone in case the package name is already specified
454 service_class = Class.forName(service_name);
455
456 }catch(ClassNotFoundException ae) {
457 logger.info(ae.getMessage());
458 }
459 }
460 try {
461
462 ServiceRack s = (ServiceRack)service_class.newInstance();
463 s.setSiteHome(this.site_home);
464 s.setSiteAddress(this.site_http_address);
465 s.setLibraryName(this.library_name);
466 s.setMessageRouter(this);
467 // pass the XML node to the service for service configuration
468 if (!s.configure(n, null)) {
469 logger.error ("couldn't configure ServiceRack "+service_name);
470 continue;
471 }
472
473 // find out the supported services for this service module
474 Element service_response = (Element) s.process(service_message);
475 NodeList services = service_response.getElementsByTagName(GSXML.SERVICE_ELEM);
476 if (services.getLength()==0) {
477 logger.error("MessageRouter configure error: serviceRack "+service_name+" has no services!");
478 } else {
479 for (int j=0; j<services.getLength();j++) {
480 String service = ((Element)services.item(j)).getAttribute(GSXML.NAME_ATT);
481
482 this.module_map.put(service, s);
483
484 // add short info to service_list_ XML
485 this.service_list.appendChild(this.doc.importNode(services.item(j), true));
486 }
487 }
488 } catch (Exception e ) {
489 logger.error("MessageRouter configure exception: in ServiceRack class specification: "+ e.getMessage());
490 e.printStackTrace();
491 }
492 } // for each service module
493 return true;
494 }
495
496 protected boolean configureClusters(Element config_cluster_list) {
497
498 // load up the service clusters
499 logger.info("loading service clusters ...");
500 if (config_cluster_list == null) {
501 logger.info("... none to be loaded");
502 return true;
503 }
504 NodeList service_clusters = config_cluster_list.getElementsByTagName(GSXML.CLUSTER_ELEM);
505 if (service_clusters.getLength()==0) {
506 logger.info("... none to be loaded");
507 return true;
508 }
509
510 for (int i=0; i<service_clusters.getLength(); i++) {
511 Element cluster = (Element)service_clusters.item(i);
512 String name = cluster.getAttribute(GSXML.NAME_ATT);
513 logger.info("..."+name);
514 ServiceCluster sc = new ServiceCluster();
515 sc.setSiteHome(this.site_home);
516 sc.setSiteAddress(this.site_http_address);
517 sc.setClusterName(name);
518 sc.setMessageRouter(this);
519 if (!sc.configure(cluster)) {
520 logger.error ("couldn't configure ServiceCluster "+name);
521 continue;
522 }
523
524 this.module_map.put(name, sc); // this replaces the old one if there was one already present
525 //add short info to cluster list
526 Element e = this.doc.createElement(GSXML.CLUSTER_ELEM);
527 e.setAttribute(GSXML.NAME_ATT, name);
528 this.cluster_list.appendChild(e);
529
530 }
531 return true;
532 }
533
534 /** 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 */
535 protected boolean configureCollections() {
536
537 // read thru the collect directory and activate all the valid collections
538 File collectDir = new File(GSFile.collectDir(this.site_home));
539 if (collectDir.exists()) {
540 logger.info("Reading thru directory "+collectDir.getPath()+" to find collections.");
541 File[] contents = collectDir.listFiles();
542 for (int i=0; i<contents.length;i++) {
543 if(contents[i].isDirectory()) {
544
545 String colName = contents[i].getName();
546 if (!colName.startsWith("CVS") && !colName.startsWith(".svn")) {
547 activateCollectionByName(colName);
548 }
549 }
550 }
551 } // collectDir
552 return true;
553 }
554
555 /** creates and configures a new collection
556 if this is done for a reconfigure, the collection should be deactivated first.
557 *
558 *@param col_name the name of the collection
559 *@return true if collection created ok
560 */
561 protected boolean activateCollectionByName(String col_name) {
562
563 logger.info("Activating collection: "+col_name+".");
564
565 // Look for the etc/collectionInit.xml file, and see what sort of Collection to load
566 Collection c = null;
567 File init_file = new File(GSFile.collectionInitFile(this.site_home, col_name));
568
569 if (init_file.exists()) {
570 Document init_doc = this.converter.getDOM(init_file);
571 if (init_doc != null) {
572 Element init_elem = init_doc.getDocumentElement();
573 if (init_elem != null) {
574 String coll_class_name = init_elem.getAttribute("class");
575 if (!coll_class_name.equals("")) {
576 try {
577 c = (Collection)Class.forName("org.greenstone.gsdl3.collection."+coll_class_name).newInstance();
578 } catch (Exception e) {
579 logger.info(" couldn't create a new collection, type "+coll_class_name+", defaulting to class Collection");
580 }
581 }
582 }
583 }
584 }
585 if (c==null) { // we haven't found another classname to use
586 c = new Collection();
587 }
588
589 c.setCollectionName(col_name);
590 c.setSiteHome(this.site_home);
591 c.setSiteAddress(this.site_http_address);
592 c.setMessageRouter(this);
593 if (c.configure()) {
594 logger.info("have just configured collection " + col_name);
595 // add to list of collections
596 this.module_map.put(col_name, c);
597 Element e = this.doc.createElement(GSXML.COLLECTION_ELEM);
598 e.setAttribute(GSXML.NAME_ATT, col_name);
599
600 if(c.isPublic()) {
601 // only public collections will appear on the home page
602 // add short description_ to collection_list_
603 this.collection_list.appendChild(e);
604
605 if (c.hasOAI()) {
606 Element ane = this.doc.createElement(GSXML.COLLECTION_ELEM);
607 //The collection name is returned as site_name:coll_name, which is in fact the set specification
608 ane.setAttribute(GSXML.NAME_ATT, site_name + ":" + col_name);
609 ane.setAttribute(OAIXML.LASTMODIFIED, "" + c.getLastmodified());
610
611 this.oai_collection_list.appendChild(ane);
612 //logger.info(GSXML.xmlNodeToString(oai_collection_list));
613 }
614
615 } else {
616 this.private_collection_list.appendChild(e);
617 }
618 return true;
619 } else {
620 logger.error("Couldn't configure collection: "+
621 col_name+".");
622 return false;
623 }
624 }
625
626
627 /** Goes through the siteList and activates each site found. If this is done for a reconfigure, a clean up must be done first ****HOW??? */
628 protected boolean configureExternalSites(Element config_site_list) {
629
630 // load up the sites
631 logger.info("loading external sites...");
632 if (config_site_list ==null ) {
633 logger.info("...none found");
634 return true;
635 }
636
637 NodeList sites = config_site_list.getElementsByTagName(GSXML.SITE_ELEM);
638 if (sites.getLength()==0) {
639 logger.info("...none found");
640 return true;
641 }
642
643 // this is a name to identify the current site in the Communicator
644 String local_site_name = config_site_list.getAttribute(GSXML.LOCAL_SITE_NAME_ATT);
645 if (local_site_name.equals("")) {
646 local_site_name = site_name;
647 }
648
649 for (int i=0; i<sites.getLength(); i++) {
650 Element s = (Element)sites.item(i);
651 activateSite(s, local_site_name);
652 }
653 return true;
654 }
655
656 protected boolean activateSiteByName(String site_name) {
657 logger.info("Activating site: "+site_name+".");
658
659 File configFile = new File(GSFile.siteConfigFile(this.site_home));
660
661 if (!configFile.exists() ) {
662 logger.error(" site config file: "+configFile.getPath()+" not found!");
663 return false;
664 }
665 Document config_doc = this.converter.getDOM(configFile);
666 if (config_doc == null) {
667 logger.error(" couldn't parse site config file: "+configFile.getPath());
668 return false;
669 }
670 Element config_elem = config_doc.getDocumentElement();
671
672 Element config_site_list = (Element)GSXML.getChildByTagName(config_elem, GSXML.SITE_ELEM+GSXML.LIST_MODIFIER);
673 if (config_site_list ==null ) {
674 logger.error("activateSite, no sites found");
675 return false;
676 }
677 // this is a name to identify the current site in the Communicator
678 String local_site_name = config_site_list.getAttribute("localSiteName");
679 if (local_site_name.equals("")) {
680 local_site_name = site_name;
681 }
682
683 Element this_site_elem = GSXML.getNamedElement(config_site_list, GSXML.SITE_ELEM, GSXML.NAME_ATT, site_name);
684 if (this_site_elem == null) {
685 logger.error("activateSite, site "+site_name+" not found");
686 return false;
687 }
688
689 return activateSite(this_site_elem, local_site_name);
690 }
691
692 protected boolean activateSite(Element site_elem, String local_site_name) {
693
694 Communicator comm=null;
695 String type = site_elem.getAttribute(GSXML.TYPE_ATT);
696 String name = site_elem.getAttribute(GSXML.NAME_ATT);
697 if (type.equals(GSXML.COMM_TYPE_SOAP_JAVA)) {
698 logger.info("activating SOAP site "+name);
699 comm = new SOAPCommunicator();
700 if (comm.configure(site_elem)) {
701 comm.setLocalSiteName(local_site_name);
702
703 // add to map of modules
704 this.module_map.put(name, comm);
705 this.site_list.appendChild(this.doc.importNode(site_elem, true));
706 // need to get collection list and service
707 // list from here- if the site isn't up yet, the site will
708 // have to be added later
709 if (!getRemoteSiteInfo(comm, name)) {
710 logger.error(" couldn't get info from site");
711 }
712 } else {
713 logger.error(" couldn't configure site");
714 return false;
715 }
716
717 } else {
718 System.err.print(" cant talk to server of type:"+type + ", so not making a connection to "+name);
719 return false;
720 }
721 return true;
722 }
723
724 /** get site info from external site
725 *
726 * @param comm - the communicator object for the external site
727 * @param site_name - the name of the external site
728 * @return true if successful
729 */
730 protected boolean getRemoteSiteInfo(Communicator comm, String site_name) {
731
732 logger.info(" getting info from site:"+site_name);
733
734 Element info_request = this.doc.createElement(GSXML.MESSAGE_ELEM);
735 Element req = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_DESCRIBE, "", "", "");
736 info_request.appendChild(req);
737
738 // process the message
739 Element info_response = comm.process(info_request);
740 if (info_response == null) {
741 return false;
742 }
743 // collection info
744 NodeList colls = info_response.getElementsByTagName(GSXML.COLLECTION_ELEM);
745 if (colls.getLength()>0) {
746 for (int i=0; i<colls.getLength(); i++) {
747 Element e = (Element)colls.item(i);
748 String col_name = e.getAttribute(GSXML.NAME_ATT);
749 // add the info to own coll list - may want to keep
750 // this separate in future - so can distinguish own and
751 // other collections ??
752 e.setAttribute(GSXML.NAME_ATT, GSPath.prependLink(col_name, site_name));
753 this.collection_list.appendChild(this.doc.importNode(e, true));
754 }
755 }
756
757 // service info
758 NodeList services = info_response.getElementsByTagName(GSXML.SERVICE_ELEM);
759 if (services.getLength()>0) {
760 for (int i=0; i<services.getLength(); i++) {
761 Element e = (Element)services.item(i);
762 String serv_name = e.getAttribute(GSXML.NAME_ATT);
763 e.setAttribute(GSXML.NAME_ATT, GSPath.prependLink(serv_name, site_name));
764 this.service_list.appendChild(this.doc.importNode(e, true));
765 }
766 }
767
768 // serviceCluster info
769 NodeList clusters = info_response.getElementsByTagName(GSXML.CLUSTER_ELEM);
770 if (clusters.getLength()>0) {
771 for (int i=0; i<clusters.getLength(); i++) {
772 Element e = (Element)clusters.item(i);
773 String clus_name = e.getAttribute(GSXML.NAME_ATT);
774 e.setAttribute(GSXML.NAME_ATT, GSPath.prependLink(clus_name, site_name));
775 this.cluster_list.appendChild(this.doc.importNode(e, true));
776 }
777 }
778 return true;
779 }
780
781
782
783 protected boolean activateServiceClusterByName(String cluster_name) {
784 return false;
785
786 }
787
788 protected boolean activateServiceRackByName(String module_name) {
789 return false;
790 }
791
792 protected boolean deactivateModule(String type, String name) {
793
794 logger.info("deactivating "+ type+" module: "+name);
795 if (this.module_map.containsKey(name)) {
796
797 logger.info("found the module");
798 ModuleInterface m = (ModuleInterface)this.module_map.remove(name);
799 // also remove the xml bit from description list
800 if (type.equals(GSXML.COLLECTION_ELEM)) {
801 if (((Collection)m).isPublic()) {
802 Element this_col = GSXML.getNamedElement(this.collection_list, GSXML.COLLECTION_ELEM, GSXML.NAME_ATT, name);
803 if (this_col != null) {
804 this.collection_list.removeChild(this_col);
805 }
806 if (((Collection)m).hasOAI()) {
807 this_col = GSXML.getNamedElement(this.oai_collection_list, GSXML.COLLECTION_ELEM, GSXML.NAME_ATT, name);
808 if (this_col != null) {
809 this.oai_collection_list.removeChild(this_col);
810 }
811 }
812 } else {
813 // a private collection
814 Element this_col = GSXML.getNamedElement(this.private_collection_list, GSXML.COLLECTION_ELEM, GSXML.NAME_ATT, name);
815 if (this_col != null) {
816 this.private_collection_list.removeChild(this_col);
817 }
818 }
819 } else if (type.equals(GSXML.SERVICE_ELEM)) {
820 Element this_service = GSXML.getNamedElement(this.service_list, GSXML.SERVICE_ELEM, GSXML.NAME_ATT, name);
821 if (this_service != null) {
822 this.service_list.removeChild(this_service);
823 }
824 } else if (type.equals(GSXML.CLUSTER_ELEM)) {
825 Element this_cluster = GSXML.getNamedElement(this.cluster_list, GSXML.CLUSTER_ELEM, GSXML.NAME_ATT, name);
826 if (this_cluster != null) {
827 this.cluster_list.removeChild(this_cluster);
828 }
829 } else if (type.equals(GSXML.SITE_ELEM)) {
830 Element this_site = GSXML.getNamedElement(this.site_list, GSXML.SITE_ELEM, GSXML.NAME_ATT, name);
831 if (this_site != null) {
832 this.site_list.removeChild(this_site);
833
834 // also remove this sites colls, services, clusters etc
835 cleanUpModuleMapSubset(this.collection_list, name);
836 cleanUpModuleMapSubset(this.cluster_list, name);
837 cleanUpModuleMapSubset(this.service_list, name);
838
839 // can remote collections be in the oai_coll list, or private coll list ??
840 }
841 } else {
842 logger.error("invalid module type: "+type+", can't remove info about this module");
843 }
844
845 m.cleanUp(); // clean up any open files/connections etc - can cause trouble on windows
846 m=null;
847 return true;
848 }
849 // else not deactivated
850 logger.error(name+" module not found");
851 return false;
852
853 }
854
855 //*****************************************************************
856 // auxiliary process methods
857 //*****************************************************************
858
859 /** handles requests made to the MessageRouter itself
860 *
861 * @param req - the request Element- <request>
862 * @return the result Element - should be <response>
863 */
864 protected Element processMessage(Element req) {
865
866 // message for self, should be type=describe/configure at this stage
867 String type = req.getAttribute(GSXML.TYPE_ATT);
868 Element response = this.doc.createElement(GSXML.RESPONSE_ELEM);
869 response.setAttribute(GSXML.FROM_ATT, "");
870 if (type.equals(GSXML.REQUEST_TYPE_DESCRIBE)) {
871 response.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_DESCRIBE);
872 // check the param list
873 Element param_list = (Element) GSXML.getChildByTagName(req, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
874 if (param_list == null) {
875 response.appendChild(this.collection_list);
876 response.appendChild(this.cluster_list);
877 response.appendChild(this.site_list);
878 response.appendChild(this.service_list);
879 return response;
880 }
881 NodeList params = param_list.getElementsByTagName(GSXML.PARAM_ELEM);
882
883 // go through the param list and see what components are wanted
884 for (int i=0; i<params.getLength(); i++) {
885
886 Element param = (Element)params.item(i);
887 // Identify the structure information desired
888 if (param.getAttribute(GSXML.NAME_ATT).equals(GSXML.SUBSET_PARAM)) {
889 String info = param.getAttribute(GSXML.VALUE_ATT);
890 if (info.equals(GSXML.COLLECTION_ELEM+GSXML.LIST_MODIFIER)) {
891 response.appendChild(this.collection_list);
892
893 } else if (info.equals(GSXML.CLUSTER_ELEM+GSXML.LIST_MODIFIER)) {
894 response.appendChild(this.cluster_list);
895
896 } else if (info.equals(GSXML.SERVICE_ELEM+GSXML.LIST_MODIFIER)) {
897 response.appendChild(this.service_list);
898 } else if (info.equals(GSXML.SITE_ELEM+GSXML.LIST_MODIFIER)) {
899 response.appendChild(this.site_list);
900 }
901 }
902 }
903 return response;
904
905 }
906
907 if (type.equals(OAIXML.OAI_SET_LIST)) {
908 logger.info("oaiSetList request received");
909 //this is the oai receptionist asking for a list of oai-support collections
910 response.setAttribute(GSXML.TYPE_ATT, OAIXML.OAI_SET_LIST );
911 response.appendChild(this.oai_collection_list);
912 return response;
913 }
914
915
916 if (type.equals(GSXML.REQUEST_TYPE_SYSTEM)) {
917
918 // a list of system requests - should put any error messages
919 // or success messages into response
920 NodeList commands = req.getElementsByTagName(GSXML.SYSTEM_ELEM);
921 Element site_config_elem = null;
922 boolean success = false;
923
924 for (int i=0; i<commands.getLength(); i++) {
925 // all the commands should be Elements
926 Element elem = (Element)commands.item(i);
927 String action = elem.getAttribute(GSXML.TYPE_ATT);
928 if (action.equals(GSXML.SYSTEM_TYPE_CONFIGURE)) {
929 String subset = elem.getAttribute(GSXML.SYSTEM_SUBSET_ATT);
930 if (subset.equals("")) {
931 // need to reconfigure the MR
932 this.configureLocalSite();
933 Element s = GSXML.createTextElement(this.doc, GSXML.STATUS_ELEM, "MessageRouter reconfigured successfully");
934 response.appendChild(s);
935
936 } else {
937 // else it a specific request
938 if (subset.equals(GSXML.COLLECTION_ELEM+GSXML.LIST_MODIFIER)) {
939 // get rid of all the old collection stuff (not counting remote ones) before activating all the new ones
940 cleanUpModuleMapSubset(this.collection_list, null);
941 cleanUpModuleMapSubset(this.private_collection_list, null);
942 success = configureCollections();
943 } else {
944
945 // need the site config file
946 if (site_config_elem==null) {
947
948 File configFile = new File(GSFile.siteConfigFile(this.site_home));
949 if (!configFile.exists() ) {
950 logger.error(" site config file: "+configFile.getPath()+" not found!");
951 continue;
952 }
953 Document site_config_doc = this.converter.getDOM(configFile);
954 if (site_config_doc == null) {
955 logger.error(" couldn't parse site config file: "+configFile.getPath());
956 continue;
957 }
958 site_config_elem = site_config_doc.getDocumentElement();
959 }
960 if (subset.equals(GSXML.SERVICE_ELEM+GSXML.LIST_MODIFIER)) {
961 Element service_rack_list = (Element)GSXML.getChildByTagName(site_config_elem, GSXML.SERVICE_CLASS_ELEM+GSXML.LIST_MODIFIER);
962 cleanUpModuleMapSubset(this.service_list, null);
963 success = configureServices(service_rack_list);
964 } else if (subset.equals(GSXML.CLUSTER_ELEM+GSXML.LIST_MODIFIER)) {
965 Element cluster_list = (Element)GSXML.getChildByTagName(site_config_elem, GSXML.CLUSTER_ELEM+GSXML.LIST_MODIFIER);
966 cleanUpModuleMapSubset(this.cluster_list, null);
967 success = configureClusters(cluster_list);
968 } else if (subset.equals(GSXML.SITE_ELEM+GSXML.LIST_MODIFIER)) {
969 Element site_list = (Element)GSXML.getChildByTagName(site_config_elem, GSXML.SITE_ELEM+GSXML.LIST_MODIFIER);
970 cleanUpAllExternalSiteInfo();
971 success = configureExternalSites(site_list);
972 }
973 }
974 String message=null;
975 if (success) {
976 message = subset + "reconfigured successfully";
977 } else {
978 message = "Error in reconfiguring "+subset;
979 }
980 Element s = GSXML.createTextElement(this.doc, GSXML.STATUS_ELEM, message);
981 response.appendChild(s);
982 }
983
984
985 } else {
986 String module_name = elem.getAttribute(GSXML.SYSTEM_MODULE_NAME_ATT);
987 String module_type = elem.getAttribute(GSXML.SYSTEM_MODULE_TYPE_ATT);
988
989 if (action.equals(GSXML.SYSTEM_TYPE_DEACTIVATE)) {
990 success = deactivateModule(module_type, module_name);
991 if (success) {
992 Element s = GSXML.createTextElement(this.doc, GSXML.STATUS_ELEM, module_type+": "+module_name+" deactivated");
993 response.appendChild(s);
994 } else {
995 Element s = GSXML.createTextElement(this.doc, GSXML.STATUS_ELEM, module_type+": "+module_name+" could not be deactivated");
996 response.appendChild(s);
997 }
998
999 } else if (action.equals(GSXML.SYSTEM_TYPE_ACTIVATE)) {
1000 // we need to deactivate the module first, in case this is a
1001 // reconfigure
1002 deactivateModule(module_type, module_name);
1003 if (module_type.equals(GSXML.COLLECTION_ELEM)) {
1004 success = activateCollectionByName(module_name);
1005 } else if (module_type.equals(GSXML.SITE_ELEM)) {
1006 success = activateSiteByName(module_name);
1007 } else if (module_type.equals(GSXML.CLUSTER_ELEM)) {
1008 success = activateServiceClusterByName(module_name);
1009 }
1010 if (success) {
1011 Element s = GSXML.createTextElement(this.doc, GSXML.STATUS_ELEM, module_type+": "+module_name+" activated");
1012 response.appendChild(s);
1013 } else {
1014 Element s = GSXML.createTextElement(this.doc, GSXML.STATUS_ELEM, module_type+": "+module_name+" could not be activated");
1015 response.appendChild(s);
1016 }
1017 }
1018 } // else not a configure action
1019 } // for all commands
1020 return response;
1021
1022
1023 } // system type request
1024
1025 // if get here something has gone wrong
1026 logger.error(" cant process request:");
1027 logger.error(this.converter.getString(req));
1028 return null;
1029
1030 }
1031
1032 //* 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... */
1033
1034 protected Element modifyMessages(Element request, Element message, Element result) {
1035 Element response = this.doc.createElement(GSXML.RESPONSE_ELEM);
1036 response.setAttribute(GSXML.FROM_ATT, "");
1037 response.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_MESSAGING);
1038
1039 NodeList commands = request.getElementsByTagName("command");
1040 if (commands == null) {
1041 logger.error("no commands, "+converter.getPrettyString(request));
1042 return response;
1043 }
1044 for (int i=0; i<commands.getLength(); i++) {
1045 Element action = (Element)commands.item(i);
1046 String type = action.getAttribute(GSXML.TYPE_ATT);
1047 if (type.equals("copyNode")) {
1048 // copies the from node as a child of to node
1049 String from_path = action.getAttribute("from");
1050 String to_path = action.getAttribute("to");
1051 Element from_node = null;
1052 String from_node_root = GSPath.getFirstLink(from_path);
1053 if (from_node_root.startsWith(GSXML.REQUEST_ELEM)) {
1054 from_node = message;
1055 } else if (from_node_root.startsWith(GSXML.RESPONSE_ELEM)) {
1056 from_node = result;
1057 }
1058 if (from_node == null) {
1059 continue;
1060 }
1061 Element to_node = null;
1062 String to_node_root = GSPath.getFirstLink(to_path);
1063 if (to_node_root.startsWith(GSXML.REQUEST_ELEM)) {
1064 to_node = message;
1065 } else if (to_node_root.startsWith(GSXML.RESPONSE_ELEM)) {
1066 to_node = result;
1067 }
1068 if (to_node == null) {
1069 continue;
1070 }
1071 // now we know what node to copy where
1072 Node orig_node = GSXML.getNodeByPathIndexed(from_node, from_path);
1073 if (orig_node == null) {
1074 continue;
1075 }
1076 Node new_parent = GSXML.getNodeByPathIndexed(to_node, to_path);
1077 if (new_parent == null) {
1078 continue;
1079
1080 }
1081 new_parent.appendChild(to_node.getOwnerDocument().importNode(orig_node, true));
1082 }
1083
1084 else if (type.equals("copyChildren")) {
1085
1086 }
1087 } // for each command
1088 return response;
1089 }
1090
1091 // ****************************************************
1092 // other methods
1093 // ****************************************************
1094
1095
1096
1097}
1098
1099
Note: See TracBrowser for help on using the repository browser.