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

Last change on this file since 28856 was 28856, checked in by kjdon, 10 years ago

removed this.doc, as DOM is not thread safe. Use a new DOM each time we create a response

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