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

Last change on this file since 19893 was 19893, checked in by xiao, 15 years ago

added a method getPrivateCollectionList

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