All Downloads are FREE. Search and download functionalities are using the official Maven repository.

bboss.org.jgroups.conf.XmlConfigurator Maven / Gradle / Ivy

The newest version!

package bboss.org.jgroups.conf;

/**
 * Uses XML to configure a protocol stack
 * @author Vladimir Blagojevic
 * @version $Id: XmlConfigurator.java,v 1.27 2009/10/23 17:01:40 vlada Exp $
 */

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.Vector;
import java.util.concurrent.atomic.AtomicReference;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import bboss.org.jgroups.Global;
import bboss.org.jgroups.logging.Log;
import bboss.org.jgroups.logging.LogFactory;
import bboss.org.jgroups.stack.Configurator;
import bboss.org.jgroups.stack.Configurator.ProtocolConfiguration;
import bboss.org.jgroups.util.Util;
import org.w3c.dom.Attr;
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;
import org.xml.sax.EntityResolver;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

public class XmlConfigurator implements ProtocolStackConfigurator {
   
    private static final String JAXP_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";

    private static final String W3C_XML_SCHEMA = "http://www.w3.org/2001/XMLSchema";

    public static final String ATTR_NAME="name";
    public static final String ATTR_VALUE="value";
    public static final String ATTR_INHERIT="inherit";
    public static final String ELMT_PROT_OVERRIDE="protocol-override";
    public static final String ELMT_PROT="protocol";
    public static final String ELMT_PROT_NAME="protocol-name";
    public static final String ELMT_CLASS="class-name";
    public static final String ELMT_DESCRIPTION="description";
    public static final String ELMT_PROT_PARAMS="protocol-params";

    private final ArrayList mProtocolStack=new ArrayList();
    private final String mStackName;
    protected static final Log log=LogFactory.getLog(XmlConfigurator.class);

    protected XmlConfigurator(String stackName,ProtocolData[] protocols) {
        mStackName=stackName;
        mProtocolStack.addAll(Arrays.asList(protocols));
    }

    protected XmlConfigurator(String stackName) {
        this(stackName, new ProtocolData[0]);
    }

    public static XmlConfigurator getInstance(URL url) throws java.io.IOException {
        return getInstance(url, null);
    }

    public static XmlConfigurator getInstance(InputStream stream) throws java.io.IOException {
        return getInstance(stream, null);
    }

    public static XmlConfigurator getInstance(Element el) throws java.io.IOException {
        return parse(el);
    }

    public static XmlConfigurator getInstance(URL url, Boolean validate) throws java.io.IOException {
        InputStream is = url.openStream();
        try {
            return getInstance(is, validate);
        } finally {
            try {
                is.close();
            } catch (IOException e) {
                log.warn("Failed to close InputStream", e);
            }
        }
    }

    public static XmlConfigurator getInstance(InputStream stream, Boolean validate) throws java.io.IOException {
        return parse(stream, validate);
    }

    /**
     * 
     * @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=mProtocolStack.iterator();
        if(convert)
            buf.append("\n");
        while(it.hasNext()) {
            ProtocolData 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 ProtocolData[] getProtocolStack() {
        return mProtocolStack.toArray(new ProtocolData[mProtocolStack.size()]);
    }

    public String getName() {
        return mStackName;
    }

    public void override(ProtocolData data) throws IOException {
        int index=mProtocolStack.indexOf(data);
        if(index < 0)
            throw new IOException("You can not override a protocol that doesn't exist");
        ProtocolData source=mProtocolStack.get(index);
        source.override(data.getParametersAsArray());
    }

    public void add(ProtocolData data) {
        mProtocolStack.add(data);
    }



    protected static XmlConfigurator parse(InputStream stream, Boolean validate) throws java.io.IOException {
        /**
         * CAUTION: crappy code ahead ! I (bela) am not an XML expert, so the code below is pretty
         * amateurish... But it seems to work, and it is executed only on startup, so no perf loss
         * on the critical path. If somebody wants to improve this, please be my guest.
         */
        try {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            boolean validation = false;
            String tmp = Util.getProperty(new String[] { Global.XML_VALIDATION }, null, null, false, null);
            if (tmp != null) {
                validation = Boolean.valueOf(tmp).booleanValue();
            } else if (validate != null) {
                validation = validate.booleanValue();
            }
            factory.setValidating(validation);
            factory.setNamespaceAware(validation);
            if (validation) {
                factory.setAttribute(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA);
            }
            
            DocumentBuilder builder = factory.newDocumentBuilder();
            builder.setEntityResolver(new EntityResolver() {

                public InputSource resolveEntity(String publicId, String systemId) throws IOException {
                    if (systemId != null && systemId.startsWith("http://www.jgroups.org/schema/JGroups-")) {
                        String schemaName = systemId.substring("http://www.jgroups.org/".length());                        
                        InputStream schemaIs = getAsInputStreamFromClassLoader(schemaName);
                        if (schemaIs == null) {
                            throw new IOException("Schema not found from classloader: " + schemaName);
                        }
                        InputSource source = new InputSource(schemaIs);
                        source.setPublicId(publicId);
                        source.setSystemId(systemId);
                        return source;
                    }
                    return null;
                }
            });
            // Use AtomicReference to allow make variable final, not for atomicity
            // We store only last exception
            final AtomicReference exceptionRef = new AtomicReference();
            builder.setErrorHandler(new ErrorHandler() {

                public void warning(SAXParseException exception) throws SAXException {
                    log.warn("Warning during parse", exception);
                }

                public void fatalError(SAXParseException exception) throws SAXException {
                    log.fatal("Error during parse", exception);
                    exceptionRef.set(exception);
                }

                public void error(SAXParseException exception) throws SAXException {
                    log.error("Error during parse", exception);
                    exceptionRef.set(exception);
                }
            });
            Document document = builder.parse(stream);
            if (exceptionRef.get() != null) {
                throw exceptionRef.get();
            }

            // 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);
        } catch (Exception x) {
            if (x instanceof java.io.IOException)
                throw (java.io.IOException) x;
            else {
                IOException tmp = new IOException();
                tmp.initCause(x);
                throw tmp;
            }
        }
    }

    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(Element root_element) throws java.io.IOException {
        XmlConfigurator configurator=null;

        /** LinkedList */
        LinkedList prot_data=new LinkedList();

        /**
         * CAUTION: crappy code ahead ! I (bela) am not an XML expert, so the
         * code below is pretty amateurish... But it seems to work, and it is
         * executed only on startup, so no perf loss on the critical path. If
         * somebody wants to improve this, please be my guest.
         */
        try {
            String root_name=root_element.getNodeName();
            if(!"config".equals(root_name.trim().toLowerCase())) {
                log.fatal("XML protocol stack configuration does not start with a '' element; " + "maybe the XML configuration needs to be converted to the new format ?\n"
                          + "use 'java bboss.org.jgroups.conf.XmlConfigurator  -new_format' to do so");
                throw new IOException("invalid XML configuration");
            }

            NodeList prots=root_element.getChildNodes();
            for(int i=0;i < prots.getLength();i++) {
                Node node=prots.item(i);
                if(node.getNodeType() != Node.ELEMENT_NODE)
                    continue;

                Element tag=(Element)node;
                String protocol=tag.getTagName();
                // System.out.println("protocol: " + protocol);
                LinkedList tmp=new LinkedList();

                NamedNodeMap attrs=tag.getAttributes();
                int attrLength=attrs.getLength();
                for(int a=0;a < attrLength;a++) {
                    Attr attr=(Attr)attrs.item(a);
                    String name=attr.getName();
                    String value=attr.getValue();
                    // System.out.println("    name=" + name + ", value=" + value);
                    tmp.add(new ProtocolParameter(name, value));
                }
                ProtocolParameter[] params=new ProtocolParameter[tmp.size()];
                for(int j=0;j < tmp.size();j++)
                    params[j]=tmp.get(j);
                ProtocolData data=new ProtocolData(protocol, protocol, params);
                prot_data.add(data);
            }

            ProtocolData[] data=new ProtocolData[(prot_data.size())];
            for(int k=0;k < prot_data.size();k++)
                data[k]=prot_data.get(k);
            configurator=new XmlConfigurator("bla", data);
        }
        catch(Exception x) {
            if(x instanceof java.io.IOException)
                throw (java.io.IOException)x;
            else {
                IOException tmp=new IOException();
                tmp.initCause(x);
                throw tmp;
            }
        }
        return configurator;
    }



    protected static ProtocolParameter[] parseProtocolParameters(Element protparams) throws IOException {
        try {
            Vector v=new Vector();
            protparams.normalize();
            NodeList parameters=protparams.getChildNodes();
            for(int i=0;i < parameters.getLength();i++) {
                if(parameters.item(i).getNodeType() == Node.ELEMENT_NODE) {
                    String pname=parameters.item(i).getAttributes().getNamedItem(ATTR_NAME).getNodeValue();
                    String pvalue=parameters.item(i).getAttributes().getNamedItem(ATTR_VALUE).getNodeValue();
                    ProtocolParameter p=new ProtocolParameter(pname, pvalue);
                    v.addElement(p);
                }//end if
            }//for
            ProtocolParameter[] result=new ProtocolParameter[v.size()];
            v.copyInto(result);
            return result;
        }
        catch(Exception x) {
            IOException tmp=new IOException();
            tmp.initCause(x);
            throw tmp;
        }
    }

    public static void main(String[] args) throws Exception {
        String input_file=null;
        XmlConfigurator conf;
        boolean old_format=false;

        for(int i=0;i < args.length;i++) {
            if(args[i].equals("-old")) {
                old_format=true;
                continue;
            }
            if(args[i].equals("-file")) {
                input_file=args[++i];
                continue;
            }
            help();
            return;
        }

        if(input_file != null) {
            InputStream input=null;

            try {
                input=new FileInputStream(new File(input_file));
            }
            catch(Throwable t) {
            }
            if(input == null) {
                try {
                    input=new URL(input_file).openStream();
                }
                catch(Throwable t) {
                }
            }

            if(input == null)
                input=Thread.currentThread().getContextClassLoader().getResourceAsStream(input_file);

            if(old_format) {
                String cfg=inputAsString(input);
                Vector tmp=Configurator.parseConfigurations(cfg);
                System.out.println(dump(tmp));

                //                conf=XmlConfigurator.getInstanceOldFormat(input);
                //                output=conf.getProtocolStackString(true);
                //                output=replace(output, "bboss.org.jgroups.protocols.", "");
                //                System.out.println(getTitle(input_file));
                //                System.out.println('\n' + output);
            }
            else {
                conf=XmlConfigurator.getInstance(input);
                String tmp=conf.getProtocolStackString();
                System.out.println("\n" + tmp);
            }
        }
        else {
            log.error("no input file given");
        }
    }

    /**
     * @param tmp
     *                Vector of Configurator.ProtocolConfiguration
     * @return String (XML format)
     */
    private static String dump(Collection configs) {
        StringBuilder sb=new StringBuilder();
        String indent="  ";
        sb.append("\n");

        for(ProtocolConfiguration cfg: configs) {
            sb.append(indent).append("<").append(cfg.getProtocolName());
            Map props=cfg.getProperties();
            if(props.isEmpty()) {
                sb.append(" />\n");
            }
            else {
                sb.append("\n").append(indent).append(indent);
                for(Map.Entry entry: props.entrySet()) {
                    String key=entry.getKey();
                    String val=entry.getValue();
                    key=trim(key);
                    val=trim(val);
                    sb.append(key).append("=\"").append(val).append("\"");
                }
                sb.append(" />\n");
            }
        }

        sb.append("\n");
        return sb.toString();
    }

    private static String trim(String val) {
        String retval="";
        int index;

        val=val.trim();
        while(true) {
            index=val.indexOf('\n');
            if(index == -1) {
                retval+=val;
                break;
            }
            retval+=val.substring(0, index);
            val=val.substring(index + 1);
        }

        return retval;
    }

    private static String inputAsString(InputStream input) throws IOException {
        int len=input.available();
        byte[] buf=new byte[len];
        input.read(buf, 0, len);
        return new String(buf);
    }

    public static String replace(String input, final String expr, String replacement) {
        StringBuilder sb=new StringBuilder();
        int new_index=0, index=0, len=expr.length(), input_len=input.length();

        while(true) {
            new_index=input.indexOf(expr, index);
            if(new_index == -1) {
                sb.append(input.substring(index, input_len));
                break;
            }
            sb.append(input.substring(index, new_index));
            sb.append(replacement);
            index=new_index + len;
        }

        return sb.toString();
    }

    static void help() {
        System.out.println("XmlConfigurator -file  [-old]");
        System.out.println("(-old: converts old (plain-text) input format into new XML format)");
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy