org.jgroups.conf.XmlConfigurator Maven / Gradle / Ivy
Go to download
This artifact provides a single jar that contains all classes required to use remote EJB and JMS, including
all dependencies. It is intended for use by those not using maven, maven users should just import the EJB and
JMS BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up
with different versions on classes on the class path).
package org.jgroups.conf;
import org.jgroups.logging.Log;
import org.jgroups.logging.LogFactory;
import org.jgroups.util.Tuple;
import org.jgroups.util.Util;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import static org.jgroups.util.Util.readTillMatchingCharacter;
/**
* Uses XML to configure a protocol stack
* @author Vladimir Blagojevic
* @author Bela Ban
*/
public class XmlConfigurator implements ProtocolStackConfigurator {
private final List configuration=new ArrayList<>();
protected static final Log log=LogFactory.getLog(XmlConfigurator.class);
protected enum ElementType {
START, COMPLETE, END, COMMENT, UNDEFINED
}
protected XmlConfigurator(List protocols) {
configuration.addAll(protocols);
}
public static XmlConfigurator getInstance(InputStream stream) throws java.io.IOException {
return parse(stream);
}
/**
*
* @param convert If false: print old plain output, else print new XML format
* @return String with protocol stack in specified format
*/
public String getProtocolStackString(boolean convert) {
StringBuilder buf=new StringBuilder();
Iterator it=configuration.iterator();
if(convert)
buf.append("\n");
while(it.hasNext()) {
ProtocolConfiguration d=it.next();
if(convert)
buf.append(" <");
buf.append(d.getProtocolString(convert));
if(convert)
buf.append("/>");
if(it.hasNext()) {
if(convert)
buf.append('\n');
else
buf.append(':');
}
}
if(convert)
buf.append("\n ");
return buf.toString();
}
public String getProtocolStackString() {
return getProtocolStackString(false);
}
public List getProtocolStack() {
return configuration;
}
protected static XmlConfigurator parse(InputStream stream) throws java.io.IOException {
try {
XmlNode root=parseXmlDocument(stream);
return parse(root);
}
catch (Exception x) {
throw new IOException(String.format(Util.getMessage("ParseError"), x.getLocalizedMessage()));
}
}
private static InputStream getAsInputStreamFromClassLoader(String filename) {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
InputStream is = cl == null ? null : cl.getResourceAsStream(filename);
if (is == null) {
// check system class loader
is = XmlConfigurator.class.getClassLoader().getResourceAsStream(filename);
}
return is;
}
protected static XmlConfigurator parse(XmlNode root) throws Exception {
return new XmlConfigurator(parseProtocols(root));
}
public static List parseProtocols(XmlNode root) throws Exception {
String root_name=root.getName().trim().toLowerCase();
if(!"config".equals(root_name))
throw new IOException("the configuration does not start with a element: " + root_name);
List prot_data=new ArrayList<>();
for(XmlNode node: root.getChildren()) {
String protocol=node.getName();
Map attrs=node.getAttributes();
ProtocolConfiguration cfg=new ProtocolConfiguration(protocol, attrs);
prot_data.add(cfg);
// store protocol-specific configuration (if available); this will be passed to the protocol on
// creation to to parse
List subnodes=node.getChildren();
if(subnodes == null)
continue;
for(XmlNode subnode: subnodes) {
cfg.addSubtree(subnode);
}
}
return prot_data;
}
/** Reads XML and returns a simple tree of XmlNodes */
public static XmlNode parseXmlDocument(InputStream in) throws IOException {
Deque stack=new ArrayDeque<>();
XmlNode current=null;
while(true) {
String s=readNode(in);
if(s == null)
break;
s=sanitize(s);
ElementType type=getType(s);
if(type == ElementType.COMMENT)
continue;
// remove "<", "/> and ">"
s=s.replace("<", "").replace( "/>", "").replace(">", "")
.trim();
InputStream input=new ByteArrayInputStream(s.getBytes());
String name=Util.readToken(input);
XmlNode n=new XmlNode(name);
for(;;) {
Tuple tuple=readAttribute(input);
if(tuple == null)
break;
n.addAttribute(tuple.getVal1(), tuple.getVal2());
}
current=stack.peekFirst();
switch(type) {
case COMPLETE:
current.addChild(n);
break;
case START:
if(current != null)
current.addChild(n);
stack.push(n);
break;
case END:
stack.pop();
}
}
return current;
}
protected static String readNode(InputStream in) throws IOException {
String tmp=readTillMatchingCharacter(in, '<');
if(tmp == null)
return null;
StringBuilder sb=new StringBuilder("<");
tmp=readTillMatchingCharacter(in, '>');
if(tmp == null)
return null;
sb.append(tmp);
return sb.toString();
}
/** Fixes errors like "/ >" with "/>" */
protected static String sanitize(String s) {
return s.replaceAll("/\\s*>", "/>");
}
protected static Tuple readAttribute(InputStream in) throws IOException {
String attr_name=readTillMatchingCharacter(in, '=');
if(attr_name == null)
return null;
attr_name=attr_name.replace("=", "").trim();
String val=readQuotedString(in);
if(val == null)
return null;
return new Tuple<>(attr_name, val);
}
/** Reads the characters between a start and end quote ("). Skips chars escaped with '\' */
protected static String readQuotedString(InputStream in) throws IOException {
String s=readTillMatchingCharacter(in, '"');
if(s == null)
return null;
StringBuilder sb=new StringBuilder();
boolean escaped=false;
for(;;) {
int ch=in.read();
if(ch == -1)
break;
if(ch == '\\') {
escaped=true;
continue;
}
if(escaped)
escaped=false;
else if(ch == '"')
break;
sb.append((char)ch);
}
return sb.toString();
}
protected static ElementType getType(String s) {
s=s.trim();
if(s.startsWith("