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

Last change on this file since 23938 was 23938, checked in by ak19, 13 years ago

GS3's OAIserver passes final official oaiserver validation tests: to do with earliestDatestamp. Both the datestamp of the records (documents) returned by listRecords, listIdentifiers and getRecord, as well as the earliestDatestamp returned by an Identify request are now in sync with each other. Related code changes made to perllib to write the earliestDatestamp into GS3's buildconfig.xml (and build.cfg for GS2), and to write new fields oailastmodified and oailastmodifieddate into the collection's database for each document.

  • 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 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: 23938 $
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 mainResult.appendChild(this.doc.importNode(result, true));
271 } else {
272 // The message needs to go to another module. The same message can
273 // be passed to multiple modules - they will be in a comma
274 // separated list in the 'to' attribute
275 String [] modules = StringUtils.split(path, ",");
276
277 for (int j=0; j<modules.length; j++) {
278 // why can't we do this outside the loop??
279 Element mess = this.doc.createElement(GSXML.MESSAGE_ELEM);
280 Element copied_request = (Element)this.doc.importNode(req, true);
281 mess.appendChild(copied_request);
282
283 String this_mod = modules[j];
284 // find the module to pass it on to
285 // need to put the request into a message element
286 String obj = GSPath.getFirstLink(this_mod);
287
288 if (this.module_map.containsKey(obj)) {
289 copied_request.setAttribute(GSXML.TO_ATT, this_mod);
290 result = ((ModuleInterface)this.module_map.get(obj)).process(mess);
291 if (result !=null ) {
292 // append the contents of the message to the mainResult - there will only be one response at this stage
293 Node res = GSXML.getChildByTagName(result, GSXML.RESPONSE_ELEM);
294 if (res != null){
295 mainResult.appendChild(this.doc.importNode(res, true));
296
297 }
298 } else {
299 // add in a place holder response
300 Element response = this.doc.createElement(GSXML.RESPONSE_ELEM);
301 response.setAttribute(GSXML.FROM_ATT, this_mod);
302 mainResult.appendChild(response);
303 logger.error("MessageRouter Error: request had null result!");
304 }
305
306 } else {
307 logger.error("MessageRouter Error: request has illegal module name in:\n"+this.converter.getString(req));
308 }
309 }
310 }
311
312 } // for each request
313
314 logger.debug("MR returned response");
315 logger.debug(this.converter.getString(mainResult));
316
317 return mainResult;
318 }
319 public Element getCollectionList() {
320 return collection_list;
321 }
322 public Element getPrivateCollectionList() {
323 return private_collection_list;
324 }
325 public HashMap getModuleMap() {
326 return module_map;
327 }
328 // ********************************************************************
329 // auxiliary configure and cleanup methods
330 // *******************************************************************
331
332 /** Calls clean up on all modules referenced in the module_map and
333 removes them . */
334 protected void cleanUpModuleMapEntire() {
335 if (this.module_map != null) {
336 Iterator i = this.module_map.values().iterator();
337 while (i.hasNext()) {
338 ((ModuleInterface)i.next()).cleanUp();
339 i.remove();
340 }
341 }
342 }
343
344 /**
345 Goes through the children of list, and for each local/site-specific
346 name attribute, calls cleanUp on the module and removes it from the
347 module_map and removes it from the list
348 */
349 protected void cleanUpModuleMapSubset(Element list, String remote_site) {
350 logger.error(this.converter.getString(list));
351 NodeList elements = list.getChildNodes(); // we are assuming no extraneous nodes
352 for(int i=elements.getLength()-1; i>=0; i--) {
353 Element item = (Element)elements.item(i);
354 String name = item.getAttribute(GSXML.NAME_ATT);
355 String potential_site_name = GSPath.getFirstLink(name);
356 if (remote_site != null) {
357 if (remote_site.equals(potential_site_name)) {
358 list.removeChild(item);
359 }
360 } else {
361 if (name.equals(potential_site_name)) {// there was no site
362 list.removeChild(item);
363 ModuleInterface m = (ModuleInterface)this.module_map.remove(name);
364 m.cleanUp(); // clean up any open files/connections etc
365 m=null;
366 }
367 }
368 }
369 logger.error(this.converter.getString(list));
370 }
371
372 /** removes all site modules from module_map, and any stored info about this sites collections and services */
373 protected void cleanUpAllExternalSiteInfo() {
374
375 NodeList site_nodes = this.site_list.getChildNodes();
376 for(int i=site_nodes.getLength()-1; i>=0; i--) {
377 Element item = (Element)site_nodes.item(i);
378 String name = item.getAttribute(GSXML.NAME_ATT);
379 // will remove the node from site_list
380 deactivateModule(GSXML.SITE_ELEM, name);
381 }
382
383 }
384
385 /** read thru own site config file - create services and connect to sites
386 */
387 protected boolean configureLocalSite() {
388
389 // this may be a reconfigure, so clean up the old moduleMap
390 cleanUpModuleMapEntire();
391
392 File configFile = new File(GSFile.siteConfigFile(this.site_home));
393
394 if (!configFile.exists() ) {
395 logger.error(" site config file: "+configFile.getPath()+" not found!");
396 return false;
397 }
398
399 Document config_doc = this.converter.getDOM(configFile);
400 if (config_doc == null) {
401 logger.error(" couldn't parse site config file: "+configFile.getPath());
402 return false;
403 }
404
405 this.config_info = config_doc.getDocumentElement();
406
407 // load up the services: serviceRackList
408 this.service_list = this.doc.createElement(GSXML.SERVICE_ELEM+GSXML.LIST_MODIFIER);
409 Element service_rack_list_elem = (Element)GSXML.getChildByTagName(config_info, GSXML.SERVICE_CLASS_ELEM+GSXML.LIST_MODIFIER);
410 configureServices(service_rack_list_elem);
411
412 // load up the service clusters
413 this.cluster_list = this.doc.createElement(GSXML.CLUSTER_ELEM+GSXML.LIST_MODIFIER);
414 Element cluster_list_elem = (Element)GSXML.getChildByTagName(config_info, GSXML.CLUSTER_ELEM+GSXML.LIST_MODIFIER);
415 configureClusters(cluster_list_elem);
416
417 // load up the collections
418 this.collection_list = this.doc.createElement(GSXML.COLLECTION_ELEM+GSXML.LIST_MODIFIER);
419 this.private_collection_list = this.doc.createElement(GSXML.COLLECTION_ELEM+GSXML.LIST_MODIFIER);
420 this.oai_collection_list = this.doc.createElement(GSXML.COLLECTION_ELEM+GSXML.LIST_MODIFIER);
421 configureCollections();
422
423 // load up the external sites - this also adds their services/clusters/collections to the other lists - so must be done last
424 this.site_list = this.doc.createElement(GSXML.SITE_ELEM+GSXML.LIST_MODIFIER);
425 Element site_list_elem = (Element)GSXML.getChildByTagName(config_info, GSXML.SITE_ELEM+GSXML.LIST_MODIFIER);
426 configureExternalSites(site_list_elem);
427
428 // load up the site metadata
429 this.metadata_list = this.doc.createElement(GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER);
430 Element metadata_list_elem = (Element)GSXML.getChildByTagName(config_info, GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER);
431 loadMetadata(metadata_list_elem);
432
433
434 return true;
435
436 }
437
438 protected boolean configureServices(Element service_rack_list) {
439
440
441 // load up the individual services
442 logger.info("loading service modules...");
443
444 if (service_rack_list == null) {
445 logger.info("... none to be loaded");
446 return true;
447 }
448
449 NodeList service_racks = service_rack_list.getElementsByTagName(GSXML.SERVICE_CLASS_ELEM);
450 if (service_racks.getLength()==0) {
451 logger.info("... none to be loaded");
452 return true;
453 }
454
455 Element service_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
456 Element service_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_DESCRIBE, "", "", "");
457 service_message.appendChild(service_request);
458
459 for(int i=0; i<service_racks.getLength(); i++) {
460 Element n = (Element)service_racks.item(i);
461 String service_name = n.getAttribute(GSXML.NAME_ATT);
462 logger.info("..."+service_name);
463
464 Class service_class = null;
465 try {
466 service_class = Class.forName("org.greenstone.gsdl3.service."+service_name);
467 } catch(ClassNotFoundException e) {
468 try {
469 //try the service_name alone in case the package name is already specified
470 service_class = Class.forName(service_name);
471 }catch(ClassNotFoundException ae) {
472 logger.info(ae.getMessage());
473 }
474 }
475 try {
476 ServiceRack s = (ServiceRack)service_class.newInstance();
477 s.setSiteHome(this.site_home);
478 s.setSiteAddress(this.site_http_address);
479 s.setLibraryName(this.library_name);
480 s.setMessageRouter(this);
481 // pass the XML node to the service for service configuration
482 if (!s.configure(n, null)) {
483 logger.error ("couldn't configure ServiceRack "+service_name);
484 continue;
485 }
486
487 // find out the supported services for this service module
488 Element service_response = (Element) s.process(service_message);
489 NodeList services = service_response.getElementsByTagName(GSXML.SERVICE_ELEM);
490 if (services.getLength()==0) {
491 logger.error("MessageRouter configure error: serviceRack "+service_name+" has no services!");
492 } else {
493 for (int j=0; j<services.getLength();j++) {
494 String service = ((Element)services.item(j)).getAttribute(GSXML.NAME_ATT);
495
496 this.module_map.put(service, s);
497
498 // add short info to service_list_ XML
499 this.service_list.appendChild(this.doc.importNode(services.item(j), true));
500 }
501 }
502 } catch (Exception e ) {
503 logger.error("MessageRouter configure exception: in ServiceRack class specification: "+ e.getMessage());
504 e.printStackTrace();
505 }
506 } // for each service module
507 return true;
508 }
509
510 protected boolean configureClusters(Element config_cluster_list) {
511
512 // load up the service clusters
513 logger.info("loading service clusters ...");
514 if (config_cluster_list == null) {
515 logger.info("... none to be loaded");
516 return true;
517 }
518 NodeList service_clusters = config_cluster_list.getElementsByTagName(GSXML.CLUSTER_ELEM);
519 if (service_clusters.getLength()==0) {
520 logger.info("... none to be loaded");
521 return true;
522 }
523
524 for (int i=0; i<service_clusters.getLength(); i++) {
525 Element cluster = (Element)service_clusters.item(i);
526 String name = cluster.getAttribute(GSXML.NAME_ATT);
527 logger.info("..."+name);
528 ServiceCluster sc = new ServiceCluster();
529 sc.setSiteHome(this.site_home);
530 sc.setSiteAddress(this.site_http_address);
531 sc.setClusterName(name);
532 sc.setMessageRouter(this);
533 if (!sc.configure(cluster)) {
534 logger.error ("couldn't configure ServiceCluster "+name);
535 continue;
536 }
537
538 this.module_map.put(name, sc); // this replaces the old one if there was one already present
539 //add short info to cluster list
540 Element e = this.doc.createElement(GSXML.CLUSTER_ELEM);
541 e.setAttribute(GSXML.NAME_ATT, name);
542 this.cluster_list.appendChild(e);
543
544 }
545 return true;
546 }
547
548 /** 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 */
549 protected boolean configureCollections() {
550
551 // read thru the collect directory and activate all the valid collections
552 File collectDir = new File(GSFile.collectDir(this.site_home));
553 if (collectDir.exists()) {
554 logger.info("Reading thru directory "+collectDir.getPath()+" to find collections.");
555 File[] contents = collectDir.listFiles();
556 for (int i=0; i<contents.length;i++) {
557 if(contents[i].isDirectory()) {
558
559 String colName = contents[i].getName();
560 if (!colName.startsWith("CVS") && !colName.startsWith(".svn")) {
561 activateCollectionByName(colName);
562 }
563 }
564 }
565 } // collectDir
566 return true;
567 }
568
569 /** creates and configures a new collection
570 if this is done for a reconfigure, the collection should be deactivated first.
571 *
572 *@param col_name the name of the collection
573 *@return true if collection created ok
574 */
575 protected boolean activateCollectionByName(String col_name) {
576
577 logger.info("Activating collection: "+col_name+".");
578
579 // Look for the etc/collectionInit.xml file, and see what sort of Collection to load
580 Collection c = null;
581 File init_file = new File(GSFile.collectionInitFile(this.site_home, col_name));
582
583 if (init_file.exists()) {
584 Document init_doc = this.converter.getDOM(init_file);
585 if (init_doc != null) {
586 Element init_elem = init_doc.getDocumentElement();
587 if (init_elem != null) {
588 String coll_class_name = init_elem.getAttribute("class");
589 if (!coll_class_name.equals("")) {
590 try {
591 c = (Collection)Class.forName("org.greenstone.gsdl3.collection."+coll_class_name).newInstance();
592 } catch (Exception e) {
593 logger.info(" couldn't create a new collection, type "+coll_class_name+", defaulting to class Collection");
594 }
595 }
596 }
597 }
598 }
599 if (c==null) { // we haven't found another classname to use
600 c = new Collection();
601 }
602
603 c.setCollectionName(col_name);
604 c.setSiteHome(this.site_home);
605 c.setSiteAddress(this.site_http_address);
606 c.setMessageRouter(this);
607 if (c.configure()) {
608 logger.info("have just configured collection " + col_name);
609 // add to list of collections
610 this.module_map.put(col_name, c);
611 Element e = this.doc.createElement(GSXML.COLLECTION_ELEM);
612 e.setAttribute(GSXML.NAME_ATT, col_name);
613
614 if(c.isPublic()) {
615 // only public collections will appear on the home page
616 // add short description_ to collection_list_
617 this.collection_list.appendChild(e);
618
619 if (c.hasOAI()) {
620 Element ane = this.doc.createElement(GSXML.COLLECTION_ELEM);
621 //The collection name is returned as site_name:coll_name, which is in fact the set specification
622 ane.setAttribute(GSXML.NAME_ATT, site_name + ":" + col_name);
623 ane.setAttribute(OAIXML.LASTMODIFIED, "" + c.getLastmodified());
624 // lastmodified not of use anymore for OAI, perhaps useful as general information
625 ane.setAttribute(OAIXML.EARLIEST_DATESTAMP, "" + c.getEarliestDatestamp()); // for OAI
626
627 this.oai_collection_list.appendChild(ane);
628 //logger.info(GSXML.xmlNodeToString(oai_collection_list));
629 }
630
631 } else {
632 this.private_collection_list.appendChild(e);
633 }
634 return true;
635 } else {
636 logger.error("Couldn't configure collection: "+
637 col_name+".");
638 return false;
639 }
640 }
641
642
643 /** Goes through the siteList and activates each site found. If this is done for a reconfigure, a clean up must be done first ****HOW??? */
644 protected boolean configureExternalSites(Element config_site_list) {
645
646 // load up the sites
647 logger.info("loading external sites...");
648 if (config_site_list ==null ) {
649 logger.info("...none found");
650 return true;
651 }
652
653 NodeList sites = config_site_list.getElementsByTagName(GSXML.SITE_ELEM);
654 if (sites.getLength()==0) {
655 logger.info("...none found");
656 return true;
657 }
658
659 // this is a name to identify the current site in the Communicator
660 String local_site_name = config_site_list.getAttribute(GSXML.LOCAL_SITE_NAME_ATT);
661 if (local_site_name.equals("")) {
662 local_site_name = site_name;
663 }
664
665 for (int i=0; i<sites.getLength(); i++) {
666 Element s = (Element)sites.item(i);
667 activateSite(s, local_site_name);
668 }
669 return true;
670 }
671
672 protected boolean activateSiteByName(String site_name) {
673 logger.info("Activating site: "+site_name+".");
674
675 File configFile = new File(GSFile.siteConfigFile(this.site_home));
676
677 if (!configFile.exists() ) {
678 logger.error(" site config file: "+configFile.getPath()+" not found!");
679 return false;
680 }
681 Document config_doc = this.converter.getDOM(configFile);
682 if (config_doc == null) {
683 logger.error(" couldn't parse site config file: "+configFile.getPath());
684 return false;
685 }
686 Element config_elem = config_doc.getDocumentElement();
687
688 Element config_site_list = (Element)GSXML.getChildByTagName(config_elem, GSXML.SITE_ELEM+GSXML.LIST_MODIFIER);
689 if (config_site_list ==null ) {
690 logger.error("activateSite, no sites found");
691 return false;
692 }
693 // this is a name to identify the current site in the Communicator
694 String local_site_name = config_site_list.getAttribute("localSiteName");
695 if (local_site_name.equals("")) {
696 local_site_name = site_name;
697 }
698
699 Element this_site_elem = GSXML.getNamedElement(config_site_list, GSXML.SITE_ELEM, GSXML.NAME_ATT, site_name);
700 if (this_site_elem == null) {
701 logger.error("activateSite, site "+site_name+" not found");
702 return false;
703 }
704
705 return activateSite(this_site_elem, local_site_name);
706 }
707
708 protected boolean activateSite(Element site_elem, String local_site_name) {
709
710 Communicator comm=null;
711 String type = site_elem.getAttribute(GSXML.TYPE_ATT);
712 String name = site_elem.getAttribute(GSXML.NAME_ATT);
713 if (type.equals(GSXML.COMM_TYPE_SOAP_JAVA)) {
714 logger.info("activating SOAP site "+name);
715 comm = new SOAPCommunicator();
716 if (comm.configure(site_elem)) {
717 comm.setLocalSiteName(local_site_name);
718
719 // add to map of modules
720 this.module_map.put(name, comm);
721 this.site_list.appendChild(this.doc.importNode(site_elem, true));
722 // need to get collection list and service
723 // list from here- if the site isn't up yet, the site will
724 // have to be added later
725 if (!getRemoteSiteInfo(comm, name)) {
726 logger.error(" couldn't get info from site");
727 }
728 } else {
729 logger.error(" couldn't configure site");
730 return false;
731 }
732
733 } else {
734 logger.error(" cant talk to server of type:"+type + ", so not making a connection to "+name);
735 return false;
736 }
737 return true;
738 }
739
740 /** Goes through the metadataList and loads each metadatum found */
741 protected boolean loadMetadata(Element config_metadata_list) {
742
743 // load up the sites
744 logger.info("loading site metadata...");
745 if (config_metadata_list ==null ) {
746 logger.info("...none found");
747 return true;
748 }
749
750 NodeList metadata = config_metadata_list.getElementsByTagName(GSXML.METADATA_ELEM);
751 if (metadata.getLength()==0) {
752 logger.info("...none found");
753 return true;
754 }
755
756
757 for (int i=0; i<metadata.getLength(); i++) {
758 Element s = (Element)metadata.item(i);
759 this.metadata_list.appendChild(this.doc.importNode(s, true));
760 }
761 return true;
762 }
763
764
765 /** get site info from external site
766 *
767 * @param comm - the communicator object for the external site
768 * @param site_name - the name of the external site
769 * @return true if successful
770 */
771 protected boolean getRemoteSiteInfo(Communicator comm, String site_name) {
772
773 logger.info(" getting info from site:"+site_name);
774
775 Element info_request = this.doc.createElement(GSXML.MESSAGE_ELEM);
776 Element req = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_DESCRIBE, "", "", "");
777 info_request.appendChild(req);
778
779 // process the message
780 Node info_response_node = comm.process(info_request);
781 Element info_response = converter.nodeToElement(info_response_node);
782
783 if (info_response == null) {
784 return false;
785 }
786 // collection info
787 NodeList colls = info_response.getElementsByTagName(GSXML.COLLECTION_ELEM);
788 if (colls.getLength()>0) {
789 for (int i=0; i<colls.getLength(); i++) {
790 Element e = (Element)colls.item(i);
791 String col_name = e.getAttribute(GSXML.NAME_ATT);
792 // add the info to own coll list - may want to keep
793 // this separate in future - so can distinguish own and
794 // other collections ??
795 e.setAttribute(GSXML.NAME_ATT, GSPath.prependLink(col_name, site_name));
796 this.collection_list.appendChild(this.doc.importNode(e, true));
797 }
798 }
799
800 // service info
801 NodeList services = info_response.getElementsByTagName(GSXML.SERVICE_ELEM);
802 if (services.getLength()>0) {
803 for (int i=0; i<services.getLength(); i++) {
804 Element e = (Element)services.item(i);
805 String serv_name = e.getAttribute(GSXML.NAME_ATT);
806 e.setAttribute(GSXML.NAME_ATT, GSPath.prependLink(serv_name, site_name));
807 this.service_list.appendChild(this.doc.importNode(e, true));
808 }
809 }
810
811 // serviceCluster info
812 NodeList clusters = info_response.getElementsByTagName(GSXML.CLUSTER_ELEM);
813 if (clusters.getLength()>0) {
814 for (int i=0; i<clusters.getLength(); i++) {
815 Element e = (Element)clusters.item(i);
816 String clus_name = e.getAttribute(GSXML.NAME_ATT);
817 e.setAttribute(GSXML.NAME_ATT, GSPath.prependLink(clus_name, site_name));
818 this.cluster_list.appendChild(this.doc.importNode(e, true));
819 }
820 }
821 return true;
822 }
823
824
825
826 protected boolean activateServiceClusterByName(String cluster_name) {
827 return false;
828
829 }
830
831 protected boolean activateServiceRackByName(String module_name) {
832 return false;
833 }
834
835 protected boolean deactivateModule(String type, String name) {
836
837 logger.info("deactivating "+ type+" module: "+name);
838 if (this.module_map.containsKey(name)) {
839
840 logger.info("found the module");
841 ModuleInterface m = (ModuleInterface)this.module_map.remove(name);
842 // also remove the xml bit from description list
843 if (type.equals(GSXML.COLLECTION_ELEM)) {
844 if (((Collection)m).isPublic()) {
845 Element this_col = GSXML.getNamedElement(this.collection_list, GSXML.COLLECTION_ELEM, GSXML.NAME_ATT, name);
846 if (this_col != null) {
847 this.collection_list.removeChild(this_col);
848 }
849 if (((Collection)m).hasOAI()) {
850 this_col = GSXML.getNamedElement(this.oai_collection_list, GSXML.COLLECTION_ELEM, GSXML.NAME_ATT, name);
851 if (this_col != null) {
852 this.oai_collection_list.removeChild(this_col);
853 }
854 }
855 } else {
856 // a private collection
857 Element this_col = GSXML.getNamedElement(this.private_collection_list, GSXML.COLLECTION_ELEM, GSXML.NAME_ATT, name);
858 if (this_col != null) {
859 this.private_collection_list.removeChild(this_col);
860 }
861 }
862 } else if (type.equals(GSXML.SERVICE_ELEM)) {
863 Element this_service = GSXML.getNamedElement(this.service_list, GSXML.SERVICE_ELEM, GSXML.NAME_ATT, name);
864 if (this_service != null) {
865 this.service_list.removeChild(this_service);
866 }
867 } else if (type.equals(GSXML.CLUSTER_ELEM)) {
868 Element this_cluster = GSXML.getNamedElement(this.cluster_list, GSXML.CLUSTER_ELEM, GSXML.NAME_ATT, name);
869 if (this_cluster != null) {
870 this.cluster_list.removeChild(this_cluster);
871 }
872 } else if (type.equals(GSXML.SITE_ELEM)) {
873 Element this_site = GSXML.getNamedElement(this.site_list, GSXML.SITE_ELEM, GSXML.NAME_ATT, name);
874 if (this_site != null) {
875 this.site_list.removeChild(this_site);
876
877 // also remove this sites colls, services, clusters etc
878 cleanUpModuleMapSubset(this.collection_list, name);
879 cleanUpModuleMapSubset(this.cluster_list, name);
880 cleanUpModuleMapSubset(this.service_list, name);
881
882 // can remote collections be in the oai_coll list, or private coll list ??
883 }
884 } else {
885 logger.error("invalid module type: "+type+", can't remove info about this module");
886 }
887
888 m.cleanUp(); // clean up any open files/connections etc - can cause trouble on windows
889 m=null;
890 return true;
891 }
892 // else not deactivated
893 logger.error(name+" module not found");
894 return false;
895
896 }
897
898 //*****************************************************************
899 // auxiliary process methods
900 //*****************************************************************
901
902 /** handles requests made to the MessageRouter itself
903 *
904 * @param req - the request Element- <request>
905 * @return the result Element - should be <response>
906 */
907 protected Element processMessage(Element req) {
908
909 // message for self, should be type=describe/configure at this stage
910 String type = req.getAttribute(GSXML.TYPE_ATT);
911 Element response = this.doc.createElement(GSXML.RESPONSE_ELEM);
912 response.setAttribute(GSXML.FROM_ATT, "");
913 if (type.equals(GSXML.REQUEST_TYPE_DESCRIBE)) {
914 response.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_DESCRIBE);
915 // check the param list
916 Element param_list = (Element) GSXML.getChildByTagName(req, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
917 if (param_list == null) {
918 response.appendChild(this.collection_list);
919 response.appendChild(this.cluster_list);
920 response.appendChild(this.site_list);
921 response.appendChild(this.service_list);
922 response.appendChild(this.metadata_list);
923 return response;
924 }
925
926 NodeList params = param_list.getElementsByTagName(GSXML.PARAM_ELEM);
927
928 // go through the param list and see what components are wanted
929 for (int i=0; i<params.getLength(); i++) {
930
931 Element param = (Element)params.item(i);
932 // Identify the structure information desired
933 if (param.getAttribute(GSXML.NAME_ATT).equals(GSXML.SUBSET_PARAM)) {
934 String info = param.getAttribute(GSXML.VALUE_ATT);
935 if (info.equals(GSXML.COLLECTION_ELEM+GSXML.LIST_MODIFIER)) {
936 response.appendChild(this.collection_list);
937 } else if (info.equals(GSXML.CLUSTER_ELEM+GSXML.LIST_MODIFIER)) {
938 response.appendChild(this.cluster_list);
939 } else if (info.equals(GSXML.SERVICE_ELEM+GSXML.LIST_MODIFIER)) {
940 response.appendChild(this.service_list);
941 } else if (info.equals(GSXML.SITE_ELEM+GSXML.LIST_MODIFIER)) {
942 response.appendChild(this.site_list);
943 } else if (info.equals(GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER)) {
944 response.appendChild(this.metadata_list);
945 }
946 }
947 }
948 return response;
949
950 }
951
952 if (type.equals(OAIXML.OAI_SET_LIST)) {
953 logger.info("oaiSetList request received");
954 //this is the oai receptionist asking for a list of oai-support collections
955 response.setAttribute(GSXML.TYPE_ATT, OAIXML.OAI_SET_LIST );
956 response.appendChild(this.oai_collection_list);
957 return response;
958 }
959
960
961 if (type.equals(GSXML.REQUEST_TYPE_SYSTEM)) {
962
963 // a list of system requests - should put any error messages
964 // or success messages into response
965 NodeList commands = req.getElementsByTagName(GSXML.SYSTEM_ELEM);
966 Element site_config_elem = null;
967 boolean success = false;
968
969 for (int i=0; i<commands.getLength(); i++) {
970 // all the commands should be Elements
971 Element elem = (Element)commands.item(i);
972 String action = elem.getAttribute(GSXML.TYPE_ATT);
973 if (action.equals(GSXML.SYSTEM_TYPE_CONFIGURE)) {
974 String subset = elem.getAttribute(GSXML.SYSTEM_SUBSET_ATT);
975 if (subset.equals("")) {
976 // need to reconfigure the MR
977 this.configureLocalSite();
978 Element s = GSXML.createTextElement(this.doc, GSXML.STATUS_ELEM, "MessageRouter reconfigured successfully");
979 response.appendChild(s);
980
981 } else {
982 // else it a specific request
983 if (subset.equals(GSXML.COLLECTION_ELEM+GSXML.LIST_MODIFIER)) {
984 // get rid of all the old collection stuff (not counting remote ones) before activating all the new ones
985 cleanUpModuleMapSubset(this.collection_list, null);
986 cleanUpModuleMapSubset(this.private_collection_list, null);
987 success = configureCollections();
988 } else {
989
990 // need the site config file
991 if (site_config_elem==null) {
992
993 File configFile = new File(GSFile.siteConfigFile(this.site_home));
994 if (!configFile.exists() ) {
995 logger.error(" site config file: "+configFile.getPath()+" not found!");
996 continue;
997 }
998 Document site_config_doc = this.converter.getDOM(configFile);
999 if (site_config_doc == null) {
1000 logger.error(" couldn't parse site config file: "+configFile.getPath());
1001 continue;
1002 }
1003 site_config_elem = site_config_doc.getDocumentElement();
1004 }
1005 if (subset.equals(GSXML.SERVICE_ELEM+GSXML.LIST_MODIFIER)) {
1006 Element service_rack_list = (Element)GSXML.getChildByTagName(site_config_elem, GSXML.SERVICE_CLASS_ELEM+GSXML.LIST_MODIFIER);
1007 cleanUpModuleMapSubset(this.service_list, null);
1008 success = configureServices(service_rack_list);
1009 } else if (subset.equals(GSXML.CLUSTER_ELEM+GSXML.LIST_MODIFIER)) {
1010 Element cluster_list = (Element)GSXML.getChildByTagName(site_config_elem, GSXML.CLUSTER_ELEM+GSXML.LIST_MODIFIER);
1011 cleanUpModuleMapSubset(this.cluster_list, null);
1012 success = configureClusters(cluster_list);
1013 } else if (subset.equals(GSXML.SITE_ELEM+GSXML.LIST_MODIFIER)) {
1014 Element site_list = (Element)GSXML.getChildByTagName(site_config_elem, GSXML.SITE_ELEM+GSXML.LIST_MODIFIER);
1015 cleanUpAllExternalSiteInfo();
1016 success = configureExternalSites(site_list);
1017 }
1018 }
1019 String message=null;
1020 if (success) {
1021 message = subset + "reconfigured successfully";
1022 } else {
1023 message = "Error in reconfiguring "+subset;
1024 }
1025 Element s = GSXML.createTextElement(this.doc, GSXML.STATUS_ELEM, message);
1026 response.appendChild(s);
1027 }
1028
1029
1030 } else {
1031 String module_name = elem.getAttribute(GSXML.SYSTEM_MODULE_NAME_ATT);
1032 String module_type = elem.getAttribute(GSXML.SYSTEM_MODULE_TYPE_ATT);
1033
1034 if (action.equals(GSXML.SYSTEM_TYPE_DEACTIVATE)) {
1035 success = deactivateModule(module_type, module_name);
1036 if (success) {
1037 Element s = GSXML.createTextElement(this.doc, GSXML.STATUS_ELEM, module_type+": "+module_name+" deactivated",
1038 GSXML.SYSTEM_TYPE_DEACTIVATE, GSXML.SUCCESS);
1039 response.appendChild(s);
1040 } else {
1041 Element s = GSXML.createTextElement(this.doc, GSXML.STATUS_ELEM, module_type+": "+module_name+" could not be deactivated",
1042 GSXML.SYSTEM_TYPE_DEACTIVATE, GSXML.ERROR);
1043 response.appendChild(s);
1044 }
1045
1046 } else if (action.equals(GSXML.SYSTEM_TYPE_ACTIVATE)) {
1047 // we need to deactivate the module first, in case this is a
1048 // reconfigure
1049 deactivateModule(module_type, module_name);
1050 if (module_type.equals(GSXML.COLLECTION_ELEM)) {
1051 success = activateCollectionByName(module_name);
1052 } else if (module_type.equals(GSXML.SITE_ELEM)) {
1053 success = activateSiteByName(module_name);
1054 } else if (module_type.equals(GSXML.CLUSTER_ELEM)) {
1055 success = activateServiceClusterByName(module_name);
1056 }
1057 if (success) {
1058 Element s = GSXML.createTextElement(this.doc, GSXML.STATUS_ELEM, module_type+": "+module_name+" activated",
1059 GSXML.SYSTEM_TYPE_ACTIVATE, GSXML.SUCCESS);
1060 response.appendChild(s);
1061 } else {
1062 Element s = GSXML.createTextElement(this.doc, GSXML.STATUS_ELEM, module_type+": "+module_name+" could not be activated",
1063 GSXML.SYSTEM_TYPE_ACTIVATE, GSXML.ERROR);
1064 response.appendChild(s);
1065 }
1066 }
1067 } // else not a configure action
1068 } // for all commands
1069 return response;
1070
1071
1072 } // system type request
1073
1074 // if get here something has gone wrong
1075 logger.error(" cant process request:");
1076 logger.error(this.converter.getString(req));
1077 return null;
1078
1079 }
1080
1081 //* 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... */
1082
1083 protected Element modifyMessages(Element request, Element message, Element result) {
1084 Element response = this.doc.createElement(GSXML.RESPONSE_ELEM);
1085 response.setAttribute(GSXML.FROM_ATT, "");
1086 response.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_MESSAGING);
1087
1088 NodeList commands = request.getElementsByTagName("command");
1089 if (commands == null) {
1090 logger.error("no commands, "+converter.getPrettyString(request));
1091 return response;
1092 }
1093 for (int i=0; i<commands.getLength(); i++) {
1094 Element action = (Element)commands.item(i);
1095 String type = action.getAttribute(GSXML.TYPE_ATT);
1096 if (type.equals("copyNode")) {
1097 // copies the from node as a child of to node
1098 String from_path = action.getAttribute("from");
1099 String to_path = action.getAttribute("to");
1100 Element from_node = null;
1101 String from_node_root = GSPath.getFirstLink(from_path);
1102 if (from_node_root.startsWith(GSXML.REQUEST_ELEM)) {
1103 from_node = message;
1104 } else if (from_node_root.startsWith(GSXML.RESPONSE_ELEM)) {
1105 from_node = result;
1106 }
1107 if (from_node == null) {
1108 continue;
1109 }
1110 Element to_node = null;
1111 String to_node_root = GSPath.getFirstLink(to_path);
1112 if (to_node_root.startsWith(GSXML.REQUEST_ELEM)) {
1113 to_node = message;
1114 } else if (to_node_root.startsWith(GSXML.RESPONSE_ELEM)) {
1115 to_node = result;
1116 }
1117 if (to_node == null) {
1118 continue;
1119 }
1120 // now we know what node to copy where
1121 Node orig_node = GSXML.getNodeByPathIndexed(from_node, from_path);
1122 if (orig_node == null) {
1123 continue;
1124 }
1125 Node new_parent = GSXML.getNodeByPathIndexed(to_node, to_path);
1126 if (new_parent == null) {
1127 continue;
1128
1129 }
1130 new_parent.appendChild(to_node.getOwnerDocument().importNode(orig_node, true));
1131 }
1132
1133 else if (type.equals("copyChildren")) {
1134
1135 }
1136 } // for each command
1137 return response;
1138 }
1139
1140 // ****************************************************
1141 // other methods
1142 // ****************************************************
1143
1144
1145
1146}
1147
1148
Note: See TracBrowser for help on using the repository browser.