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

Last change on this file since 25872 was 25748, checked in by sjm84, 12 years ago

Some tidying

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