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

Last change on this file since 31127 was 31127, checked in by ak19, 7 years ago

Related to previous revision (31125). Fix to concurrency problem when setting multiple metadata using doc editor 1. Better reporting in the status element of the response returned after setting metadata, now it indicates that it has finished setting meta on success. 2. Removed debug statements from experimental fix. 3. Not using logger error for info message in MessageRouter.

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