log4JToXml.xmlToProperties.XmlToLog4jConverterImpl.java Source code

Java tutorial

Introduction

Here is the source code for log4JToXml.xmlToProperties.XmlToLog4jConverterImpl.java

Source

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package log4JToXml.xmlToProperties;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.channels.FileChannel;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import javax.xml.stream.XMLEventFactory;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLEventWriter;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.XMLEvent;
import javax.xml.stream.util.EventReaderDelegate;
import javax.xml.transform.stream.StreamSource;
import org.apache.commons.io.FileUtils;
import org.dom4j.Document;
import org.apache.log4j.Logger;
import org.dom4j.DocumentException;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

/**
 * Converter log4j.xml to log4j.properties implementation
 *
 * @author xstefank
 * @version 1.0
 */
public class XmlToLog4jConverterImpl implements XmlToLog4jConverter {

    private static final Logger log = Logger.getLogger(XmlToLog4jConverterImpl.class);

    private File tempXML;
    private File tempDTD;
    private PrintStream documentStream;
    private Document doc;
    private Properties log4jProperties;

    /**
     * Constructor for basic converter, default settings
     *
     * @throws IOException if there is problem creating temporary file in project location
     */
    public XmlToLog4jConverterImpl() throws IOException {

        //needed for the order of the properties
        log4jProperties = new LinkedProperties();
        doc = null;

        tempXML = File.createTempFile("tempXML", ".xml");
        documentStream = new PrintStream(tempXML);

        InputStream initialStream = this.getClass().getResourceAsStream("/log4j.dtd");

        tempDTD = File.createTempFile("tempDTD", ".dtd");
        FileUtils.copyInputStreamToFile(initialStream, tempDTD);

    }

    @Override
    public void load(String filename) {

        if (filename == null) {
            throw new IllegalArgumentException("path cannot be null");
        }

        URL url = null;

        //add DTD declaration, fill temp file
        try {
            addDTDDeclaration(filename);
        } catch (XMLStreamException ex) {
            log.error("Error opening input file: " + filename, ex);
            throw new IllegalArgumentException("Invalid input: " + filename, ex);
        }

        try {
            url = tempXML.toURI().toURL();
        } catch (MalformedURLException ex) {
            log.error("Error transforming given filename to URL: " + filename, ex);
            throw new IllegalArgumentException("Invalid file name", ex);
        }

        try {
            doc = parse(url);
        } catch (DocumentException ex) {
            log.error("Error parsing input file: " + filename, ex);
            throw new IllegalArgumentException("Invalid input file content; Error parsing input file", ex);
        }
    }

    @Override
    public void convert() {

        if (doc == null) {
            throw new IllegalStateException("There is no loaded input to be converted");
        }

        processRoot();

        processRenderers();

        processAppenders();

        processCategories();

        processLoggers();

    }

    @Override
    public void convert(String filename) {

        load(filename);
        convert();
    }

    @Override
    public void saveTo(String filename) {

        if (filename == null) {
            throw new IllegalArgumentException("path cannot be null");
        }

        if (log4jProperties.isEmpty()) {
            throw new IllegalStateException("There are no converted properties to be saved");
        }

        try (PrintStream output = new PrintStream(new FileOutputStream(filename, false))) {

            log4jProperties.list(output);

        } catch (FileNotFoundException ex) {
            log.error("Directory not found; Invalid path", ex);
            throw new IllegalArgumentException("Directory not found; Invalid path", ex);
        }

    }

    @Override
    public void convertAndSave(String inputFileName, String outputFileName) {

        load(inputFileName);
        convert();
        saveTo(outputFileName);

    }

    private void processRoot() {
        //root node parsing, root element is optional
        Node rootNode = doc.selectSingleNode("/log4j:configuration/root");

        if (rootNode != null) {

            String rootContent = "";

            Node priority = rootNode.selectSingleNode("./priority | ./level");
            rootContent += priority.valueOf("@value").toUpperCase();

            //appenders refernces
            List<Node> appendersRefs = rootNode.selectNodes("./appender-ref");
            for (Node appender : appendersRefs) {
                rootContent += ", " + appender.valueOf("@ref");
            }

            String rootName = "log4j.rootLogger";
            log4jProperties.setProperty(rootName, rootContent);

            //root params
            List<Node> rootParams = rootNode.selectNodes("./param");

            if (!rootParams.isEmpty()) {
                for (Node param : rootParams) {
                    log4jProperties.setProperty(rootName + "." + param.valueOf("@name"), param.valueOf("@value"));
                }
            }

        }
    }

    private void processRenderers() {
        //renderer nodes, optional
        List<Node> rendererNodes = doc.selectNodes("/log4j:configuration/renderer");

        if (!rendererNodes.isEmpty()) {
            for (Node renderer : rendererNodes) {
                log4jProperties.setProperty("log4j.renderer." + renderer.valueOf("@renderedClass"),
                        renderer.valueOf("@renderingClass"));
            }
        }
    }

    private void processAppenders() {
        //appender nodes, optional
        List<Node> appenderNodes = doc.selectNodes("/log4j:configuration/appender");

        if (!appenderNodes.isEmpty()) {

            String appenderName = null;

            for (Node appender : appenderNodes) {
                appenderName = "log4j.appender." + appender.valueOf("@name");

                log4jProperties.setProperty(appenderName, appender.valueOf("@class"));

                //errorHandler, optional 0-1
                Node errorHandler = appender.selectSingleNode("./errorHandler");

                if (errorHandler != null) {

                    String errorHandlerName = appenderName + ".errorhandler";

                    log4jProperties.setProperty(errorHandlerName, errorHandler.valueOf("@class"));

                    //EH params, optional
                    List<Node> eHParams = errorHandler.selectNodes("./param");

                    if (!eHParams.isEmpty()) {
                        for (Node param : eHParams) {
                            log4jProperties.setProperty(errorHandlerName + "." + param.valueOf("@name"),
                                    param.valueOf("@value"));
                        }
                    }

                    //EH root-ref, 0-1
                    Node rootRef = errorHandler.selectSingleNode("./root-ref");

                    if (rootRef != null) {
                        log4jProperties.setProperty(errorHandlerName + ".root-ref", "true");
                    }

                    //EH logger-ref, optional
                    List<Node> eHLoggerRefs = errorHandler.selectNodes("./logger-ref");

                    if (!eHLoggerRefs.isEmpty()) {
                        String loggersRefValue = eHLoggerRefs.get(0).valueOf("@ref");

                        for (int i = 1; i < eHLoggerRefs.size(); i++) {
                            loggersRefValue += ", " + eHLoggerRefs.get(i).valueOf("@ref");
                        }

                        log4jProperties.setProperty(errorHandlerName + ".logger-ref", loggersRefValue);
                    }

                    //EH appender-ref, 0-1
                    Node appenderRef = errorHandler.selectSingleNode("./appender-ref");

                    if (appenderRef != null) {
                        log4jProperties.setProperty(errorHandlerName + ".appender-ref",
                                appenderRef.valueOf("@ref"));
                    }
                }

                //appender params, optional
                List<Node> appenderParams = appender.selectNodes("./param");

                if (!appenderParams.isEmpty()) {
                    for (Node param : appenderParams) {
                        log4jProperties.setProperty(appenderName + "." + param.valueOf("@name"),
                                param.valueOf("@value"));
                    }
                }

                //appender layout, 0-1
                Node appenderLayout = appender.selectSingleNode("./layout");

                if (appenderLayout != null) {
                    String appenderLayoutName = appenderName + ".layout";

                    log4jProperties.setProperty(appenderLayoutName, appenderLayout.valueOf("@class"));

                    //AL params, optional
                    List<Node> appenderLayoutParams = appenderLayout.selectNodes("./param");

                    if (!appenderLayoutParams.isEmpty()) {
                        for (Node param : appenderLayoutParams) {
                            log4jProperties.setProperty(appenderLayoutName + "." + param.valueOf("@name"),
                                    param.valueOf("@value"));
                        }
                    }
                }

                //appender filter, optional
                List<Node> appenderFilters = appender.selectNodes("./filter");

                if (!appenderFilters.isEmpty()) {
                    String appenderFilterName = "";
                    int filterCount = 0;

                    for (Node filter : appenderFilters) {
                        filterCount++;
                        appenderFilterName = appenderName + ".filter." + filterCount;

                        log4jProperties.setProperty(appenderFilterName, filter.valueOf("@class"));

                        //filter params, optional
                        List<Node> filterParams = filter.selectNodes("./param");

                        if (!filterParams.isEmpty()) {
                            for (Node param : filterParams) {
                                log4jProperties.setProperty(appenderFilterName + "." + param.valueOf("@name"),
                                        param.valueOf("@value"));
                            }
                        }
                    }
                }

                //appender appender-refs, optional
                List<Node> appenderAppenderRefs = appender.selectNodes("./appender-ref");

                if (!appenderAppenderRefs.isEmpty()) {
                    String appenderRefsValue = appenderAppenderRefs.get(0).valueOf("@ref");

                    for (int i = 1; i < appenderAppenderRefs.size(); i++) {
                        appenderRefsValue += ", " + appenderAppenderRefs.get(i).valueOf("@ref");
                    }

                    log4jProperties.setProperty(appenderName + ".appender-ref", appenderRefsValue);
                }
            }
        }
    }

    private void processCategories() {
        //category, optional
        List<Node> categoryNodes = doc.selectNodes("/log4j:configuration/category");

        if (!categoryNodes.isEmpty()) {
            for (Node category : categoryNodes) {

                String categoryContent = "";

                //(priority | level)?
                Node categoryPriority = category.selectSingleNode("./priority");
                Node categoryLevel = category.selectSingleNode("./level");

                if (categoryPriority != null) {
                    categoryContent += categoryPriority.valueOf("@value").toUpperCase();
                } else if (categoryLevel != null) {
                    categoryContent += categoryLevel.valueOf("@value").toUpperCase();
                }

                //appender-refs, optional
                List<Node> categoryAppenderRefs = category.selectNodes("./appender-ref");

                if (!categoryAppenderRefs.isEmpty()) {
                    for (Node appenderRef : categoryAppenderRefs) {
                        categoryContent += ", " + appenderRef.valueOf("@ref");
                    }
                }

                String categoryName = "log4j.category." + category.valueOf("@name");
                log4jProperties.setProperty(categoryName, categoryContent);

                //params, optional
                List<Node> categoryParams = category.selectNodes("./param");

                if (!categoryParams.isEmpty()) {
                    for (Node param : categoryParams) {
                        log4jProperties.setProperty(categoryName + "." + param.valueOf("@name"),
                                param.valueOf("@value"));
                    }
                }

                //category additivity
                if (category.valueOf("@additivity").equals("false")) {
                    log4jProperties.setProperty("log4j.additivity." + category.valueOf("@name"), "false");
                }
            }
        }
    }

    private void processLoggers() {
        //logger, optional
        List<Node> loggerNodes = doc.selectNodes("/log4j:configuration/logger");

        if (!loggerNodes.isEmpty()) {
            for (Node logger : loggerNodes) {

                String loggerContent = "";

                //level, 0-1
                Node loggerLevel = logger.selectSingleNode("./level");

                if (loggerLevel != null) {
                    loggerContent += loggerLevel.valueOf("@value").toUpperCase();
                }

                //appender-refs, optional
                List<Node> loggerAppenderRefs = logger.selectNodes("./appender-ref");

                if (!loggerAppenderRefs.isEmpty()) {
                    for (Node appenderRef : loggerAppenderRefs) {
                        loggerContent += ", " + appenderRef.valueOf("@ref");
                    }
                }

                String loggerName = "log4j.logger." + logger.valueOf("@name");
                log4jProperties.setProperty(loggerName, loggerContent);

                //logger additivity
                if (logger.valueOf("@additivity").equals("false")) {
                    log4jProperties.setProperty("log4j.additivity." + logger.valueOf("@name"), "false");
                }
            }
        }
    }

    private void addDTDDeclaration(String filename) throws XMLStreamException {
        XMLEventFactory eventFactory = XMLEventFactory.newInstance();
        XMLEvent dtd = eventFactory
                .createDTD("<!DOCTYPE log4j:configuration SYSTEM \"" + tempDTD.getAbsolutePath() + "\">");

        XMLInputFactory inFactory = XMLInputFactory.newInstance();
        XMLOutputFactory outFactory = XMLOutputFactory.newInstance();

        XMLEventReader reader = inFactory.createXMLEventReader(new StreamSource(filename));
        reader = new DTDReplacer(reader, dtd);
        XMLEventWriter writer = outFactory.createXMLEventWriter(documentStream);
        writer.add(reader);
        writer.flush();

        writer.close();
    }

    private Document parse(URL url) throws DocumentException {
        /*SAXReader reader = new SAXReader();
         Document document = reader.read(url);
         return document;*/

        SAXReader reader = new SAXReader();
        reader.setValidation(true);
        reader.setErrorHandler(new SimpleErrorHandler());
        return reader.read(url);
    }

    private static void copyFile(File sourceFile, File destFile) throws IOException {

        FileChannel source = null;
        FileChannel destination = null;

        try {
            source = new FileInputStream(sourceFile).getChannel();
            destination = new FileOutputStream(destFile).getChannel();
            destination.transferFrom(source, 0, source.size());
        } finally {
            if (source != null) {
                source.close();
            }
            if (destination != null) {
                destination.close();
            }
        }
    }

    private class SimpleErrorHandler implements ErrorHandler {

        public void warning(SAXParseException e) throws SAXException {
            log.warn(e.getMessage());
            throw new IllegalArgumentException("Invalid input file content; Error parsing input file", e);
        }

        public void error(SAXParseException e) throws SAXException {
            log.error(e.getMessage());
            throw new IllegalArgumentException("Invalid input file content; Error parsing input file", e);
        }

        public void fatalError(SAXParseException e) throws SAXException {
            log.fatal(e.getMessage());
            throw new IllegalArgumentException("Invalid input file content; Error parsing input file", e);
        }
    }

    private class DTDReplacer extends EventReaderDelegate {

        private final XMLEvent dtd;
        private boolean sendDtd = false;

        public DTDReplacer(XMLEventReader reader, XMLEvent dtd) {
            super(reader);
            if (dtd.getEventType() != XMLEvent.DTD) {
                throw new IllegalArgumentException("" + dtd);
            }
            this.dtd = dtd;
        }

        @Override
        public XMLEvent nextEvent() throws XMLStreamException {
            if (sendDtd) {
                sendDtd = false;
                return dtd;
            }
            XMLEvent evt = super.nextEvent();
            if (evt.getEventType() == XMLEvent.START_DOCUMENT) {
                sendDtd = true;
            } else if (evt.getEventType() == XMLEvent.DTD) {
                // discard old DTD
                return super.nextEvent();
            }
            return evt;
        }

    }

    private class LinkedProperties extends Properties {

        private Map<Object, Object> linkMap;

        public LinkedProperties() {
            linkMap = new LinkedHashMap<Object, Object>();
        }

        @Override
        public synchronized Object setProperty(String key, String value) {
            return linkMap.put(key, value);
        }

        @Override
        public void list(PrintStream out) {
            for (Object key : linkMap.keySet()) {
                out.println(key.toString() + "=" + linkMap.get(key));
            }
        }

        @Override
        public boolean isEmpty() {
            return linkMap.isEmpty();
        }

        //---------------------------
        @Override
        public synchronized Object put(Object key, Object value) {
            return linkMap.put(key, value);
        }

        @Override
        public synchronized boolean contains(Object value) {
            return linkMap.containsValue(value);
        }

        @Override
        public boolean containsValue(Object value) {
            return linkMap.containsValue(value);
        }

        @Override
        public synchronized Enumeration<Object> elements() {
            throw new UnsupportedOperationException(
                    "Enumerations are so old-school, don't use them, " + "use keySet() or entrySet() instead");
        }

        @Override
        public synchronized void clear() {
            linkMap.clear();
        }

        @Override
        public synchronized boolean containsKey(Object key) {
            return linkMap.containsKey(key);
        }

    }
}