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

Last change on this file since 31790 was 31790, checked in by kjdon, 7 years ago

removed an unecessary log message

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