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

Last change on this file since 33080 was 33080, checked in by kjdon, 5 years ago

test for null element

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