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

Last change on this file since 25635 was 25635, checked in by sjm84, 12 years ago

Fixing Greenstone 3's use (or lack thereof) of generics, this was done automatically so we may want to change it over time. This change will also auto-format any files that have not already been formatted.

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