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

org.fuin.kickstart4j.ConfigParser Maven / Gradle / Ivy

/**
 * Copyright (C) 2009 Future Invent Informationsmanagement GmbH. All rights
 * reserved. 
 *
 * This library 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 3 of the License, or (at your option) any
 * later version.
 *
 * This library 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 library. If not, see .
 */
package org.fuin.kickstart4j;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.io.Reader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.fuin.utils4j.Utils4J;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

/**
 * Parses a XML configuration.
 */
public final class ConfigParser {

    private final ConfigHandler handler;

    /**
     * Default constructor.
     */
    public ConfigParser() {
        super();
        handler = new ConfigHandler();
    }

    /**
     * Starts the parsing process.
     * 
     * @param url
     *            URL of the XML configuration file.
     * 
     * @throws InvalidConfigException
     *             Error parsing the configuration.
     */
    public void parse(final URL url) throws InvalidConfigException {
        try {
            final String encoding = parseEncoding(url);
            final SAXParserFactory factory = SAXParserFactory.newInstance();
            factory.setValidating(false);
            final SAXParser saxParser = factory.newSAXParser();
            final Reader reader = new BufferedReader(new InputStreamReader(url.openStream(),
                    encoding));
            try {
                saxParser.parse(new InputSource(reader), handler);
            } finally {
                reader.close();
            }
        } catch (final SAXException e) {
            throw new InvalidConfigException(url, e);
        } catch (final ParserConfigurationException e) {
            throw new InvalidConfigException(url, e);
        } catch (final IOException e) {
            throw new InvalidConfigException(url, e);
        }
    }

    /**
     * Determines the encoding from the
     * "<?xml version="1.0" encoding="UTF-8"?>" header in the documents. If
     * no encoding is found within the first three lines "UTF-8" is returned.
     * 
     * @param url
     *            URL with the XML document.
     * 
     * @return Encoding attribute.
     * 
     * @throws InvalidConfigException
     *             Error reading the XML document.
     */
    private String parseEncoding(final URL url) throws InvalidConfigException {
        try {
            String encoding = "UTF-8";
            final LineNumberReader reader = new LineNumberReader(new BufferedReader(
                    new InputStreamReader(url.openStream())));
            try {
                final StringBuffer sb = new StringBuffer();
                int count = 1;
                String line;
                while (((line = reader.readLine()) != null) && (count < 3)) {
                    sb.append(line);
                    count++;                    
                }
                final int start = sb.indexOf("encoding=\"");
                if (start > -1) {
                    final int end = sb.indexOf("\"", start + 10);
                    if (end > -1) {
                        encoding = sb.substring(start + 10, end);
                    }
                }
            } finally {
                reader.close();
            }
            return encoding;

        } catch (final IOException e) {
            throw new InvalidConfigException(url, e);
        }
    }

    /**
     * Copies the values from the handler into the config.
     * 
     * @param config
     *            Configuration to use.
     * 
     * @throws InvalidConfigException
     *             Error copying the values.
     */
    public void copyToConfig(final Config config) throws InvalidConfigException {

        final List elements = handler.getElements();
        for (int i = 0; i < elements.size(); i++) {
            final ConfigElement element = (ConfigElement) elements.get(i);
            if (element.getName().equals("file")) {
                final Map atts = element.getAttributes();
                final String path = (String) atts.get("path");
                checkNotNull(element, "path", path);
                final String file = (String) atts.get("file");
                checkNotNull(element, "file", file);
                final String hash = (String) atts.get("hash");
                checkNotNull(element, "hash", hash);
                final String size = (String) atts.get("size");
                checkNotNull(element, "size", size);
                final boolean unzip = getBoolean(atts, "unzip", false);
                final boolean loadAlways = getBoolean(atts, "loadAlways", false);
                final boolean addToClasspath = getBoolean(atts, "addToClasspath", false);
                final String srcFileUrl = (String) atts.get("srcFileUrl");
                checkNotNull(element, "srcFileUrl", srcFileUrl);
                final int order = getInteger(atts, "order", 0);
                config.getSrcFiles().add(
                        new SrcFile(path, file, hash, Long.valueOf(size).longValue(), unzip,
                                loadAlways, addToClasspath, srcFileUrl, order));
            } else if (element.getName().equals("mkdir")) {
                final Map atts = element.getAttributes();
                final String path = (String) atts.get("path");
                checkNotNull(element, "path", path);
                config.getMkDirs().add(new MkDir(path));
            } else if (element.getName().equals("dir")) {
                final Map atts = element.getAttributes();
                final String path = (String) atts.get("path");
                checkNotNull(element, "path", path);
                final String srcPathUrl = (String) atts.get("srcPathUrl");
                checkNotNull(element, "srcPathUrl", srcPathUrl);
                config.getSrcDirs().add(new SrcDir(path, srcPathUrl));
            } else {
                put(config, element.getName(), element.getText());
            }
        }

    }

    /**
     * Set a property in the configuration by it's name. If the key is not known
     * it is ignored.
     * 
     * @param config
     *            Configuration to populate.
     * @param key
     *            Name of the property.
     * @param value
     *            Value of the property.
     */
    // CHECKSTYLE:OFF Cyclomatic Complexity is OK here...
    public final void put(final Config config, final String key, final String value) {
        if (key.equals("title")) {
            config.setTitle(value);
        } else if (key.equals("vendor")) {
            config.setVendor(value);
        } else if (key.equals("description")) {
            config.setDescription(value);
        } else if (key.equals("exitAfterExecute")) {
            config.setExitAfterExecute(toBoolean(value));
        } else if (key.equals("destPath")) {
            config.setDestPath(value);
        } else if (key.equals("idFilename")) {
            config.setIdFilename(value);
        } else if (key.equals("silentInstall")) {
            config.setSilentInstall(toBoolean(value));
        } else if (key.equals("silentUpdate")) {
            config.setSilentUpdate(toBoolean(value));
        } else if (key.equals("locale")) {
            config.setLocale(value);
        } else if (key.equals("lazyLoading")) {
            config.setLazyLoading(toBoolean(value));
        } else if (key.equals("showStartFrame")) {
            config.setShowStartFrame(toBoolean(value));
        } else if (key.equals("startFrameDelaySeconds")) {
            config.setStartFrameDelaySeconds(toInt(value));
        } else if (key.equals("javaExe")) {
            config.setJavaExe(value);
        } else if (key.equals("javaArgs")) {
            config.setJavaArgs(value);
        } else if (key.equals("version")) {
            config.setVersion(value);
        } else if (key.equals("msgFileUrl")) {
            config.setMsgFileUrl(value);
        } else if (key.equals("logFilename")) {
            config.setLogFilename(value);
        } else if (key.equals("lookAndFeelClassName")) {
            config.setLookAndFeelClassName(value);
        } else if (key.equals("xmlEncoding")) {
            config.setXmlEncoding(value);
        }
    }

    // CHECKSTYLE:ON

    private boolean toBoolean(final String str) {
        if (str == null) {
            return false;
        }
        final String trimmed = str.trim();
        if (trimmed.length() == 0) {
            return false;
        }
        return Boolean.valueOf(trimmed).booleanValue();
    }

    private int toInt(final String str) {
        if (str == null) {
            return 0;
        }
        final String trimmed = str.trim();
        if (trimmed.length() == 0) {
            return 0;
        }
        return Integer.valueOf(trimmed).intValue();
    }

    private static void checkNotNull(final ConfigElement element, final String attrName,
            final String attrValue) throws InvalidConfigException {
        if (attrValue == null) {
            throw new InvalidConfigException("Element '" + element.getName()
                    + "' missing required attribute '" + attrName + "'!");
        }
    }

    private static boolean getBoolean(final Map atts, final String key, final boolean defaultValue) {
        final String value = (String) atts.get(key);
        if (value == null) {
            return defaultValue;
        }
        final String str = value.trim();
        if (str.length() == 0) {
            return defaultValue;
        }
        return Boolean.valueOf(str).booleanValue();
    }

    private static int getInteger(final Map atts, final String key, final int defaultValue) {
        final String value = (String) atts.get(key);
        if (value == null) {
            return defaultValue;
        }
        final String str = value.trim();
        if (str.length() == 0) {
            return defaultValue;
        }
        return Integer.valueOf(str).intValue();
    }

    /**
     * Element in the configuration.
     */
    private static final class ConfigElement {

        private final String name;

        private final Map attributes;

        private String text = null;

        public ConfigElement(final String name, final Attributes atts) {
            super();

            this.name = name;
            this.attributes = new HashMap();

            final int length = atts.getLength();
            for (int i = 0; i < length; i++) {
                attributes.put(atts.getQName(i), atts.getValue(i));
            }
        }

        public final Map getAttributes() {
            return attributes;
        }

        public final String getName() {
            return name;
        }

        public final String getText() {
            return text;
        }

        public final void setText(final String text) {
            if (text == null) {
                this.text = null;
            } else {
                this.text = text.trim();
                if (this.text.length() == 0) {
                    this.text = null;
                }
            }
        }

        public String toString() {
            final StringBuffer sb = new StringBuffer();
            sb.append(name);
            sb.append("=");
            sb.append(text);
            sb.append(" {");
            int count = 0;
            final Iterator it = attributes.keySet().iterator();
            while (it.hasNext()) {
                final String key = (String) it.next();
                final String value = (String) attributes.get(key);
                if (count > 0) {
                    sb.append(", ");
                }
                sb.append(key);
                sb.append("=");
                sb.append(value);
                count++;
            }
            sb.append("}");
            return sb.toString();
        }

    }

    /**
     * Handler for parsing the XML.
     */
    private static class ConfigHandler extends DefaultHandler {

        private final List elements = new ArrayList();

        private ConfigElement element = null;

        private int level = 0;

        public void startElement(final String uri, final String localName, final String qName,
                final Attributes atts) throws SAXException {

            if (level == 1) {
                element = new ConfigElement(qName, atts);
                elements.add(element);
            }
            level++;

        }

        public void characters(final char[] ch, final int start, final int length)
                throws SAXException {
            if ((level == 2) && (element != null)) {
                element.setText(String.copyValueOf(ch, start, length));
            }
        }

        public void endElement(final String uri, final String localName, final String qName)
                throws SAXException {
            if (level == 1) {
                element = null;
            }
            level--;
        }

        public List getElements() {
            return elements;
        }

    }

    /**
     * Fills an object from an XML configuration file.
     * 
     * @param config
     *            Configuration to populate.
     * @param configFile
     *            Configuration file.
     * 
     * @throws InvalidConfigException
     *             Error reading the file.
     */
    public static void parse(final Config config, final File configFile)
            throws InvalidConfigException {
        Utils4J.checkNotNull("config", config);
        Utils4J.checkNotNull("configFile", configFile);
        Utils4J.checkValidFile(configFile);
        try {
            parse(config, configFile.toURI().toURL());
        } catch (final MalformedURLException ex) {
            throw new RuntimeException("Error creating file URL '" + configFile + "'!", ex);
        }
    }

    /**
     * Fills an object from an XML configuration file.
     * 
     * @param config
     *            Configuration to populate.
     * @param configFileURL
     *            URL of the configuration file.
     * 
     * @throws InvalidConfigException
     *             Error reading the file.
     */
    public static void parse(final Config config, final URL configFileURL)
            throws InvalidConfigException {

        Utils4J.checkNotNull("config", config);
        Utils4J.checkNotNull("configFileURL", configFileURL);

        final ConfigParser parser = new ConfigParser();
        parser.parse(configFileURL);
        parser.copyToConfig(config);

    }

    /**
     * Creates an object from a XML configuration file.
     * 
     * @param configFileURL
     *            URL of the configuration file.
     * 
     * @return Configuration filled with values from the file.
     * 
     * @throws InvalidConfigException
     *             Error reading the file.
     */
    public static Config create(final URL configFileURL) throws InvalidConfigException {
        Utils4J.checkNotNull("configFileURL", configFileURL);
        final Config config = new Config();
        parse(config, configFileURL);
        return config;
    }

    /**
     * Creates an object from a XML configuration file.
     * 
     * @param configFile
     *            Configuration file.
     * 
     * @return Configuration filled with values from the file.
     * 
     * @throws InvalidConfigException
     *             Error reading the file.
     */
    public static Config create(final File configFile) throws InvalidConfigException {
        Utils4J.checkNotNull("configFile", configFile);
        Utils4J.checkValidFile(configFile);
        try {
            return create(configFile.toURI().toURL());
        } catch (final MalformedURLException ex) {
            throw new RuntimeException("Error creating file URL '" + configFile + "'!", ex);
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy