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

Last change on this file since 26908 was 26908, checked in by davidb, 11 years ago

Some (commented out) debug statements that focus on cleanUp

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