ch.entwine.weblounge.common.impl.util.config.ConfigurationUtils.java Source code

Java tutorial

Introduction

Here is the source code for ch.entwine.weblounge.common.impl.util.config.ConfigurationUtils.java

Source

/*
 *  Weblounge: Web Content Management System
 *  Copyright (c) 2003 - 2011 The Weblounge Team
 *  http://entwinemedia.com/weblounge
 *
 *  This program 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
 *  of the License, or (at your option) any later version.
 *
 *  This program 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 program; if not, write to the Free Software Foundation
 *  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

package ch.entwine.weblounge.common.impl.util.config;

import ch.entwine.weblounge.common.Times;
import ch.entwine.weblounge.common.site.Environment;
import ch.entwine.weblounge.common.site.Module;
import ch.entwine.weblounge.common.site.Site;

import org.apache.commons.lang.StringUtils;
import org.w3c.dom.Node;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Utility class used to handle parameters from configuration files.
 */
public final class ConfigurationUtils {

    /**
     * This class is not intended to be instantiated.
     */
    private ConfigurationUtils() {
        // Nothing to be done here
    }

    /**
     * Returns <code>object</code> if it is not <code>null</code>,
     * <code>defaultObject</code> otherwise.
     * <p>
     * Note that this method will try to process templates that are contained in
     * either one of <code>object</code> or <code>defaultObject</code>.
     * 
     * @param object
     *          the object to use if not <code>null</code>
     * @param defaultObject
     *          the default object to use if <code>object</code> is
     *          <code>null</code>
     * @return <code>object</code> if it is not <code>null</code>,
     *         <code>defaultObject</code> otherwise
     */
    public static Object getValue(Object object, Object defaultObject) {
        return getValue(object, defaultObject, true);
    }

    /**
     * Returns <code>object</code> if it is not <code>null</code>,
     * <code>defaultObject</code> otherwise.
     * 
     * @param object
     *          the object to use if not <code>null</code>
     * @param defaultObject
     *          the default object to use if <code>object</code> is
     *          <code>null</code>
     * @param processTemplates
     *          <code>true</code> to process templates
     * @return <code>object</code> if it is not <code>null</code>,
     *         <code>defaultObject</code> otherwise
     */
    public static Object getValue(Object object, Object defaultObject, boolean processTemplates) {
        Object o = object != null ? object : defaultObject;
        if (processTemplates && o instanceof String)
            return processTemplate((String) o);
        else
            return o;
    }

    /**
     * Returns the <code>int</code> value or <code>defaultValue</code> if
     * <code>value</code> is either <code>null</code> or blank.
     * 
     * @param value
     *          the value as a string
     * @param defaultValue
     *          the default value
     * @return the value
     * @throws NumberFormatException
     *           if <code>value</code> can't be parsed into an <code>int</code>
     */
    public static int getValue(String value, int defaultValue) throws NumberFormatException {
        if (StringUtils.isBlank(value))
            return defaultValue;
        return Integer.parseInt(value);
    }

    /**
     * Returns the <code>long</code> value or <code>defaultValue</code> if
     * <code>value</code> is either <code>null</code> or blank.
     * 
     * @param value
     *          the value as a string
     * @param defaultValue
     *          the default value
     * @return the value
     * @throws NumberFormatException
     *           if <code>value</code> can't be parsed into a <code>long</code>
     */
    public static long getValue(String value, long defaultValue) throws NumberFormatException {
        if (StringUtils.isBlank(value))
            return defaultValue;
        return Long.parseLong(value);
    }

    /**
     * Returns the single option values as a <code>String[]</code> array. The
     * values are expected to be separated by either comma, semicolon or space
     * characters.
     * 
     * @param optionValue
     *          the option value
     * @return the values
     */
    public static String[] getMultiOptionValues(String optionValue) {
        if (optionValue == null) {
            return new String[] {};
        }
        List<String> values = new ArrayList<String>();
        StringTokenizer tok = new StringTokenizer(optionValue, " ,;");
        while (tok.hasMoreTokens()) {
            values.add(tok.nextToken());
        }
        return values.toArray(new String[values.size()]);
    }

    /**
     * Returns <code>true</code> if the node contains an attribute named
     * <tt>default</tt> with a value that corresponds to any of:
     * <ul>
     * <li>true</li>
     * <li>on</li>
     * <li>yes</li>
     * </ul>
     * 
     * @param value
     *          the value to test
     * @return <code>true</code> if the value can be interpreted as
     *         <code>true</code>
     */
    public static boolean isDefault(Node node) {
        if (node == null)
            return false;
        Node defaultAttribute = node.getAttributes().getNamedItem("default");
        if (defaultAttribute == null || defaultAttribute.getNodeValue() == null)
            return false;
        return isTrue(defaultAttribute.getNodeValue());
    }

    /**
     * Returns <code>true</code> if the lowercase and trimmed value is not
     * <code>null</code> and corresponds to any of:
     * <ul>
     * <li>true</li>
     * <li>on</li>
     * <li>yes</li>
     * </ul>
     * 
     * @param value
     *          the value to test
     * @return <code>true</code> if the value can be interpreted as
     *         <code>true</code>
     */
    public static boolean isTrue(Node node) {
        if (node == null || node.getNodeValue() == null)
            return false;
        return isTrue(node.getNodeValue());
    }

    /**
     * Returns <code>true</code> if the lowercase and trimmed value is not
     * <code>null</code> and corresponds to any of:
     * <ul>
     * <li>true</li>
     * <li>on</li>
     * <li>yes</li>
     * </ul>
     * 
     * @param value
     *          the value to test
     * @return <code>true</code> if the value can be interpreted as
     *         <code>true</code>
     */
    public static boolean isTrue(String value) {
        return isTrue(value, false);
    }

    /**
     * Returns <code>true</code> if the lowercase and trimmed value is not
     * <code>null</code> and corresponds to any of:
     * <ul>
     * <li>true</li>
     * <li>on</li>
     * <li>yes</li>
     * </ul>
     * If <code>value</code> is either <code>null</code> or blank,
     * <code>defaultValue</code> is returned.
     * 
     * @param value
     *          the value to test
     * @param defaultValue
     *          the default value if <code>value</code> is blank
     * @return <code>true</code> if the value can be interpreted as
     *         <code>true</code>
     */
    public static boolean isTrue(String value, boolean defaultValue) {
        if (StringUtils.isBlank(value))
            return defaultValue;
        value = value.trim().toLowerCase();
        return "true".equals(value) || "on".equals(value) || "yes".equals(value);
    }

    /**
     * Returns <code>true</code> if the lowercase and trimmed value is not
     * <code>null<code> and corresponds to any of:
     * <ul>
     * <li>true</li>
     * <li>on</li>
     * <li>yes</li>
     * </ul>
     * 
     * @param value
     *          the value to test
     * @return <code>true</code> if the value can be interpreted as
     *         <code>true</code>
     */
    public static boolean isFalse(String value) {
        return isFalse(value, false);
    }

    /**
     * Returns <code>true</code> if the lowercase and trimmed value is not
     * <code>null<code> and corresponds to any of:
     * <ul>
     * <li>true</li>
     * <li>on</li>
     * <li>yes</li>
     * </ul>
     * If <code>value</code> is either <code>null</code> or blank,
     * <code>defaultValue</code> is returned.
     * 
     * @param value
     *          the value to test
     * @param defaultValue
     *          the default value if <code>value</code> is blank
     * @return <code>true</code> if the value can be interpreted as
     *         <code>true</code>
     */
    public static boolean isFalse(String value, boolean defaultValue) {
        if (value == null)
            return defaultValue;
        value = value.trim().toLowerCase();
        return "false".equals(value) || "off".equals(value) || "no".equals(value);
    }

    /**
     * Returns <code>true</code> if the lowercase and trimmed value is not
     * <code>null</code> and corresponds to any of:
     * <ul>
     * <li>active</li>
     * <li>enabled</li>
     * <li>on</li>
     * </ul>
     * 
     * @param value
     *          the value to test
     * @return <code>true</code> if the value can be interpreted as
     *         <code>enabled</code>
     */
    public static boolean isEnabled(String value) {
        return isEnabled(value, false);
    }

    /**
     * Returns <code>true</code> if the lowercase and trimmed value is not
     * <code>null</code> and corresponds to any of:
     * <ul>
     * <li>active</li>
     * <li>enabled</li>
     * <li>on</li>
     * </ul>
     * If <code>value</code> is either <code>null</code> or blank,
     * <code>defaultValue</code> is returned.
     * 
     * @param value
     *          the value to test
     * @param defaultValue
     *          the default value if <code>value</code> is blank
     * @return <code>true</code> if the value can be interpreted as
     *         <code>enabled</code>
     */
    public static boolean isEnabled(String value, boolean defaultValue) {
        if (value == null)
            return defaultValue;
        value = value.trim().toLowerCase();
        return "active".equals(value) || "enabled".equals(value) || "on".equals(value);
    }

    /**
     * Returns <code>true</code> if the lowercase and trimmed value is not
     * <code>null<code> and corresponds to any of:
     * <ul>
     * <li>inactive</li>
     * <li>disabled</li>
     * <li>off</li>
     * </ul>
     * 
     * @param value
     *          the value to test
     * @return <code>true</code> if the value can be interpreted as
     *         <code>true</code>
     */
    public static boolean isDisabled(String value) {
        return isDisabled(value, false);
    }

    /**
     * Returns <code>true</code> if the lowercase and trimmed value is not
     * <code>null<code> and corresponds to any of:
     * <ul>
     * <li>inactive</li>
     * <li>disabled</li>
     * <li>off</li>
     * </ul>
     * If <code>value</code> is either <code>null</code> or blank,
     * <code>defaultValue</code> is returned.
     * 
     * @param value
     *          the value to test
     * @param defaultValue
     *          the default value if <code>value</code> is blank
     * @return <code>true</code> if the value can be interpreted as
     *         <code>true</code>
     */
    public static boolean isDisabled(String value, boolean defaultValue) {
        if (value == null)
            return defaultValue;
        value = value.trim().toLowerCase();
        return "inactive".equals(value) || "disabled".equals(value) || "off".equals(value);
    }

    /**
     * Returns the string representation of the given duration in milliseconds.
     * The string follows the pattern <code>ymwdHMS</code>, with the following
     * meanings:
     * <ul>
     * <li><b>y</b> - years</li>
     * <li><b>m</b> - months</li>
     * <li><b>w</b> - weeks</li>
     * <li><b>d</b> - days</li>
     * <li><b>H</b> - hours</li>
     * <li><b>M</b> - minutes</li>
     * <li><b>S</b> - seconds</li>
     * </ul>
     * Therefore, an example representing 1 week, 3 days and 25 minutes would
     * result in <code>1w3d25M</code>.
     * 
     * @param millis
     *          the duration in milliseconds
     * @return the duration as a human readable string
     */
    public static String toHumanReadableDuration(long millis) {
        return toDuration(millis, true);
    }

    /**
     * Returns the string representation of the given duration in milliseconds.
     * The string follows the pattern <code>ymwdHMS</code>, with the following
     * meanings:
     * <ul>
     * <li><b>y</b> - years</li>
     * <li><b>m</b> - months</li>
     * <li><b>w</b> - weeks</li>
     * <li><b>d</b> - days</li>
     * <li><b>H</b> - hours</li>
     * <li><b>M</b> - minutes</li>
     * <li><b>S</b> - seconds</li>
     * </ul>
     * Therefore, an example representing 1 week, 3 days and 25 minutes would
     * result in <code>1w3d25M</code>.
     * 
     * @param millis
     *          the duration in milliseconds
     * @return the duration as a human readable string
     */
    public static String toDuration(long millis) {
        return toDuration(millis, false);
    }

    /**
     * Returns the string representation of the given duration in milliseconds.
     * The string follows the pattern <code>ymwdHMS</code>, with the following
     * meanings:
     * <ul>
     * <li><b>y</b> - years</li>
     * <li><b>m</b> - months</li>
     * <li><b>w</b> - weeks</li>
     * <li><b>d</b> - days</li>
     * <li><b>H</b> - hours</li>
     * <li><b>M</b> - minutes</li>
     * <li><b>S</b> - seconds</li>
     * </ul>
     * Therefore, an example representing 1 week, 3 days and 25 minutes would
     * result in <code>1w3d25M</code>.
     * 
     * @param millis
     *          the duration in milliseconds
     * @param humanReadable
     *          <code>true</code> to generate human readable output
     * @return the duration as a human readable string
     */
    private static String toDuration(long millis, boolean humanReadable) {
        StringBuffer result = new StringBuffer();
        long v = 0;

        // Years
        if (millis >= Times.MS_PER_YEAR) {
            v = millis / Times.MS_PER_YEAR;
            millis -= v * Times.MS_PER_YEAR;
            result.append(v).append(humanReadable ? " years " : "y");
        }

        // Months
        if (millis >= Times.MS_PER_MONTH) {
            v = millis / Times.MS_PER_MONTH;
            millis -= v * Times.MS_PER_MONTH;
            result.append(v).append(humanReadable ? " months " : "m");
        }

        // Weeks
        if (millis >= Times.MS_PER_WEEK) {
            v = millis / Times.MS_PER_WEEK;
            millis -= v * Times.MS_PER_WEEK;
            result.append(v).append(humanReadable ? " weeks " : "w");
        }

        // Days
        if (millis >= Times.MS_PER_DAY) {
            v = millis / Times.MS_PER_DAY;
            millis -= v * Times.MS_PER_DAY;
            result.append(v).append(humanReadable ? " days " : "d");
        }

        // Hours
        if (millis >= Times.MS_PER_HOUR) {
            v = millis / Times.MS_PER_HOUR;
            millis -= v * Times.MS_PER_HOUR;
            result.append(v).append(humanReadable ? " hours " : "H");
        }

        // Minutes
        if (millis >= Times.MS_PER_MIN) {
            v = millis / Times.MS_PER_MIN;
            millis -= v * Times.MS_PER_MIN;
            result.append(v).append(humanReadable ? " minutes " : "M");
        }

        // Seconds
        if (millis >= Times.MS_PER_SECOND) {
            v = millis / Times.MS_PER_SECOND;
            millis -= v * Times.MS_PER_SECOND;
            result.append(v).append(humanReadable ? " seconds " : "S");
        }

        // Cleanup
        if (millis > 0) {
            result.append(millis);
            result.append(v).append(humanReadable ? " milliseconds" : "");
        } else if (result.length() == 0)
            result.append("0");

        return result.toString().trim();
    }

    /**
     * Parses <code>duration</code> to determine the number of milliseconds that
     * it represents. <code>duration</code> may either be a <code>Long</code>
     * value or a duration encoded using the following characters:
     * <ul>
     * <li><b>y</b> - years</li>
     * <li><b>m</b> - months</li>
     * <li><b>w</b> - weeks</li>
     * <li><b>d</b> - days</li>
     * <li><b>H</b> - hours</li>
     * <li><b>M</b> - minutes</li>
     * <li><b>S</b> - seconds</li>
     * </ul>
     * Therefore, an example representing 1 week, 3 days and 25 minutes would
     * result in <code>1w3d25m</code>.
     * 
     * @param duration
     *          the duration either in milliseconds or encoded
     * @return the duration in milliseconds
     * @throws IllegalArgumentException
     *           if the duration cannot be parsed
     */
    public static long parseDuration(String duration) throws IllegalArgumentException {
        if (duration == null)
            return 0;
        long millis = 0;
        try {
            return Long.parseLong(duration);
        } catch (NumberFormatException e) {
            Pattern p = Pattern.compile("^([\\d]+y)?([\\d]+m)?([\\d]+w)?([\\d]+d)?([\\d]+H)?([\\d]+M)?([\\d]+S)?$");
            Matcher m = p.matcher(duration);
            if (m.matches()) {
                for (int i = 1; i <= m.groupCount(); i++) {
                    String match = m.group(i);
                    if (match == null)
                        continue;
                    if (match.endsWith("y"))
                        millis += Long.parseLong(match.substring(0, match.length() - 1)) * Times.MS_PER_YEAR;
                    if (match.endsWith("m"))
                        millis += Long.parseLong(match.substring(0, match.length() - 1)) * Times.MS_PER_MONTH;
                    if (match.endsWith("w"))
                        millis += Long.parseLong(match.substring(0, match.length() - 1)) * Times.MS_PER_WEEK;
                    if (match.endsWith("d"))
                        millis += Long.parseLong(match.substring(0, match.length() - 1)) * Times.MS_PER_DAY;
                    if (match.endsWith("H"))
                        millis += Long.parseLong(match.substring(0, match.length() - 1)) * Times.MS_PER_HOUR;
                    if (match.endsWith("M"))
                        millis += Long.parseLong(match.substring(0, match.length() - 1)) * Times.MS_PER_MIN;
                    if (match.endsWith("S"))
                        millis += Long.parseLong(match.substring(0, match.length() - 1)) * Times.MS_PER_SECOND;
                }
            } else {
                throw new IllegalArgumentException("Unknown duration format: " + duration);
            }
        }
        return millis;
    }

    /**
     * Processes the given text by replacing placeholders in the form of
     * <code>${key}</code> with their actual values as found in the system
     * properties, e. g.
     * <ul>
     * <li><code>${java.io.tmpdir}</code> becomes <code>/tmp</li>
     * </ul>
     * 
     * @param text
     *          the text to process
     * @return the processed text
     */
    public static String processTemplate(String text) {
        if (text.indexOf("${") >= 0 && text.indexOf("}") > 2) {
            Map<Object, Object> systemProperties = new HashMap<Object, Object>(System.getProperties());
            for (Entry<Object, Object> entry : systemProperties.entrySet()) {
                String variable = "\\$\\{" + (String) entry.getKey() + "\\}";
                String replacement = (String) entry.getValue();
                text = text.replaceAll(variable, replacement);
            }
            Map<String, String> systemEnv = new HashMap<String, String>(System.getenv());
            for (Entry<String, String> entry : systemEnv.entrySet()) {
                String variable = "\\$\\{" + entry.getKey() + "\\}";
                String replacement = entry.getValue();
                text = text.replaceAll(variable, replacement);
            }
        }
        return text;
    }

    /**
     * Processes the given text by replacing these placeholders with their actual
     * values:
     * <ul>
     * <li><code>file://${site.root}</code> with
     * <code>http://&lt;servername&gt;/weblounge-sites/&lt;sitegt;</li>
     * </ul>
     * 
     * @param text
     *          the text to process
     * @param variables
     *          keys and values to replace with
     * @return the processed text
     */
    public static String processTemplate(String text, Map<String, String> variables) {
        text = processTemplate(text);
        for (Map.Entry<String, String> entry : variables.entrySet()) {
            String find = "\\$\\{" + entry.getKey() + "\\}";
            String replace = entry.getValue();
            text = text.replaceAll(find, replace);
        }
        return text;
    }

    /**
     * Processes the given text by replacing these placeholders with their actual
     * values:
     * <ul>
     * <li><code>file://${site.root}</code> with
     * <code>http://&lt;servername&gt;/weblounge-sites/&lt;sitegt;</li>
     * <li><code>file://${module.root}</code> with
     * <code>http://&lt;servername&gt;/weblounge-sites/&lt;sitegt;/modules/&lt;module&gt;</code>
     * </li>
     * </ul>
     * 
     * @param text
     *          the text to process
     * @param module
     *          the module
     * @param environment
     *          the environment
     * @return the processed text
     */
    public static String processTemplate(String text, Module module, Environment environment) {
        text = processTemplate(text);

        Map<String, String> replacements = new HashMap<String, String>();
        Site site = module.getSite();

        // ${site.root}
        StringBuffer siteRootReplacement = new StringBuffer();
        siteRootReplacement.append(site.getHostname(environment).toExternalForm());
        siteRootReplacement.append("/weblounge-sites/").append(site.getIdentifier());
        replacements.put("file://\\$\\{site.root\\}", siteRootReplacement.toString());

        // ${module.root}
        StringBuffer moduleRootReplacement = new StringBuffer(siteRootReplacement);
        moduleRootReplacement.append("/modules/").append(module.getIdentifier());
        replacements.put("file://\\$\\{module.root\\}", moduleRootReplacement.toString());

        // Site options
        for (String option : site.getOptionNames()) {
            String value = site.getOptionValue(option);
            replacements.put("\\$\\{" + option + "\\}", value);
        }

        // Replace with whatever is available
        for (Map.Entry<String, String> entry : replacements.entrySet()) {
            text = text.replaceAll(entry.getKey(), entry.getValue());
        }

        return text;
    }

    /**
     * Processes the given text by replacing these placeholders with their actual
     * values:
     * <ul>
     * <li><code>file://${site.root}</code> with
     * <code>http://&lt;servername&gt;/weblounge-sites/&lt;sitegt;</li>
     * </li>
     * </ul>
     * 
     * @param text
     *          the text to process
     * @param site
     *          the site
     * @param environment
     *          the environment
     * @return the processed text
     */
    public static String processTemplate(String text, Site site, Environment environment) {
        text = processTemplate(text);

        Map<String, String> replacements = new HashMap<String, String>();

        // ${site.root}
        StringBuffer siteRootReplacement = new StringBuffer();
        siteRootReplacement.append(site.getHostname(environment).toExternalForm());
        siteRootReplacement.append("/weblounge-sites/").append(site.getIdentifier());
        replacements.put("file://\\$\\{site.root\\}", siteRootReplacement.toString());

        // Site options
        for (String option : site.getOptionNames()) {
            String value = site.getOptionValue(option);
            replacements.put("\\$\\{" + option + "\\}", value);
        }

        // Replace with whatever is available
        for (Map.Entry<String, String> entry : replacements.entrySet()) {
            text = text.replaceAll(entry.getKey(), entry.getValue());
        }

        return text;
    }

}