/*
* MessageRouter.java
* Copyright (C) 2002 New Zealand Digital Library, http://www.nzdl.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package org.greenstone.gsdl3.core;
import org.greenstone.gsdl3.util.*;
import org.greenstone.gsdl3.service.*;
import org.greenstone.gsdl3.comms.*;
import org.greenstone.gsdl3.collection.*;
// XML classes
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.InputSource;
import javax.xml.parsers.*;
// other java classes
import java.io.File;
import java.util.HashMap;
import java.util.Iterator;
import java.io.Reader;
import java.io.StringReader;
/**
* The hub of a Greenstone system.
*
* Accepts XML requests (via process method of ModuleInterface) and routes them to the appropriate collection or
* service or external entity.
*
* contains a map of module objects - may be services, collections, comms
* objects talking to other MessageRouters etc.
*
*
* @author Katherine Don
* @version $Revision: 4141 $
* @see ModuleInterface
* @see Collection
* @see ServiceRack
* @see Communicator
*
*/
public class MessageRouter implements ModuleInterface {
/** site home - the home directory for the site */
protected String site_home=null;
/** the http address for this site */
protected String site_http_address=null;
/** the global name for this site */
protected String global_site_name=null;
/** map of names to Module objects */
protected HashMap module_map=null;
/** container Document to create XML Nodes */
protected Document doc=null;
/** the full description of this site */
// should these things be separated into local and remote??
/** list of collections that can be reached */
protected Element collection_list = null;
/** list of service clusters that can be reached */
protected Element cluster_list = null;
/** list of single services that can be reached */
protected Element service_list = null;
/** list of sites that can be reached */
protected Element site_list = null;
/** a converter class to parse XML and create Docs */
protected XMLConverter converter=null;
//***************************************************************
// public methods
//***************************************************************
/** constructor */
public MessageRouter() {
this.converter = new XMLConverter();
this.doc = this.converter.newDOM();
}
/** site_home must be set before configure called */
public void setSiteHome(String home) {
this.site_home = home;
}
/**
* configures the system
*
* looks in site_home/collect for collections, reads config file
* site_home/sitecfg.xml
*
*/
public boolean configure() {
System.out.println("MessageRouter:configuring site");
if (this.site_home==null) {
System.err.println("You must set site_home before calling configure");
return false;
}
// read thru own config file - create services and connect to sites
File configFile = new File(GSFile.siteConfigFile(this.site_home));
if (!configFile.exists() ) {
System.err.println("MessageRouter: site config file: "+configFile.getPath()+" not found!");
return false;
}
this.module_map = new HashMap();
Element config = this.converter.getDOM(configFile).getDocumentElement();
Element local_site_name = (Element)GSXML.getChildByTagName(config, GSXML.SITE_NAME_ELEM);
if (local_site_name == null) {
System.err.println("MessageRouter configure error:no site name in config file");
return false;
} else {
this.global_site_name = local_site_name.getAttribute(GSXML.VALUE_ATT);
}
Element http_address = (Element)GSXML.getChildByTagName(config, GSXML.SITE_HTTP_ADDRESS_ELEM);
if (http_address == null) {
System.err.println("MessageRouter configure error: no http address in config file");
return false;
} else {
this.site_http_address = http_address.getAttribute(GSXML.VALUE_ATT);
}
// load up the services
Element service_rack_list = (Element)GSXML.getChildByTagName(config, GSXML.SERVICE_CLASS_ELEM+GSXML.LIST_MODIFIER);
configureServices(service_rack_list);
// load up the service clusters
Element cluster_list = (Element)GSXML.getChildByTagName(config, GSXML.CLUSTER_ELEM+GSXML.LIST_MODIFIER);
configureClusters(cluster_list);
// load up the collections
configureCollections();
// load up the external sites - this also adds their services/clusters/collections to the other lists - so must be done last
Element site_list = (Element)GSXML.getChildByTagName(config, GSXML.SITE_ELEM+GSXML.LIST_MODIFIER);
configureSites(site_list);
return true;
}
/**
* Process an XML request - as a String
*
* @param xml_in the request to process
* @return the response - contains any error messages
* @see String
*/
public String process(String xml_in) {
Document doc = this.converter.getDOM(xml_in);
Element result = process(doc.getDocumentElement());
return this.converter.getString(result);
}
/**
* Process an XML request - as a DOM Element
*
* @param xml_in the message to process - should be
* @return the response - contains any error messages
* @see Element
*/
public Element process(Element message) {
System.out.println("MR received request");
System.out.println(this.converter.getString(message));
// check that its a correct message tag
if (!message.getTagName().equals(GSXML.MESSAGE_ELEM)) {
System.err.println("Invalid message. GSDL message should start with <"+GSXML.MESSAGE_ELEM+">, instead it starts with:"+message.getTagName()+".");
return null;
}
NodeList requests = message.getElementsByTagName(GSXML.REQUEST_ELEM);
Element mainResult = this.doc.createElement(GSXML.MESSAGE_ELEM);
// empty request
if (requests.getLength()==0) {
return mainResult;
}
Document message_doc = message.getOwnerDocument();
// for now, just process each request one by one, and append the results to mainResult
// Note: if you add an element to another node in the same document, it
// 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
int num_requests = requests.getLength();
for (int i=0; i< num_requests; i++) {
Node result=null;
Element req = (Element)requests.item(0);
String path = req.getAttribute(GSXML.TO_ATT); // returns "" if no att of this name
if (path.equals("")) {
// its a message for the message router
result = processMessage(req);
mainResult.appendChild(this.doc.importNode(result, true));
} else {
// find the module to pass it on to
// need to put the request into a message element
Element mess = message_doc.createElement(GSXML.MESSAGE_ELEM);
mess.appendChild(req);
String obj = GSPath.getFirstLink(path);
if (this.module_map.containsKey(obj)) {
result = ((ModuleInterface)this.module_map.get(obj)).process(mess);
if (result !=null ) {
// append the contents of the message to the mainResult - there will only be one response at this stage
mainResult.appendChild(this.doc.importNode(GSXML.getChildByTagName(result, GSXML.RESPONSE_ELEM), true));
} else {
System.err.println("MessageRouter Error: request had null result!");
}
} else {
System.err.println("MessageRouter Error: request has illegal module name in:\n"+this.converter.getString(req));
}
}
} // for each request
System.out.println("MR returned response");
System.out.println(this.converter.getString(mainResult));
return mainResult;
}
// ********************************************************************
// auxiliary configure methods
// *******************************************************************
protected boolean configureServices(Element service_rack_list) {
this.service_list = this.doc.createElement(GSXML.SERVICE_ELEM+GSXML.LIST_MODIFIER);
// load up the individual services
System.out.println("loading service modules...");
if (service_rack_list == null) {
System.out.println("... none to be loaded");
return true;
}
NodeList service_racks = service_rack_list.getElementsByTagName(GSXML.SERVICE_CLASS_ELEM);
if (service_racks.getLength()==0) {
System.out.println("... none to be loaded");
return true;
}
Element service_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
Element service_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_DESCRIBE, "", "");
service_message.appendChild(service_request);
for(int i=0; i0) {
for (int i=0; i0) {
for (int i=0; i0) {
for (int i=0; i
* @return the result Element - should be
*/
protected Element processMessage(Element req) {
// message for self, should be type=describe/configure at this stage
String type = req.getAttribute(GSXML.TYPE_ATT);
Element response = this.doc.createElement(GSXML.RESPONSE_ELEM);
response.setAttribute(GSXML.FROM_ATT, "");
if (type.equals(GSXML.REQUEST_TYPE_DESCRIBE)) {
response.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_DESCRIBE);
// check the param list
Element param_list = (Element) GSXML.getChildByTagName(req, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
if (param_list == null) {
response.appendChild(this.collection_list);
response.appendChild(this.cluster_list);
response.appendChild(this.site_list);
response.appendChild(this.service_list);
return response;
}
System.out.println("params found, getting subset");
NodeList params = param_list.getElementsByTagName(GSXML.PARAM_ELEM);
// go through the param list and see what components are wanted
for (int i=0; i