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

Last change on this file since 21910 was 21910, checked in by xiao, 14 years ago

in processMessage, changed to return configure action response element with success/error flag as attribute

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