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

Last change on this file since 25580 was 25580, checked in by ak19, 12 years ago

SystemAction now supports pinging on a collection with ?a=s&sa=ping&st=collection&sn=colName

  • 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: 25580 $
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 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();
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 = ((ModuleInterface)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 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 i = this.module_map.values().iterator();
340 while (i.hasNext()) {
341 ((ModuleInterface)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 = (ModuleInterface)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 = (ModuleInterface)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.