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

Last change on this file since 26195 was 26195, checked in by kjdon, 12 years ago

if the greenstone context (/greenstone3 normally) is empty, and therefore gsdl3webaddress is empty, then start site_http_address with sites, not /sites

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