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

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

Lots of changes. Mainly to do with removing this.doc from everywhere. Document is not thread safe. Now we tend to create a new Document everytime we are starting a new page/message etc. in service this.desc_doc is available as teh document to create service info stuff. But it should only be used for this and not for other messages. newDOM is now static for XMLConverter. method param changes for some GSXML methods.

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