/*
* JBoss, Home of Professional Open Source.
* Copyright 2009, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.ha.framework.server;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.jboss.logging.Logger;
import org.jgroups.conf.ConfiguratorFactory;
import org.jgroups.conf.ProtocolData;
import org.jgroups.conf.ProtocolParameter;
import org.jgroups.conf.ProtocolStackConfigurator;
import org.jgroups.conf.XmlConfigurator;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* Utilities related to JGroups protocol stack manipulation.
*
* @author Brian Stansberry
*
* @version $Revision: $
*/
public final class ProtocolStackUtil
{
private static final Logger log = Logger.getLogger(ProtocolStackUtil.class);
private static final String PROTOCOL_STACKS="protocol_stacks";
private static final String STACK="stack";
private static final String NAME="name";
private static final String DESCR="description";
private static final String CONFIG="config";
/**
* Parses the contents of <code>input</code> into a map of the
* protocol stack configurations contained in the XML.
*
* @param input stream which must contain XML content in the JGroups
* <code>stacks.xml</code> format
*
* @return a map of the protocol stack configurations contained in the XML
*
* @throws IllegalArgumentException if <code>input</code> is <code>null</code>
* @throws Exception
*/
public static Map<String, ProtocolStackConfigInfo> parse(InputStream input) throws Exception
{
if (input == null)
{
throw new IllegalArgumentException("null input");
}
DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
factory.setValidating(false); //for now
DocumentBuilder builder=factory.newDocumentBuilder();
Document document=builder.parse(input);
// The root element of the document should be the "config" element,
// but the parser(Element) method checks this so a check is not
// needed here.
Element configElement = document.getDocumentElement();
return parse(configElement);
}
/**
* Parses the contents of <code>root</code> into a map of the
* protocol stack configurations contained in the XML.
*
* @param root document root node for XML content in the JGroups
* <code>stacks.xml</code> format
*
* @return a map of the protocol stack configurations contained in the XML
*
* @throws IllegalArgumentException if <code>input</code> is <code>null</code>
* @throws Exception
*/
public static Map<String, ProtocolStackConfigInfo> parse(Element root) throws Exception
{
if (root == null)
{
throw new IllegalArgumentException("null root");
}
String root_name = root.getNodeName();
if (!PROTOCOL_STACKS.equals(root_name.trim().toLowerCase()))
{
throw new IOException("Invalid XML configuration: configuration does not start with a '" +
PROTOCOL_STACKS + "' element");
}
Map<String, ProtocolStackConfigInfo> result = new HashMap<String, ProtocolStackConfigInfo>();
NodeList tmp_stacks = root.getChildNodes();
for (int i = 0; i < tmp_stacks.getLength(); i++)
{
Node node = tmp_stacks.item(i);
if (node.getNodeType() != Node.ELEMENT_NODE)
continue;
Element stack = (Element) node;
String tmp = stack.getNodeName();
if (!STACK.equals(tmp.trim().toLowerCase()))
{
throw new IOException("Invalid configuration: didn't find a \"" + STACK + "\" element under \""
+ PROTOCOL_STACKS + "\"");
}
NamedNodeMap attrs = stack.getAttributes();
Node name = attrs.getNamedItem(NAME);
String st_name = name.getNodeValue();
Node descr=attrs.getNamedItem(DESCR);
String stack_descr=descr.getNodeValue();
if (log.isTraceEnabled())
{
log.trace("Parsing \"" + st_name + "\" (" + stack_descr + ")");
}
NodeList configs = stack.getChildNodes();
for (int j = 0; j < configs.getLength(); j++)
{
Node tmp_config = configs.item(j);
if (tmp_config.getNodeType() != Node.ELEMENT_NODE)
continue;
Element cfg = (Element) tmp_config;
tmp = cfg.getNodeName();
if (!CONFIG.equals(tmp))
{
throw new IOException("Invalid configuration: didn't find a \"" +
CONFIG + "\" element under \"" + STACK + "\"");
}
XmlConfigurator conf = XmlConfigurator.getInstance(cfg);
// fixes http://jira.jboss.com/jira/browse/JGRP-290
ConfiguratorFactory.substituteVariables(conf); // replace vars with system props
result.put(st_name, new ProtocolStackConfigInfo(st_name, stack_descr, conf));
}
}
return result;
}
public static ProtocolData[] getProtocolData(ProtocolStackConfigurator config)
{
ProtocolData[] result = null;
try
{
result = config.getProtocolStack();
}
catch (UnsupportedOperationException e)
{
String s = config.getProtocolStackString();
String[] prots = s.split(":");
result = new ProtocolData[prots.length];
for (int i = 0; i < prots.length; i++)
{
ProtocolParameter[] params = null;
int paren = prots[i].indexOf('(');
String name = paren > - 1 ? prots[i].substring(0, paren) : prots[1];
if (paren > -1 && paren < prots[1].length() - 2)
{
String unsplit = prots[i].substring(paren + 1, prots[i].length() -1);
String[] split = unsplit.split(";");
params = new ProtocolParameter[split.length];
for (int j = 0; j < split.length; j++)
{
String[] keyVal = split[j].split("=");
params[j] = new ProtocolParameter(keyVal[0], keyVal[1]);
}
}
else
{
params = new ProtocolParameter[0];
}
result[i] = new ProtocolData(name, null, name, params);
}
}
return result == null ? new ProtocolData[0] : result;
}
/**
* Prevent instantiation.
*/
private ProtocolStackUtil()
{
}
}